react-native-fincra-checkout 1.0.0 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +58 -10
- package/lib/commonjs/checkout/FincraCheckout.js +41 -45
- package/lib/commonjs/components/FincraInlineCheckout.js +110 -97
- package/lib/commonjs/components/FincraWebViewCheckout.js +99 -72
- package/lib/commonjs/inline/JsBridge.js +21 -15
- package/lib/commonjs/inline/htmlGenerator.js +53 -31
- package/lib/commonjs/utils/UrlHandler.js +62 -3
- package/lib/typescript/checkout/FincraCheckout.d.ts +0 -1
- package/lib/typescript/components/FincraInlineCheckout.d.ts +1 -2
- package/lib/typescript/components/FincraWebViewCheckout.d.ts +1 -1
- package/lib/typescript/inline/JsBridge.d.ts +4 -1
- package/lib/typescript/inline/htmlGenerator.d.ts +30 -0
- package/lib/typescript/types/index.d.ts +14 -3
- package/lib/typescript/utils/UrlHandler.d.ts +30 -1
- package/package.json +4 -4
- package/src/checkout/FincraCheckout.tsx +75 -69
- package/src/components/FincraInlineCheckout.tsx +202 -159
- package/src/components/FincraWebViewCheckout.tsx +184 -138
- package/src/inline/JsBridge.ts +28 -20
- package/src/inline/htmlGenerator.ts +65 -35
- package/src/types/index.ts +14 -3
- package/src/utils/UrlHandler.ts +76 -3
package/src/utils/UrlHandler.ts
CHANGED
|
@@ -5,6 +5,8 @@ import type { FincraPaymentResponse } from '../types';
|
|
|
5
5
|
// Direct TypeScript port of flutter_fincra_checkout/lib/src/utils/url_handler.dart
|
|
6
6
|
// Mirrors UrlHandler.isCompletionUrl() and UrlHandler.extractResponseParams()
|
|
7
7
|
|
|
8
|
+
const DEFAULT_PORTS: Record<string, string> = { http: '80', https: '443' };
|
|
9
|
+
|
|
8
10
|
/**
|
|
9
11
|
* Utilities for detecting Fincra payment completion URLs and
|
|
10
12
|
* extracting normalized response parameters.
|
|
@@ -14,7 +16,8 @@ export class UrlHandler {
|
|
|
14
16
|
* Returns `true` if the given URL signals a Fincra payment completion.
|
|
15
17
|
*
|
|
16
18
|
* Logic (mirrors Flutter):
|
|
17
|
-
* 1. If `expectedRedirectUrl` is provided,
|
|
19
|
+
* 1. If `expectedRedirectUrl` is provided, the URL must match it strictly —
|
|
20
|
+
* see {@link UrlHandler.matchesRedirectUrl}.
|
|
18
21
|
* 2. Fallback: Fincra appends `status` (or `payment_status`) AND `reference` as query params.
|
|
19
22
|
*
|
|
20
23
|
* @param url - The URL being navigated to.
|
|
@@ -24,7 +27,7 @@ export class UrlHandler {
|
|
|
24
27
|
if (!url) return false;
|
|
25
28
|
|
|
26
29
|
if (expectedRedirectUrl && expectedRedirectUrl.length > 0) {
|
|
27
|
-
return
|
|
30
|
+
return UrlHandler.matchesRedirectUrl(url, expectedRedirectUrl);
|
|
28
31
|
}
|
|
29
32
|
|
|
30
33
|
// Fallback: detect via query parameters
|
|
@@ -39,6 +42,53 @@ export class UrlHandler {
|
|
|
39
42
|
}
|
|
40
43
|
}
|
|
41
44
|
|
|
45
|
+
/**
|
|
46
|
+
* Strictly matches `url` against the expected redirect URL.
|
|
47
|
+
*
|
|
48
|
+
* - Scheme, host (case-insensitive) and port (default ports normalised) must be equal.
|
|
49
|
+
* - The path must equal the expected path or continue it at a `/` boundary
|
|
50
|
+
* (trailing slashes ignored). An empty expected path matches any path.
|
|
51
|
+
* - Query string and fragment are ignored.
|
|
52
|
+
* - Falls back to `startsWith` only if the expected URL cannot be parsed.
|
|
53
|
+
*
|
|
54
|
+
* Prevents lookalike hosts such as `https://google.com.evil.io` matching
|
|
55
|
+
* `https://google.com`.
|
|
56
|
+
*/
|
|
57
|
+
static matchesRedirectUrl(url: string, expectedRedirectUrl: string): boolean {
|
|
58
|
+
const expected = UrlHandler._parseUrl(expectedRedirectUrl);
|
|
59
|
+
if (!expected) return url.startsWith(expectedRedirectUrl);
|
|
60
|
+
|
|
61
|
+
const actual = UrlHandler._parseUrl(url);
|
|
62
|
+
if (!actual) return false;
|
|
63
|
+
|
|
64
|
+
if (
|
|
65
|
+
actual.scheme !== expected.scheme ||
|
|
66
|
+
actual.host !== expected.host ||
|
|
67
|
+
actual.port !== expected.port
|
|
68
|
+
) {
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (expected.path === '') return true;
|
|
73
|
+
return (
|
|
74
|
+
actual.path === expected.path ||
|
|
75
|
+
actual.path.startsWith(`${expected.path}/`)
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Reads the payment status from completion params, accepting either
|
|
81
|
+
* `status` or `payment_status`. Returns lower-case.
|
|
82
|
+
*
|
|
83
|
+
* A missing status is treated as `'success'` because the sandbox redirect
|
|
84
|
+
* omits it. **Always verify the payment on your backend** (Fincra API or
|
|
85
|
+
* webhook) before fulfilling an order.
|
|
86
|
+
*/
|
|
87
|
+
static extractStatus(params: Record<string, string>): string {
|
|
88
|
+
const raw = params['status'] ?? params['payment_status'];
|
|
89
|
+
return raw?.toLowerCase() ?? 'success';
|
|
90
|
+
}
|
|
91
|
+
|
|
42
92
|
/**
|
|
43
93
|
* Extracts all query parameters from the URL as a `Record<string, string>`.
|
|
44
94
|
*
|
|
@@ -81,7 +131,7 @@ export class UrlHandler {
|
|
|
81
131
|
return {
|
|
82
132
|
reference: finalRef,
|
|
83
133
|
transactionId: finalTxId ?? '',
|
|
84
|
-
status: params['status'] ?? 'unknown',
|
|
134
|
+
status: params['status'] ?? params['payment_status'] ?? 'unknown',
|
|
85
135
|
message: params['message'],
|
|
86
136
|
rawResponse: params,
|
|
87
137
|
};
|
|
@@ -99,6 +149,29 @@ export class UrlHandler {
|
|
|
99
149
|
|
|
100
150
|
// ── Internal ────────────────────────────────────────────────────────────────
|
|
101
151
|
|
|
152
|
+
/**
|
|
153
|
+
* Minimal absolute-URL parser. React Native's `URL` polyfill does not
|
|
154
|
+
* implement `hostname`/`port`, so this is done by hand.
|
|
155
|
+
* Returns `null` if the string is not an absolute `scheme://host` URL.
|
|
156
|
+
*/
|
|
157
|
+
private static _parseUrl(
|
|
158
|
+
url: string
|
|
159
|
+
): { scheme: string; host: string; port: string; path: string } | null {
|
|
160
|
+
const match =
|
|
161
|
+
/^([a-z][a-z0-9+.-]*):\/\/(?:[^@/?#]*@)?(\[[^\]]*\]|[^:/?#]*)(?::(\d*))?([^?#]*)/i.exec(
|
|
162
|
+
url.trim()
|
|
163
|
+
);
|
|
164
|
+
if (!match || !match[2]) return null;
|
|
165
|
+
|
|
166
|
+
const scheme = match[1].toLowerCase();
|
|
167
|
+
const defaultPort = DEFAULT_PORTS[scheme] ?? '';
|
|
168
|
+
const port = match[3] || defaultPort;
|
|
169
|
+
// Normalise trailing slashes so `/callback/` equals `/callback`
|
|
170
|
+
const path = match[4].replace(/\/+$/, '');
|
|
171
|
+
|
|
172
|
+
return { scheme, host: match[2].toLowerCase(), port, path };
|
|
173
|
+
}
|
|
174
|
+
|
|
102
175
|
/**
|
|
103
176
|
* Parses URL query string into a `URLSearchParams`-like `Map`.
|
|
104
177
|
* Works in React Native (no DOM `URL` API available).
|