@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.
Files changed (124) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/MIGRATION.md +112 -0
  3. package/README.md +173 -36
  4. package/lib/bridge/file-input-handler.d.ts +25 -0
  5. package/lib/bridge/file-input-handler.d.ts.map +1 -0
  6. package/lib/bridge/file-input-handler.js +38 -0
  7. package/lib/bridge/file-save-handler.d.ts +32 -0
  8. package/lib/bridge/file-save-handler.d.ts.map +1 -0
  9. package/lib/bridge/file-save-handler.js +92 -0
  10. package/lib/bridge/message-router.d.ts +44 -0
  11. package/lib/bridge/message-router.d.ts.map +1 -0
  12. package/lib/bridge/message-router.js +48 -0
  13. package/lib/bridge/payment-payload.d.ts +18 -0
  14. package/lib/bridge/payment-payload.d.ts.map +1 -0
  15. package/lib/bridge/payment-payload.js +31 -0
  16. package/lib/capabilities/file-save.d.ts +40 -0
  17. package/lib/capabilities/file-save.d.ts.map +1 -0
  18. package/lib/capabilities/file-save.js +101 -0
  19. package/lib/capabilities/index.d.ts +22 -0
  20. package/lib/capabilities/index.d.ts.map +1 -0
  21. package/lib/capabilities/index.js +34 -0
  22. package/lib/capabilities/use-capability-reporting.d.ts +24 -0
  23. package/lib/capabilities/use-capability-reporting.d.ts.map +1 -0
  24. package/lib/capabilities/use-capability-reporting.js +44 -0
  25. package/lib/config/base.d.ts +12 -0
  26. package/lib/config/base.d.ts.map +1 -1
  27. package/lib/config/base.js +13 -1
  28. package/lib/glomo-checkout.d.ts +6 -1
  29. package/lib/glomo-checkout.d.ts.map +1 -1
  30. package/lib/glomo-checkout.js +11 -5
  31. package/lib/glomo-lrs-checkout.d.ts.map +1 -1
  32. package/lib/glomo-lrs-checkout.js +33 -10
  33. package/lib/glomo-standard-checkout.d.ts +3 -1
  34. package/lib/glomo-standard-checkout.d.ts.map +1 -1
  35. package/lib/glomo-standard-checkout.js +21 -13
  36. package/lib/glomo-subscriptions-checkout.d.ts.map +1 -1
  37. package/lib/glomo-subscriptions-checkout.js +1 -1
  38. package/lib/index.d.ts +2 -2
  39. package/lib/index.d.ts.map +1 -1
  40. package/lib/index.js +4 -3
  41. package/lib/injections/index.d.ts +24 -0
  42. package/lib/injections/index.d.ts.map +1 -1
  43. package/lib/injections/index.js +41 -0
  44. package/lib/injections/webview-flow.injection.d.ts.map +1 -1
  45. package/lib/injections/webview-flow.injection.js +76 -0
  46. package/lib/injections/webview-main.injection.d.ts.map +1 -1
  47. package/lib/injections/webview-main.injection.js +31 -0
  48. package/lib/injections/webview-standard.injection.d.ts.map +1 -1
  49. package/lib/injections/webview-standard.injection.js +31 -0
  50. package/lib/services/file-saver.d.ts +109 -0
  51. package/lib/services/file-saver.d.ts.map +1 -0
  52. package/lib/services/file-saver.js +416 -0
  53. package/lib/types/checkout.d.ts +58 -6
  54. package/lib/types/checkout.d.ts.map +1 -1
  55. package/lib/types/checkout.js +24 -2
  56. package/lib/types/standard-checkout.d.ts +6 -6
  57. package/lib/types/standard-checkout.d.ts.map +1 -1
  58. package/lib/types/subscriptions-checkout.d.ts +3 -3
  59. package/lib/types/subscriptions-checkout.d.ts.map +1 -1
  60. package/lib/use-glomo-checkout.js +2 -2
  61. package/lib/use-lrs-checkout.d.ts +9 -5
  62. package/lib/use-lrs-checkout.d.ts.map +1 -1
  63. package/lib/use-lrs-checkout.js +317 -171
  64. package/lib/use-standard-checkout.d.ts +17 -13
  65. package/lib/use-standard-checkout.d.ts.map +1 -1
  66. package/lib/use-standard-checkout.js +281 -207
  67. package/lib/utils/analytics.d.ts +177 -51
  68. package/lib/utils/analytics.d.ts.map +1 -1
  69. package/lib/utils/analytics.js +299 -81
  70. package/lib/utils/device-compliance.d.ts +57 -12
  71. package/lib/utils/device-compliance.d.ts.map +1 -1
  72. package/lib/utils/device-compliance.js +101 -37
  73. package/lib/utils/event-projections.d.ts +56 -0
  74. package/lib/utils/event-projections.d.ts.map +1 -0
  75. package/lib/utils/event-projections.js +42 -0
  76. package/lib/utils/file-metadata.d.ts +52 -0
  77. package/lib/utils/file-metadata.d.ts.map +1 -0
  78. package/lib/utils/file-metadata.js +134 -0
  79. package/lib/utils/use-sdk-session.d.ts +12 -0
  80. package/lib/utils/use-sdk-session.d.ts.map +1 -0
  81. package/lib/utils/use-sdk-session.js +37 -0
  82. package/lib/utils/validation.d.ts +37 -3
  83. package/lib/utils/validation.d.ts.map +1 -1
  84. package/lib/utils/validation.js +64 -8
  85. package/lib/webview/capability-props.d.ts +27 -0
  86. package/lib/webview/capability-props.d.ts.map +1 -0
  87. package/lib/webview/capability-props.js +61 -0
  88. package/lib/webview/use-permission-request.d.ts +33 -0
  89. package/lib/webview/use-permission-request.d.ts.map +1 -0
  90. package/lib/webview/use-permission-request.js +89 -0
  91. package/package.json +10 -2
  92. package/src/bridge/file-input-handler.ts +66 -0
  93. package/src/bridge/file-save-handler.ts +141 -0
  94. package/src/bridge/message-router.ts +92 -0
  95. package/src/bridge/payment-payload.ts +31 -0
  96. package/src/capabilities/file-save.ts +124 -0
  97. package/src/capabilities/index.ts +34 -0
  98. package/src/capabilities/use-capability-reporting.ts +55 -0
  99. package/src/config/base.ts +13 -0
  100. package/src/glomo-checkout.tsx +11 -7
  101. package/src/glomo-lrs-checkout.tsx +41 -26
  102. package/src/glomo-standard-checkout.tsx +31 -34
  103. package/src/glomo-subscriptions-checkout.tsx +1 -0
  104. package/src/index.ts +4 -2
  105. package/src/injections/index.ts +43 -0
  106. package/src/injections/webview-flow.injection.ts +76 -0
  107. package/src/injections/webview-main.injection.ts +31 -0
  108. package/src/injections/webview-standard.injection.ts +31 -0
  109. package/src/services/file-saver.ts +497 -0
  110. package/src/types/checkout.ts +62 -6
  111. package/src/types/standard-checkout.ts +6 -6
  112. package/src/types/subscriptions-checkout.ts +7 -3
  113. package/src/use-glomo-checkout.tsx +2 -2
  114. package/src/use-lrs-checkout.tsx +656 -365
  115. package/src/use-standard-checkout.tsx +728 -466
  116. package/src/utils/analytics.ts +422 -117
  117. package/src/utils/device-compliance.ts +148 -38
  118. package/src/utils/event-projections.ts +74 -0
  119. package/src/utils/file-metadata.ts +140 -0
  120. package/src/utils/use-sdk-session.ts +41 -0
  121. package/src/utils/validation.ts +70 -10
  122. package/src/webview/capability-props.ts +86 -0
  123. package/src/webview/use-permission-request.ts +114 -0
  124. package/src/jail-monkey.d.ts +0 -19
