@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
@@ -0,0 +1,92 @@
1
+ "use strict";
2
+ /** The `file.save` bridge message, wired once and registered on every WebView that can receive it */
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.createFileSaveHandler = createFileSaveHandler;
5
+ const file_saver_1 = require("../services/file-saver");
6
+ const file_metadata_1 = require("../utils/file-metadata");
7
+ const analytics_1 = require("../utils/analytics");
8
+ const validation_1 = require("../utils/validation");
9
+ /**
10
+ * Correlates the request/completion pair when the page supplies no id.
11
+ *
12
+ * Module scope rather than per handler, because the same SDK session registers this on the main and
13
+ * flow WebViews and a per-handler counter would have both minting `sdk-1`. Saves are not serialised
14
+ * either - the agreements screen has three download controls, so two taps in quick succession
15
+ * interleave and would otherwise be indistinguishable in telemetry.
16
+ */
17
+ let fallbackSaveId = 0;
18
+ /** Prefers the page's requestId so one id spans both sides' telemetry. */
19
+ function resolveSaveId(message) {
20
+ const supplied = message.requestId;
21
+ if (typeof supplied === "string" && supplied.length > 0) {
22
+ return supplied;
23
+ }
24
+ return `sdk-${++fallbackSaveId}`;
25
+ }
26
+ /**
27
+ * Builds the handler for `file.save`.
28
+ *
29
+ * Fire-and-forget by contract - the page gets no acknowledgement and must not wait for one. Once
30
+ * past the guard below, every outcome lands on `File Save Completed`, and a failure additionally
31
+ * reaches the host's onSdkError without ending the checkout.
32
+ *
33
+ * The handler itself is synchronous because the router's handlers are; the save runs detached and
34
+ * reports through telemetry rather than a return value, which is the same shape the contract
35
+ * describes on the page side.
36
+ */
37
+ function createFileSaveHandler({ flowType, orderId, publicKey, checkoutUrl, mockMode, devMode, onSdkError, }) {
38
+ return (message) => {
39
+ const saveId = resolveSaveId(message);
40
+ const report = (result) => {
41
+ if (devMode) {
42
+ console.log(`[Glomo-RN-SDK] file.save ${saveId} completed: ${result.outcome}`);
43
+ }
44
+ (0, analytics_1.trackFileSaveCompleted)(saveId, (0, file_saver_1.toFileSaveEventData)(result), orderId, publicKey, devMode, mockMode, checkoutUrl, flowType);
45
+ if ((0, file_saver_1.isFileSaveFailure)(result)) {
46
+ (0, validation_1.safeCallback)(onSdkError, [[(0, file_saver_1.toFileSaveSdkError)(result)]], "onSdkError", devMode);
47
+ }
48
+ };
49
+ if (devMode) {
50
+ console.log(`[Glomo-RN-SDK] file.save ${saveId} requested`);
51
+ }
52
+ (0, analytics_1.trackFileSaveRequested)(saveId, orderId, publicKey, devMode, mockMode, checkoutUrl, flowType);
53
+ const url = message.url;
54
+ if (typeof url !== "string" || url.length === 0) {
55
+ /**
56
+ * Reported rather than dropped. The Flutter SDK returns here without emitting anything
57
+ * and relies on its error tracker to surface it; RN has none yet, so silence would make
58
+ * a malformed message invisible. Completing the pair keeps the "every request has an
59
+ * outcome" invariant that makes a missing completion mean the handler died.
60
+ */
61
+ report({
62
+ outcome: file_saver_1.FILE_SAVE_OUTCOMES.REJECTED,
63
+ fileExtension: file_metadata_1.EXTENSION_EXTRACTION_FAILED,
64
+ fileSize: file_metadata_1.SIZE_UNAVAILABLE,
65
+ failureType: "missing_url",
66
+ });
67
+ return;
68
+ }
69
+ void (0, file_saver_1.saveDocumentToDevice)({
70
+ url,
71
+ filename: typeof message.filename === "string" ? message.filename : undefined,
72
+ devMode,
73
+ })
74
+ .then(report)
75
+ .catch((error) => {
76
+ /**
77
+ * saveDocumentToDevice is documented never to throw, so this is the case where that
78
+ * promise is broken. It still has to close the pair - and only the failure type
79
+ * leaves here, never the message that produced it.
80
+ */
81
+ if (devMode) {
82
+ console.error("[Glomo-RN-SDK] file.save handler failed:", error);
83
+ }
84
+ report({
85
+ outcome: file_saver_1.FILE_SAVE_OUTCOMES.SAVE_FAILED,
86
+ fileExtension: file_metadata_1.EXTENSION_EXTRACTION_FAILED,
87
+ fileSize: file_metadata_1.SIZE_UNAVAILABLE,
88
+ failureType: "handler_threw",
89
+ });
90
+ });
91
+ };
92
+ }
@@ -0,0 +1,44 @@
1
+ /** Shared WebView message routing for every GlomoPay checkout flow */
2
+ import { type WebViewMessageEvent } from "react-native-webview";
3
+ /**
4
+ * A parsed bridge message.
5
+ *
6
+ * Deliberately loose: the page and our own injection scripts both post here, and the
7
+ * shapes differ per type. Handlers narrow what they need.
8
+ */
9
+ export interface WebViewMessage {
10
+ type?: string;
11
+ [key: string]: unknown;
12
+ }
13
+ /** Handles one message type. Registered by the flow that cares about it. */
14
+ export type WebViewMessageHandler = (message: WebViewMessage) => void;
15
+ /** The options for createMessageRouter */
16
+ export interface CreateMessageRouterOptions {
17
+ /** Log prefix of the calling flow, e.g. "[Glomo-RN-SDK LRS]" */
18
+ logPrefix: string;
19
+ /** Which WebView this router serves. Appears in logs only. */
20
+ source: string;
21
+ /**
22
+ * Called when the event carries no usable string payload, before the router gives up.
23
+ * The caller reports it, because the tracker needs flow-level context the router has no
24
+ * business knowing.
25
+ */
26
+ onInvalidMessage?: (data: unknown) => void;
27
+ /**
28
+ * Message type to handler. A type with no handler is ignored silently, which is what
29
+ * the open-coded switches did by falling through. Inherited keys are not handlers.
30
+ */
31
+ handlers: Record<string, WebViewMessageHandler>;
32
+ devMode?: boolean;
33
+ }
34
+ /**
35
+ * Builds the onMessage handler for a WebView.
36
+ *
37
+ * Exists because all four message handlers opened with the same twenty-five lines - guard the
38
+ * payload, parse it, log it, then dispatch on `message.type`. Only the dispatch differed. New
39
+ * message types now register in one place per flow instead of being added to each switch, which
40
+ * is what let `file.input` telemetry and the education carousel's invalid-message tracking go
41
+ * missing on some WebViews and not others.
42
+ */
43
+ export declare function createMessageRouter({ logPrefix, source, onInvalidMessage, handlers, devMode, }: CreateMessageRouterOptions): (event: WebViewMessageEvent) => void;
44
+ //# sourceMappingURL=message-router.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"message-router.d.ts","sourceRoot":"","sources":["../../src/bridge/message-router.ts"],"names":[],"mappings":"AAAA,sEAAsE;AAEtE,OAAO,EAAE,KAAK,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAEhE;;;;;GAKG;AACH,MAAM,WAAW,cAAc;IAC3B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CAC1B;AAED,4EAA4E;AAC5E,MAAM,MAAM,qBAAqB,GAAG,CAAC,OAAO,EAAE,cAAc,KAAK,IAAI,CAAC;AAEtE,0CAA0C;AAC1C,MAAM,WAAW,0BAA0B;IACvC,gEAAgE;IAChE,SAAS,EAAE,MAAM,CAAC;IAElB,8DAA8D;IAC9D,MAAM,EAAE,MAAM,CAAC;IAEf;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IAE3C;;;OAGG;IACH,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,qBAAqB,CAAC,CAAC;IAEhD,OAAO,CAAC,EAAE,OAAO,CAAC;CACrB;AAED;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CAAC,EAChC,SAAS,EACT,MAAM,EACN,gBAAgB,EAChB,QAAQ,EACR,OAAe,GAClB,EAAE,0BAA0B,IACjB,OAAO,mBAAmB,KAAG,IAAI,CAiC5C"}
@@ -0,0 +1,48 @@
1
+ "use strict";
2
+ /** Shared WebView message routing for every GlomoPay checkout flow */
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.createMessageRouter = createMessageRouter;
5
+ /**
6
+ * Builds the onMessage handler for a WebView.
7
+ *
8
+ * Exists because all four message handlers opened with the same twenty-five lines - guard the
9
+ * payload, parse it, log it, then dispatch on `message.type`. Only the dispatch differed. New
10
+ * message types now register in one place per flow instead of being added to each switch, which
11
+ * is what let `file.input` telemetry and the education carousel's invalid-message tracking go
12
+ * missing on some WebViews and not others.
13
+ */
14
+ function createMessageRouter({ logPrefix, source, onInvalidMessage, handlers, devMode = false, }) {
15
+ return (event) => {
16
+ var _a;
17
+ try {
18
+ const data = (_a = event.nativeEvent) === null || _a === void 0 ? void 0 : _a.data;
19
+ if (!data || typeof data !== "string") {
20
+ if (devMode) {
21
+ console.warn(`${logPrefix} Invalid message data from ${source}`);
22
+ }
23
+ onInvalidMessage === null || onInvalidMessage === void 0 ? void 0 : onInvalidMessage(data);
24
+ return;
25
+ }
26
+ const message = JSON.parse(data);
27
+ if (devMode) {
28
+ console.log(`${logPrefix} ${source} Message received:`, message.type, message);
29
+ }
30
+ /**
31
+ * Own-property lookup, not a bare index. `message.type` is page-controlled, and this is
32
+ * now the single dispatch point for every flow - a bare index resolves `__proto__` to
33
+ * `Object.prototype` and throws into the catch below, and `constructor`/`toString` to
34
+ * real functions that then get called. The switches this replaced had neither case.
35
+ */
36
+ const type = message.type;
37
+ const handler = type && Object.prototype.hasOwnProperty.call(handlers, type) ? handlers[type] : undefined;
38
+ if (typeof handler === "function") {
39
+ handler(message);
40
+ }
41
+ }
42
+ catch (error) {
43
+ if (devMode) {
44
+ console.error(`${logPrefix} Error parsing ${source} message:`, error);
45
+ }
46
+ }
47
+ };
48
+ }
@@ -0,0 +1,18 @@
1
+ /** What the SDK says about a payment payload it could not use */
2
+ import { type SdkError } from "../utils/analytics";
3
+ /**
4
+ * The key names on a bridge payload, for telemetry.
5
+ *
6
+ * Names only. The values are payment identifiers and a signature, which is why the dropped-payload
7
+ * event reports the shape of what arrived rather than what it contained.
8
+ */
9
+ export declare function payloadKeysOf(payload: unknown): string[];
10
+ /**
11
+ * The host-facing form of a payment payload the SDK could not route.
12
+ *
13
+ * Surfaced rather than swallowed: the page reported a terminal outcome and the merchant would
14
+ * otherwise never learn that one happened. `generatedCheckoutUrl` is the nearest existing `field`
15
+ * value - this is a fault in what the checkout page sent, not in anything the merchant configured.
16
+ */
17
+ export declare function droppedPayloadSdkError(event: string): SdkError;
18
+ //# sourceMappingURL=payment-payload.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"payment-payload.d.ts","sourceRoot":"","sources":["../../src/bridge/payment-payload.ts"],"names":[],"mappings":"AAAA,iEAAiE;AAEjE,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAEnD;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,EAAE,CAKxD;AAED;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,MAAM,GAAG,QAAQ,CAM9D"}
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+ /** What the SDK says about a payment payload it could not use */
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.payloadKeysOf = payloadKeysOf;
5
+ exports.droppedPayloadSdkError = droppedPayloadSdkError;
6
+ /**
7
+ * The key names on a bridge payload, for telemetry.
8
+ *
9
+ * Names only. The values are payment identifiers and a signature, which is why the dropped-payload
10
+ * event reports the shape of what arrived rather than what it contained.
11
+ */
12
+ function payloadKeysOf(payload) {
13
+ if (!payload || typeof payload !== "object") {
14
+ return [];
15
+ }
16
+ return Object.keys(payload);
17
+ }
18
+ /**
19
+ * The host-facing form of a payment payload the SDK could not route.
20
+ *
21
+ * Surfaced rather than swallowed: the page reported a terminal outcome and the merchant would
22
+ * otherwise never learn that one happened. `generatedCheckoutUrl` is the nearest existing `field`
23
+ * value - this is a fault in what the checkout page sent, not in anything the merchant configured.
24
+ */
25
+ function droppedPayloadSdkError(event) {
26
+ return {
27
+ type: "validation_error",
28
+ message: `Received a ${event} event with a payload the SDK could not route. The payment outcome was not reported.`,
29
+ field: "generatedCheckoutUrl",
30
+ };
31
+ }
@@ -0,0 +1,40 @@
1
+ /** Loads the optional dependencies that back document saving, and reports whether they are there */
2
+ /**
3
+ * The picker surface this SDK uses, as a type only.
4
+ *
5
+ * `typeof import(...)` is erased at compile time, so this gives full typechecking against the real
6
+ * package without emitting an import that would make an optional dependency mandatory.
7
+ */
8
+ type DocumentPickerModule = {
9
+ saveDocuments: typeof import("@react-native-documents/picker").saveDocuments;
10
+ errorCodes: typeof import("@react-native-documents/picker").errorCodes;
11
+ isErrorWithCode: typeof import("@react-native-documents/picker").isErrorWithCode;
12
+ };
13
+ type BlobUtilModule = import("react-native-blob-util").ReactNativeBlobUtil;
14
+ /** Package names, so a missing one can be named in a warning and in telemetry */
15
+ export declare const FILE_SAVE_PACKAGES: readonly ["react-native-blob-util", "@react-native-documents/picker"];
16
+ /** What the probe found. Shared by the capability list, the start() warning and telemetry. */
17
+ export interface FileSaveAvailability {
18
+ /** True only when every package loaded */
19
+ available: boolean;
20
+ /** Packages that could not be loaded, in FILE_SAVE_PACKAGES order */
21
+ missing: string[];
22
+ }
23
+ export declare function loadBlobUtil(): BlobUtilModule | null;
24
+ export declare function loadDocumentPicker(): DocumentPickerModule | null;
25
+ /**
26
+ * Whether the SDK can put a document on the device.
27
+ *
28
+ * Both packages are needed and neither substitutes for the other - blob-util streams the download
29
+ * to a temp file, the picker presents the system save dialog for the user to choose a destination.
30
+ * A build missing either one cannot complete a save, so the capability is not advertised and the
31
+ * checkout page keeps its own download path.
32
+ *
33
+ * Reads through the same loaders the saver calls, so the answer here and the behaviour there cannot
34
+ * disagree. Both resolved once at module init and returned from there - see loadBlobUtil on why that
35
+ * is required rather than an optimisation. Safe regardless, since a native module cannot appear
36
+ * mid-session.
37
+ */
38
+ export declare function resolveFileSaveAvailability(): FileSaveAvailability;
39
+ export {};
40
+ //# sourceMappingURL=file-save.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-save.d.ts","sourceRoot":"","sources":["../../src/capabilities/file-save.ts"],"names":[],"mappings":"AAAA,oGAAoG;AAEpG;;;;;GAKG;AACH,KAAK,oBAAoB,GAAG;IACxB,aAAa,EAAE,cAAc,gCAAgC,EAAE,aAAa,CAAC;IAC7E,UAAU,EAAE,cAAc,gCAAgC,EAAE,UAAU,CAAC;IACvE,eAAe,EAAE,cAAc,gCAAgC,EAAE,eAAe,CAAC;CACpF,CAAC;AAEF,KAAK,cAAc,GAAG,OAAO,wBAAwB,EAAE,mBAAmB,CAAC;AAE3E,iFAAiF;AACjF,eAAO,MAAM,kBAAkB,uEAAwE,CAAC;AAExG,8FAA8F;AAC9F,MAAM,WAAW,oBAAoB;IACjC,0CAA0C;IAC1C,SAAS,EAAE,OAAO,CAAC;IAEnB,qEAAqE;IACrE,OAAO,EAAE,MAAM,EAAE,CAAC;CACrB;AAwDD,wBAAgB,YAAY,IAAI,cAAc,GAAG,IAAI,CAEpD;AAWD,wBAAgB,kBAAkB,IAAI,oBAAoB,GAAG,IAAI,CAEhE;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,2BAA2B,IAAI,oBAAoB,CAWlE"}
@@ -0,0 +1,101 @@
1
+ "use strict";
2
+ /** Loads the optional dependencies that back document saving, and reports whether they are there */
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.FILE_SAVE_PACKAGES = void 0;
5
+ exports.loadBlobUtil = loadBlobUtil;
6
+ exports.loadDocumentPicker = loadDocumentPicker;
7
+ exports.resolveFileSaveAvailability = resolveFileSaveAvailability;
8
+ /** Package names, so a missing one can be named in a warning and in telemetry */
9
+ exports.FILE_SAVE_PACKAGES = ["react-native-blob-util", "@react-native-documents/picker"];
10
+ /**
11
+ * Metro's interop puts an ES default export on `.default`; the picker uses named exports.
12
+ *
13
+ * Widened rather than narrowed because these two packages are loaded through the same seam and
14
+ * disagree on export style.
15
+ */
16
+ function unwrap(loaded) {
17
+ var _a, _b;
18
+ const module = loaded;
19
+ return (_b = (_a = module === null || module === void 0 ? void 0 : module.default) !== null && _a !== void 0 ? _a : module) !== null && _b !== void 0 ? _b : null;
20
+ }
21
+ /**
22
+ * Streams a document to disk. Null when the package is absent or its native module is not linked.
23
+ *
24
+ * Metro requires a string literal here, and requires the call to sit directly inside a `try` block.
25
+ *
26
+ * Both halves are load-bearing and neither is obvious:
27
+ *
28
+ * - A `require()` whose argument Metro cannot evaluate statically is rejected at bundle time in
29
+ * project code, and compiled to a runtime throw inside `node_modules` - which is where this file
30
+ * lives in a merchant app. So a loop over FILE_SAVE_PACKAGES calling `require(name)` would not
31
+ * fail loudly; it would report every package missing in every merchant build and silently
32
+ * withdraw the capability.
33
+ * - Metro only tolerates an unresolvable literal when the call is lexically inside a `try` block
34
+ * (`collectDependencies.isOptionalDependency`), and only when `allowOptionalDependencies` is on.
35
+ * `@react-native/metro-config` sets it, which is what makes the optional-peer-dependency pattern
36
+ * work at all - the same mechanism the existing `jail-monkey` require in utils/device-compliance
37
+ * already depends on.
38
+ *
39
+ * - The require must run while this module is still initialising, which is why it sits in an IIFE
40
+ * at module scope rather than inside the exported function. Metro's `guardedLoadModule` reports a
41
+ * failed module load through `ErrorUtils.reportFatalError` and then swallows it, but only when it
42
+ * is not already loading something (`inGuard`). A lazy first `require` - from a hook, a render, or
43
+ * anything after startup - is outside that guard, so an absent package is reported as a *fatal*
44
+ * error and raises a full-screen LogBox in every dev build, even though our `catch` here means the
45
+ * capability degrades correctly and nothing actually breaks. Resolving at module init keeps the
46
+ * throw inside the guard, where it propagates to our `catch` silently.
47
+ *
48
+ * The consequence for structure: these two loaders cannot be collapsed into one parameterised
49
+ * helper, the `try` cannot be hoisted into a caller, and the resolution cannot be made lazy.
50
+ *
51
+ * Deliberately treats "not installed" and "installed but will not load" alike. Both packages ship
52
+ * native modules, so a merchant who installs them without rebuilding the app has them present in
53
+ * node_modules and still unusable - and either way the SDK cannot save a file. The distinction
54
+ * matters only to the warning text, which names both causes rather than guessing between them.
55
+ */
56
+ const blobUtilModule = (() => {
57
+ try {
58
+ return unwrap(require("react-native-blob-util"));
59
+ }
60
+ catch (_a) {
61
+ return null;
62
+ }
63
+ })();
64
+ function loadBlobUtil() {
65
+ return blobUtilModule;
66
+ }
67
+ /** Presents the system save dialog. Null, and shaped, on the same terms as loadBlobUtil above. */
68
+ const documentPickerModule = (() => {
69
+ try {
70
+ return unwrap(require("@react-native-documents/picker"));
71
+ }
72
+ catch (_a) {
73
+ return null;
74
+ }
75
+ })();
76
+ function loadDocumentPicker() {
77
+ return documentPickerModule;
78
+ }
79
+ /**
80
+ * Whether the SDK can put a document on the device.
81
+ *
82
+ * Both packages are needed and neither substitutes for the other - blob-util streams the download
83
+ * to a temp file, the picker presents the system save dialog for the user to choose a destination.
84
+ * A build missing either one cannot complete a save, so the capability is not advertised and the
85
+ * checkout page keeps its own download path.
86
+ *
87
+ * Reads through the same loaders the saver calls, so the answer here and the behaviour there cannot
88
+ * disagree. Both resolved once at module init and returned from there - see loadBlobUtil on why that
89
+ * is required rather than an optimisation. Safe regardless, since a native module cannot appear
90
+ * mid-session.
91
+ */
92
+ function resolveFileSaveAvailability() {
93
+ const missing = [];
94
+ if (!loadBlobUtil()) {
95
+ missing.push(exports.FILE_SAVE_PACKAGES[0]);
96
+ }
97
+ if (!loadDocumentPicker()) {
98
+ missing.push(exports.FILE_SAVE_PACKAGES[1]);
99
+ }
100
+ return { available: missing.length === 0, missing };
101
+ }
@@ -0,0 +1,22 @@
1
+ /** What this SDK build can do, resolved at runtime */
2
+ /**
3
+ * Capability strings the checkout page gates on.
4
+ *
5
+ * The page reads these from `window.__glomoSdkCapabilities__` at the moment it needs one, and
6
+ * falls back to its own behaviour when a string is absent. It deliberately does not infer support
7
+ * from the bridge existing - every Glomo SDK has a bridge, so a build without the handler would
8
+ * take delivery of the message into a router that ignores it, and the user's tap would vanish.
9
+ */
10
+ export declare const CAPABILITIES: {
11
+ readonly FILE_SAVE: "file.save";
12
+ };
13
+ /**
14
+ * The capabilities this build can honour.
15
+ *
16
+ * Append only, and only when the handler actually exists in this build - removing a string
17
+ * silently reverts the page to its own path, which is the correct degradation but a confusing
18
+ * one to debug if it happens by accident.
19
+ */
20
+ export declare function resolveCapabilities(): string[];
21
+ export { resolveFileSaveAvailability, FILE_SAVE_PACKAGES, type FileSaveAvailability } from "./file-save";
22
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/capabilities/index.ts"],"names":[],"mappings":"AAAA,sDAAsD;AAItD;;;;;;;GAOG;AACH,eAAO,MAAM,YAAY;;CAEf,CAAC;AAEX;;;;;;GAMG;AACH,wBAAgB,mBAAmB,IAAI,MAAM,EAAE,CAQ9C;AAED,OAAO,EAAE,2BAA2B,EAAE,kBAAkB,EAAE,KAAK,oBAAoB,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+ /** What this SDK build can do, resolved at runtime */
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.FILE_SAVE_PACKAGES = exports.resolveFileSaveAvailability = exports.CAPABILITIES = void 0;
5
+ exports.resolveCapabilities = resolveCapabilities;
6
+ const file_save_1 = require("./file-save");
7
+ /**
8
+ * Capability strings the checkout page gates on.
9
+ *
10
+ * The page reads these from `window.__glomoSdkCapabilities__` at the moment it needs one, and
11
+ * falls back to its own behaviour when a string is absent. It deliberately does not infer support
12
+ * from the bridge existing - every Glomo SDK has a bridge, so a build without the handler would
13
+ * take delivery of the message into a router that ignores it, and the user's tap would vanish.
14
+ */
15
+ exports.CAPABILITIES = {
16
+ FILE_SAVE: "file.save",
17
+ };
18
+ /**
19
+ * The capabilities this build can honour.
20
+ *
21
+ * Append only, and only when the handler actually exists in this build - removing a string
22
+ * silently reverts the page to its own path, which is the correct degradation but a confusing
23
+ * one to debug if it happens by accident.
24
+ */
25
+ function resolveCapabilities() {
26
+ const capabilities = [];
27
+ if ((0, file_save_1.resolveFileSaveAvailability)().available) {
28
+ capabilities.push(exports.CAPABILITIES.FILE_SAVE);
29
+ }
30
+ return capabilities;
31
+ }
32
+ var file_save_2 = require("./file-save");
33
+ Object.defineProperty(exports, "resolveFileSaveAvailability", { enumerable: true, get: function () { return file_save_2.resolveFileSaveAvailability; } });
34
+ Object.defineProperty(exports, "FILE_SAVE_PACKAGES", { enumerable: true, get: function () { return file_save_2.FILE_SAVE_PACKAGES; } });
@@ -0,0 +1,24 @@
1
+ /** Tells the host, once per mount, about capabilities this build cannot offer */
2
+ import { type SdkError } from "../utils/analytics";
3
+ /** The options for useCapabilityReporting */
4
+ export interface UseCapabilityReportingOptions {
5
+ onSdkError: (errors: Array<SdkError>) => void;
6
+ devMode?: boolean;
7
+ }
8
+ /**
9
+ * Reports missing optional dependencies to the host on mount.
10
+ *
11
+ * Paired with the ungated `console.warn` in `start()`, and deliberately not merged with it: the
12
+ * warning reaches a developer watching a console, this reaches a merchant's error handling, and a
13
+ * merchant who has wired up logging should not have to read logs to discover that a feature they
14
+ * were told exists is inert in their build.
15
+ *
16
+ * Not an error the SDK raises about itself - the checkout still works, and the page falls back to
17
+ * its own download path. `field` is set so it can be filtered apart from a configuration fault on
18
+ * the same callback.
19
+ *
20
+ * Fires once per mounted component rather than once per process, and never on a build where the
21
+ * dependencies are present.
22
+ */
23
+ export declare function useCapabilityReporting({ onSdkError, devMode }: UseCapabilityReportingOptions): void;
24
+ //# sourceMappingURL=use-capability-reporting.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-capability-reporting.d.ts","sourceRoot":"","sources":["../../src/capabilities/use-capability-reporting.ts"],"names":[],"mappings":"AAAA,iFAAiF;AAMjF,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAEnD,6CAA6C;AAC7C,MAAM,WAAW,6BAA6B;IAC1C,UAAU,EAAE,CAAC,MAAM,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,IAAI,CAAC;IAC9C,OAAO,CAAC,EAAE,OAAO,CAAC;CACrB;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,sBAAsB,CAAC,EAAE,UAAU,EAAE,OAAe,EAAE,EAAE,6BAA6B,GAAG,IAAI,CAyB3G"}
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+ /** Tells the host, once per mount, about capabilities this build cannot offer */
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.useCapabilityReporting = useCapabilityReporting;
5
+ const react_1 = require("react");
6
+ const file_save_1 = require("./file-save");
7
+ const validation_1 = require("../utils/validation");
8
+ /**
9
+ * Reports missing optional dependencies to the host on mount.
10
+ *
11
+ * Paired with the ungated `console.warn` in `start()`, and deliberately not merged with it: the
12
+ * warning reaches a developer watching a console, this reaches a merchant's error handling, and a
13
+ * merchant who has wired up logging should not have to read logs to discover that a feature they
14
+ * were told exists is inert in their build.
15
+ *
16
+ * Not an error the SDK raises about itself - the checkout still works, and the page falls back to
17
+ * its own download path. `field` is set so it can be filtered apart from a configuration fault on
18
+ * the same callback.
19
+ *
20
+ * Fires once per mounted component rather than once per process, and never on a build where the
21
+ * dependencies are present.
22
+ */
23
+ function useCapabilityReporting({ onSdkError, devMode = false }) {
24
+ const reportedRef = (0, react_1.useRef)(false);
25
+ (0, react_1.useEffect)(() => {
26
+ if (reportedRef.current) {
27
+ return;
28
+ }
29
+ reportedRef.current = true;
30
+ const fileSave = (0, file_save_1.resolveFileSaveAvailability)();
31
+ if (fileSave.available) {
32
+ return;
33
+ }
34
+ const errors = [
35
+ {
36
+ type: "validation_error",
37
+ message: `Document downloads are unavailable: ${fileSave.missing.join(" and ")} could not be loaded. ` +
38
+ "Install the package(s) and rebuild the app to enable them.",
39
+ field: "file.save",
40
+ },
41
+ ];
42
+ (0, validation_1.safeCallback)(onSdkError, [errors], "onSdkError", devMode);
43
+ }, [onSdkError, devMode]);
44
+ }
@@ -19,6 +19,18 @@ export interface GlomoServerConfig {
19
19
  }
