@alfalab/bridge-to-native 1.4.2 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/client/index.d.ts +3 -0
- package/client/index.js +8 -1
- package/client/services-and-utils/external-links-service.d.ts +6 -0
- package/client/services-and-utils/external-links-service.js +23 -48
- package/client/services-and-utils/native-features.d.ts +12 -0
- package/client/services-and-utils/native-features.js +34 -0
- package/client/services-and-utils/native-links.d.ts +26 -0
- package/client/services-and-utils/native-links.js +76 -0
- package/client/services-and-utils/native-params-service.js +4 -18
- package/client/services-and-utils/utils.js +11 -1
- package/client/types.d.ts +4 -0
- package/package.json +1 -1
package/client/index.d.ts
CHANGED
|
@@ -1 +1,4 @@
|
|
|
1
1
|
export { BridgeToNative } from './bridge-to-native';
|
|
2
|
+
export { canUseNativeFeature } from './services-and-utils/native-features';
|
|
3
|
+
export { prepareNativeDeeplinkUrl, prepareOpenInBrowserUrl, prepareOpenInNewWebviewDeeplink, preparePdfUrl, } from './services-and-utils/native-links';
|
|
4
|
+
export type { Environment, NativeAppTarget, NativeFeatureKey, PdfType } from './types';
|
package/client/index.js
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.BridgeToNative = void 0;
|
|
3
|
+
exports.preparePdfUrl = exports.prepareOpenInNewWebviewDeeplink = exports.prepareOpenInBrowserUrl = exports.prepareNativeDeeplinkUrl = exports.canUseNativeFeature = exports.BridgeToNative = void 0;
|
|
4
4
|
var bridge_to_native_1 = require("./bridge-to-native");
|
|
5
5
|
Object.defineProperty(exports, "BridgeToNative", { enumerable: true, get: function () { return bridge_to_native_1.BridgeToNative; } });
|
|
6
|
+
var native_features_1 = require("./services-and-utils/native-features");
|
|
7
|
+
Object.defineProperty(exports, "canUseNativeFeature", { enumerable: true, get: function () { return native_features_1.canUseNativeFeature; } });
|
|
8
|
+
var native_links_1 = require("./services-and-utils/native-links");
|
|
9
|
+
Object.defineProperty(exports, "prepareNativeDeeplinkUrl", { enumerable: true, get: function () { return native_links_1.prepareNativeDeeplinkUrl; } });
|
|
10
|
+
Object.defineProperty(exports, "prepareOpenInBrowserUrl", { enumerable: true, get: function () { return native_links_1.prepareOpenInBrowserUrl; } });
|
|
11
|
+
Object.defineProperty(exports, "prepareOpenInNewWebviewDeeplink", { enumerable: true, get: function () { return native_links_1.prepareOpenInNewWebviewDeeplink; } });
|
|
12
|
+
Object.defineProperty(exports, "preparePdfUrl", { enumerable: true, get: function () { return native_links_1.preparePdfUrl; } });
|
|
@@ -14,5 +14,11 @@ export declare class ExternalLinksService {
|
|
|
14
14
|
openInBrowser(link: string): void;
|
|
15
15
|
openInNewWebview(link: string, nativeTitle?: string, closeCurrentWebview?: boolean): void;
|
|
16
16
|
openPdf(url: string, type?: PdfType, title?: string): void;
|
|
17
|
+
private get nativeAppTarget();
|
|
18
|
+
/**
|
|
19
|
+
* Логирует невалидный URL через `logError` и бросает ошибку.
|
|
20
|
+
* Чистые функции сборки URL бросают ту же ошибку, но без логирования.
|
|
21
|
+
*/
|
|
22
|
+
private validateUrlOrThrow;
|
|
17
23
|
private navigateByNativeApp;
|
|
18
24
|
}
|
|
@@ -1,12 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.ExternalLinksService = void 0;
|
|
4
|
-
const
|
|
5
|
-
const constants_1 = require("../constants");
|
|
4
|
+
const native_links_1 = require("./native-links");
|
|
6
5
|
const utils_1 = require("./utils");
|
|
7
6
|
const CANCEL_NEW_CALLS_TO_NA_TIME = 150;
|
|
8
|
-
const QUERY_OPEN_IN_BROWSER_KEY = 'openInBrowser';
|
|
9
|
-
const QUERY_OPEN_IN_BROWSER_VALUE = 'true';
|
|
10
7
|
/**
|
|
11
8
|
* Сервис, предоставляющий методы для открытия внешних для текущего WA экранов
|
|
12
9
|
* и связанных с этим действий.
|
|
@@ -21,11 +18,7 @@ class ExternalLinksService {
|
|
|
21
18
|
if (this.navigationByNativeAppInProgress) {
|
|
22
19
|
return;
|
|
23
20
|
}
|
|
24
|
-
const
|
|
25
|
-
const originalNativeUrl = `${this.nativeParamsService.appId}://${clearedDeeplinkPath}`;
|
|
26
|
-
const preparedNativeUrl = this.nativeParamsService.environment === 'ios'
|
|
27
|
-
? (0, utils_1.appendFromCurrentQueryParamForIos)(originalNativeUrl)
|
|
28
|
-
: originalNativeUrl;
|
|
21
|
+
const preparedNativeUrl = (0, native_links_1.prepareNativeDeeplinkUrl)(this.nativeAppTarget, deeplink);
|
|
29
22
|
if (closeWebviewBeforeCallNativeDeeplinkHandler &&
|
|
30
23
|
this.nativeParamsService.canUseNativeFeature('savedBackStack')) {
|
|
31
24
|
(0, utils_1.closeWebviewUtil)();
|
|
@@ -40,58 +33,40 @@ class ExternalLinksService {
|
|
|
40
33
|
if (!this.nativeParamsService.canUseNativeFeature('linksInBrowser')) {
|
|
41
34
|
return `${this.nativeParamsService.appId}://webFeature?type=recommendation&url=${encodeURIComponent(link)}`;
|
|
42
35
|
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
throw new Error(`invalid url: ${link}`);
|
|
46
|
-
}
|
|
47
|
-
url.searchParams.append(QUERY_OPEN_IN_BROWSER_KEY, QUERY_OPEN_IN_BROWSER_VALUE);
|
|
48
|
-
return url.href;
|
|
36
|
+
this.validateUrlOrThrow(link);
|
|
37
|
+
return (0, native_links_1.prepareOpenInBrowserUrl)(this.nativeAppTarget, link, true);
|
|
49
38
|
}
|
|
50
39
|
openInBrowser(link) {
|
|
51
40
|
if (this.navigationByNativeAppInProgress) {
|
|
52
41
|
return;
|
|
53
42
|
}
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
return;
|
|
57
|
-
}
|
|
58
|
-
const url = (0, utils_1.validateUrl)(link, this.logError);
|
|
59
|
-
if (!url) {
|
|
60
|
-
throw new Error(`invalid url: ${link}`);
|
|
61
|
-
}
|
|
62
|
-
url.searchParams.append(QUERY_OPEN_IN_BROWSER_KEY, QUERY_OPEN_IN_BROWSER_VALUE);
|
|
63
|
-
this.navigateByNativeApp(url.href);
|
|
43
|
+
this.validateUrlOrThrow(link);
|
|
44
|
+
this.navigateByNativeApp((0, native_links_1.prepareOpenInBrowserUrl)(this.nativeAppTarget, link, this.nativeParamsService.canUseNativeFeature('linksInBrowser')));
|
|
64
45
|
}
|
|
65
46
|
openInNewWebview(link, nativeTitle = '', closeCurrentWebview = false) {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
throw new Error(`invalid url: ${link}`);
|
|
69
|
-
}
|
|
70
|
-
if (nativeTitle) {
|
|
71
|
-
url.searchParams.set(query_and_headers_keys_1.QUERY_B2N_TITLE, nativeTitle);
|
|
72
|
-
}
|
|
73
|
-
this.handleNativeDeeplink(`/webFeature?type=recommendation&url=${encodeURIComponent(url.toString())}`, closeCurrentWebview);
|
|
47
|
+
this.validateUrlOrThrow(link);
|
|
48
|
+
this.handleNativeDeeplink((0, native_links_1.prepareOpenInNewWebviewDeeplink)(link, nativeTitle), closeCurrentWebview);
|
|
74
49
|
}
|
|
75
50
|
openPdf(url, type = 'pdfFile', title) {
|
|
76
51
|
if (this.navigationByNativeAppInProgress) {
|
|
77
52
|
return;
|
|
78
53
|
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
54
|
+
this.navigateByNativeApp((0, native_links_1.preparePdfUrl)(this.nativeAppTarget, url, type, title));
|
|
55
|
+
}
|
|
56
|
+
get nativeAppTarget() {
|
|
57
|
+
return {
|
|
58
|
+
platform: this.nativeParamsService.environment,
|
|
59
|
+
appId: this.nativeParamsService.appId,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Логирует невалидный URL через `logError` и бросает ошибку.
|
|
64
|
+
* Чистые функции сборки URL бросают ту же ошибку, но без логирования.
|
|
65
|
+
*/
|
|
66
|
+
validateUrlOrThrow(link) {
|
|
67
|
+
if (!(0, utils_1.validateUrl)(link, this.logError)) {
|
|
68
|
+
throw new Error(`invalid url: ${link}`);
|
|
89
69
|
}
|
|
90
|
-
replaceUrl =
|
|
91
|
-
this.nativeParamsService.environment === 'ios'
|
|
92
|
-
? (0, utils_1.appendFromCurrentQueryParamForIos)(replaceUrl)
|
|
93
|
-
: replaceUrl;
|
|
94
|
-
this.navigateByNativeApp(replaceUrl);
|
|
95
70
|
}
|
|
96
71
|
navigateByNativeApp(url) {
|
|
97
72
|
this.navigationByNativeAppInProgress = true;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type Environment, type NativeFeatureKey } from '../types';
|
|
2
|
+
export declare const isValidVersionFormat: (version?: string) => version is string;
|
|
3
|
+
/**
|
|
4
|
+
* Сравнивает версии формата `x.y.z` покомпонентно, как числа.
|
|
5
|
+
* Если хоть одна из версий в другом формате — возвращает `false`.
|
|
6
|
+
*/
|
|
7
|
+
export declare const isVersionHigherOrEqual: (version: string, versionToCompare: string) => boolean;
|
|
8
|
+
/**
|
|
9
|
+
* Проверяет, поддерживает ли NA указанной платформы и версии нативную фичу.
|
|
10
|
+
* Версия в неизвестном формате считается `0.0.0`.
|
|
11
|
+
*/
|
|
12
|
+
export declare const canUseNativeFeature: (platform: Environment, appVersion: string, feature: NativeFeatureKey) => boolean;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.canUseNativeFeature = exports.isVersionHigherOrEqual = exports.isValidVersionFormat = void 0;
|
|
4
|
+
const constants_1 = require("../constants");
|
|
5
|
+
const VERSION_FORMAT_PATTERN = /^\d+\.\d+\.\d+$/;
|
|
6
|
+
const isValidVersionFormat = (version) => Boolean(version) && VERSION_FORMAT_PATTERN.test(version);
|
|
7
|
+
exports.isValidVersionFormat = isValidVersionFormat;
|
|
8
|
+
/**
|
|
9
|
+
* Сравнивает версии формата `x.y.z` покомпонентно, как числа.
|
|
10
|
+
* Если хоть одна из версий в другом формате — возвращает `false`.
|
|
11
|
+
*/
|
|
12
|
+
const isVersionHigherOrEqual = (version, versionToCompare) => {
|
|
13
|
+
if (!(0, exports.isValidVersionFormat)(version) || !(0, exports.isValidVersionFormat)(versionToCompare)) {
|
|
14
|
+
return false;
|
|
15
|
+
}
|
|
16
|
+
const versionComponents = version.split('.').map(Number);
|
|
17
|
+
const versionToCompareComponents = versionToCompare.split('.').map(Number);
|
|
18
|
+
for (let i = 0; i < versionComponents.length; i++) {
|
|
19
|
+
if (versionComponents[i] !== versionToCompareComponents[i]) {
|
|
20
|
+
return versionComponents[i] > versionToCompareComponents[i];
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
return true;
|
|
24
|
+
};
|
|
25
|
+
exports.isVersionHigherOrEqual = isVersionHigherOrEqual;
|
|
26
|
+
/**
|
|
27
|
+
* Проверяет, поддерживает ли NA указанной платформы и версии нативную фичу.
|
|
28
|
+
* Версия в неизвестном формате считается `0.0.0`.
|
|
29
|
+
*/
|
|
30
|
+
const canUseNativeFeature = (platform, appVersion, feature) => {
|
|
31
|
+
const { fromVersion } = constants_1.NATIVE_FEATURES_FROM_VERSION[platform][feature];
|
|
32
|
+
return (0, exports.isVersionHigherOrEqual)((0, exports.isValidVersionFormat)(appVersion) ? appVersion : '0.0.0', fromVersion);
|
|
33
|
+
};
|
|
34
|
+
exports.canUseNativeFeature = canUseNativeFeature;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { type NativeAppTarget, type PdfType } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* Собирает URL для открытия диплинка NA: `alfabank:///dashboard/x`, `/x`, `alfabank://x` → `<appId>://x`.
|
|
4
|
+
* На iOS добавляет `fromCurrent=true`.
|
|
5
|
+
*/
|
|
6
|
+
export declare const prepareNativeDeeplinkUrl: ({ platform, appId }: NativeAppTarget, deeplink: string) => string;
|
|
7
|
+
/**
|
|
8
|
+
* Собирает диплинк (без схемы) на открытие ссылки в новом WV.
|
|
9
|
+
* Результат передаётся в `prepareNativeDeeplinkUrl` или `handleNativeDeeplink`.
|
|
10
|
+
*
|
|
11
|
+
* @throws Если `link` не абсолютный http(s) URL.
|
|
12
|
+
*/
|
|
13
|
+
export declare const prepareOpenInNewWebviewDeeplink: (link: string, nativeTitle?: string) => string;
|
|
14
|
+
/**
|
|
15
|
+
* Собирает URL на открытие ссылки в браузере.
|
|
16
|
+
* Если NA не умеет открывать ссылки в браузере — URL на открытие ссылки в новом WV.
|
|
17
|
+
*
|
|
18
|
+
* @param linksInBrowser Результат `canUseNativeFeature(platform, appVersion, 'linksInBrowser')`.
|
|
19
|
+
* @throws Если `link` не абсолютный http(s) URL.
|
|
20
|
+
*/
|
|
21
|
+
export declare const prepareOpenInBrowserUrl: (target: NativeAppTarget, link: string, linksInBrowser: boolean) => string;
|
|
22
|
+
/**
|
|
23
|
+
* Собирает URL на открытие PDF. На iOS — диплинк на нативный pdf_viewer,
|
|
24
|
+
* на Android — исходный URL (его перехватывает NA).
|
|
25
|
+
*/
|
|
26
|
+
export declare const preparePdfUrl: ({ platform, appId }: NativeAppTarget, url: string, type?: PdfType, title?: string) => string;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.preparePdfUrl = exports.prepareOpenInBrowserUrl = exports.prepareOpenInNewWebviewDeeplink = exports.prepareNativeDeeplinkUrl = void 0;
|
|
4
|
+
const query_and_headers_keys_1 = require("../../query-and-headers-keys");
|
|
5
|
+
const constants_1 = require("../constants");
|
|
6
|
+
const utils_1 = require("./utils");
|
|
7
|
+
const QUERY_OPEN_IN_BROWSER_KEY = 'openInBrowser';
|
|
8
|
+
const QUERY_OPEN_IN_BROWSER_VALUE = 'true';
|
|
9
|
+
/*
|
|
10
|
+
* Чистые функции сборки URL, по которым NA открывает свои экраны.
|
|
11
|
+
* Используются `ExternalLinksService` и экспортируются для окружений,
|
|
12
|
+
* где экземпляр `BridgeToNative` не создаётся (например, миниаппы).
|
|
13
|
+
*/
|
|
14
|
+
const parseUrl = (link) => {
|
|
15
|
+
const url = (0, utils_1.validateUrl)(link);
|
|
16
|
+
if (!url) {
|
|
17
|
+
throw new Error(`invalid url: ${link}`);
|
|
18
|
+
}
|
|
19
|
+
return url;
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* Собирает URL для открытия диплинка NA: `alfabank:///dashboard/x`, `/x`, `alfabank://x` → `<appId>://x`.
|
|
23
|
+
* На iOS добавляет `fromCurrent=true`.
|
|
24
|
+
*/
|
|
25
|
+
const prepareNativeDeeplinkUrl = ({ platform, appId }, deeplink) => {
|
|
26
|
+
const nativeUrl = `${appId}://${deeplink.replace(constants_1.DEEP_LINK_PATTERN, '')}`;
|
|
27
|
+
return platform === 'ios' ? (0, utils_1.appendFromCurrentQueryParamForIos)(nativeUrl) : nativeUrl;
|
|
28
|
+
};
|
|
29
|
+
exports.prepareNativeDeeplinkUrl = prepareNativeDeeplinkUrl;
|
|
30
|
+
/**
|
|
31
|
+
* Собирает диплинк (без схемы) на открытие ссылки в новом WV.
|
|
32
|
+
* Результат передаётся в `prepareNativeDeeplinkUrl` или `handleNativeDeeplink`.
|
|
33
|
+
*
|
|
34
|
+
* @throws Если `link` не абсолютный http(s) URL.
|
|
35
|
+
*/
|
|
36
|
+
const prepareOpenInNewWebviewDeeplink = (link, nativeTitle = '') => {
|
|
37
|
+
const url = parseUrl(link);
|
|
38
|
+
if (nativeTitle) {
|
|
39
|
+
url.searchParams.set(query_and_headers_keys_1.QUERY_B2N_TITLE, nativeTitle);
|
|
40
|
+
}
|
|
41
|
+
return `webFeature?type=recommendation&url=${encodeURIComponent(url.toString())}`;
|
|
42
|
+
};
|
|
43
|
+
exports.prepareOpenInNewWebviewDeeplink = prepareOpenInNewWebviewDeeplink;
|
|
44
|
+
/**
|
|
45
|
+
* Собирает URL на открытие ссылки в браузере.
|
|
46
|
+
* Если NA не умеет открывать ссылки в браузере — URL на открытие ссылки в новом WV.
|
|
47
|
+
*
|
|
48
|
+
* @param linksInBrowser Результат `canUseNativeFeature(platform, appVersion, 'linksInBrowser')`.
|
|
49
|
+
* @throws Если `link` не абсолютный http(s) URL.
|
|
50
|
+
*/
|
|
51
|
+
const prepareOpenInBrowserUrl = (target, link, linksInBrowser) => {
|
|
52
|
+
if (!linksInBrowser) {
|
|
53
|
+
return (0, exports.prepareNativeDeeplinkUrl)(target, (0, exports.prepareOpenInNewWebviewDeeplink)(link));
|
|
54
|
+
}
|
|
55
|
+
const url = parseUrl(link);
|
|
56
|
+
url.searchParams.append(QUERY_OPEN_IN_BROWSER_KEY, QUERY_OPEN_IN_BROWSER_VALUE);
|
|
57
|
+
return url.href;
|
|
58
|
+
};
|
|
59
|
+
exports.prepareOpenInBrowserUrl = prepareOpenInBrowserUrl;
|
|
60
|
+
/**
|
|
61
|
+
* Собирает URL на открытие PDF. На iOS — диплинк на нативный pdf_viewer,
|
|
62
|
+
* на Android — исходный URL (его перехватывает NA).
|
|
63
|
+
*/
|
|
64
|
+
const preparePdfUrl = ({ platform, appId }, url, type = 'pdfFile', title) => {
|
|
65
|
+
if (platform !== 'ios') {
|
|
66
|
+
return url;
|
|
67
|
+
}
|
|
68
|
+
const params = new URLSearchParams();
|
|
69
|
+
params.append('type', type);
|
|
70
|
+
params.append('url', decodeURIComponent(url));
|
|
71
|
+
if (title) {
|
|
72
|
+
params.append('title', title.replace(/\s/g, '_'));
|
|
73
|
+
}
|
|
74
|
+
return (0, utils_1.appendFromCurrentQueryParamForIos)(`${appId}:///dashboard/pdf_viewer?${params.toString()}`);
|
|
75
|
+
};
|
|
76
|
+
exports.preparePdfUrl = preparePdfUrl;
|
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.NativeParamsService = void 0;
|
|
4
4
|
const query_and_headers_keys_1 = require("../../query-and-headers-keys");
|
|
5
5
|
const constants_1 = require("../constants");
|
|
6
|
+
const native_features_1 = require("./native-features");
|
|
6
7
|
/**
|
|
7
8
|
* Сервис, аккумулирующий детали о NA и предоставляющий методы, связанные с этим.
|
|
8
9
|
*/
|
|
@@ -24,28 +25,13 @@ class NativeParamsService {
|
|
|
24
25
|
this.webviewLaunchTime = (nativeParams === null || nativeParams === void 0 ? void 0 : nativeParams.webviewLaunchTime) || null;
|
|
25
26
|
}
|
|
26
27
|
canUseNativeFeature(feature) {
|
|
27
|
-
|
|
28
|
-
return this.isCurrentVersionHigherOrEqual(fromVersion);
|
|
28
|
+
return (0, native_features_1.canUseNativeFeature)(this.environment, this.appVersion, feature);
|
|
29
29
|
}
|
|
30
30
|
isCurrentVersionHigherOrEqual(versionToCompare) {
|
|
31
|
-
|
|
32
|
-
return false;
|
|
33
|
-
}
|
|
34
|
-
const matchPattern = /(\d+)\.(\d+)\.(\d+)/;
|
|
35
|
-
const [, ...appVersionComponents] = this.appVersion.match(matchPattern); // Формат версии проверен в конструкторе, можно смело убирать `null` из типа.
|
|
36
|
-
const [, ...versionToCompareComponents] = versionToCompare.match(matchPattern);
|
|
37
|
-
for (let i = 0; i < appVersionComponents.length; i++) {
|
|
38
|
-
if (appVersionComponents[i] !== versionToCompareComponents[i]) {
|
|
39
|
-
return appVersionComponents[i] >= versionToCompareComponents[i];
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
return true;
|
|
31
|
+
return (0, native_features_1.isVersionHigherOrEqual)(this.appVersion, versionToCompare);
|
|
43
32
|
}
|
|
44
33
|
static isValidVersionFormat(version) {
|
|
45
|
-
|
|
46
|
-
return false;
|
|
47
|
-
const versionPattern = /^\d+\.\d+\.\d+$/;
|
|
48
|
-
return versionPattern.test(version);
|
|
34
|
+
return (0, native_features_1.isValidVersionFormat)(version);
|
|
49
35
|
}
|
|
50
36
|
getAppId(knownIosAppId) {
|
|
51
37
|
if (this.environment !== 'ios') {
|
|
@@ -26,7 +26,7 @@ exports.closeWebviewUtil = closeWebviewUtil;
|
|
|
26
26
|
const validateUrl = (link, logError) => {
|
|
27
27
|
let url;
|
|
28
28
|
try {
|
|
29
|
-
url =
|
|
29
|
+
url = new URL(link);
|
|
30
30
|
}
|
|
31
31
|
catch (error) {
|
|
32
32
|
logError === null || logError === void 0 ? void 0 : logError('validateUrl: URL parsing error', {
|
|
@@ -35,6 +35,16 @@ const validateUrl = (link, logError) => {
|
|
|
35
35
|
});
|
|
36
36
|
return null;
|
|
37
37
|
}
|
|
38
|
+
const isAllowedProtocol = url.protocol === 'https:' || url.protocol === 'http:';
|
|
39
|
+
const hasCredentials = Boolean(url.username || url.password);
|
|
40
|
+
if (!isAllowedProtocol || !url.hostname || hasCredentials) {
|
|
41
|
+
logError === null || logError === void 0 ? void 0 : logError('validateUrl: URL validation error', {
|
|
42
|
+
hostname: url.hostname,
|
|
43
|
+
link,
|
|
44
|
+
protocol: url.protocol,
|
|
45
|
+
});
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
38
48
|
return url;
|
|
39
49
|
};
|
|
40
50
|
exports.validateUrl = validateUrl;
|
package/client/types.d.ts
CHANGED
|
@@ -4,6 +4,10 @@ export type BrowserHistoryApiWrappers = {
|
|
|
4
4
|
replace?: (url: HistoryReplaceStateParams[2], state: HistoryReplaceStateParams[0]) => void;
|
|
5
5
|
};
|
|
6
6
|
export type Environment = 'android' | 'ios';
|
|
7
|
+
export type NativeAppTarget = {
|
|
8
|
+
platform: Environment;
|
|
9
|
+
appId: string;
|
|
10
|
+
};
|
|
7
11
|
export type HistoryPushStateParams = Parameters<typeof window.history.pushState>;
|
|
8
12
|
export type HistoryReplaceStateParams = Parameters<typeof window.history.replaceState>;
|
|
9
13
|
export type LocationAssignParam = Parameters<typeof window.location.assign>[0];
|