@@ -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
- function useLrsCheckout({ server, publicKey, orderId, onPaymentSuccess, onPaymentFailure, onConnectionError, onPaymentTerminate, onSdkError, devMode = false, }, mockMode, internalOptions) {
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.useCallback)((event) => {
172
- var _a;
173
- try {
174
- const data = (_a = event.nativeEvent) === null || _a === void 0 ? void 0 : _a.data;
175
- if (!data || typeof data !== "string") {
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
- console.warn("[Glomo-RN-SDK LRS] Invalid message data from MainWebView");
231
+ const level = (typeof message.level === "string" && message.level) || "log";
232
+ console.log(`${LOG_PREFIX} [WebView ${level.toUpperCase()}]`, message.message);
178
233
  }
179
- // Tracking invalid message received
180
- (0, analytics_1.trackInvalidMessageReceived)("main", data, checkoutUrl, orderId, publicKey, devMode, mockMode, checkoutUrl);
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(`[Glomo-RN-SDK LRS] window.open called from MainWebView: ${url}`);
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("[Glomo-RN-SDK LRS] Invalid URL in window.open from MainWebView:", url, typeof url === "undefined" ? "undefined" : "");
249
+ console.log(`${LOG_PREFIX} Invalid URL in window.open from MainWebView:`, url, typeof url === "undefined" ? "undefined" : "");
209
250
  }
210
251
  }
211
- return;
212
- }
213
- if (message.type === "window.close") {
252
+ },
253
+ "window.close": () => {
214
254
  if (devMode) {
215
- console.log("[Glomo-RN-SDK LRS] Child window close requested from MainWebView");
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
- return;
223
- }
262
+ },
224
263
  // Handling merchant JS callbacks on flow completion