20
20
  export declare const DEFAULT_SERVER: InternalGlomoServer;
21
21
  export declare const SERVER_CONFIGS: Record<InternalGlomoServer, GlomoServerConfig>;
22
+ /**
23
+ * Identifies this SDK to the checkout page, which forwards both onto the order it creates.
24
+ *
25
+ * Exists because nothing in `payments`, `payment_sessions`, `terminals` or `api_audits` carries a
26
+ * surface dimension, so an SDK-originated order is indistinguishable from a dashboard one
27
+ * (KAN-6551). The Flutter SDK sends the analogous pair (`checkout-flutter-sdk` / `flutter`).
28
+ *
29
+ * Inert until the checkout page is redeployed to read them - neither `apps/checkout` nor
30
+ * `lrs-checkout-page` allow-lists query params, so unknown ones are ignored rather than rejected.
31
+ */
32
+ export declare const ANALYTICS_PRODUCT = "checkout-react-native-sdk";
33
+ export declare const ANALYTICS_SURFACE = "react_native";
22
34
  /** Returns the full server config for the given environment, falling back to prod */
23
35
  export declare function resolveServerConfig(server?: InternalGlomoServer): GlomoServerConfig;
24
36
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"base.d.ts","sourceRoot":"","sources":["../../src/config/base.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,yEAAyE;AACzE,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,SAAS,CAAC;AAE7C,8EAA8E;AAC9E,KAAK,mBAAmB,GAAG,WAAW,GAAG,OAAO,CAAC;AAEjD,+CAA+C;AAC/C,MAAM,WAAW,mBAAmB;IAChC,WAAW,EAAE,MAAM,CAAC;IACpB,gBAAgB,EAAE,MAAM,CAAC;IACzB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,GAAG,EAAE,MAAM,CAAC;CACf;AAED,0CAA0C;AAC1C,MAAM,WAAW,iBAAiB;IAC9B,OAAO,EAAE,mBAAmB,CAAC;CAChC;AAED,eAAO,MAAM,cAAc,EAAE,mBAA4B,CAAC;AAE1D,eAAO,MAAM,cAAc,EAAE,MAAM,CAAC,mBAAmB,EAAE,iBAAiB,CAyBzE,CAAC;AAEF,qFAAqF;AACrF,wBAAgB,mBAAmB,CAAC,MAAM,CAAC,EAAE,mBAAmB,GAAG,iBAAiB,CAInF"}
1
+ {"version":3,"file":"base.d.ts","sourceRoot":"","sources":["../../src/config/base.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,yEAAyE;AACzE,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,SAAS,CAAC;AAE7C,8EAA8E;AAC9E,KAAK,mBAAmB,GAAG,WAAW,GAAG,OAAO,CAAC;AAEjD,+CAA+C;AAC/C,MAAM,WAAW,mBAAmB;IAChC,WAAW,EAAE,MAAM,CAAC;IACpB,gBAAgB,EAAE,MAAM,CAAC;IACzB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,GAAG,EAAE,MAAM,CAAC;CACf;AAED,0CAA0C;AAC1C,MAAM,WAAW,iBAAiB;IAC9B,OAAO,EAAE,mBAAmB,CAAC;CAChC;AAED,eAAO,MAAM,cAAc,EAAE,mBAA4B,CAAC;AAE1D,eAAO,MAAM,cAAc,EAAE,MAAM,CAAC,mBAAmB,EAAE,iBAAiB,CAyBzE,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,iBAAiB,8BAA8B,CAAC;AAC7D,eAAO,MAAM,iBAAiB,iBAAiB,CAAC;AAEhD,qFAAqF;AACrF,wBAAgB,mBAAmB,CAAC,MAAM,CAAC,EAAE,mBAAmB,GAAG,iBAAiB,CAInF"}
@@ -4,7 +4,7 @@
4
4
  * This file contains the default base configuration variables for the GlomoPay RN SDK.
5
5
  */
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
- exports.SERVER_CONFIGS = exports.DEFAULT_SERVER = void 0;
7
+ exports.ANALYTICS_SURFACE = exports.ANALYTICS_PRODUCT = exports.SERVER_CONFIGS = exports.DEFAULT_SERVER = void 0;
8
8
  exports.resolveServerConfig = resolveServerConfig;
9
9
  exports.DEFAULT_SERVER = "prod";
10
10
  exports.SERVER_CONFIGS = {
@@ -33,6 +33,18 @@ exports.SERVER_CONFIGS = {
33
33
  },
34
34
  },
35
35
  };
