@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
@@ -13,6 +13,16 @@
13
13
  import { Platform } from "react-native";
14
14
  import { getSegmentClient, isSegmentAvailable, getAnonymousId, getSegmentWriteKey } from "../config/segment";
15
15
 
16
+ /**
17
+ * Type-only, so nothing is emitted and the cycle with `types/checkout.ts` - which imports SdkError
18
+ * from here - stays a compile-time one.
19
+ */
20
+ /**
21
+ * Runtime allowlists, not type constraints - see the module comment in event-projections.ts for why
22
+ * a tracker must never take a payload type directly.
23
+ */
24
+ import { type PaymentEventData, type TerminationEventData, type JourneyEventData } from "./event-projections";
25
+
16
26
  /**
17
27
  * Flow type for checkout
18
28
  */
@@ -23,6 +33,13 @@ export type FlowType = "lrs" | "standard" | "unified" | "subscriptions";
23
33
  */
24
34
  export interface CommonEventProperties {
25
35
  sdkVersion?: string;
36
+
37
+ /** Correlates every event from one mounted checkout, across repeated start() calls */
38
+ sessionId?: string;
39
+
40
+ /** Resolved at capture time from the bound getter, so it is never stale */
41
+ checkoutStatus?: string;
42
+
26
43
  devMode?: boolean;
27
44
  mockMode?: boolean;
28
45
  orderId?: string;
@@ -36,11 +53,105 @@ export interface CommonEventProperties {
36
53
  [key: string]: unknown;
37
54
  }
38
55
 
56
+ /** Why start() refused to run. Distinguishes a compromised device from one we could not check. */
57
+ export type StartFailureReason =
58
+ | "device_forbidden"
59
+ | "device_compliance_unknown"
60
+ | "validation_error"
61
+ | "payment_successful"
62
+ | "invalid_status"
63
+ | "invalid_url";
64
+
65
+ /**
66
+ * What the SDK could and could not load in this build, carried on start_attempted and start_failed.
67
+ *
68
+ * Optional dependencies degrade silently by design, so this inventory is the only way to tell a
69
+ * merchant who chose not to install one from a build where something failed to link. Names packages
70
+ * and check names, never device identifiers.
71
+ */
72
+ export interface SdkDependencyInfo {
73
+ jailbreakDetectionLibraryInstalled: boolean;
74
+ jailbreakDetected: boolean | null;
75
+ complianceSource?: string;
76
+ complianceSignals?: string[];
77
+ fileSaveAvailable?: boolean;
78
+ missingFileSavePackages?: string[];
79
+ }
80
+
81
+ /** Where a permission refusal was observed. The two are not interchangeable - see the tracker. */
82
+ export type DevicePermissionSource = "permission_request" | "get_user_media";
83
+
39
84
  /** SDK error information */
40
85
  export interface SdkError {
41
86
  type: "validation_error" | "device_forbidden";
42
87
  message: string;
43
- field?: "publicKey" | "orderId" | "subscriptionId" | "baseCheckoutUrl" | "generatedCheckoutUrl";
88
+ /**
89
+ * What produced the error. The first five are configuration the merchant supplied; `file.save`
90
+ * is a bridge message type, and is here so a document that failed to save can be filtered apart
91
+ * from a bad public key on a callback that carries both.
92
+ */
93
+ field?: "publicKey" | "orderId" | "subscriptionId" | "baseCheckoutUrl" | "generatedCheckoutUrl" | "file.save";
94
+ }
95
+
96
+ /**
97
+ * The current checkout attempt, and how to read its status.
98
+ *
99
+ * Module scope because `buildCommonProperties` is spread into every event and takes no context
100
+ * argument. Installed by useSdkSession for as long as a checkout component is mounted, so nothing
101
+ * here survives a merchant's screen being torn down.
102
+ */
103
+ let activeSessionId: string | undefined;
104
+ let readCheckoutStatus: (() => string) | undefined;
105
+
106
+ /**
107
+ * Installs the id that correlates every event from one checkout attempt.
108
+ *
109
+ * Nothing else does: joining on `orderId` fails the moment a merchant retries `start()`, which
110
+ * produces two attempts that are indistinguishable without this. Scoped per mount rather than per
111
+ * `start()`, so a retry reads as two start_attempted events inside one session - which is the signal
112
+ * worth having.
113
+ */
114
+ export function setSdkSession(sessionId: string | undefined): void {
115
+ activeSessionId = sessionId;
116
+ }
117
+
118
+ /**
119
+ * Binds a getter for the checkout status, resolved at capture time.
120
+ *
121
+ * A getter rather than a value, deliberately. Pushing the status per call would mean touching every
122
+ * tracker and would go stale between transitions - which is exactly the bug the Flutter SDK fixed in
123
+ * KAN-8085, where `checkout_status` was null on every real event.
124
+ */
125
+ export function bindCheckoutStatus(read: (() => string) | undefined): void {
126
+ readCheckoutStatus = read;
127
+ }
128
+
129
+ /**
130
+ * Releases the session a mount installed, and only if it is still the active one.
131
+ *
132
+ * Clearing unconditionally is wrong whenever two checkout components overlap - a merchant who keeps
133
+ * a previous screen mounted, or renders one per row in a list. The component unmounting would strip
134
+ * `sessionId` and `checkoutStatus` off every later event of a sibling that is still mid-payment, and
135
+ * an event missing them is indistinguishable from one sent by a pre-v5 build.
136
+ *
137
+ * It does not make the singletons safe for concurrent mounts - the last mount still wins while both
138
+ * are alive. It removes the case where the survivor is left reporting nothing at all.
139
+ */
140
+ export function releaseSdkSession(sessionId: string): void {
141
+ if (activeSessionId !== sessionId) {
142
+ return;
143
+ }
144
+ activeSessionId = undefined;
145
+ readCheckoutStatus = undefined;
146
+ }
147
+
148
+ /** Never lets a merchant's status getter break an event */
149
+ function currentCheckoutStatus(): string | undefined {
150
+ try {
151
+ return readCheckoutStatus?.();
152
+ } catch {
153
+ return undefined;
154
+ }
44
155
  }
45
156
 
46
157
  /**
@@ -91,6 +202,8 @@ function buildCommonProperties(
91
202
  sdkVersion: getSdkVersion(),
92
203
  timestamp: new Date().toISOString(),
93
204
  ...(flowType && { flowType }),
205
+ ...(activeSessionId && { sessionId: activeSessionId }),
206
+ ...(currentCheckoutStatus() !== undefined && { checkoutStatus: currentCheckoutStatus() }),
94
207
  };
95
208
  }
96
209
 
@@ -173,7 +286,7 @@ async function trackEvent(
173
286
  * @param devMode - Whether dev mode is enabled
174
287
  * @param mockMode - Whether mock mode is enabled
175
288
  * @param lrsUrl - The LRS checkout URL
176
- * @param jailbreakDetectionInfo - Optional jailbreak detection information
289
+ * @param dependencyInfo - Optional inventory of what this build could and could not load
177
290
  */
178
291
  export function trackStartSuccess(
179
292
  orderId: string,
@@ -181,17 +294,11 @@ export function trackStartSuccess(
181
294
  devMode: boolean = false,
182
295
  mockMode: boolean = false,
183
296
  lrsUrl?: string,
184
- jailbreakDetectionInfo?: {
185
- jailbreakDetectionLibraryInstalled: boolean;
186
- jailbreakDetected: boolean | null;
187
- }
297
+ dependencyInfo?: SdkDependencyInfo
188
298
  ): void {
189
299
  const properties = {
190
300
  ...buildCommonProperties(orderId, publicKey, devMode, mockMode, lrsUrl),
191
- ...(jailbreakDetectionInfo && {
192
- jailbreakDetectionLibraryInstalled: jailbreakDetectionInfo.jailbreakDetectionLibraryInstalled,
193
- jailbreakDetected: jailbreakDetectionInfo.jailbreakDetected,
194
- }),
301
+ ...dependencyInfo,
195
302
  };
196
303
  // Async tracking to avoid blocking the main thread
197
304
  trackEvent("LRS Checkout Started", properties, devMode).catch((error) => {
@@ -210,7 +317,7 @@ export function trackStartSuccess(
210
317
  * @param devMode - Whether dev mode is enabled
211
318
  * @param mockMode - Whether mock mode is enabled
212
319
  * @param lrsUrl - The LRS checkout URL
213
- * @param jailbreakDetectionInfo - Optional jailbreak detection information
320
+ * @param dependencyInfo - Optional inventory of what this build could and could not load
214
321
  */
215
322
  export function trackStartAttempt(
216
323
  status: string,
@@ -219,18 +326,12 @@ export function trackStartAttempt(
219
326
  devMode: boolean = false,
220
327
  mockMode: boolean = false,
221
328
  lrsUrl?: string,
222
- jailbreakDetectionInfo?: {
223
- jailbreakDetectionLibraryInstalled: boolean;
224
- jailbreakDetected: boolean | null;
225
- }
329
+ dependencyInfo?: SdkDependencyInfo
226
330
  ): void {
227
331
  const properties = {
228
332
  ...buildCommonProperties(orderId, publicKey, devMode, mockMode, lrsUrl),
229
333
  status,
230
- ...(jailbreakDetectionInfo && {
231
- jailbreakDetectionLibraryInstalled: jailbreakDetectionInfo.jailbreakDetectionLibraryInstalled,
232
- jailbreakDetected: jailbreakDetectionInfo.jailbreakDetected,
233
- }),
334
+ ...dependencyInfo,
234
335
  };
235
336
  // Async tracking to avoid blocking the main thread
236
337
  trackEvent("LRS Checkout Start Attempted", properties, devMode).catch((error) => {
@@ -249,27 +350,21 @@ export function trackStartAttempt(
249
350
  * @param devMode - Whether dev mode is enabled
250
351
  * @param mockMode - Whether mock mode is enabled
251
352
  * @param lrsUrl - The LRS checkout URL
252
- * @param jailbreakDetectionInfo - Optional jailbreak detection information
353
+ * @param dependencyInfo - Optional inventory of what this build could and could not load
253
354
  */
254
355
  export function trackStartFailure(
255
- reason: "device_forbidden" | "validation_error" | "payment_successful" | "invalid_status" | "invalid_url",
356
+ reason: StartFailureReason,
256
357
  orderId?: string,
257
358
  publicKey?: string,
258
359
  devMode: boolean = false,
259
360
  mockMode: boolean = false,
260
361
  lrsUrl?: string,
261
- jailbreakDetectionInfo?: {
262
- jailbreakDetectionLibraryInstalled: boolean;
263
- jailbreakDetected: boolean | null;
264
- }
362
+ dependencyInfo?: SdkDependencyInfo
265
363
  ): void {
266
364
  const properties = {
267
365
  ...buildCommonProperties(orderId, publicKey, devMode, mockMode, lrsUrl),
268
366
  failureReason: reason,
269
- ...(jailbreakDetectionInfo && {
270
- jailbreakDetectionLibraryInstalled: jailbreakDetectionInfo.jailbreakDetectionLibraryInstalled,
271
- jailbreakDetected: jailbreakDetectionInfo.jailbreakDetected,
272
- }),
367
+ ...dependencyInfo,
273
368
  };
274
369
  // Async tracking to avoid blocking the main thread
275
370
  trackEvent("LRS Checkout Start Failed", properties, devMode).catch((error) => {
@@ -408,16 +503,15 @@ export function trackInvalidMessageReceived(
408
503
  * @param lrsUrl - The LRS checkout URL
409
504
  */
410
505
  export function trackPaymentSuccess(
411
- orderId: string,
412
- paymentId: string,
506
+ payment: PaymentEventData,
413
507
  publicKey: string,
414
508
  devMode: boolean = false,
415
509
  mockMode: boolean = false,
416
510
  lrsUrl?: string
417
511
  ): void {
418
512
  const properties = {
419
- ...buildCommonProperties(orderId, publicKey, devMode, mockMode, lrsUrl),
420
- paymentId,
513
+ ...buildCommonProperties(payment.orderId, publicKey, devMode, mockMode, lrsUrl),
514
+ ...payment,
421
515
  };
422
516
  // Async tracking to avoid blocking the main thread
423
517
  trackEvent("LRS Payment Success", properties, devMode).catch((error) => {
@@ -438,16 +532,15 @@ export function trackPaymentSuccess(
438
532
  * @param lrsUrl - The LRS checkout URL
439
533
  */
440
534
  export function trackPaymentFailure(
441
- orderId: string,
442
- paymentId: string,
535
+ payment: PaymentEventData,
443
536
  publicKey: string,
444
537
  devMode: boolean = false,
445
538
  mockMode: boolean = false,
446
539
  lrsUrl?: string
447
540
  ): void {
448
541
  const properties = {
449
- ...buildCommonProperties(orderId, publicKey, devMode, mockMode, lrsUrl),
450
- paymentId,
542
+ ...buildCommonProperties(payment.orderId, publicKey, devMode, mockMode, lrsUrl),
543
+ ...payment,
451
544
  };
452
545
  // Async tracking to avoid blocking the main thread
453
546
  trackEvent("LRS Payment Failure", properties, devMode).catch((error) => {
@@ -469,7 +562,7 @@ export function trackPaymentFailure(
469
562
  */
470
563
  export function trackPaymentTerminate(
471
564
  orderId: string,
472
- source: "user_dismiss" | "back_button" | "checkout_closed",
565
+ termination: TerminationEventData,
473
566
  publicKey: string,
474
567
  devMode: boolean = false,
475
568
  mockMode: boolean = false,
@@ -477,7 +570,7 @@ export function trackPaymentTerminate(
477
570
  ): void {
478
571
  const properties = {
479
572
  ...buildCommonProperties(orderId, publicKey, devMode, mockMode, lrsUrl),
480
- terminationSource: source,
573
+ ...termination,
481
574
  };
482
575
  // Async tracking to avoid blocking the main thread
483
576
  trackEvent("LRS Payment Terminated", properties, devMode).catch((error) => {
@@ -619,17 +712,11 @@ export function trackStandardStartSuccess(
619
712
  devMode: boolean = false,
620
713
  mockMode: boolean = false,
621
714
  standardUrl?: string,
622
- jailbreakDetectionInfo?: {
623
- jailbreakDetectionLibraryInstalled: boolean;
624
- jailbreakDetected: boolean | null;
625
- }
715
+ dependencyInfo?: SdkDependencyInfo
626
716
  ): void {
627
717
  const properties = {
628
718
  ...buildCommonProperties(orderId, publicKey, devMode, mockMode, standardUrl, "standard"),
629
- ...(jailbreakDetectionInfo && {
630
- jailbreakDetectionLibraryInstalled: jailbreakDetectionInfo.jailbreakDetectionLibraryInstalled,
631
- jailbreakDetected: jailbreakDetectionInfo.jailbreakDetected,
632
- }),
719
+ ...dependencyInfo,
633
720
  };
634
721
  trackEvent("Standard Checkout Started", properties, devMode).catch((error) => {
635
722
  if (devMode) {
@@ -648,18 +735,12 @@ export function trackStandardStartAttempt(
648
735
  devMode: boolean = false,
649
736
  mockMode: boolean = false,
650
737
  standardUrl?: string,
651
- jailbreakDetectionInfo?: {
652
- jailbreakDetectionLibraryInstalled: boolean;
653
- jailbreakDetected: boolean | null;
654
- }
738
+ dependencyInfo?: SdkDependencyInfo
655
739
  ): void {
656
740
  const properties = {
657
741
  ...buildCommonProperties(orderId, publicKey, devMode, mockMode, standardUrl, "standard"),
658
742
  status,
659
- ...(jailbreakDetectionInfo && {
660
- jailbreakDetectionLibraryInstalled: jailbreakDetectionInfo.jailbreakDetectionLibraryInstalled,
661
- jailbreakDetected: jailbreakDetectionInfo.jailbreakDetected,
662
- }),
743
+ ...dependencyInfo,
663
744
  };
664
745
  trackEvent("Standard Checkout Start Attempted", properties, devMode).catch((error) => {
665
746
  if (devMode) {
@@ -672,24 +753,18 @@ export function trackStandardStartAttempt(
672
753
  * Tracks when the standard checkout start() method fails
673
754
  */
674
755
  export function trackStandardStartFailure(
675
- reason: "device_forbidden" | "validation_error" | "payment_successful" | "invalid_status" | "invalid_url",
756
+ reason: StartFailureReason,
676
757
  orderId?: string,
677
758
  publicKey?: string,
678
759
  devMode: boolean = false,
679
760
  mockMode: boolean = false,
680
761
  standardUrl?: string,
681
- jailbreakDetectionInfo?: {
682
- jailbreakDetectionLibraryInstalled: boolean;
683
- jailbreakDetected: boolean | null;
684
- }
762
+ dependencyInfo?: SdkDependencyInfo
685
763
  ): void {
686
764
  const properties = {
687
765
  ...buildCommonProperties(orderId, publicKey, devMode, mockMode, standardUrl, "standard"),
688
766
  failureReason: reason,
689
- ...(jailbreakDetectionInfo && {
690
- jailbreakDetectionLibraryInstalled: jailbreakDetectionInfo.jailbreakDetectionLibraryInstalled,
691
- jailbreakDetected: jailbreakDetectionInfo.jailbreakDetected,
692
- }),
767
+ ...dependencyInfo,
693
768
  };
694
769
  trackEvent("Standard Checkout Start Failed", properties, devMode).catch((error) => {
695
770
  if (devMode) {
@@ -792,16 +867,15 @@ export function trackStandardInvalidMessageReceived(
792
867
  * Tracks when standard checkout onPaymentSuccess callback is invoked
793
868
  */
794
869
  export function trackStandardPaymentSuccess(
795
- orderId: string,
796
- paymentId: string,
870
+ payment: PaymentEventData,
797
871
  publicKey: string,
798
872
  devMode: boolean = false,
799
873
  mockMode: boolean = false,
800
874
  standardUrl?: string
801
875
  ): void {
802
876
  const properties = {
803
- ...buildCommonProperties(orderId, publicKey, devMode, mockMode, standardUrl, "standard"),
804
- paymentId,
877
+ ...buildCommonProperties(payment.orderId, publicKey, devMode, mockMode, standardUrl, "standard"),
878
+ ...payment,
805
879
  };
806
880
  trackEvent("Standard Payment Success", properties, devMode).catch((error) => {
807
881
  if (devMode) {
@@ -814,16 +888,15 @@ export function trackStandardPaymentSuccess(
814
888
  * Tracks when standard checkout onPaymentFailure callback is invoked
815
889
  */
816
890
  export function trackStandardPaymentFailure(
817
- orderId: string,
818
- paymentId: string,
891
+ payment: PaymentEventData,
819
892
  publicKey: string,
820
893
  devMode: boolean = false,
821
894
  mockMode: boolean = false,
822
895
  standardUrl?: string
823
896
  ): void {
824
897
  const properties = {
825
- ...buildCommonProperties(orderId, publicKey, devMode, mockMode, standardUrl, "standard"),
826
- paymentId,
898
+ ...buildCommonProperties(payment.orderId, publicKey, devMode, mockMode, standardUrl, "standard"),
899
+ ...payment,
827
900
  };
828
901
  trackEvent("Standard Payment Failure", properties, devMode).catch((error) => {
829
902
  if (devMode) {
@@ -837,7 +910,7 @@ export function trackStandardPaymentFailure(
837
910
  */
838
911
  export function trackStandardPaymentTerminate(
839
912
  orderId: string,
840
- source: "user_dismiss" | "back_button" | "checkout_closed",
913
+ termination: TerminationEventData,
841
914
  publicKey: string,
842
915
  devMode: boolean = false,
843
916
  mockMode: boolean = false,
@@ -845,7 +918,7 @@ export function trackStandardPaymentTerminate(
845
918
  ): void {
846
919
  const properties = {
847
920
  ...buildCommonProperties(orderId, publicKey, devMode, mockMode, standardUrl, "standard"),
848
- terminationSource: source,
921
+ ...termination,
849
922
  };
850
923
  trackEvent("Standard Payment Terminated", properties, devMode).catch((error) => {
851
924
  if (devMode) {
@@ -901,6 +974,7 @@ export function trackStandardSdkError(
901
974
 
902
975
  export function trackStandardBankTransferSubmitted(
903
976
  orderId: string,
977
+ journey: JourneyEventData,
904
978
  publicKey: string,
905
979
  devMode: boolean = false,
906
980
  mockMode: boolean = false,
@@ -908,6 +982,7 @@ export function trackStandardBankTransferSubmitted(
908
982
  ): void {
909
983
  const properties = {
910
984
  ...buildCommonProperties(orderId, publicKey, devMode, mockMode, standardUrl, "standard"),
985
+ ...journey,
911
986
  };
912
987
  trackEvent("Standard Bank Transfer Submitted", properties, devMode).catch((error) => {
913
988
  if (devMode) {
@@ -918,15 +993,15 @@ export function trackStandardBankTransferSubmitted(
918
993
 
919
994
  export function trackStandardPayViaBankCompleted(
920
995
  orderId: string,
996
+ journey: JourneyEventData,
921
997
  publicKey: string,
922
- status: string,
923
998
  devMode: boolean = false,
924
999
  mockMode: boolean = false,
925
1000
  standardUrl?: string
926
1001
  ): void {
927
1002
  const properties = {
928
1003
  ...buildCommonProperties(orderId, publicKey, devMode, mockMode, standardUrl, "standard"),
929
- payViaBankStatus: status,
1004
+ ...journey,
930
1005
  };
931
1006
  trackEvent("Standard Pay Via Bank Completed", properties, devMode).catch((error) => {
932
1007
  if (devMode) {
@@ -1042,19 +1117,13 @@ export function trackSubscriptionStartAttempt(
1042
1117
  devMode: boolean = false,
1043
1118
  mockMode: boolean = false,
1044
1119
  checkoutUrl?: string,
1045
- jailbreakDetectionInfo?: {
1046
- jailbreakDetectionLibraryInstalled: boolean;
1047
- jailbreakDetected: boolean | null;
1048
- }
1120
+ dependencyInfo?: SdkDependencyInfo
1049
1121
  ): void {
1050
1122
  const properties = {
1051
1123
  ...buildCommonProperties(orderId, publicKey, devMode, mockMode, checkoutUrl, "subscriptions"),
1052
1124
  subscriptionId: orderId,
1053
1125
  status,
1054
- ...(jailbreakDetectionInfo && {
1055
- jailbreakDetectionLibraryInstalled: jailbreakDetectionInfo.jailbreakDetectionLibraryInstalled,
1056
- jailbreakDetected: jailbreakDetectionInfo.jailbreakDetected,
1057
- }),
1126
+ ...dependencyInfo,
1058
1127
  };
1059
1128
  trackEvent("Subscription Checkout Start Attempted", properties, devMode).catch((error) => {
1060
1129
  if (devMode) {
@@ -1072,18 +1141,12 @@ export function trackSubscriptionStartSuccess(
1072
1141
  devMode: boolean = false,
1073
1142
  mockMode: boolean = false,
1074
1143
  checkoutUrl?: string,
1075
- jailbreakDetectionInfo?: {
1076
- jailbreakDetectionLibraryInstalled: boolean;
1077
- jailbreakDetected: boolean | null;
1078
- }
1144
+ dependencyInfo?: SdkDependencyInfo
1079
1145
  ): void {
1080
1146
  const properties = {
1081
1147
  ...buildCommonProperties(orderId, publicKey, devMode, mockMode, checkoutUrl, "subscriptions"),
1082
1148
  subscriptionId: orderId,
1083
- ...(jailbreakDetectionInfo && {
1084
- jailbreakDetectionLibraryInstalled: jailbreakDetectionInfo.jailbreakDetectionLibraryInstalled,
1085
- jailbreakDetected: jailbreakDetectionInfo.jailbreakDetected,
1086
- }),
1149
+ ...dependencyInfo,
1087
1150
  };
1088
1151
  trackEvent("Subscription Checkout Started", properties, devMode).catch((error) => {
1089
1152
  if (devMode) {
@@ -1096,25 +1159,19 @@ export function trackSubscriptionStartSuccess(
1096
1159
  * Tracks when the subscription checkout start() method fails
1097
1160
  */
1098
1161
  export function trackSubscriptionStartFailure(
1099
- reason: "device_forbidden" | "validation_error" | "payment_successful" | "invalid_status" | "invalid_url",
1162
+ reason: StartFailureReason,
1100
1163
  orderId?: string,
1101
1164
  publicKey?: string,
1102
1165
  devMode: boolean = false,
1103
1166
  mockMode: boolean = false,
1104
1167
  checkoutUrl?: string,
1105
- jailbreakDetectionInfo?: {
1106
- jailbreakDetectionLibraryInstalled: boolean;
1107
- jailbreakDetected: boolean | null;
1108
- }
1168
+ dependencyInfo?: SdkDependencyInfo
1109
1169
  ): void {
1110
1170
  const properties = {
1111
1171
  ...buildCommonProperties(orderId, publicKey, devMode, mockMode, checkoutUrl, "subscriptions"),
1112
1172
  subscriptionId: orderId,
1113
1173
  failureReason: reason,
1114
- ...(jailbreakDetectionInfo && {
1115
- jailbreakDetectionLibraryInstalled: jailbreakDetectionInfo.jailbreakDetectionLibraryInstalled,
1116
- jailbreakDetected: jailbreakDetectionInfo.jailbreakDetected,
1117
- }),
1174
+ ...dependencyInfo,
1118
1175
  };
1119
1176
  trackEvent("Subscription Checkout Start Failed", properties, devMode).catch((error) => {
1120
1177
  if (devMode) {
@@ -1220,17 +1277,16 @@ export function trackSubscriptionInvalidMessageReceived(
1220
1277
  * Tracks when subscription checkout onPaymentSuccess callback is invoked
1221
1278
  */
1222
1279
  export function trackSubscriptionPaymentSuccess(
1223
- orderId: string,
1224
- paymentId: string,
1280
+ payment: PaymentEventData,
1225
1281
  publicKey: string,
1226
1282
  devMode: boolean = false,
1227
1283
  mockMode: boolean = false,
1228
1284
  checkoutUrl?: string
1229
1285
  ): void {
1230
1286
  const properties = {
1231
- ...buildCommonProperties(orderId, publicKey, devMode, mockMode, checkoutUrl, "subscriptions"),
1232
- subscriptionId: orderId,
1233
- paymentId,
1287
+ ...buildCommonProperties(payment.orderId, publicKey, devMode, mockMode, checkoutUrl, "subscriptions"),
1288
+ subscriptionId: payment.orderId,
1289
+ ...payment,
1234
1290
  };
1235
1291
  trackEvent("Subscription Payment Success", properties, devMode).catch((error) => {
1236
1292
  if (devMode) {
@@ -1243,17 +1299,16 @@ export function trackSubscriptionPaymentSuccess(
1243
1299
  * Tracks when subscription checkout onPaymentFailure callback is invoked
1244
1300
  */
1245
1301
  export function trackSubscriptionPaymentFailure(
1246
- orderId: string,
1247
- paymentId: string,
1302
+ payment: PaymentEventData,
1248
1303
  publicKey: string,
1249
1304
  devMode: boolean = false,
1250
1305
  mockMode: boolean = false,
1251
1306
  checkoutUrl?: string
1252
1307
  ): void {
1253
1308
  const properties = {
1254
- ...buildCommonProperties(orderId, publicKey, devMode, mockMode, checkoutUrl, "subscriptions"),
1255
- subscriptionId: orderId,
1256
- paymentId,
1309
+ ...buildCommonProperties(payment.orderId, publicKey, devMode, mockMode, checkoutUrl, "subscriptions"),
1310
+ subscriptionId: payment.orderId,
1311
+ ...payment,
1257
1312
  };
1258
1313
  trackEvent("Subscription Payment Failure", properties, devMode).catch((error) => {
1259
1314
  if (devMode) {
@@ -1267,7 +1322,7 @@ export function trackSubscriptionPaymentFailure(
1267
1322
  */
1268
1323
  export function trackSubscriptionPaymentTerminate(
1269
1324
  orderId: string,
1270
- source: "user_dismiss" | "back_button" | "checkout_closed",
1325
+ termination: TerminationEventData,
1271
1326
  publicKey: string,
1272
1327
  devMode: boolean = false,
1273
1328
  mockMode: boolean = false,
@@ -1276,7 +1331,7 @@ export function trackSubscriptionPaymentTerminate(
1276
1331
  const properties = {
1277
1332
  ...buildCommonProperties(orderId, publicKey, devMode, mockMode, checkoutUrl, "subscriptions"),
1278
1333
  subscriptionId: orderId,
1279
- terminationSource: source,
1334
+ ...termination,
1280
1335
  };
1281
1336
  trackEvent("Subscription Payment Terminated", properties, devMode).catch((error) => {
1282
1337
  if (devMode) {
@@ -1360,6 +1415,258 @@ export function trackUseOfUnsupportedFunctionality(
1360
1415
  });
1361
1416
  }
1362
1417
 
1418
+ // ---------------------------------------------------------------------------
1419
+ // SDK Navigation Telemetry
1420
+ // ---------------------------------------------------------------------------
1421
+
1422
+ /**
1423
+ * Internal telemetry - fires when the user taps the SDK's back chevron over a bank flow.
1424
+ *
1425
+ * Its own event rather than `window.close`, which it used to reuse. The chevron is back-navigation:
1426
+ * it returns the user to the main checkout with the session intact and the ability to pay, where
1427
+ * `window.close` means something actually closed. Reusing it made a user pressing back
1428
+ * indistinguishable in Segment from the page closing a window.
1429
+ *
1430
+ * This is the only host-invisible interaction the SDK has - the chevron deliberately does not reach
1431
+ * onPaymentTerminate, because a merchant who cancels the order on terminate would cancel live
1432
+ * orders every time a user backed out of one bank to try another. This event is how it stays
1433
+ * visible to us without becoming a termination.
1434
+ */
1435
+ export function trackBackNavigationViaSdkBackButton(
1436
+ orderId: string,
1437
+ publicKey: string,
1438
+ devMode: boolean,
1439
+ mockMode: boolean,
1440
+ checkoutUrl: string,
1441
+ flowType?: FlowType
1442
+ ): void {
1443
+ const properties = buildCommonProperties(orderId, publicKey, devMode, mockMode, checkoutUrl, flowType);
1444
+ trackEvent("Back Navigation Via SDK Back Button", properties, devMode).catch((error) => {
1445
+ if (devMode) {
1446
+ console.error("[Glomo-RN-SDK] Event tracking error on SDK back navigation:", error);
1447
+ }
1448
+ });
1449
+ }
1450
+
1451
+ // ---------------------------------------------------------------------------
1452
+ // Device Permission Telemetry
1453
+ // ---------------------------------------------------------------------------
1454
+
1455
+ /**
1456
+ * Internal telemetry - fires when the user refuses a device permission the bank's page asked for.
1457
+ *
1458
+ * This was the one callback in the SDK with no tracker at all, so a refusal was invisible: there was
1459
+ * no way to answer how often it happens or on which flows.
1460
+ *
1461
+ * `source` says where the observation came from, and the two are not equivalent:
1462
+ *
1463
+ * - `permission_request` is the Android WebView asking us, which is also what drives
1464
+ * `onUserRefusedDevicePermissions`. Android only - iOS raises its own prompt inside WKWebView and
1465
+ * never reports the answer back.
1466
+ * - `get_user_media` is the flow injection watching `getUserMedia` reject with `NotAllowedError`.
1467
+ * It reaches iOS, and it fires no callback: coverage depends on whether a given bank uses
1468
+ * `getUserMedia` at all, and a callback with partial coverage is a contract we cannot hold.
1469
+ *
1470
+ * So an absent event still means "not observable" rather than "did not happen", and `source` plus
1471
+ * the `deviceOS` already on every event is what separates the cases.
1472
+ */
1473
+ export function trackDevicePermissionRefused(
1474
+ resource: string,
1475
+ source: DevicePermissionSource,
1476
+ orderId: string | undefined,
1477
+ publicKey: string,
1478
+ devMode: boolean,
1479
+ mockMode: boolean,
1480
+ checkoutUrl: string,
1481
+ flowType?: FlowType
1482
+ ): void {
1483
+ const properties = {
1484
+ ...buildCommonProperties(orderId, publicKey, devMode, mockMode, checkoutUrl, flowType),
1485
+ resource,
1486
+ source,
1487
+ };
1488
+ trackEvent("Device Permission Refused", properties, devMode).catch((error) => {
1489
+ if (devMode) {
1490
+ console.error("[Glomo-RN-SDK] Event tracking error on device permission refused:", error);
1491
+ }
1492
+ });
1493
+ }
1494
+
1495
+ // ---------------------------------------------------------------------------
1496
+ // Payment Payload Integrity Telemetry
1497
+ // ---------------------------------------------------------------------------
1498
+
1499
+ /**
1500
+ * Internal telemetry - fires when a terminal payment payload arrives without `paymentId` or
1501
+ * `signature`.
1502
+ *
1503
+ * The callback still fires; this measures how often the page reports an outcome before the backend
1504
+ * has resolved ids, which is the thing that made the old strict validation drop real payments.
1505
+ * Names the missing fields, never their values.
1506
+ */
1507
+ export function trackIncompletePaymentPayload(
1508
+ event: string,
1509
+ missingFields: string[],
1510
+ source: string,
1511
+ orderId: string,
1512
+ publicKey: string,
1513
+ devMode: boolean,
1514
+ mockMode: boolean,
1515
+ checkoutUrl: string,
1516
+ flowType?: FlowType
1517
+ ): void {
1518
+ const properties = {
1519
+ ...buildCommonProperties(orderId, publicKey, devMode, mockMode, checkoutUrl, flowType),
1520
+ event,
1521
+ source,
1522
+ missingFields,
1523
+ missingFieldCount: missingFields.length,
1524
+ };
1525
+ trackEvent("Incomplete Payment Payload", properties, devMode).catch((error) => {
1526
+ if (devMode) {
1527
+ console.error("[Glomo-RN-SDK] Event tracking error on incomplete payment payload:", error);
1528
+ }
1529
+ });
1530
+ }
1531
+
1532
+ /**
1533
+ * Internal telemetry - fires when a payment payload cannot be routed at all.
1534
+ *
1535
+ * Reached only when `orderId` is absent or the optional fields carry the wrong type, so there is no
1536
+ * outcome to report to the merchant without fabricating one. Before v5 this path was a
1537
+ * devMode-only `console.error`, which meant a dropped payment left no trace in a release build.
1538
+ *
1539
+ * Carries the payload's **key names** and nothing else - the values are payment identifiers.
1540
+ */
1541
+ export function trackDroppedPaymentPayload(
1542
+ event: string,
1543
+ payloadKeys: string[],
1544
+ source: string,
1545
+ orderId: string | undefined,
1546
+ publicKey: string,
1547
+ devMode: boolean,
1548
+ mockMode: boolean,
1549
+ checkoutUrl: string,
1550
+ flowType?: FlowType
1551
+ ): void {
1552
+ const properties = {
1553
+ ...buildCommonProperties(orderId, publicKey, devMode, mockMode, checkoutUrl, flowType),
1554
+ event,
1555
+ source,
1556
+ payloadKeys,
1557
+ };
1558
+ trackEvent("Payment Payload Dropped", properties, devMode).catch((error) => {
1559
+ if (devMode) {
1560
+ console.error("[Glomo-RN-SDK] Event tracking error on dropped payment payload:", error);
1561
+ }
1562
+ });
1563
+ }
1564
+
1565
+ // ---------------------------------------------------------------------------
1566
+ // File Upload Telemetry
1567
+ // ---------------------------------------------------------------------------
1568
+
1569
+ /**
1570
+ * Internal telemetry - fires when the user taps a file input on a bank's page.
1571
+ *
1572
+ * **The attempt only.** react-native-webview runs the whole chooser natively through
1573
+ * `onShowFileChooser` and `startPhotoPickerIntent`, so no outcome - picked, cancelled or failed -
1574
+ * ever reaches JavaScript. Getting one would need either a patched rnw or a page-side `change`
1575
+ * listener reporting over the bridge, and the page here is a third party's.
1576
+ *
1577
+ * So an absent follow-up event means "not observable", never "the upload failed". Do not build a
1578
+ * success rate on this.
1579
+ */
1580
+ export function trackFileUploadRequested(
1581
+ acceptTypes: string | undefined,
1582
+ hasCapture: boolean,
1583
+ orderId: string | undefined,
1584
+ publicKey: string,
1585
+ devMode: boolean,
1586
+ mockMode: boolean,
1587
+ checkoutUrl: string,
1588
+ flowType?: FlowType
1589
+ ): void {
1590
+ const properties = {
1591
+ ...buildCommonProperties(orderId, publicKey, devMode, mockMode, checkoutUrl, flowType),
1592
+ acceptTypes,
1593
+ hasCapture,
1594
+ };
1595
+ trackEvent("File Upload Requested", properties, devMode).catch((error) => {
1596
+ if (devMode) {
1597
+ console.error("[Glomo-RN-SDK] Event tracking error on file upload requested:", error);
1598
+ }
1599
+ });
1600
+ }
1601
+
1602
+ // ---------------------------------------------------------------------------
1603
+ // File Save Telemetry
1604
+ // ---------------------------------------------------------------------------
1605
+
1606
+ /**
1607
+ * Event names carry no flow prefix, unlike every payment event above.
1608
+ *
1609
+ * Saving a document is not owned by a flow - the capability is advertised to every WebView the SDK
1610
+ * opens - so a prefix would assert a distinction that does not exist. `flowType` rides the common
1611
+ * properties for anyone who wants to slice by it. The names match the Flutter SDK's so one query
1612
+ * spans both.
1613
+ */
1614
+
1615
+ /**
1616
+ * Internal telemetry - fires when the page asks the SDK to put a document on the device.
1617
+ *
1618
+ * Paired with trackFileSaveCompleted by `saveId`, which fires for every request that got this far,
1619
+ * including the failures and the dismissals. A requested with no completion means the handler died.
1620
+ */
1621
+ export function trackFileSaveRequested(
1622
+ saveId: string,
1623
+ orderId: string | undefined,
1624
+ publicKey: string,
1625
+ devMode: boolean,
1626
+ mockMode: boolean,
1627
+ checkoutUrl: string,
1628
+ flowType?: FlowType
1629
+ ): void {
1630
+ const properties = {
1631
+ ...buildCommonProperties(orderId, publicKey, devMode, mockMode, checkoutUrl, flowType),
1632
+ saveId,
1633
+ };
1634
+ trackEvent("File Save Requested", properties, devMode).catch((error) => {
1635
+ if (devMode) {
1636
+ console.error("[Glomo-RN-SDK] Event tracking error on file save requested:", error);
1637
+ }
1638
+ });
1639
+ }
1640
+
1641
+ /**
1642
+ * Internal telemetry - fires once per request, whatever the outcome.
1643
+ *
1644
+ * `eventData` is the projection the saver builds, never the result object itself. The inputs to a
1645
+ * save are a signed URL and a filename; the projection is what is safe to send, and taking it
1646
+ * pre-built keeps the decision about what that means in one place next to the values it excludes.
1647
+ */
1648
+ export function trackFileSaveCompleted(
1649
+ saveId: string,
1650
+ eventData: Record<string, unknown>,
1651
+ orderId: string | undefined,
1652
+ publicKey: string,
1653
+ devMode: boolean,
1654
+ mockMode: boolean,
1655
+ checkoutUrl: string,
1656
+ flowType?: FlowType
1657
+ ): void {
1658
+ const properties = {
1659
+ ...buildCommonProperties(orderId, publicKey, devMode, mockMode, checkoutUrl, flowType),
1660
+ ...eventData,
1661
+ saveId,
1662
+ };
1663
+ trackEvent("File Save Completed", properties, devMode).catch((error) => {
1664
+ if (devMode) {
1665
+ console.error("[Glomo-RN-SDK] Event tracking error on file save completed:", error);
1666
+ }
1667
+ });
1668
+ }
1669
+
1363
1670
  // ---------------------------------------------------------------------------
1364
1671
  // Checkout Analytics Tracker Map
1365
1672
  // ---------------------------------------------------------------------------
@@ -1416,14 +1723,12 @@ export const subscriptionCheckoutTrackers: CheckoutAnalyticsTrackers = {
1416
1723
  trackPaymentTerminate: trackSubscriptionPaymentTerminate,
1417
1724
  trackConnectionError: trackSubscriptionConnectionError,
1418
1725
  trackSdkError: trackSubscriptionSdkError,
1419
- trackBankTransferSubmitted: (...args) => {
1420
- const devMode = args[2];
1726
+ trackBankTransferSubmitted: (_orderId, _journey, _publicKey, devMode) => {
1421
1727
  if (devMode) {
1422
1728
  console.warn("[Glomo-RN-SDK] Unexpected bank transfer event in subscription flow");
1423
1729
  }
1424
1730
  },
1425
- trackPayViaBankCompleted: (...args) => {
1426
- const devMode = args[3];
1731
+ trackPayViaBankCompleted: (_orderId, _journey, _publicKey, devMode) => {
1427
1732
  if (devMode) {
1428
1733
  console.warn("[Glomo-RN-SDK] Unexpected pay via bank completed event in subscription flow");
1429
1734
  }