225
- if (message.type === "message" && message.message) {
264
+ message: (message) => {
226
265
  const messageData = message.message;
227
- const messageType = messageData === null || messageData === void 0 ? void 0 : messageData.type;
266
+ if (!messageData)
267
+ return;
268
+ const messageType = messageData.type;
228
269
  if (messageType === "payment.success" || messageType === "payment.complete") {
229
- const paymentMessage = messageData;
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("[Glomo-RN-SDK LRS] Payment successful via merchant callback!");
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)(payload.orderId, payload.paymentId, publicKey, devMode, mockMode, checkoutUrl);
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("[Glomo-RN-SDK LRS] Invalid payment success payload:", payload);
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 paymentMessage = messageData;
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("[Glomo-RN-SDK LRS] Payment failed via merchant callback");
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)(payload.orderId, payload.paymentId, publicKey, devMode, mockMode, checkoutUrl);
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("[Glomo-RN-SDK LRS] Invalid payment failure payload:", payload);
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("[Glomo-RN-SDK LRS] Checkout closed event received");
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
- (0, validation_1.safeCallback)(onPaymentTerminate, [], "onPaymentTerminate", devMode);
284
- // Tracking payment terminate callback
285
- (0, analytics_1.trackPaymentTerminate)(orderId, "checkout_closed", publicKey, devMode, mockMode, checkoutUrl);
286
- return;
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
- catch (error) {
291
- if (devMode) {
292
- console.error("[Glomo-RN-SDK LRS] Error parsing MainWebView message:", error);
293
- }
294
- }
295
- }, [onPaymentSuccess, onPaymentFailure, onPaymentTerminate, devMode, mockMode, orderId, publicKey, checkoutUrl]);
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.useCallback)((event) => {
298
- var _a;
299
- try {
300
- const data = (_a = event.nativeEvent) === null || _a === void 0 ? void 0 : _a.data;
301
- if (!data || typeof data !== "string") {
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.warn("[Glomo-RN-SDK LRS] Invalid message data from FlowWebView");
388
+ console.log(`${LOG_PREFIX} [Flow] ${message.message}`);
304
389
  }
305
- // Tracking invalid message received
306
- (0, analytics_1.trackInvalidMessageReceived)("flow", data, flowWebViewUrl, orderId, publicKey, devMode, mockMode, checkoutUrl);
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(`[Glomo-RN-SDK LRS] window.open called from FlowWebView: ${url}`);
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("[Glomo-RN-SDK LRS] Invalid URL in window.open from FlowWebView:", url, typeof url === "undefined" ? "undefined" : "");
404
+ console.log(`${LOG_PREFIX} Invalid URL in window.open from FlowWebView:`, url, typeof url === "undefined" ? "undefined" : "");
333
405
  }
334
406
  }
335
- return;
336
- }
337
- if (message.type === "window.close") {
407
+ },
408
+ "window.close": () => {
338
409
  if (devMode) {
339
- console.log("[Glomo-RN-SDK LRS] FlowWebView close requested");
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
- return;
347
- }
348
- if (message.type === "message" && message.message) {
417
+ },
418
+ // Handling merchant JS callbacks on flow completion
419
+ message: (message) => {
349
420
  const messageData = message.message;
350
- const messageType = messageData === null || messageData === void 0 ? void 0 : messageData.type;
421
+ if (!messageData)
422
+ return;
423
+ const messageType = messageData.type;
351
424
  if (messageType === "payment.success" || messageType === "payment.complete") {
352
- const paymentMessage = messageData;
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("[Glomo-RN-SDK LRS] Payment successful via FlowWebView callback!");
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)(payload.orderId, payload.paymentId, publicKey, devMode, mockMode, checkoutUrl);
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("[Glomo-RN-SDK LRS] Invalid payment success payload from FlowWebView:", payload);
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 paymentMessage = messageData;
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("[Glomo-RN-SDK LRS] Payment failed via FlowWebView callback");
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)(payload.orderId, payload.paymentId, publicKey, devMode, mockMode, checkoutUrl);
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("[Glomo-RN-SDK LRS] Invalid payment failure payload from FlowWebView:", payload);
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
- catch (error) {
400
- if (devMode) {
401
- console.error("[Glomo-RN-SDK LRS] Error parsing FlowWebView message:", error);
402
- }
403
- }
404
- }, [onPaymentSuccess, onPaymentFailure, devMode, mockMode, orderId, publicKey, flowWebViewUrl, checkoutUrl]);
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.useCallback)((event) => {
407
- var _a;
408
- try {
409
- const data = (_a = event.nativeEvent) === null || _a === void 0 ? void 0 : _a.data;
410
- if (!data || typeof data !== "string") {
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.warn("[Glomo-RN-SDK LRS] Invalid message data from EducationCarouselWebView");
514
+ console.log(`${LOG_PREFIX} [EducationCarousel] ${message.message}`);
413
515
  }
414
- return;
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(`[Glomo-RN-SDK LRS] [EducationCarousel] ${message.message}`);
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
- return;
425
- }
426
- if (message.type === "lrs.has_education_steps") {
427
- const nextState = "hasContent";
428
- if (devMode) {
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
- (0, validation_1.safeCallback)(onPaymentTerminate, [], "onPaymentTerminate", devMode);
473
- // Tracking payment terminate callback (user dismiss/back button)
474
- const terminateSource = react_native_1.Platform.OS === "ios" ? "user_dismiss" : "back_button";
475
- (0, analytics_1.trackPaymentTerminate)(orderId, terminateSource, publicKey, devMode, mockMode, checkoutUrl);
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.trackWindowClose)("flow", orderId, publicKey, devMode, mockMode, checkoutUrl);
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 deviceComplianceCheck = (0, device_compliance_1.checkDeviceCompliance)(devMode);
511
- const jailbreakDetectionLibraryInstalled = (0, device_compliance_1.isComplianceCheckAvailable)();
512
- const jailbreakDetectionInfo = {
513
- jailbreakDetectionLibraryInstalled,
514
- jailbreakDetected: deviceComplianceCheck,
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, jailbreakDetectionInfo);
521
- if (deviceComplianceCheck === true) {
522
- // Device detected as compromised
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("[Glomo-RN-SDK LRS] Cannot start checkout. Device is rooted or jailbroken.");
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: "LRS checkout is not allowed on rooted or jailbroken devices.",
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, jailbreakDetectionInfo);
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, jailbreakDetectionInfo);
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, jailbreakDetectionInfo);
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, jailbreakDetectionInfo);
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, jailbreakDetectionInfo);
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, jailbreakDetectionInfo);
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, jailbreakDetectionInfo);
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
- ? index_1.InjectionScripts.main + internalOptions._testInjectionScript
697
- : index_1.InjectionScripts.main,
698
- injectedFlow: index_1.InjectionScripts.flow,
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
- ? index_1.InjectionScripts.educationCarousel + internalOptions._testCarouselInjectionScript
701
- : index_1.InjectionScripts.educationCarousel,
846
+ ? injectionScripts.educationCarousel + internalOptions._testCarouselInjectionScript
847
+ : injectionScripts.educationCarousel,
702
848
  };
703
849
  }