@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/use-lrs-checkout.js
CHANGED
|
@@ -8,9 +8,21 @@ 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 use_permission_request_1 = require("./webview/use-permission-request");
|
|
15
|
+
const message_router_1 = require("./bridge/message-router");
|
|
16
|
+
const file_save_handler_1 = require("./bridge/file-save-handler");
|
|
17
|
+
const file_input_handler_1 = require("./bridge/file-input-handler");
|
|
18
|
+
const index_2 = require("./capabilities/index");
|
|
19
|
+
const use_capability_reporting_1 = require("./capabilities/use-capability-reporting");
|
|
20
|
+
const use_sdk_session_1 = require("./utils/use-sdk-session");
|
|
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 LRS]";
|
|
25
|
+
function useLrsCheckout({ server, publicKey, orderId, onPaymentSuccess, onPaymentFailure, onConnectionError, onPaymentTerminate, onSdkError, onUserRefusedDevicePermissions, devMode = false, }, mockMode, internalOptions) {
|
|
14
26
|
// Refs for the WebViews
|
|
15
27
|
const mainWebViewRef = (0, react_1.useRef)(null);
|
|
16
28
|
const flowWebViewRef = (0, react_1.useRef)(null);
|
|
@@ -27,7 +39,7 @@ function useLrsCheckout({ server, publicKey, orderId, onPaymentSuccess, onPaymen
|
|
|
27
39
|
// Building the query string manually since URLSearchParams is not fully supported in React Native
|
|
28
40
|
const baseParams = [`orderId=${encodeURIComponent(orderId)}`];
|
|
29
41
|
const mode = mockMode ? "mock" : "live";
|
|
30
|
-
const params = baseParams.concat(`mode=${encodeURIComponent(mode)}`, `publicKey=${encodeURIComponent(publicKey)}`);
|
|
42
|
+
const params = baseParams.concat(`mode=${encodeURIComponent(mode)}`, `publicKey=${encodeURIComponent(publicKey)}`, `product=${encodeURIComponent(base_1.ANALYTICS_PRODUCT)}`, `surface=${encodeURIComponent(base_1.ANALYTICS_SURFACE)}`);
|
|
31
43
|
const queryString = params.join("&");
|
|
32
44
|
// Handling base URL with or without existing query parameters
|
|
33
45
|
const separator = baseCheckoutUrl.includes("?") ? "&" : "?";
|
|
@@ -60,7 +72,9 @@ function useLrsCheckout({ server, publicKey, orderId, onPaymentSuccess, onPaymen
|
|
|
60
72
|
const baseEducationCarouselUrl = serverConfig.baseUrl.lrsEducationCarousel;
|
|
61
73
|
const separator = baseEducationCarouselUrl.includes("?") ? "&" : "?";
|
|
62
74
|
const finalUrl = `${baseEducationCarouselUrl}${separator}orderId=${encodeURIComponent(orderId)}` +
|
|
63
|
-
`&publicKey=${encodeURIComponent(publicKey)}
|
|
75
|
+
`&publicKey=${encodeURIComponent(publicKey)}` +
|
|
76
|
+
`&product=${encodeURIComponent(base_1.ANALYTICS_PRODUCT)}` +
|
|
77
|
+
`&surface=${encodeURIComponent(base_1.ANALYTICS_SURFACE)}`;
|
|
64
78
|
if (!(0, validation_1.isValidUrl)(finalUrl)) {
|
|
65
79
|
if (devMode) {
|
|
66
80
|
console.error("[Glomo-RN-SDK LRS] Generated invalid education carousel URL:", finalUrl);
|
|
@@ -167,35 +181,62 @@ function useLrsCheckout({ server, publicKey, orderId, onPaymentSuccess, onPaymen
|
|
|
167
181
|
}
|
|
168
182
|
}
|
|
169
183
|
}, [devMode]);
|
|
184
|
+
// Correlates every event from this mount, and keeps checkoutStatus current on all of them
|
|
185
|
+
(0, use_sdk_session_1.useSdkSession)(() => status);
|
|
186
|
+
// Missing optional dependencies reach the host here; start() warns on the console separately
|
|
187
|
+
(0, use_capability_reporting_1.useCapabilityReporting)({ onSdkError, devMode });
|
|
188
|
+
/**
|
|
189
|
+
* Handler for `file.input` - the user tapping a file input on a bank's page.
|
|
190
|
+
*
|
|
191
|
+
* Registered beside `file.save` on the same WebViews, for the same reason: uploads are not a
|
|
192
|
+
* property of one flow, and until now this message had no handler anywhere.
|
|
193
|
+
*/
|
|
194
|
+
const fileInputHandler = (0, react_1.useMemo)(() => (0, file_input_handler_1.createFileInputHandler)({
|
|
195
|
+
flowType: "lrs",
|
|
196
|
+
orderId,
|
|
197
|
+
publicKey,
|
|
198
|
+
checkoutUrl,
|
|
199
|
+
mockMode,
|
|
200
|
+
devMode,
|
|
201
|
+
}), [orderId, publicKey, checkoutUrl, mockMode, devMode]);
|
|
202
|
+
/**
|
|
203
|
+
* Handler for `file.save` - the page asking the SDK to put a document on the device.
|
|
204
|
+
*
|
|
205
|
+
* One handler, registered on the main and flow WebViews both. Not on the education carousel:
|
|
206
|
+
* that renders our own content, which has nothing to gate, and the capability is not advertised
|
|
207
|
+
* there either.
|
|
208
|
+
*/
|
|
209
|
+
const fileSaveHandler = (0, react_1.useMemo)(() => (0, file_save_handler_1.createFileSaveHandler)({
|
|
210
|
+
flowType: "lrs",
|
|
211
|
+
orderId,
|
|
212
|
+
publicKey,
|
|
213
|
+
checkoutUrl,
|
|
214
|
+
mockMode,
|
|
215
|
+
devMode,
|
|
216
|
+
onSdkError,
|
|
217
|
+
}), [orderId, publicKey, checkoutUrl, mockMode, devMode, onSdkError]);
|
|
170
218
|
// Handler for the main WebView messages
|
|
171
|
-
const handleMainWebViewMessage = (0, react_1.
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
219
|
+
const handleMainWebViewMessage = (0, react_1.useMemo)(() => (0, message_router_1.createMessageRouter)({
|
|
220
|
+
logPrefix: LOG_PREFIX,
|
|
221
|
+
source: "MainWebView",
|
|
222
|
+
devMode,
|
|
223
|
+
onInvalidMessage: (data) => {
|
|
224
|
+
(0, analytics_1.trackInvalidMessageReceived)("main", data, checkoutUrl, orderId, publicKey, devMode, mockMode, checkoutUrl);
|
|
225
|
+
},
|
|
226
|
+
handlers: {
|
|
227
|
+
"file.save": fileSaveHandler,
|
|
228
|
+
"file.input": fileInputHandler,
|
|
229
|
+
console: (message) => {
|
|
176
230
|
if (devMode) {
|
|
177
|
-
|
|
231
|
+
const level = (typeof message.level === "string" && message.level) || "log";
|
|
232
|
+
console.log(`${LOG_PREFIX} [WebView ${level.toUpperCase()}]`, message.message);
|
|
178
233
|
}
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
return;
|
|
182
|
-
}
|
|
183
|
-
const message = JSON.parse(data);
|
|
184
|
-
if (devMode) {
|
|
185
|
-
console.log("[Glomo-RN-SDK LRS] MainWebView Message received:", message.type, message);
|
|
186
|
-
}
|
|
187
|
-
if (message.type === "console") {
|
|
188
|
-
if (devMode) {
|
|
189
|
-
const level = message.level || "log";
|
|
190
|
-
console.log(`[Glomo-RN-SDK LRS] [WebView ${level.toUpperCase()}]`, message.message);
|
|
191
|
-
}
|
|
192
|
-
return;
|
|
193
|
-
}
|
|
194
|
-
if (message.type === "window.open") {
|
|
234
|
+
},
|
|
235
|
+
"window.open": (message) => {
|
|
195
236
|
const url = message.url;
|
|
196
237
|
if (url && typeof url === "string" && (0, validation_1.isValidUrl)(url)) {
|
|
197
238
|
if (devMode) {
|
|
198
|
-
console.log(
|
|
239
|
+
console.log(`${LOG_PREFIX} window.open called from MainWebView: ${url}`);
|
|
199
240
|
}
|
|
200
241
|
setFlowWebViewUrl(url);
|
|
201
242
|
setShowFlowWebView(true);
|
|
@@ -205,32 +246,31 @@ function useLrsCheckout({ server, publicKey, orderId, onPaymentSuccess, onPaymen
|
|
|
205
246
|
}
|
|
206
247
|
else {
|
|
207
248
|
if (devMode) {
|
|
208
|
-
console.log(
|
|
249
|
+
console.log(`${LOG_PREFIX} Invalid URL in window.open from MainWebView:`, url, typeof url === "undefined" ? "undefined" : "");
|
|
209
250
|
}
|
|
210
251
|
}
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
if (message.type === "window.close") {
|
|
252
|
+
},
|
|
253
|
+
"window.close": () => {
|
|
214
254
|
if (devMode) {
|
|
215
|
-
console.log(
|
|
255
|
+
console.log(`${LOG_PREFIX} Child window close requested from MainWebView`);
|
|
216
256
|
}
|
|
217
257
|
setShowFlowWebView(false);
|
|
218
258
|
setFlowWebViewUrl("");
|
|
219
259
|
setEducationCarouselState("pending");
|
|
220
260
|
// Tracking window.close interception
|
|
221
261
|
(0, analytics_1.trackWindowClose)("main", orderId, publicKey, devMode, mockMode, checkoutUrl);
|
|
222
|
-
|
|
223
|
-
}
|
|
262
|
+
},
|
|
224
263
|
// Handling merchant JS callbacks on flow completion
|
|
225
|
-
|
|
264
|
+
message: (message) => {
|
|
226
265
|
const messageData = message.message;
|
|
227
|
-
|
|
266
|
+
if (!messageData)
|
|
267
|
+
return;
|
|
268
|
+
const messageType = messageData.type;
|
|
228
269
|
if (messageType === "payment.success" || messageType === "payment.complete") {
|
|
229
|
-
const
|
|
230
|
-
const payload = paymentMessage === null || paymentMessage === void 0 ? void 0 : paymentMessage.payload;
|
|
270
|
+
const payload = messageData.payload;
|
|
231
271
|
if ((0, validation_1.isValidPaymentPayload)(payload)) {
|
|
232
272
|
if (devMode) {
|
|
233
|
-
console.log(
|
|
273
|
+
console.log(`${LOG_PREFIX} Payment successful via merchant callback!`);
|
|
234
274
|
}
|
|
235
275
|
setShowCheckout(false);
|
|
236
276
|
setShowFlowWebView(false);
|
|
@@ -239,21 +279,32 @@ function useLrsCheckout({ server, publicKey, orderId, onPaymentSuccess, onPaymen
|
|
|
239
279
|
setStatus("payment_successful");
|
|
240
280
|
(0, validation_1.safeCallback)(onPaymentSuccess, [payload], "onPaymentSuccess", devMode);
|
|
241
281
|
// Tracking payment success callback
|
|
242
|
-
(0, analytics_1.trackPaymentSuccess)(
|
|
282
|
+
(0, analytics_1.trackPaymentSuccess)((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.success", missingFields, "main", payload.orderId, publicKey, devMode, mockMode, checkoutUrl, "lrs");
|
|
287
|
+
}
|
|
243
288
|
}
|
|
244
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
|
+
*/
|
|
245
295
|
if (devMode) {
|
|
246
|
-
console.error(
|
|
296
|
+
console.error(`${LOG_PREFIX} Unroutable payment.success payload from main:`, payload);
|
|
247
297
|
}
|
|
298
|
+
(0, analytics_1.trackDroppedPaymentPayload)("payment.success", (0, payment_payload_1.payloadKeysOf)(payload), "main", orderId, publicKey, devMode, mockMode, checkoutUrl, "lrs");
|
|
299
|
+
(0, validation_1.safeCallback)(onSdkError, [[(0, payment_payload_1.droppedPayloadSdkError)("payment.success")]], "onSdkError", devMode);
|
|
248
300
|
}
|
|
249
301
|
return;
|
|
250
302
|
}
|
|
251
303
|
if (messageType === "payment.failure" || messageType === "payment.error") {
|
|
252
|
-
const
|
|
253
|
-
const payload = paymentMessage === null || paymentMessage === void 0 ? void 0 : paymentMessage.payload;
|
|
304
|
+
const payload = messageData.payload;
|
|
254
305
|
if ((0, validation_1.isValidPaymentPayload)(payload)) {
|
|
255
306
|
if (devMode) {
|
|
256
|
-
console.error(
|
|
307
|
+
console.error(`${LOG_PREFIX} Payment failed via merchant callback`);
|
|
257
308
|
}
|
|
258
309
|
setShowCheckout(false);
|
|
259
310
|
setShowFlowWebView(false);
|
|
@@ -262,65 +313,86 @@ function useLrsCheckout({ server, publicKey, orderId, onPaymentSuccess, onPaymen
|
|
|
262
313
|
setStatus("payment_failed");
|
|
263
314
|
(0, validation_1.safeCallback)(onPaymentFailure, [payload], "onPaymentFailure", devMode);
|
|
264
315
|
// Tracking payment failure callback
|
|
265
|
-
(0, analytics_1.trackPaymentFailure)(
|
|
316
|
+
(0, analytics_1.trackPaymentFailure)((0, event_projections_1.toPaymentEventData)(payload), publicKey, devMode, mockMode, checkoutUrl);
|
|
317
|
+
// Fires alongside the callback, not instead of it - the outcome is real, the payload is thin
|
|
318
|
+
const missingFields = (0, validation_1.missingPaymentFields)(payload);
|
|
319
|
+
if (missingFields.length > 0) {
|
|
320
|
+
(0, analytics_1.trackIncompletePaymentPayload)("payment.failure", missingFields, "main", payload.orderId, publicKey, devMode, mockMode, checkoutUrl, "lrs");
|
|
321
|
+
}
|
|
266
322
|
}
|
|
267
323
|
else {
|
|
324
|
+
/**
|
|
325
|
+
* Reported, not dropped. Before v5 this branch was a devMode-only console.error, so in a
|
|
326
|
+
* release build a terminal payment outcome the SDK could not route left no trace
|
|
327
|
+
* anywhere - no callback, no telemetry, nothing for support to find.
|
|
328
|
+
*/
|
|
268
329
|
if (devMode) {
|
|
269
|
-
console.error(
|
|
330
|
+
console.error(`${LOG_PREFIX} Unroutable payment.failure payload from main:`, payload);
|
|
270
331
|
}
|
|
332
|
+
(0, analytics_1.trackDroppedPaymentPayload)("payment.failure", (0, payment_payload_1.payloadKeysOf)(payload), "main", orderId, publicKey, devMode, mockMode, checkoutUrl, "lrs");
|
|
333
|
+
(0, validation_1.safeCallback)(onSdkError, [[(0, payment_payload_1.droppedPayloadSdkError)("payment.failure")]], "onSdkError", devMode);
|
|
271
334
|
}
|
|
272
335
|
return;
|
|
273
336
|
}
|
|
274
337
|
// Handling checkout.closed events
|
|
275
338
|
if (messageType === "checkout.closed") {
|
|
276
339
|
if (devMode) {
|
|
277
|
-
console.log(
|
|
340
|
+
console.log(`${LOG_PREFIX} Checkout closed event received`);
|
|
278
341
|
}
|
|
279
342
|
setShowCheckout(false);
|
|
280
343
|
setShowFlowWebView(false);
|
|
281
344
|
setFlowWebViewUrl("");
|
|
282
345
|
setEducationCarouselState("pending");
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
346
|
+
const termination = { source: checkout_1.TERMINATION_SOURCES.CHECKOUT_CLOSED };
|
|
347
|
+
(0, validation_1.safeCallback)(onPaymentTerminate, [termination], "onPaymentTerminate", devMode);
|
|
348
|
+
// One object to the host and to telemetry, so the two cannot drift
|
|
349
|
+
(0, analytics_1.trackPaymentTerminate)(orderId, (0, event_projections_1.toTerminationEventData)(termination), publicKey, devMode, mockMode, checkoutUrl);
|
|
287
350
|
}
|
|
288
|
-
}
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
351
|
+
},
|
|
352
|
+
},
|
|
353
|
+
}), [
|
|
354
|
+
onPaymentSuccess,
|
|
355
|
+
onPaymentFailure,
|
|
356
|
+
onPaymentTerminate,
|
|
357
|
+
devMode,
|
|
358
|
+
mockMode,
|
|
359
|
+
orderId,
|
|
360
|
+
publicKey,
|
|
361
|
+
checkoutUrl,
|
|
362
|
+
fileSaveHandler,
|
|
363
|
+
onSdkError,
|
|
364
|
+
fileInputHandler,
|
|
365
|
+
]);
|
|
296
366
|
// Handler for the flow WebView messages
|
|
297
|
-
const handleFlowWebViewMessage = (0, react_1.
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
367
|
+
const handleFlowWebViewMessage = (0, react_1.useMemo)(() => (0, message_router_1.createMessageRouter)({
|
|
368
|
+
logPrefix: LOG_PREFIX,
|
|
369
|
+
source: "FlowWebView",
|
|
370
|
+
devMode,
|
|
371
|
+
onInvalidMessage: (data) => {
|
|
372
|
+
(0, analytics_1.trackInvalidMessageReceived)("flow", data, flowWebViewUrl, orderId, publicKey, devMode, mockMode, checkoutUrl);
|
|
373
|
+
},
|
|
374
|
+
handlers: {
|
|
375
|
+
/**
|
|
376
|
+
* Telemetry only, and deliberately not wired to onUserRefusedDevicePermissions.
|
|
377
|
+
* The flow injection sees this by watching getUserMedia, so coverage depends on
|
|
378
|
+
* whether a given bank uses it - partial coverage on a merchant callback is
|
|
379
|
+
* worse than none, because silence would stop being unambiguous.
|
|
380
|
+
*/
|
|
381
|
+
"permission.denied": (message) => {
|
|
382
|
+
(0, analytics_1.trackDevicePermissionRefused)(typeof message.resource === "string" ? message.resource : "camera", "get_user_media", orderId, publicKey, devMode, mockMode, checkoutUrl, "lrs");
|
|
383
|
+
},
|
|
384
|
+
"file.save": fileSaveHandler,
|
|
385
|
+
"file.input": fileInputHandler,
|
|
386
|
+
console: (message) => {
|
|
302
387
|
if (devMode) {
|
|
303
|
-
console.
|
|
388
|
+
console.log(`${LOG_PREFIX} [Flow] ${message.message}`);
|
|
304
389
|
}
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
return;
|
|
308
|
-
}
|
|
309
|
-
const message = JSON.parse(data);
|
|
310
|
-
if (devMode) {
|
|
311
|
-
console.log("[Glomo-RN-SDK LRS] FlowWebView Message received:", message.type, message);
|
|
312
|
-
}
|
|
313
|
-
if (message.type === "console") {
|
|
314
|
-
if (devMode) {
|
|
315
|
-
console.log(`[Glomo-RN-SDK LRS] [Flow] ${message.message}`);
|
|
316
|
-
}
|
|
317
|
-
return;
|
|
318
|
-
}
|
|
319
|
-
if (message.type === "window.open") {
|
|
390
|
+
},
|
|
391
|
+
"window.open": (message) => {
|
|
320
392
|
const url = message.url;
|
|
321
393
|
if (url && typeof url === "string" && (0, validation_1.isValidUrl)(url)) {
|
|
322
394
|
if (devMode) {
|
|
323
|
-
console.log(
|
|
395
|
+
console.log(`${LOG_PREFIX} window.open called from FlowWebView: ${url}`);
|
|
324
396
|
}
|
|
325
397
|
setFlowWebViewUrl(url);
|
|
326
398
|
setEducationCarouselState("pending");
|
|
@@ -329,31 +401,31 @@ function useLrsCheckout({ server, publicKey, orderId, onPaymentSuccess, onPaymen
|
|
|
329
401
|
}
|
|
330
402
|
else {
|
|
331
403
|
if (devMode) {
|
|
332
|
-
console.log(
|
|
404
|
+
console.log(`${LOG_PREFIX} Invalid URL in window.open from FlowWebView:`, url, typeof url === "undefined" ? "undefined" : "");
|
|
333
405
|
}
|
|
334
406
|
}
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
if (message.type === "window.close") {
|
|
407
|
+
},
|
|
408
|
+
"window.close": () => {
|
|
338
409
|
if (devMode) {
|
|
339
|
-
console.log(
|
|
410
|
+
console.log(`${LOG_PREFIX} FlowWebView close requested`);
|
|
340
411
|
}
|
|
341
412
|
setShowFlowWebView(false);
|
|
342
413
|
setFlowWebViewUrl("");
|
|
343
414
|
setEducationCarouselState("pending");
|
|
344
415
|
// Tracking window.close interception
|
|
345
416
|
(0, analytics_1.trackWindowClose)("flow", orderId, publicKey, devMode, mockMode, checkoutUrl);
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
417
|
+
},
|
|
418
|
+
// Handling merchant JS callbacks on flow completion
|
|
419
|
+
message: (message) => {
|
|
349
420
|
const messageData = message.message;
|
|
350
|
-
|
|
421
|
+
if (!messageData)
|
|
422
|
+
return;
|
|
423
|
+
const messageType = messageData.type;
|
|
351
424
|
if (messageType === "payment.success" || messageType === "payment.complete") {
|
|
352
|
-
const
|
|
353
|
-
const payload = paymentMessage === null || paymentMessage === void 0 ? void 0 : paymentMessage.payload;
|
|
425
|
+
const payload = messageData.payload;
|
|
354
426
|
if ((0, validation_1.isValidPaymentPayload)(payload)) {
|
|
355
427
|
if (devMode) {
|
|
356
|
-
console.log(
|
|
428
|
+
console.log(`${LOG_PREFIX} Payment successful via FlowWebView callback!`);
|
|
357
429
|
}
|
|
358
430
|
setShowFlowWebView(false);
|
|
359
431
|
setShowCheckout(false);
|
|
@@ -362,21 +434,32 @@ function useLrsCheckout({ server, publicKey, orderId, onPaymentSuccess, onPaymen
|
|
|
362
434
|
setStatus("payment_successful");
|
|
363
435
|
(0, validation_1.safeCallback)(onPaymentSuccess, [payload], "onPaymentSuccess", devMode);
|
|
364
436
|
// Tracking payment success callback
|
|
365
|
-
(0, analytics_1.trackPaymentSuccess)(
|
|
437
|
+
(0, analytics_1.trackPaymentSuccess)((0, event_projections_1.toPaymentEventData)(payload), publicKey, devMode, mockMode, checkoutUrl);
|
|
438
|
+
// Fires alongside the callback, not instead of it - the outcome is real, the payload is thin
|
|
439
|
+
const missingFields = (0, validation_1.missingPaymentFields)(payload);
|
|
440
|
+
if (missingFields.length > 0) {
|
|
441
|
+
(0, analytics_1.trackIncompletePaymentPayload)("payment.success", missingFields, "flow", payload.orderId, publicKey, devMode, mockMode, checkoutUrl, "lrs");
|
|
442
|
+
}
|
|
366
443
|
}
|
|
367
444
|
else {
|
|
445
|
+
/**
|
|
446
|
+
* Reported, not dropped. Before v5 this branch was a devMode-only console.error, so in a
|
|
447
|
+
* release build a terminal payment outcome the SDK could not route left no trace
|
|
448
|
+
* anywhere - no callback, no telemetry, nothing for support to find.
|
|
449
|
+
*/
|
|
368
450
|
if (devMode) {
|
|
369
|
-
console.error(
|
|
451
|
+
console.error(`${LOG_PREFIX} Unroutable payment.success payload from flow:`, payload);
|
|
370
452
|
}
|
|
453
|
+
(0, analytics_1.trackDroppedPaymentPayload)("payment.success", (0, payment_payload_1.payloadKeysOf)(payload), "flow", orderId, publicKey, devMode, mockMode, checkoutUrl, "lrs");
|
|
454
|
+
(0, validation_1.safeCallback)(onSdkError, [[(0, payment_payload_1.droppedPayloadSdkError)("payment.success")]], "onSdkError", devMode);
|
|
371
455
|
}
|
|
372
456
|
return;
|
|
373
457
|
}
|
|
374
458
|
if (messageType === "payment.failure" || messageType === "payment.error") {
|
|
375
|
-
const
|
|
376
|
-
const payload = paymentMessage === null || paymentMessage === void 0 ? void 0 : paymentMessage.payload;
|
|
459
|
+
const payload = messageData.payload;
|
|
377
460
|
if ((0, validation_1.isValidPaymentPayload)(payload)) {
|
|
378
461
|
if (devMode) {
|
|
379
|
-
console.error(
|
|
462
|
+
console.error(`${LOG_PREFIX} Payment failed via FlowWebView callback`);
|
|
380
463
|
}
|
|
381
464
|
setShowFlowWebView(false);
|
|
382
465
|
setShowCheckout(false);
|
|
@@ -385,60 +468,61 @@ function useLrsCheckout({ server, publicKey, orderId, onPaymentSuccess, onPaymen
|
|
|
385
468
|
setStatus("payment_failed");
|
|
386
469
|
(0, validation_1.safeCallback)(onPaymentFailure, [payload], "onPaymentFailure", devMode);
|
|
387
470
|
// Tracking payment failure callback
|
|
388
|
-
(0, analytics_1.trackPaymentFailure)(
|
|
471
|
+
(0, analytics_1.trackPaymentFailure)((0, event_projections_1.toPaymentEventData)(payload), publicKey, devMode, mockMode, checkoutUrl);
|
|
472
|
+
// Fires alongside the callback, not instead of it - the outcome is real, the payload is thin
|
|
473
|
+
const missingFields = (0, validation_1.missingPaymentFields)(payload);
|
|
474
|
+
if (missingFields.length > 0) {
|
|
475
|
+
(0, analytics_1.trackIncompletePaymentPayload)("payment.failure", missingFields, "flow", payload.orderId, publicKey, devMode, mockMode, checkoutUrl, "lrs");
|
|
476
|
+
}
|
|
389
477
|
}
|
|
390
478
|
else {
|
|
479
|
+
/**
|
|
480
|
+
* Reported, not dropped. Before v5 this branch was a devMode-only console.error, so in a
|
|
481
|
+
* release build a terminal payment outcome the SDK could not route left no trace
|
|
482
|
+
* anywhere - no callback, no telemetry, nothing for support to find.
|
|
483
|
+
*/
|
|
391
484
|
if (devMode) {
|
|
392
|
-
console.error(
|
|
485
|
+
console.error(`${LOG_PREFIX} Unroutable payment.failure payload from flow:`, payload);
|
|
393
486
|
}
|
|
487
|
+
(0, analytics_1.trackDroppedPaymentPayload)("payment.failure", (0, payment_payload_1.payloadKeysOf)(payload), "flow", orderId, publicKey, devMode, mockMode, checkoutUrl, "lrs");
|
|
488
|
+
(0, validation_1.safeCallback)(onSdkError, [[(0, payment_payload_1.droppedPayloadSdkError)("payment.failure")]], "onSdkError", devMode);
|
|
394
489
|
}
|
|
395
|
-
return;
|
|
396
490
|
}
|
|
397
|
-
}
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
491
|
+
},
|
|
492
|
+
},
|
|
493
|
+
}), [
|
|
494
|
+
onPaymentSuccess,
|
|
495
|
+
onPaymentFailure,
|
|
496
|
+
devMode,
|
|
497
|
+
mockMode,
|
|
498
|
+
orderId,
|
|
499
|
+
publicKey,
|
|
500
|
+
flowWebViewUrl,
|
|
501
|
+
checkoutUrl,
|
|
502
|
+
fileSaveHandler,
|
|
503
|
+
onSdkError,
|
|
504
|
+
fileInputHandler,
|
|
505
|
+
]);
|
|
405
506
|
// Handler for the education carousel WebView messages
|
|
406
|
-
const handleEducationCarouselWebViewMessage = (0, react_1.
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
507
|
+
const handleEducationCarouselWebViewMessage = (0, react_1.useMemo)(() => (0, message_router_1.createMessageRouter)({
|
|
508
|
+
logPrefix: LOG_PREFIX,
|
|
509
|
+
source: "EducationCarouselWebView",
|
|
510
|
+
devMode,
|
|
511
|
+
handlers: {
|
|
512
|
+
console: (message) => {
|
|
411
513
|
if (devMode) {
|
|
412
|
-
console.
|
|
514
|
+
console.log(`${LOG_PREFIX} [EducationCarousel] ${message.message}`);
|
|
413
515
|
}
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
const message = JSON.parse(data);
|
|
417
|
-
if (devMode) {
|
|
418
|
-
console.log("[Glomo-RN-SDK LRS] EducationCarouselWebView Message received:", message.type, message);
|
|
419
|
-
}
|
|
420
|
-
if (message.type === "console") {
|
|
516
|
+
},
|
|
517
|
+
"lrs.has_education_steps": (message) => {
|
|
421
518
|
if (devMode) {
|
|
422
|
-
console.log(
|
|
519
|
+
console.log(`${LOG_PREFIX} Education carousel signal received: value=${String(message.value)} source=${message.source || "unknown"} payload=${JSON.stringify(message.payload || {})}`);
|
|
423
520
|
}
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
console.log(`[Glomo-RN-SDK LRS] Education carousel signal received: value=${String(message.value)} source=${message.source || "unknown"} payload=${JSON.stringify(message.payload || {})}`);
|
|
430
|
-
}
|
|
431
|
-
(0, analytics_1.trackEducationStepsShown)(orderId, publicKey, devMode, mockMode, checkoutUrl, message.source);
|
|
432
|
-
setEducationCarouselState(nextState);
|
|
433
|
-
return;
|
|
434
|
-
}
|
|
435
|
-
}
|
|
436
|
-
catch (error) {
|
|
437
|
-
if (devMode) {
|
|
438
|
-
console.error("[Glomo-RN-SDK LRS] Error parsing EducationCarouselWebView message:", error);
|
|
439
|
-
}
|
|
440
|
-
}
|
|
441
|
-
}, [checkoutUrl, devMode, mockMode, orderId, publicKey]);
|
|
521
|
+
(0, analytics_1.trackEducationStepsShown)(orderId, publicKey, devMode, mockMode, checkoutUrl, typeof message.source === "string" ? message.source : undefined);
|
|
522
|
+
setEducationCarouselState("hasContent");
|
|
523
|
+
},
|
|
524
|
+
},
|
|
525
|
+
}), [checkoutUrl, devMode, mockMode, orderId, publicKey]);
|
|
442
526
|
// Handler for the navigation state changes
|
|
443
527
|
const handleNavigationStateChange = (0, react_1.useCallback)((navState) => {
|
|
444
528
|
if (devMode) {
|
|
@@ -469,10 +553,18 @@ function useLrsCheckout({ server, publicKey, orderId, onPaymentSuccess, onPaymen
|
|
|
469
553
|
console.log("[Glomo-RN-SDK LRS] Ignoring checkout status update for: " + status);
|
|
470
554
|
}
|
|
471
555
|
}
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
556
|
+
/**
|
|
557
|
+
* Inferred from the platform rather than read off an event, because `onRequestClose` is
|
|
558
|
+
* the only wiring here and the two platforms raise it for different gestures: Android
|
|
559
|
+
* for hardware back and the back gesture, iOS for swipe-down on the pageSheet. Nothing
|
|
560
|
+
* else routes through it, so the inference is sound - but it is an inference.
|
|
561
|
+
*/
|
|
562
|
+
const termination = {
|
|
563
|
+
source: react_native_1.Platform.OS === "ios" ? checkout_1.TERMINATION_SOURCES.MODAL_DISMISS : checkout_1.TERMINATION_SOURCES.DEVICE_BACK_BUTTON,
|
|
564
|
+
};
|
|
565
|
+
(0, validation_1.safeCallback)(onPaymentTerminate, [termination], "onPaymentTerminate", devMode);
|
|
566
|
+
// One object to the host and to telemetry, so the two cannot drift
|
|
567
|
+
(0, analytics_1.trackPaymentTerminate)(orderId, (0, event_projections_1.toTerminationEventData)(termination), publicKey, devMode, mockMode, checkoutUrl);
|
|
476
568
|
}
|
|
477
569
|
catch (error) {
|
|
478
570
|
if (devMode) {
|
|
@@ -480,6 +572,28 @@ function useLrsCheckout({ server, publicKey, orderId, onPaymentSuccess, onPaymen
|
|
|
480
572
|
}
|
|
481
573
|
}
|
|
482
574
|
}, [showFlowWebView, devMode, onPaymentTerminate, status, orderId, publicKey, mockMode, checkoutUrl]);
|
|
575
|
+
/**
|
|
576
|
+
* Closing the checkout when the user refuses camera access, since the bank page cannot
|
|
577
|
+
* proceed without it. Kept here rather than inside usePermissionRequest because moving the
|
|
578
|
+
* status and notifying the merchant are flow concerns.
|
|
579
|
+
*/
|
|
580
|
+
const handleDevicePermissionDenied = (0, react_1.useCallback)(() => {
|
|
581
|
+
setShowCheckout(false);
|
|
582
|
+
setShowFlowWebView(false);
|
|
583
|
+
setFlowWebViewUrl("");
|
|
584
|
+
setEducationCarouselState("pending");
|
|
585
|
+
if (status === "payment_in_progress") {
|
|
586
|
+
setStatus("payment_cancelled");
|
|
587
|
+
}
|
|
588
|
+
(0, validation_1.safeCallback)(onUserRefusedDevicePermissions, [], "onUserRefusedDevicePermissions", devMode);
|
|
589
|
+
// The permission hook only reaches here for camera; anything else is denied without notifying
|
|
590
|
+
(0, analytics_1.trackDevicePermissionRefused)("camera", "permission_request", orderId, publicKey, devMode, mockMode, checkoutUrl, "lrs");
|
|
591
|
+
}, [status, onUserRefusedDevicePermissions, devMode, orderId, publicKey, mockMode, checkoutUrl]);
|
|
592
|
+
const handlePermissionRequest = (0, use_permission_request_1.usePermissionRequest)({
|
|
593
|
+
logPrefix: "[Glomo-RN-SDK LRS]",
|
|
594
|
+
onDenied: handleDevicePermissionDenied,
|
|
595
|
+
devMode,
|
|
596
|
+
});
|
|
483
597
|
/** Closes the flow WebView and returns to the main checkout */
|
|
484
598
|
const handleFlowBack = (0, react_1.useCallback)(() => {
|
|
485
599
|
if (devMode) {
|
|
@@ -488,7 +602,7 @@ function useLrsCheckout({ server, publicKey, orderId, onPaymentSuccess, onPaymen
|
|
|
488
602
|
setShowFlowWebView(false);
|
|
489
603
|
setFlowWebViewUrl("");
|
|
490
604
|
setEducationCarouselState("pending");
|
|
491
|
-
(0, analytics_1.
|
|
605
|
+
(0, analytics_1.trackBackNavigationViaSdkBackButton)(orderId, publicKey, devMode, mockMode, checkoutUrl, "lrs");
|
|
492
606
|
}, [devMode, orderId, publicKey, mockMode, checkoutUrl]);
|
|
493
607
|
/**
|
|
494
608
|
* Initiator method for the LRS Checkout flow.
|
|
@@ -507,38 +621,62 @@ function useLrsCheckout({ server, publicKey, orderId, onPaymentSuccess, onPaymen
|
|
|
507
621
|
* Checking device security compliance (if peerDependencies are available)
|
|
508
622
|
* A null value indicates that recommended security dependencies were not installed and compliance checks will be skipped in this case
|
|
509
623
|
*/
|
|
510
|
-
const
|
|
511
|
-
const
|
|
512
|
-
const
|
|
513
|
-
|
|
514
|
-
|
|
624
|
+
const compliance = (0, device_compliance_1.resolveDeviceCompliance)(devMode);
|
|
625
|
+
const complianceLibraryInstalled = (0, device_compliance_1.isComplianceCheckAvailable)();
|
|
626
|
+
const fileSave = (0, index_2.resolveFileSaveAvailability)();
|
|
627
|
+
const dependencyInfo = {
|
|
628
|
+
jailbreakDetectionLibraryInstalled: complianceLibraryInstalled,
|
|
629
|
+
jailbreakDetected: compliance.compromised,
|
|
630
|
+
complianceSource: compliance.source,
|
|
631
|
+
complianceSignals: compliance.trippedSignals,
|
|
632
|
+
fileSaveAvailable: fileSave.available,
|
|
633
|
+
missingFileSavePackages: fileSave.missing,
|
|
515
634
|
};
|
|
516
635
|
if (devMode) {
|
|
517
636
|
console.log(`[Glomo-RN-SDK LRS] Attempting to start checkout of ${checkoutUrl} from status: ${status}`);
|
|
518
637
|
}
|
|
519
638
|
// Tracking start attempt with current status
|
|
520
|
-
(0, analytics_1.trackStartAttempt)(status, orderId, publicKey, devMode, mockMode, checkoutUrl,
|
|
521
|
-
|
|
522
|
-
|
|
639
|
+
(0, analytics_1.trackStartAttempt)(status, orderId, publicKey, devMode, mockMode, checkoutUrl, dependencyInfo);
|
|
640
|
+
/**
|
|
641
|
+
* Ungated on purpose, both of them. An absent optional dependency degrades silently by
|
|
642
|
+
* design, so a console warning is the only thing that reaches a merchant who has not
|
|
643
|
+
* noticed - and the compliance one now precedes a hard block on live keys.
|
|
644
|
+
*/
|
|
645
|
+
if (!complianceLibraryInstalled) {
|
|
646
|
+
console.warn("[Glomo-RN-SDK LRS] jail-monkey is not installed or its native module is not linked, so " +
|
|
647
|
+
"rooted and jailbroken devices cannot be detected. As of v5 this BLOCKS live checkouts. " +
|
|
648
|
+
"Install jail-monkey and rebuild the app - see the README.");
|
|
649
|
+
}
|
|
650
|
+
if (!fileSave.available) {
|
|
651
|
+
console.warn(`[Glomo-RN-SDK LRS] Document downloads are disabled: ${fileSave.missing.join(" and ")} ` +
|
|
652
|
+
"could not be loaded. Install the package(s) and rebuild the app, or ignore this if your " +
|
|
653
|
+
"checkout does not offer downloads - the page falls back to its own behaviour.");
|
|
654
|
+
}
|
|
655
|
+
if ((0, device_compliance_1.blocksCheckout)(compliance, publicKey)) {
|
|
656
|
+
/**
|
|
657
|
+
* Two conditions, one refusal. `compromised === true` is a rooted or jailbroken device;
|
|
658
|
+
* `null` is a device we could not check, which on RN overwhelmingly means jail-monkey is
|
|
659
|
+
* absent rather than that a platform probe failed. Both fail closed on a live key, and
|
|
660
|
+
* neither fires on a test or mock key.
|
|
661
|
+
*/
|
|
662
|
+
const unknown = compliance.compromised === null;
|
|
523
663
|
if (devMode) {
|
|
524
|
-
console.error(
|
|
664
|
+
console.error(`[Glomo-RN-SDK LRS] Cannot start checkout. ${unknown ? "Device security could not be verified." : "Device is rooted or jailbroken."}`);
|
|
525
665
|
}
|
|
526
666
|
const errors = [
|
|
527
667
|
{
|
|
528
668
|
type: "device_forbidden",
|
|
529
|
-
message:
|
|
669
|
+
message: unknown
|
|
670
|
+
? "LRS checkout could not verify this device's security. Install jail-monkey and rebuild the app."
|
|
671
|
+
: "LRS checkout is not allowed on rooted or jailbroken devices.",
|
|
530
672
|
},
|
|
531
673
|
];
|
|
532
674
|
(0, validation_1.safeCallback)(onSdkError, [errors], "onSdkError", devMode);
|
|
533
675
|
// Tracking start() failure
|
|
534
|
-
(0, analytics_1.trackStartFailure)("device_forbidden", orderId, publicKey, devMode, mockMode, checkoutUrl,
|
|
676
|
+
(0, analytics_1.trackStartFailure)(unknown ? "device_compliance_unknown" : "device_forbidden", orderId, publicKey, devMode, mockMode, checkoutUrl, dependencyInfo);
|
|
535
677
|
setShowCheckout(false);
|
|
536
678
|
return false;
|
|
537
679
|
}
|
|
538
|
-
else if (deviceComplianceCheck === null) {
|
|
539
|
-
// 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.
|
|
540
|
-
console.warn("[Glomo-RN-SDK LRS] 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 LRS checkouts from compromised devices.");
|
|
541
|
-
}
|
|
542
680
|
// Enforcing devMode requirement for development servers
|
|
543
681
|
const resolvedServer = server || "prod";
|
|
544
682
|
if (!devMode && resolvedServer !== "prod") {
|
|
@@ -550,7 +688,7 @@ function useLrsCheckout({ server, publicKey, orderId, onPaymentSuccess, onPaymen
|
|
|
550
688
|
];
|
|
551
689
|
(0, validation_1.safeCallback)(onSdkError, [errors], "onSdkError", devMode);
|
|
552
690
|
(0, analytics_1.trackSdkError)(errors, orderId, publicKey, devMode, mockMode, checkoutUrl);
|
|
553
|
-
(0, analytics_1.trackStartFailure)("validation_error", orderId, publicKey, devMode, mockMode, checkoutUrl,
|
|
691
|
+
(0, analytics_1.trackStartFailure)("validation_error", orderId, publicKey, devMode, mockMode, checkoutUrl, dependencyInfo);
|
|
554
692
|
setShowCheckout(false);
|
|
555
693
|
return false;
|
|
556
694
|
}
|
|
@@ -593,7 +731,7 @@ function useLrsCheckout({ server, publicKey, orderId, onPaymentSuccess, onPaymen
|
|
|
593
731
|
(0, validation_1.safeCallback)(onSdkError, [errors], "onSdkError", devMode);
|
|
594
732
|
// Tracking start() failure
|
|
595
733
|
(0, analytics_1.trackSdkError)(errors, orderId, publicKey, devMode, mockMode, checkoutUrl);
|
|
596
|
-
(0, analytics_1.trackStartFailure)("validation_error", orderId, publicKey, devMode, mockMode, checkoutUrl,
|
|
734
|
+
(0, analytics_1.trackStartFailure)("validation_error", orderId, publicKey, devMode, mockMode, checkoutUrl, dependencyInfo);
|
|
597
735
|
setShowCheckout(false);
|
|
598
736
|
return false;
|
|
599
737
|
}
|
|
@@ -602,7 +740,7 @@ function useLrsCheckout({ server, publicKey, orderId, onPaymentSuccess, onPaymen
|
|
|
602
740
|
console.log(`[Glomo-RN-SDK LRS] Cannot start checkout. Current status: ${status}. Payment already successful.`);
|
|
603
741
|
}
|
|
604
742
|
// Tracking start() failure
|
|
605
|
-
(0, analytics_1.trackStartFailure)("payment_successful", orderId, publicKey, devMode, mockMode, checkoutUrl,
|
|
743
|
+
(0, analytics_1.trackStartFailure)("payment_successful", orderId, publicKey, devMode, mockMode, checkoutUrl, dependencyInfo);
|
|
606
744
|
setShowCheckout(false);
|
|
607
745
|
return false;
|
|
608
746
|
}
|
|
@@ -616,7 +754,7 @@ function useLrsCheckout({ server, publicKey, orderId, onPaymentSuccess, onPaymen
|
|
|
616
754
|
console.log(`[Glomo-RN-SDK LRS] Cannot start checkout. Unknown status: ${status}.`);
|
|
617
755
|
}
|
|
618
756
|
// Tracking start() failure
|
|
619
|
-
(0, analytics_1.trackStartFailure)("invalid_status", orderId, publicKey, devMode, mockMode, checkoutUrl,
|
|
757
|
+
(0, analytics_1.trackStartFailure)("invalid_status", orderId, publicKey, devMode, mockMode, checkoutUrl, dependencyInfo);
|
|
620
758
|
setShowCheckout(false);
|
|
621
759
|
return false;
|
|
622
760
|
}
|
|
@@ -625,7 +763,7 @@ function useLrsCheckout({ server, publicKey, orderId, onPaymentSuccess, onPaymen
|
|
|
625
763
|
console.error("[Glomo-RN-SDK LRS] Cannot start checkout. Invalid checkout URL.");
|
|
626
764
|
}
|
|
627
765
|
// Tracking start() failure
|
|
628
|
-
(0, analytics_1.trackStartFailure)("invalid_url", orderId, publicKey, devMode, mockMode, checkoutUrl,
|
|
766
|
+
(0, analytics_1.trackStartFailure)("invalid_url", orderId, publicKey, devMode, mockMode, checkoutUrl, dependencyInfo);
|
|
629
767
|
setShowCheckout(false);
|
|
630
768
|
return false;
|
|
631
769
|
}
|
|
@@ -637,7 +775,7 @@ function useLrsCheckout({ server, publicKey, orderId, onPaymentSuccess, onPaymen
|
|
|
637
775
|
setEducationCarouselState("pending");
|
|
638
776
|
setStatus("payment_in_progress");
|
|
639
777
|
// Tracking successful start
|
|
640
|
-
(0, analytics_1.trackStartSuccess)(orderId, publicKey, devMode, mockMode, checkoutUrl,
|
|
778
|
+
(0, analytics_1.trackStartSuccess)(orderId, publicKey, devMode, mockMode, checkoutUrl, dependencyInfo);
|
|
641
779
|
setShowCheckout(true);
|
|
642
780
|
return true;
|
|
643
781
|
}, [devMode, status, publicKey, orderId, baseCheckoutUrl, checkoutUrl, mockMode, onSdkError, server]);
|
|
@@ -672,6 +810,13 @@ function useLrsCheckout({ server, publicKey, orderId, onPaymentSuccess, onPaymen
|
|
|
672
810
|
setEducationCarouselState("pending");
|
|
673
811
|
};
|
|
674
812
|
}, []);
|
|
813
|
+
/**
|
|
814
|
+
* Scripts injected into each WebView, carrying what this build can advertise.
|
|
815
|
+
*
|
|
816
|
+
* Resolved once per mount rather than at module load, so a merchant who never opens a
|
|
817
|
+
* checkout never pays for the dependency probe.
|
|
818
|
+
*/
|
|
819
|
+
const injectionScripts = (0, react_1.useMemo)(() => (0, index_1.buildInjectionScripts)((0, index_2.resolveCapabilities)()), []);
|
|
675
820
|
return {
|
|
676
821
|
start,
|
|
677
822
|
status,
|
|
@@ -692,12 +837,13 @@ function useLrsCheckout({ server, publicKey, orderId, onPaymentSuccess, onPaymen
|
|
|
692
837
|
handleNavigationStateChange,
|
|
693
838
|
handleModalBackButton,
|
|
694
839
|
handleFlowBack,
|
|
840
|
+
handlePermissionRequest,
|
|
695
841
|
injectedMain: __DEV__ && (internalOptions === null || internalOptions === void 0 ? void 0 : internalOptions._testInjectionScript)
|
|
696
|
-
?
|
|
697
|
-
:
|
|
698
|
-
injectedFlow:
|
|
842
|
+
? injectionScripts.main + internalOptions._testInjectionScript
|
|
843
|
+
: injectionScripts.main,
|
|
844
|
+
injectedFlow: injectionScripts.flow,
|
|
699
845
|
injectedEducationCarousel: __DEV__ && (internalOptions === null || internalOptions === void 0 ? void 0 : internalOptions._testCarouselInjectionScript)
|
|
700
|
-
?
|
|
701
|
-
:
|
|
846
|
+
? injectionScripts.educationCarousel + internalOptions._testCarouselInjectionScript
|
|
847
|
+
: injectionScripts.educationCarousel,
|
|
702
848
|
};
|
|
703
849
|
}
|