@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.
- 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 +9 -1
- package/lib/glomo-checkout.d.ts.map +1 -1
- package/lib/glomo-checkout.js +14 -5
- package/lib/glomo-lrs-checkout.d.ts +3 -0
- package/lib/glomo-lrs-checkout.d.ts.map +1 -1
- package/lib/glomo-lrs-checkout.js +34 -11
- package/lib/glomo-standard-checkout.d.ts +4 -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 +67 -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 +5 -3
- package/lib/types/subscriptions-checkout.d.ts.map +1 -1
- package/lib/use-glomo-checkout.d.ts +2 -2
- package/lib/use-glomo-checkout.d.ts.map +1 -1
- package/lib/use-glomo-checkout.js +25 -4
- package/lib/use-lrs-checkout.d.ts +18 -6
- package/lib/use-lrs-checkout.d.ts.map +1 -1
- package/lib/use-lrs-checkout.js +330 -171
- package/lib/use-standard-checkout.d.ts +18 -13
- package/lib/use-standard-checkout.d.ts.map +1 -1
- package/lib/use-standard-checkout.js +282 -206
- 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 +13 -3
- 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 +28 -11
- package/src/glomo-lrs-checkout.tsx +49 -27
- package/src/glomo-standard-checkout.tsx +33 -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 +72 -6
- package/src/types/standard-checkout.ts +6 -6
- package/src/types/subscriptions-checkout.ts +9 -3
- package/src/use-glomo-checkout.tsx +32 -7
- package/src/use-lrs-checkout.tsx +684 -366
- package/src/use-standard-checkout.tsx +731 -465
- 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
|
@@ -8,14 +8,26 @@ const index_1 = require("./injections/index");
|
|
|
8
8
|
const segment_1 = require("./config/segment");
|
|
9
9
|
const base_1 = require("./config/base");
|
|
10
10
|
const validation_1 = require("./utils/validation");
|
|
11
|
+
const payment_payload_1 = require("./bridge/payment-payload");
|
|
12
|
+
const event_projections_1 = require("./utils/event-projections");
|
|
11
13
|
const device_compliance_1 = require("./utils/device-compliance");
|
|
14
|
+
const message_router_1 = require("./bridge/message-router");
|
|
15
|
+
const file_save_handler_1 = require("./bridge/file-save-handler");
|
|
16
|
+
const file_input_handler_1 = require("./bridge/file-input-handler");
|
|
17
|
+
const index_2 = require("./capabilities/index");
|
|
18
|
+
const use_capability_reporting_1 = require("./capabilities/use-capability-reporting");
|
|
19
|
+
const use_sdk_session_1 = require("./utils/use-sdk-session");
|
|
20
|
+
const use_permission_request_1 = require("./webview/use-permission-request");
|
|
12
21
|
const analytics_1 = require("./utils/analytics");
|
|
13
22
|
const checkout_1 = require("./types/checkout");
|
|
23
|
+
/** Log prefix for everything this flow emits */
|
|
24
|
+
const LOG_PREFIX = "[Glomo-RN-SDK Standard]";
|
|
14
25
|
/** The main SDK hook for the GlomoPay Standard Checkout flow */
|
|
15
|
-
function useStandardCheckout({ server, publicKey, orderId, onPaymentSuccess, onPaymentFailure, onConnectionError, onPaymentTerminate, onSdkError, onUserJourneyCompleted,
|
|
16
|
-
var _a;
|
|
26
|
+
function useStandardCheckout({ server, publicKey, orderId, onPaymentSuccess, onPaymentFailure, onConnectionError, onPaymentTerminate, onSdkError, onUserJourneyCompleted, onUserRefusedDevicePermissions, devMode = false, }, mockMode, internalOptions) {
|
|
27
|
+
var _a, _b;
|
|
17
28
|
// Resolving analytics trackers - defaults to standard, subscription flow overrides
|
|
18
29
|
const trackers = (_a = internalOptions === null || internalOptions === void 0 ? void 0 : internalOptions.analyticsTrackers) !== null && _a !== void 0 ? _a : analytics_1.standardCheckoutTrackers;
|
|
30
|
+
const flowType = (_b = internalOptions === null || internalOptions === void 0 ? void 0 : internalOptions.flowType) !== null && _b !== void 0 ? _b : "standard";
|
|
19
31
|
// Refs for the WebViews
|
|
20
32
|
const mainWebViewRef = (0, react_1.useRef)(null);
|
|
21
33
|
const flowWebViewRef = (0, react_1.useRef)(null);
|
|
@@ -32,7 +44,7 @@ function useStandardCheckout({ server, publicKey, orderId, onPaymentSuccess, onP
|
|
|
32
44
|
// Building the query string manually since URLSearchParams is not fully supported in React Native
|
|
33
45
|
const baseParams = [`orderId=${encodeURIComponent(orderId)}`];
|
|
34
46
|
const mode = mockMode ? "mock" : "live";
|
|
35
|
-
const params = baseParams.concat(`mode=${encodeURIComponent(mode)}`, `publicKey=${encodeURIComponent(publicKey)}`);
|
|
47
|
+
const params = baseParams.concat(`mode=${encodeURIComponent(mode)}`, `publicKey=${encodeURIComponent(publicKey)}`, `product=${encodeURIComponent(base_1.ANALYTICS_PRODUCT)}`, `surface=${encodeURIComponent(base_1.ANALYTICS_SURFACE)}`);
|
|
36
48
|
const queryString = params.join("&");
|
|
37
49
|
// Handling base URL with or without existing query parameters
|
|
38
50
|
const separator = baseCheckoutUrl.includes("?") ? "&" : "?";
|
|
@@ -126,43 +138,69 @@ function useStandardCheckout({ server, publicKey, orderId, onPaymentSuccess, onP
|
|
|
126
138
|
}
|
|
127
139
|
}
|
|
128
140
|
}, [devMode]);
|
|
141
|
+
// Correlates every event from this mount, and keeps checkoutStatus current on all of them
|
|
142
|
+
(0, use_sdk_session_1.useSdkSession)(() => status);
|
|
143
|
+
// Missing optional dependencies reach the host here; start() warns on the console separately
|
|
144
|
+
(0, use_capability_reporting_1.useCapabilityReporting)({ onSdkError, devMode });
|
|
145
|
+
/**
|
|
146
|
+
* Handler for `file.input` - the user tapping a file input on a bank's page.
|
|
147
|
+
*
|
|
148
|
+
* Registered beside `file.save` on the same WebViews, for the same reason: uploads are not a
|
|
149
|
+
* property of one flow, and until now this message had no handler anywhere.
|
|
150
|
+
*/
|
|
151
|
+
const fileInputHandler = (0, react_1.useMemo)(() => (0, file_input_handler_1.createFileInputHandler)({
|
|
152
|
+
flowType: flowType,
|
|
153
|
+
orderId,
|
|
154
|
+
publicKey,
|
|
155
|
+
checkoutUrl,
|
|
156
|
+
mockMode,
|
|
157
|
+
devMode,
|
|
158
|
+
}), [orderId, publicKey, checkoutUrl, mockMode, devMode, flowType]);
|
|
159
|
+
/**
|
|
160
|
+
* Handler for `file.save` - the page asking the SDK to put a document on the device.
|
|
161
|
+
*
|
|
162
|
+
* One handler, registered on the main and flow WebViews both. Not on the education carousel:
|
|
163
|
+
* that renders our own content, which has nothing to gate, and the capability is not advertised
|
|
164
|
+
* there either.
|
|
165
|
+
*/
|
|
166
|
+
const fileSaveHandler = (0, react_1.useMemo)(() => (0, file_save_handler_1.createFileSaveHandler)({
|
|
167
|
+
flowType,
|
|
168
|
+
orderId,
|
|
169
|
+
publicKey,
|
|
170
|
+
checkoutUrl,
|
|
171
|
+
mockMode,
|
|
172
|
+
devMode,
|
|
173
|
+
onSdkError,
|
|
174
|
+
}), [flowType, orderId, publicKey, checkoutUrl, mockMode, devMode, onSdkError]);
|
|
129
175
|
/**
|
|
130
176
|
* Handler for the main WebView messages.
|
|
131
177
|
* The main WebView hosts the checkout page. Messages arrive as JSON strings from the injected
|
|
132
178
|
* JavaScript bridge and include console logs, window.open/close interceptions, and payment
|
|
133
179
|
* lifecycle events (success, failure, terminate, bank transfer, pay via bank).
|
|
134
180
|
*/
|
|
135
|
-
const handleMainWebViewMessage = (0, react_1.
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
trackers.trackInvalidMessageReceived("main", data, checkoutUrl, orderId, publicKey, devMode, mockMode, checkoutUrl);
|
|
146
|
-
return;
|
|
147
|
-
}
|
|
148
|
-
const message = JSON.parse(data);
|
|
149
|
-
if (devMode) {
|
|
150
|
-
console.log("[Glomo-RN-SDK Standard] MainWebView Message received:", message.type, message);
|
|
151
|
-
}
|
|
181
|
+
const handleMainWebViewMessage = (0, react_1.useMemo)(() => (0, message_router_1.createMessageRouter)({
|
|
182
|
+
logPrefix: LOG_PREFIX,
|
|
183
|
+
source: "MainWebView",
|
|
184
|
+
devMode,
|
|
185
|
+
onInvalidMessage: (data) => {
|
|
186
|
+
trackers.trackInvalidMessageReceived("main", data, checkoutUrl, orderId, publicKey, devMode, mockMode, checkoutUrl);
|
|
187
|
+
},
|
|
188
|
+
handlers: {
|
|
189
|
+
"file.save": fileSaveHandler,
|
|
190
|
+
"file.input": fileInputHandler,
|
|
152
191
|
// Forwarding console messages from the injected script to the React Native console
|
|
153
|
-
|
|
192
|
+
console: (message) => {
|
|
154
193
|
if (devMode) {
|
|
155
|
-
const level = message.level || "log";
|
|
156
|
-
console.log(
|
|
194
|
+
const level = (typeof message.level === "string" && message.level) || "log";
|
|
195
|
+
console.log(`${LOG_PREFIX} [WebView ${level.toUpperCase()}]`, message.message);
|
|
157
196
|
}
|
|
158
|
-
|
|
159
|
-
}
|
|
197
|
+
},
|
|
160
198
|
// Intercepting window.open calls - opening the target URL in the flow WebView overlay
|
|
161
|
-
|
|
199
|
+
"window.open": (message) => {
|
|
162
200
|
const url = message.url;
|
|
163
201
|
if (url && typeof url === "string" && (0, validation_1.isValidUrl)(url)) {
|
|
164
202
|
if (devMode) {
|
|
165
|
-
console.log(
|
|
203
|
+
console.log(`${LOG_PREFIX} window.open called from MainWebView: ${url}`);
|
|
166
204
|
}
|
|
167
205
|
setFlowWebViewUrl(url);
|
|
168
206
|
setShowFlowWebView(true);
|
|
@@ -171,26 +209,27 @@ function useStandardCheckout({ server, publicKey, orderId, onPaymentSuccess, onP
|
|
|
171
209
|
}
|
|
172
210
|
else {
|
|
173
211
|
if (devMode) {
|
|
174
|
-
console.log(
|
|
212
|
+
console.log(`${LOG_PREFIX} Invalid URL in window.open from MainWebView:`, url, typeof url === "undefined" ? "undefined" : "");
|
|
175
213
|
}
|
|
176
214
|
}
|
|
177
|
-
|
|
178
|
-
}
|
|
215
|
+
},
|
|
179
216
|
// Intercepting window.close calls - closing the flow WebView overlay
|
|
180
|
-
|
|
217
|
+
"window.close": () => {
|
|
181
218
|
if (devMode) {
|
|
182
|
-
console.log(
|
|
219
|
+
console.log(`${LOG_PREFIX} Child window close requested from MainWebView`);
|
|
183
220
|
}
|
|
184
221
|
setShowFlowWebView(false);
|
|
185
222
|
setFlowWebViewUrl("");
|
|
186
223
|
// Tracking window.close interception
|
|
187
224
|
trackers.trackWindowClose("main", orderId, publicKey, devMode, mockMode, checkoutUrl);
|
|
188
|
-
|
|
189
|
-
}
|
|
225
|
+
},
|
|
190
226
|
// Handling merchant JS callbacks on flow completion (payment events, lifecycle events)
|
|
191
|
-
|
|
227
|
+
message: (message) => {
|
|
228
|
+
var _a;
|
|
192
229
|
const messageData = message.message;
|
|
193
|
-
|
|
230
|
+
if (!messageData)
|
|
231
|
+
return;
|
|
232
|
+
const messageType = messageData.type;
|
|
194
233
|
// Handling payment success - closing checkout and notifying the merchant
|
|
195
234
|
if (messageType === "payment.success" || messageType === "payment.complete") {
|
|
196
235
|
const paymentMessage = messageData;
|
|
@@ -205,12 +244,24 @@ function useStandardCheckout({ server, publicKey, orderId, onPaymentSuccess, onP
|
|
|
205
244
|
setStatus("payment_successful");
|
|
206
245
|
(0, validation_1.safeCallback)(onPaymentSuccess, [payload], "onPaymentSuccess", devMode);
|
|
207
246
|
// Tracking payment success callback
|
|
208
|
-
trackers.trackPaymentSuccess(
|
|
247
|
+
trackers.trackPaymentSuccess((0, event_projections_1.toPaymentEventData)(payload), publicKey, devMode, mockMode, checkoutUrl);
|
|
248
|
+
// Fires alongside the callback, not instead of it - the outcome is real, the payload is thin
|
|
249
|
+
const missingFields = (0, validation_1.missingPaymentFields)(payload);
|
|
250
|
+
if (missingFields.length > 0) {
|
|
251
|
+
(0, analytics_1.trackIncompletePaymentPayload)("payment.success", missingFields, "main", payload.orderId, publicKey, devMode, mockMode, checkoutUrl, flowType);
|
|
252
|
+
}
|
|
209
253
|
}
|
|
210
254
|
else {
|
|
255
|
+
/**
|
|
256
|
+
* Reported, not dropped. Before v5 this branch was a devMode-only console.error, so in a
|
|
257
|
+
* release build a terminal payment outcome the SDK could not route left no trace
|
|
258
|
+
* anywhere - no callback, no telemetry, nothing for support to find.
|
|
259
|
+
*/
|
|
211
260
|
if (devMode) {
|
|
212
|
-
console.error(
|
|
261
|
+
console.error(`${LOG_PREFIX} Unroutable payment.success payload from main:`, payload);
|
|
213
262
|
}
|
|
263
|
+
(0, analytics_1.trackDroppedPaymentPayload)("payment.success", (0, payment_payload_1.payloadKeysOf)(payload), "main", orderId, publicKey, devMode, mockMode, checkoutUrl, flowType);
|
|
264
|
+
(0, validation_1.safeCallback)(onSdkError, [[(0, payment_payload_1.droppedPayloadSdkError)("payment.success")]], "onSdkError", devMode);
|
|
214
265
|
}
|
|
215
266
|
return;
|
|
216
267
|
}
|
|
@@ -228,12 +279,24 @@ function useStandardCheckout({ server, publicKey, orderId, onPaymentSuccess, onP
|
|
|
228
279
|
setStatus("payment_failed");
|
|
229
280
|
(0, validation_1.safeCallback)(onPaymentFailure, [payload], "onPaymentFailure", devMode);
|
|
230
281
|
// Tracking payment failure callback
|
|
231
|
-
trackers.trackPaymentFailure(
|
|
282
|
+
trackers.trackPaymentFailure((0, event_projections_1.toPaymentEventData)(payload), publicKey, devMode, mockMode, checkoutUrl);
|
|
283
|
+
// Fires alongside the callback, not instead of it - the outcome is real, the payload is thin
|
|
284
|
+
const missingFields = (0, validation_1.missingPaymentFields)(payload);
|
|
285
|
+
if (missingFields.length > 0) {
|
|
286
|
+
(0, analytics_1.trackIncompletePaymentPayload)("payment.failure", missingFields, "main", payload.orderId, publicKey, devMode, mockMode, checkoutUrl, flowType);
|
|
287
|
+
}
|
|
232
288
|
}
|
|
233
289
|
else {
|
|
290
|
+
/**
|
|
291
|
+
* Reported, not dropped. Before v5 this branch was a devMode-only console.error, so in a
|
|
292
|
+
* release build a terminal payment outcome the SDK could not route left no trace
|
|
293
|
+
* anywhere - no callback, no telemetry, nothing for support to find.
|
|
294
|
+
*/
|
|
234
295
|
if (devMode) {
|
|
235
|
-
console.error(
|
|
296
|
+
console.error(`${LOG_PREFIX} Unroutable payment.failure payload from main:`, payload);
|
|
236
297
|
}
|
|
298
|
+
(0, analytics_1.trackDroppedPaymentPayload)("payment.failure", (0, payment_payload_1.payloadKeysOf)(payload), "main", orderId, publicKey, devMode, mockMode, checkoutUrl, flowType);
|
|
299
|
+
(0, validation_1.safeCallback)(onSdkError, [[(0, payment_payload_1.droppedPayloadSdkError)("payment.failure")]], "onSdkError", devMode);
|
|
237
300
|
}
|
|
238
301
|
return;
|
|
239
302
|
}
|
|
@@ -254,7 +317,7 @@ function useStandardCheckout({ server, publicKey, orderId, onPaymentSuccess, onP
|
|
|
254
317
|
transactionReference: payload === null || payload === void 0 ? void 0 : payload.transactionReference,
|
|
255
318
|
};
|
|
256
319
|
(0, validation_1.safeCallback)(onUserJourneyCompleted, [journeyPayload], "onUserJourneyCompleted", devMode);
|
|
257
|
-
trackers.trackBankTransferSubmitted(orderId, publicKey, devMode, mockMode, checkoutUrl);
|
|
320
|
+
trackers.trackBankTransferSubmitted(orderId, (0, event_projections_1.toJourneyEventData)(journeyPayload), publicKey, devMode, mockMode, checkoutUrl);
|
|
258
321
|
return;
|
|
259
322
|
}
|
|
260
323
|
/**
|
|
@@ -283,10 +346,10 @@ function useStandardCheckout({ server, publicKey, orderId, onPaymentSuccess, onP
|
|
|
283
346
|
const journeyPayload = {
|
|
284
347
|
journeyType: checkout_1.ASYNC_PAYMENT_EVENTS.PAY_VIA_BANK_COMPLETED,
|
|
285
348
|
orderId: payload === null || payload === void 0 ? void 0 : payload.orderId,
|
|
286
|
-
status: (
|
|
349
|
+
status: (_a = payload === null || payload === void 0 ? void 0 : payload.status) !== null && _a !== void 0 ? _a : "unknown",
|
|
287
350
|
};
|
|
288
351
|
(0, validation_1.safeCallback)(onUserJourneyCompleted, [journeyPayload], "onUserJourneyCompleted", devMode);
|
|
289
|
-
trackers.trackPayViaBankCompleted(orderId,
|
|
352
|
+
trackers.trackPayViaBankCompleted(orderId, (0, event_projections_1.toJourneyEventData)(journeyPayload), publicKey, devMode, mockMode, checkoutUrl);
|
|
290
353
|
return;
|
|
291
354
|
}
|
|
292
355
|
// Handling checkout.closed events
|
|
@@ -297,19 +360,15 @@ function useStandardCheckout({ server, publicKey, orderId, onPaymentSuccess, onP
|
|
|
297
360
|
setShowCheckout(false);
|
|
298
361
|
setShowFlowWebView(false);
|
|
299
362
|
setFlowWebViewUrl("");
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
363
|
+
const termination = { source: checkout_1.TERMINATION_SOURCES.CHECKOUT_CLOSED };
|
|
364
|
+
(0, validation_1.safeCallback)(onPaymentTerminate, [termination], "onPaymentTerminate", devMode);
|
|
365
|
+
// One object to the host and to telemetry, so the two cannot drift
|
|
366
|
+
trackers.trackPaymentTerminate(orderId, (0, event_projections_1.toTerminationEventData)(termination), publicKey, devMode, mockMode, checkoutUrl);
|
|
303
367
|
return;
|
|
304
368
|
}
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
if (devMode) {
|
|
309
|
-
console.error("[Glomo-RN-SDK Standard] Error parsing MainWebView message:", error);
|
|
310
|
-
}
|
|
311
|
-
}
|
|
312
|
-
}, [
|
|
369
|
+
},
|
|
370
|
+
},
|
|
371
|
+
}), [
|
|
313
372
|
onPaymentSuccess,
|
|
314
373
|
onPaymentFailure,
|
|
315
374
|
onPaymentTerminate,
|
|
@@ -320,42 +379,47 @@ function useStandardCheckout({ server, publicKey, orderId, onPaymentSuccess, onP
|
|
|
320
379
|
publicKey,
|
|
321
380
|
checkoutUrl,
|
|
322
381
|
trackers,
|
|
382
|
+
fileSaveHandler,
|
|
383
|
+
flowType,
|
|
384
|
+
onSdkError,
|
|
385
|
+
fileInputHandler,
|
|
323
386
|
]);
|
|
324
387
|
/**
|
|
325
388
|
* Handler for the flow WebView messages.
|
|
326
389
|
* The flow WebView hosts child pages opened via window.open (e.g. 3DS, bank redirects).
|
|
327
390
|
* Message structure mirrors the main WebView handler but operates on the overlay WebView.
|
|
328
391
|
*/
|
|
329
|
-
const handleFlowWebViewMessage = (0, react_1.
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
}
|
|
392
|
+
const handleFlowWebViewMessage = (0, react_1.useMemo)(() => (0, message_router_1.createMessageRouter)({
|
|
393
|
+
logPrefix: LOG_PREFIX,
|
|
394
|
+
source: "FlowWebView",
|
|
395
|
+
devMode,
|
|
396
|
+
onInvalidMessage: (data) => {
|
|
397
|
+
trackers.trackInvalidMessageReceived("flow", data, flowWebViewUrl, orderId, publicKey, devMode, mockMode, checkoutUrl);
|
|
398
|
+
},
|
|
399
|
+
handlers: {
|
|
400
|
+
/**
|
|
401
|
+
* Telemetry only, and deliberately not wired to onUserRefusedDevicePermissions.
|
|
402
|
+
* The flow injection sees this by watching getUserMedia, so coverage depends on
|
|
403
|
+
* whether a given bank uses it - partial coverage on a merchant callback is
|
|
404
|
+
* worse than none, because silence would stop being unambiguous.
|
|
405
|
+
*/
|
|
406
|
+
"permission.denied": (message) => {
|
|
407
|
+
(0, analytics_1.trackDevicePermissionRefused)(typeof message.resource === "string" ? message.resource : "camera", "get_user_media", orderId, publicKey, devMode, mockMode, checkoutUrl, flowType);
|
|
408
|
+
},
|
|
409
|
+
"file.save": fileSaveHandler,
|
|
410
|
+
"file.input": fileInputHandler,
|
|
346
411
|
// Forwarding console messages from the flow WebView's injected script
|
|
347
|
-
|
|
412
|
+
console: (message) => {
|
|
348
413
|
if (devMode) {
|
|
349
|
-
console.log(
|
|
414
|
+
console.log(`${LOG_PREFIX} [Flow] ${message.message}`);
|
|
350
415
|
}
|
|
351
|
-
|
|
352
|
-
}
|
|
416
|
+
},
|
|
353
417
|
// Intercepting window.open calls from the flow WebView - navigating within the same overlay
|
|
354
|
-
|
|
418
|
+
"window.open": (message) => {
|
|
355
419
|
const url = message.url;
|
|
356
420
|
if (url && typeof url === "string" && (0, validation_1.isValidUrl)(url)) {
|
|
357
421
|
if (devMode) {
|
|
358
|
-
console.log(
|
|
422
|
+
console.log(`${LOG_PREFIX} window.open called from FlowWebView: ${url}`);
|
|
359
423
|
}
|
|
360
424
|
setFlowWebViewUrl(url);
|
|
361
425
|
// Tracking window.open interception
|
|
@@ -363,26 +427,27 @@ function useStandardCheckout({ server, publicKey, orderId, onPaymentSuccess, onP
|
|
|
363
427
|
}
|
|
364
428
|
else {
|
|
365
429
|
if (devMode) {
|
|
366
|
-
console.log(
|
|
430
|
+
console.log(`${LOG_PREFIX} Invalid URL in window.open from FlowWebView:`, url, typeof url === "undefined" ? "undefined" : "");
|
|
367
431
|
}
|
|
368
432
|
}
|
|
369
|
-
|
|
370
|
-
}
|
|
433
|
+
},
|
|
371
434
|
// Intercepting window.close calls from the flow WebView - closing the overlay
|
|
372
|
-
|
|
435
|
+
"window.close": () => {
|
|
373
436
|
if (devMode) {
|
|
374
|
-
console.log(
|
|
437
|
+
console.log(`${LOG_PREFIX} FlowWebView close requested`);
|
|
375
438
|
}
|
|
376
439
|
setShowFlowWebView(false);
|
|
377
440
|
setFlowWebViewUrl("");
|
|
378
441
|
// Tracking window.close interception
|
|
379
442
|
trackers.trackWindowClose("flow", orderId, publicKey, devMode, mockMode, checkoutUrl);
|
|
380
|
-
|
|
381
|
-
}
|
|
443
|
+
},
|
|
382
444
|
// Handling merchant JS callbacks from the flow WebView (payment events, lifecycle events)
|
|
383
|
-
|
|
445
|
+
message: (message) => {
|
|
446
|
+
var _a;
|
|
384
447
|
const messageData = message.message;
|
|
385
|
-
|
|
448
|
+
if (!messageData)
|
|
449
|
+
return;
|
|
450
|
+
const messageType = messageData.type;
|
|
386
451
|
// Handling payment success from the flow WebView
|
|
387
452
|
if (messageType === "payment.success" || messageType === "payment.complete") {
|
|
388
453
|
const paymentMessage = messageData;
|
|
@@ -397,12 +462,24 @@ function useStandardCheckout({ server, publicKey, orderId, onPaymentSuccess, onP
|
|
|
397
462
|
setStatus("payment_successful");
|
|
398
463
|
(0, validation_1.safeCallback)(onPaymentSuccess, [payload], "onPaymentSuccess", devMode);
|
|
399
464
|
// Tracking payment success callback
|
|
400
|
-
trackers.trackPaymentSuccess(
|
|
465
|
+
trackers.trackPaymentSuccess((0, event_projections_1.toPaymentEventData)(payload), publicKey, devMode, mockMode, checkoutUrl);
|
|
466
|
+
// Fires alongside the callback, not instead of it - the outcome is real, the payload is thin
|
|
467
|
+
const missingFields = (0, validation_1.missingPaymentFields)(payload);
|
|
468
|
+
if (missingFields.length > 0) {
|
|
469
|
+
(0, analytics_1.trackIncompletePaymentPayload)("payment.success", missingFields, "flow", payload.orderId, publicKey, devMode, mockMode, checkoutUrl, flowType);
|
|
470
|
+
}
|
|
401
471
|
}
|
|
402
472
|
else {
|
|
473
|
+
/**
|
|
474
|
+
* Reported, not dropped. Before v5 this branch was a devMode-only console.error, so in a
|
|
475
|
+
* release build a terminal payment outcome the SDK could not route left no trace
|
|
476
|
+
* anywhere - no callback, no telemetry, nothing for support to find.
|
|
477
|
+
*/
|
|
403
478
|
if (devMode) {
|
|
404
|
-
console.error(
|
|
479
|
+
console.error(`${LOG_PREFIX} Unroutable payment.success payload from flow:`, payload);
|
|
405
480
|
}
|
|
481
|
+
(0, analytics_1.trackDroppedPaymentPayload)("payment.success", (0, payment_payload_1.payloadKeysOf)(payload), "flow", orderId, publicKey, devMode, mockMode, checkoutUrl, flowType);
|
|
482
|
+
(0, validation_1.safeCallback)(onSdkError, [[(0, payment_payload_1.droppedPayloadSdkError)("payment.success")]], "onSdkError", devMode);
|
|
406
483
|
}
|
|
407
484
|
return;
|
|
408
485
|
}
|
|
@@ -420,12 +497,24 @@ function useStandardCheckout({ server, publicKey, orderId, onPaymentSuccess, onP
|
|
|
420
497
|
setStatus("payment_failed");
|
|
421
498
|
(0, validation_1.safeCallback)(onPaymentFailure, [payload], "onPaymentFailure", devMode);
|
|
422
499
|
// Tracking payment failure callback
|
|
423
|
-
trackers.trackPaymentFailure(
|
|
500
|
+
trackers.trackPaymentFailure((0, event_projections_1.toPaymentEventData)(payload), publicKey, devMode, mockMode, checkoutUrl);
|
|
501
|
+
// Fires alongside the callback, not instead of it - the outcome is real, the payload is thin
|
|
502
|
+
const missingFields = (0, validation_1.missingPaymentFields)(payload);
|
|
503
|
+
if (missingFields.length > 0) {
|
|
504
|
+
(0, analytics_1.trackIncompletePaymentPayload)("payment.failure", missingFields, "flow", payload.orderId, publicKey, devMode, mockMode, checkoutUrl, flowType);
|
|
505
|
+
}
|
|
424
506
|
}
|
|
425
507
|
else {
|
|
508
|
+
/**
|
|
509
|
+
* Reported, not dropped. Before v5 this branch was a devMode-only console.error, so in a
|
|
510
|
+
* release build a terminal payment outcome the SDK could not route left no trace
|
|
511
|
+
* anywhere - no callback, no telemetry, nothing for support to find.
|
|
512
|
+
*/
|
|
426
513
|
if (devMode) {
|
|
427
|
-
console.error(
|
|
514
|
+
console.error(`${LOG_PREFIX} Unroutable payment.failure payload from flow:`, payload);
|
|
428
515
|
}
|
|
516
|
+
(0, analytics_1.trackDroppedPaymentPayload)("payment.failure", (0, payment_payload_1.payloadKeysOf)(payload), "flow", orderId, publicKey, devMode, mockMode, checkoutUrl, flowType);
|
|
517
|
+
(0, validation_1.safeCallback)(onSdkError, [[(0, payment_payload_1.droppedPayloadSdkError)("payment.failure")]], "onSdkError", devMode);
|
|
429
518
|
}
|
|
430
519
|
return;
|
|
431
520
|
}
|
|
@@ -450,20 +539,15 @@ function useStandardCheckout({ server, publicKey, orderId, onPaymentSuccess, onP
|
|
|
450
539
|
const journeyPayload = {
|
|
451
540
|
journeyType: checkout_1.ASYNC_PAYMENT_EVENTS.PAY_VIA_BANK_COMPLETED,
|
|
452
541
|
orderId: payload === null || payload === void 0 ? void 0 : payload.orderId,
|
|
453
|
-
status: (
|
|
542
|
+
status: (_a = payload === null || payload === void 0 ? void 0 : payload.status) !== null && _a !== void 0 ? _a : "unknown",
|
|
454
543
|
};
|
|
455
544
|
(0, validation_1.safeCallback)(onUserJourneyCompleted, [journeyPayload], "onUserJourneyCompleted", devMode);
|
|
456
|
-
trackers.trackPayViaBankCompleted(orderId,
|
|
545
|
+
trackers.trackPayViaBankCompleted(orderId, (0, event_projections_1.toJourneyEventData)(journeyPayload), publicKey, devMode, mockMode, checkoutUrl);
|
|
457
546
|
return;
|
|
458
547
|
}
|
|
459
|
-
}
|
|
460
|
-
}
|
|
461
|
-
|
|
462
|
-
if (devMode) {
|
|
463
|
-
console.error("[Glomo-RN-SDK Standard] Error parsing FlowWebView message:", error);
|
|
464
|
-
}
|
|
465
|
-
}
|
|
466
|
-
}, [
|
|
548
|
+
},
|
|
549
|
+
},
|
|
550
|
+
}), [
|
|
467
551
|
onPaymentSuccess,
|
|
468
552
|
onPaymentFailure,
|
|
469
553
|
onUserJourneyCompleted,
|
|
@@ -474,6 +558,10 @@ function useStandardCheckout({ server, publicKey, orderId, onPaymentSuccess, onP
|
|
|
474
558
|
flowWebViewUrl,
|
|
475
559
|
checkoutUrl,
|
|
476
560
|
trackers,
|
|
561
|
+
fileSaveHandler,
|
|
562
|
+
flowType,
|
|
563
|
+
onSdkError,
|
|
564
|
+
fileInputHandler,
|
|
477
565
|
]);
|
|
478
566
|
// Handler for the navigation state changes
|
|
479
567
|
const handleNavigationStateChange = (0, react_1.useCallback)((navState) => {
|
|
@@ -503,10 +591,18 @@ function useStandardCheckout({ server, publicKey, orderId, onPaymentSuccess, onP
|
|
|
503
591
|
console.log("[Glomo-RN-SDK Standard] Ignoring checkout status update for: " + status);
|
|
504
592
|
}
|
|
505
593
|
}
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
594
|
+
/**
|
|
595
|
+
* Inferred from the platform rather than read off an event, because `onRequestClose` is
|
|
596
|
+
* the only wiring here and the two platforms raise it for different gestures: Android
|
|
597
|
+
* for hardware back and the back gesture, iOS for swipe-down on the pageSheet. Nothing
|
|
598
|
+
* else routes through it, so the inference is sound - but it is an inference.
|
|
599
|
+
*/
|
|
600
|
+
const termination = {
|
|
601
|
+
source: react_native_1.Platform.OS === "ios" ? checkout_1.TERMINATION_SOURCES.MODAL_DISMISS : checkout_1.TERMINATION_SOURCES.DEVICE_BACK_BUTTON,
|
|
602
|
+
};
|
|
603
|
+
(0, validation_1.safeCallback)(onPaymentTerminate, [termination], "onPaymentTerminate", devMode);
|
|
604
|
+
// One object to the host and to telemetry, so the two cannot drift
|
|
605
|
+
trackers.trackPaymentTerminate(orderId, (0, event_projections_1.toTerminationEventData)(termination), publicKey, devMode, mockMode, checkoutUrl);
|
|
510
606
|
}
|
|
511
607
|
catch (error) {
|
|
512
608
|
if (devMode) {
|
|
@@ -521,88 +617,35 @@ function useStandardCheckout({ server, publicKey, orderId, onPaymentSuccess, onP
|
|
|
521
617
|
}
|
|
522
618
|
setShowFlowWebView(false);
|
|
523
619
|
setFlowWebViewUrl("");
|
|
524
|
-
|
|
525
|
-
}, [devMode, orderId, publicKey, mockMode, checkoutUrl,
|
|
620
|
+
(0, analytics_1.trackBackNavigationViaSdkBackButton)(orderId, publicKey, devMode, mockMode, checkoutUrl, flowType);
|
|
621
|
+
}, [devMode, orderId, publicKey, mockMode, checkoutUrl, flowType]);
|
|
526
622
|
/**
|
|
527
|
-
*
|
|
528
|
-
*
|
|
529
|
-
*
|
|
530
|
-
*
|
|
623
|
+
* Closing the checkout when the user refuses camera access, since the bank page cannot
|
|
624
|
+
* proceed without it. Kept here rather than inside usePermissionRequest because moving the
|
|
625
|
+
* status and notifying the merchant are flow concerns.
|
|
626
|
+
*
|
|
627
|
+
* Resets the flow overlay as well as the modal, matching the LRS handler. The prompt is raised
|
|
628
|
+
* from a bank page inside that overlay, so this is the one close path where the flow state is
|
|
629
|
+
* guaranteed non-default. Nothing visible depends on it today - the overlay renders inside the
|
|
630
|
+
* Modal and unmounts with it - but "every close path resets derived state" should not hold in
|
|
631
|
+
* one flow and not the other.
|
|
531
632
|
*/
|
|
532
|
-
const
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
if (devMode) {
|
|
539
|
-
console.log("[Glomo-RN-SDK Standard] Non-camera permission requested, denying:", resources);
|
|
540
|
-
}
|
|
541
|
-
request.deny();
|
|
542
|
-
return;
|
|
543
|
-
}
|
|
544
|
-
if (devMode) {
|
|
545
|
-
console.log("[Glomo-RN-SDK Standard] Camera permission requested by webpage");
|
|
546
|
-
}
|
|
547
|
-
if (react_native_1.Platform.OS === "android") {
|
|
548
|
-
try {
|
|
549
|
-
const granted = await react_native_1.PermissionsAndroid.request(react_native_1.PermissionsAndroid.PERMISSIONS.CAMERA, {
|
|
550
|
-
title: "Camera Permission",
|
|
551
|
-
message: "This app needs camera access for identity verification during checkout",
|
|
552
|
-
buttonNeutral: "Ask Me Later",
|
|
553
|
-
buttonNegative: "Cancel",
|
|
554
|
-
buttonPositive: "OK",
|
|
555
|
-
});
|
|
556
|
-
if (granted === react_native_1.PermissionsAndroid.RESULTS.GRANTED) {
|
|
557
|
-
if (devMode) {
|
|
558
|
-
console.log("[Glomo-RN-SDK Standard] Camera permission granted");
|
|
559
|
-
}
|
|
560
|
-
request.grant(resources);
|
|
561
|
-
}
|
|
562
|
-
else {
|
|
563
|
-
if (devMode) {
|
|
564
|
-
console.log("[Glomo-RN-SDK Standard] Camera permission denied by user");
|
|
565
|
-
}
|
|
566
|
-
setShowCheckout(false);
|
|
567
|
-
if (status === "payment_in_progress") {
|
|
568
|
-
setStatus("payment_cancelled");
|
|
569
|
-
}
|
|
570
|
-
(0, validation_1.safeCallback)(onUserRefusedCameraPermissions, [], "onUserRefusedCameraPermissions", devMode);
|
|
571
|
-
request.deny();
|
|
572
|
-
}
|
|
573
|
-
}
|
|
574
|
-
catch (err) {
|
|
575
|
-
if (devMode) {
|
|
576
|
-
console.error("[Glomo-RN-SDK Standard] Error requesting camera permission:", err);
|
|
577
|
-
}
|
|
578
|
-
setShowCheckout(false);
|
|
579
|
-
if (status === "payment_in_progress") {
|
|
580
|
-
setStatus("payment_cancelled");
|
|
581
|
-
}
|
|
582
|
-
(0, validation_1.safeCallback)(onUserRefusedCameraPermissions, [], "onUserRefusedCameraPermissions", devMode);
|
|
583
|
-
request.deny();
|
|
584
|
-
}
|
|
585
|
-
}
|
|
586
|
-
else if (react_native_1.Platform.OS === "ios") {
|
|
587
|
-
if (devMode) {
|
|
588
|
-
console.log("[Glomo-RN-SDK Standard] Granting camera permission request on iOS");
|
|
589
|
-
}
|
|
590
|
-
request.grant(resources);
|
|
591
|
-
}
|
|
592
|
-
else {
|
|
593
|
-
if (devMode) {
|
|
594
|
-
console.warn("[Glomo-RN-SDK Standard] Unsupported platform for camera permissions");
|
|
595
|
-
}
|
|
596
|
-
request.deny();
|
|
597
|
-
}
|
|
598
|
-
}
|
|
599
|
-
catch (error) {
|
|
600
|
-
if (devMode) {
|
|
601
|
-
console.error("[Glomo-RN-SDK Standard] Error in handlePermissionRequest:", error);
|
|
602
|
-
}
|
|
603
|
-
request.deny();
|
|
633
|
+
const handleCameraPermissionDenied = (0, react_1.useCallback)(() => {
|
|
634
|
+
setShowCheckout(false);
|
|
635
|
+
setShowFlowWebView(false);
|
|
636
|
+
setFlowWebViewUrl("");
|
|
637
|
+
if (status === "payment_in_progress") {
|
|
638
|
+
setStatus("payment_cancelled");
|
|
604
639
|
}
|
|
605
|
-
|
|
640
|
+
(0, validation_1.safeCallback)(onUserRefusedDevicePermissions, [], "onUserRefusedDevicePermissions", devMode);
|
|
641
|
+
// The permission hook only reaches here for camera; anything else is denied without notifying
|
|
642
|
+
(0, analytics_1.trackDevicePermissionRefused)("camera", "permission_request", orderId, publicKey, devMode, mockMode, checkoutUrl, flowType);
|
|
643
|
+
}, [status, onUserRefusedDevicePermissions, devMode, orderId, publicKey, mockMode, checkoutUrl, flowType]);
|
|
644
|
+
const handlePermissionRequest = (0, use_permission_request_1.usePermissionRequest)({
|
|
645
|
+
logPrefix: "[Glomo-RN-SDK Standard]",
|
|
646
|
+
onDenied: handleCameraPermissionDenied,
|
|
647
|
+
devMode,
|
|
648
|
+
});
|
|
606
649
|
/**
|
|
607
650
|
* Initiator method for the Standard Checkout flow.
|
|
608
651
|
* Using a ref, the standard flow can be started by calling this method.
|
|
@@ -620,38 +663,62 @@ function useStandardCheckout({ server, publicKey, orderId, onPaymentSuccess, onP
|
|
|
620
663
|
* Checking device security compliance (if peerDependencies are available)
|
|
621
664
|
* A null value indicates that recommended security dependencies were not installed and compliance checks will be skipped in this case
|
|
622
665
|
*/
|
|
623
|
-
const
|
|
624
|
-
const
|
|
625
|
-
const
|
|
626
|
-
|
|
627
|
-
|
|
666
|
+
const compliance = (0, device_compliance_1.resolveDeviceCompliance)(devMode);
|
|
667
|
+
const complianceLibraryInstalled = (0, device_compliance_1.isComplianceCheckAvailable)();
|
|
668
|
+
const fileSave = (0, index_2.resolveFileSaveAvailability)();
|
|
669
|
+
const dependencyInfo = {
|
|
670
|
+
jailbreakDetectionLibraryInstalled: complianceLibraryInstalled,
|
|
671
|
+
jailbreakDetected: compliance.compromised,
|
|
672
|
+
complianceSource: compliance.source,
|
|
673
|
+
complianceSignals: compliance.trippedSignals,
|
|
674
|
+
fileSaveAvailable: fileSave.available,
|
|
675
|
+
missingFileSavePackages: fileSave.missing,
|
|
628
676
|
};
|
|
629
677
|
if (devMode) {
|
|
630
678
|
console.log(`[Glomo-RN-SDK Standard] Attempting to start checkout of ${checkoutUrl} from status: ${status}`);
|
|
631
679
|
}
|
|
632
680
|
// Tracking start attempt with current status
|
|
633
|
-
trackers.trackStartAttempt(status, orderId, publicKey, devMode, mockMode, checkoutUrl,
|
|
634
|
-
|
|
635
|
-
|
|
681
|
+
trackers.trackStartAttempt(status, orderId, publicKey, devMode, mockMode, checkoutUrl, dependencyInfo);
|
|
682
|
+
/**
|
|
683
|
+
* Ungated on purpose, both of them. An absent optional dependency degrades silently by
|
|
684
|
+
* design, so a console warning is the only thing that reaches a merchant who has not
|
|
685
|
+
* noticed - and the compliance one now precedes a hard block on live keys.
|
|
686
|
+
*/
|
|
687
|
+
if (!complianceLibraryInstalled) {
|
|
688
|
+
console.warn("[Glomo-RN-SDK Standard] jail-monkey is not installed or its native module is not linked, so " +
|
|
689
|
+
"rooted and jailbroken devices cannot be detected. As of v5 this BLOCKS live checkouts. " +
|
|
690
|
+
"Install jail-monkey and rebuild the app - see the README.");
|
|
691
|
+
}
|
|
692
|
+
if (!fileSave.available) {
|
|
693
|
+
console.warn(`[Glomo-RN-SDK Standard] Document downloads are disabled: ${fileSave.missing.join(" and ")} ` +
|
|
694
|
+
"could not be loaded. Install the package(s) and rebuild the app, or ignore this if your " +
|
|
695
|
+
"checkout does not offer downloads - the page falls back to its own behaviour.");
|
|
696
|
+
}
|
|
697
|
+
if ((0, device_compliance_1.blocksCheckout)(compliance, publicKey)) {
|
|
698
|
+
/**
|
|
699
|
+
* Two conditions, one refusal. `compromised === true` is a rooted or jailbroken device;
|
|
700
|
+
* `null` is a device we could not check, which on RN overwhelmingly means jail-monkey is
|
|
701
|
+
* absent rather than that a platform probe failed. Both fail closed on a live key, and
|
|
702
|
+
* neither fires on a test or mock key.
|
|
703
|
+
*/
|
|
704
|
+
const unknown = compliance.compromised === null;
|
|
636
705
|
if (devMode) {
|
|
637
|
-
console.error(
|
|
706
|
+
console.error(`[Glomo-RN-SDK Standard] Cannot start checkout. ${unknown ? "Device security could not be verified." : "Device is rooted or jailbroken."}`);
|
|
638
707
|
}
|
|
639
708
|
const errors = [
|
|
640
709
|
{
|
|
641
710
|
type: "device_forbidden",
|
|
642
|
-
message:
|
|
711
|
+
message: unknown
|
|
712
|
+
? "Standard checkout could not verify this device's security. Install jail-monkey and rebuild the app."
|
|
713
|
+
: "Standard checkout is not allowed on rooted or jailbroken devices.",
|
|
643
714
|
},
|
|
644
715
|
];
|
|
645
716
|
(0, validation_1.safeCallback)(onSdkError, [errors], "onSdkError", devMode);
|
|
646
717
|
// Tracking start() failure
|
|
647
|
-
trackers.trackStartFailure("device_forbidden", orderId, publicKey, devMode, mockMode, checkoutUrl,
|
|
718
|
+
trackers.trackStartFailure(unknown ? "device_compliance_unknown" : "device_forbidden", orderId, publicKey, devMode, mockMode, checkoutUrl, dependencyInfo);
|
|
648
719
|
setShowCheckout(false);
|
|
649
720
|
return false;
|
|
650
721
|
}
|
|
651
|
-
else if (deviceComplianceCheck === null) {
|
|
652
|
-
// This warning was intentionally not gated behind a devMode check to ensure merchants are aware of the strong recommendation to install jail-monkey for enhanced security compliance.
|
|
653
|
-
console.warn("[Glomo-RN-SDK Standard] Device security library not installed - the SDK won't be able to automatically detect rooted/jailbroken devices. It is HIGHLY recommended to install jail-monkey as per the README, and prevent standard checkouts from compromised devices.");
|
|
654
|
-
}
|
|
655
722
|
// Enforcing devMode requirement for development servers
|
|
656
723
|
const resolvedServer = server || "prod";
|
|
657
724
|
if (!devMode && resolvedServer !== "prod") {
|
|
@@ -663,7 +730,7 @@ function useStandardCheckout({ server, publicKey, orderId, onPaymentSuccess, onP
|
|
|
663
730
|
];
|
|
664
731
|
(0, validation_1.safeCallback)(onSdkError, [errors], "onSdkError", devMode);
|
|
665
732
|
trackers.trackSdkError(errors, orderId, publicKey, devMode, mockMode, checkoutUrl);
|
|
666
|
-
trackers.trackStartFailure("validation_error", orderId, publicKey, devMode, mockMode, checkoutUrl,
|
|
733
|
+
trackers.trackStartFailure("validation_error", orderId, publicKey, devMode, mockMode, checkoutUrl, dependencyInfo);
|
|
667
734
|
setShowCheckout(false);
|
|
668
735
|
return false;
|
|
669
736
|
}
|
|
@@ -706,7 +773,7 @@ function useStandardCheckout({ server, publicKey, orderId, onPaymentSuccess, onP
|
|
|
706
773
|
(0, validation_1.safeCallback)(onSdkError, [errors], "onSdkError", devMode);
|
|
707
774
|
// Tracking start() failure
|
|
708
775
|
trackers.trackSdkError(errors, orderId, publicKey, devMode, mockMode, checkoutUrl);
|
|
709
|
-
trackers.trackStartFailure("validation_error", orderId, publicKey, devMode, mockMode, checkoutUrl,
|
|
776
|
+
trackers.trackStartFailure("validation_error", orderId, publicKey, devMode, mockMode, checkoutUrl, dependencyInfo);
|
|
710
777
|
setShowCheckout(false);
|
|
711
778
|
return false;
|
|
712
779
|
}
|
|
@@ -715,7 +782,7 @@ function useStandardCheckout({ server, publicKey, orderId, onPaymentSuccess, onP
|
|
|
715
782
|
console.log(`[Glomo-RN-SDK Standard] Cannot start checkout. Current status: ${status}. Payment already successful.`);
|
|
716
783
|
}
|
|
717
784
|
// Tracking start() failure
|
|
718
|
-
trackers.trackStartFailure("payment_successful", orderId, publicKey, devMode, mockMode, checkoutUrl,
|
|
785
|
+
trackers.trackStartFailure("payment_successful", orderId, publicKey, devMode, mockMode, checkoutUrl, dependencyInfo);
|
|
719
786
|
setShowCheckout(false);
|
|
720
787
|
return false;
|
|
721
788
|
}
|
|
@@ -729,7 +796,7 @@ function useStandardCheckout({ server, publicKey, orderId, onPaymentSuccess, onP
|
|
|
729
796
|
console.log(`[Glomo-RN-SDK Standard] Cannot start checkout. Unknown status: ${status}.`);
|
|
730
797
|
}
|
|
731
798
|
// Tracking start() failure
|
|
732
|
-
trackers.trackStartFailure("invalid_status", orderId, publicKey, devMode, mockMode, checkoutUrl,
|
|
799
|
+
trackers.trackStartFailure("invalid_status", orderId, publicKey, devMode, mockMode, checkoutUrl, dependencyInfo);
|
|
733
800
|
setShowCheckout(false);
|
|
734
801
|
return false;
|
|
735
802
|
}
|
|
@@ -738,7 +805,7 @@ function useStandardCheckout({ server, publicKey, orderId, onPaymentSuccess, onP
|
|
|
738
805
|
console.error("[Glomo-RN-SDK Standard] Cannot start checkout. Invalid checkout URL.");
|
|
739
806
|
}
|
|
740
807
|
// Tracking start() failure
|
|
741
|
-
trackers.trackStartFailure("invalid_url", orderId, publicKey, devMode, mockMode, checkoutUrl,
|
|
808
|
+
trackers.trackStartFailure("invalid_url", orderId, publicKey, devMode, mockMode, checkoutUrl, dependencyInfo);
|
|
742
809
|
setShowCheckout(false);
|
|
743
810
|
return false;
|
|
744
811
|
}
|
|
@@ -751,7 +818,7 @@ function useStandardCheckout({ server, publicKey, orderId, onPaymentSuccess, onP
|
|
|
751
818
|
payViaBankCompletedHandledRef.current = false;
|
|
752
819
|
setStatus("payment_in_progress");
|
|
753
820
|
// Tracking successful start
|
|
754
|
-
trackers.trackStartSuccess(orderId, publicKey, devMode, mockMode, checkoutUrl,
|
|
821
|
+
trackers.trackStartSuccess(orderId, publicKey, devMode, mockMode, checkoutUrl, dependencyInfo);
|
|
755
822
|
// Opening the checkout modal
|
|
756
823
|
setShowCheckout(true);
|
|
757
824
|
return true;
|
|
@@ -798,6 +865,13 @@ function useStandardCheckout({ server, publicKey, orderId, onPaymentSuccess, onP
|
|
|
798
865
|
setFlowWebViewUrl("");
|
|
799
866
|
};
|
|
800
867
|
}, []);
|
|
868
|
+
/**
|
|
869
|
+
* Scripts injected into each WebView, carrying what this build can advertise.
|
|
870
|
+
*
|
|
871
|
+
* Resolved once per mount rather than at module load, so a merchant who never opens a
|
|
872
|
+
* checkout never pays for the dependency probe.
|
|
873
|
+
*/
|
|
874
|
+
const injectionScripts = (0, react_1.useMemo)(() => (0, index_1.buildInjectionScripts)((0, index_2.resolveCapabilities)()), []);
|
|
801
875
|
return {
|
|
802
876
|
start,
|
|
803
877
|
status,
|
|
@@ -815,7 +889,9 @@ function useStandardCheckout({ server, publicKey, orderId, onPaymentSuccess, onP
|
|
|
815
889
|
handleNavigationStateChange,
|
|
816
890
|
handleModalBackButton,
|
|
817
891
|
handleFlowBack,
|
|
818
|
-
injectedMain:
|
|
819
|
-
|
|
892
|
+
injectedMain: __DEV__ && (internalOptions === null || internalOptions === void 0 ? void 0 : internalOptions._testInjectionScript)
|
|
893
|
+
? injectionScripts.standard + internalOptions._testInjectionScript
|
|
894
|
+
: injectionScripts.standard,
|
|
895
|
+
injectedFlow: injectionScripts.flow,
|
|
820
896
|
};
|
|
821
897
|
}
|