36
+ /**
37
+ * Identifies this SDK to the checkout page, which forwards both onto the order it creates.
38
+ *
39
+ * Exists because nothing in `payments`, `payment_sessions`, `terminals` or `api_audits` carries a
40
+ * surface dimension, so an SDK-originated order is indistinguishable from a dashboard one
41
+ * (KAN-6551). The Flutter SDK sends the analogous pair (`checkout-flutter-sdk` / `flutter`).
42
+ *
43
+ * Inert until the checkout page is redeployed to read them - neither `apps/checkout` nor
44
+ * `lrs-checkout-page` allow-lists query params, so unknown ones are ignored rather than rejected.
45
+ */
46
+ exports.ANALYTICS_PRODUCT = "checkout-react-native-sdk";
47
+ exports.ANALYTICS_SURFACE = "react_native";
36
48
  /** Returns the full server config for the given environment, falling back to prod */
37
49
  function resolveServerConfig(server) {
38
50
  const resolvedServer = server && server in exports.SERVER_CONFIGS ? server : exports.DEFAULT_SERVER;
@@ -1,7 +1,12 @@
1
1
  /**
2
- * The unified GlomoPay Checkout Component (v4).
2
+ * The unified GlomoPay Checkout Component.
3
3
  * Detects order type (LRS vs Standard) and delegates rendering to the appropriate inner component.
4
4
  * Enforces error handling via `onSdkError()` as a mandatory prop.
5
+ *
6
+ * Its props are a union over both flows, so a prop that only one flow uses is still accepted here.
7
+ * `onUserJourneyCompleted` is the one case where that matters: it is forwarded to the standard and
8
+ * subscriptions flows and silently ignored on LRS orders, because LRS never produces an
9
+ * asynchronous journey for it to report. Every other callback reaches every flow.
5
10
  */
6
11
  import React from "react";
7
12
  import { type GlomoCheckoutRef, type GlomoCheckoutProps } from "./types/checkout";
@@ -1 +1 @@
1
- {"version":3,"file":"glomo-checkout.d.ts","sourceRoot":"","sources":["../src/glomo-checkout.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAsE,MAAM,OAAO,CAAC;AAG3F,OAAO,EAAE,KAAK,gBAAgB,EAAE,KAAK,kBAAkB,EAAmC,MAAM,kBAAkB,CAAC;AA6HnH;;GAEG;AACH,eAAO,MAAM,aAAa,EAAyC,KAAK,CAAC,yBAAyB,CAC9F,kBAAkB,GAAG,KAAK,CAAC,aAAa,CAAC,gBAAgB,CAAC,CAC7D,CAAC"}
1
+ {"version":3,"file":"glomo-checkout.d.ts","sourceRoot":"","sources":["../src/glomo-checkout.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAsE,MAAM,OAAO,CAAC;AAG3F,OAAO,EAAE,KAAK,gBAAgB,EAAE,KAAK,kBAAkB,EAAmC,MAAM,kBAAkB,CAAC;AA4HnH;;GAEG;AACH,eAAO,MAAM,aAAa,EAAyC,KAAK,CAAC,yBAAyB,CAC9F,kBAAkB,GAAG,KAAK,CAAC,aAAa,CAAC,gBAAgB,CAAC,CAC7D,CAAC"}