@alfalab/bridge-to-native 1.4.1-beta.720f0f8 → 1.4.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/client/bridge-to-native.d.ts +1 -5
- package/client/bridge-to-native.js +4 -7
- package/client/services-and-utils/external-links-service.d.ts +3 -4
- package/client/services-and-utils/external-links-service.js +19 -42
- package/client/services-and-utils/native-navigation-and-title-service.d.ts +1 -3
- package/client/services-and-utils/native-navigation-and-title-service.js +17 -6
- package/client/services-and-utils/native-params-service.d.ts +2 -6
- package/client/services-and-utils/native-params-service.js +5 -20
- package/client/services-and-utils/utils.d.ts +2 -0
- package/client/services-and-utils/utils.js +16 -1
- package/client/types.d.ts +1 -4
- package/package.json +114 -114
- package/query-and-headers-keys.js +0 -2
- package/server/prepare-native-app-details-for-client.d.ts +2 -2
- package/server/prepare-native-app-details-for-client.js +3 -5
- package/server/utils.js +0 -9
- package/types.d.ts +0 -6
- package/client/services-and-utils/native-log-service.d.ts +0 -27
- package/client/services-and-utils/native-log-service.js +0 -50
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
|
|
2
|
-
import { type NoopOptions } from '../types';
|
|
3
2
|
import { type BrowserHistoryApiWrappers, type HistoryPushStateParams, type HistoryReplaceStateParams, type LocationAssignParam, type LogError, type NativeFeatureKey, type PdfType } from './types';
|
|
4
3
|
/**
|
|
5
4
|
* Сервис, предоставляет методы для WA, работающего внутри NA.
|
|
@@ -14,15 +13,12 @@ export declare class BridgeToNative {
|
|
|
14
13
|
* будут использованы стандартные `History: pushState()` и `History: go()`.
|
|
15
14
|
* @param options.logError Функция с помощью которой B2N может залогировать ошибку,
|
|
16
15
|
* если не передать, B2N не будет логировать ошибки.
|
|
17
|
-
* @param options.noop ....
|
|
18
16
|
*/
|
|
19
17
|
constructor(options?: {
|
|
20
18
|
browserHistoryApiWrappers?: BrowserHistoryApiWrappers;
|
|
21
19
|
logError?: LogError;
|
|
22
|
-
noop?: NoopOptions;
|
|
23
20
|
} | undefined);
|
|
24
21
|
private nativeParamsService;
|
|
25
|
-
private nativeLogService;
|
|
26
22
|
private externalLinksService;
|
|
27
23
|
private nativeNavigationAndTitleService;
|
|
28
24
|
/**
|
|
@@ -36,7 +32,7 @@ export declare class BridgeToNative {
|
|
|
36
32
|
/**
|
|
37
33
|
* Платформа, в окружении которой работает NA и WA.
|
|
38
34
|
*/
|
|
39
|
-
get environment(): import("
|
|
35
|
+
get environment(): import("./types").Environment;
|
|
40
36
|
/**
|
|
41
37
|
* Индикатор проблемы чтения данных о NA. Если `true`, используются умолчания,
|
|
42
38
|
* возможно ошибочные (например, версия будет `0.0.0`).
|
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
4
|
exports.BridgeToNative = void 0;
|
|
5
5
|
const external_links_service_1 = require("./services-and-utils/external-links-service");
|
|
6
|
-
const native_log_service_1 = require("./services-and-utils/native-log-service");
|
|
7
6
|
const native_navigation_and_title_service_1 = require("./services-and-utils/native-navigation-and-title-service");
|
|
8
7
|
const native_params_service_1 = require("./services-and-utils/native-params-service");
|
|
9
8
|
/**
|
|
@@ -18,15 +17,13 @@ class BridgeToNative {
|
|
|
18
17
|
* будут использованы стандартные `History: pushState()` и `History: go()`.
|
|
19
18
|
* @param options.logError Функция с помощью которой B2N может залогировать ошибку,
|
|
20
19
|
* если не передать, B2N не будет логировать ошибки.
|
|
21
|
-
* @param options.noop ....
|
|
22
20
|
*/
|
|
23
21
|
constructor(options) {
|
|
24
|
-
var _a, _b, _c, _d
|
|
22
|
+
var _a, _b, _c, _d;
|
|
25
23
|
this.options = options;
|
|
26
|
-
this.nativeParamsService = new native_params_service_1.NativeParamsService((_a = this.options) === null || _a === void 0 ? void 0 : _a.
|
|
27
|
-
this.
|
|
28
|
-
this.
|
|
29
|
-
this.nativeNavigationAndTitleService = new native_navigation_and_title_service_1.NativeNavigationAndTitleService(this.nativeParamsService, this.nativeLogService, (_e = this.options) === null || _e === void 0 ? void 0 : _e.browserHistoryApiWrappers, (_f = this.options) === null || _f === void 0 ? void 0 : _f.logError);
|
|
24
|
+
this.nativeParamsService = new native_params_service_1.NativeParamsService((_a = this.options) === null || _a === void 0 ? void 0 : _a.logError);
|
|
25
|
+
this.externalLinksService = new external_links_service_1.ExternalLinksService(this.nativeParamsService, (_b = this.options) === null || _b === void 0 ? void 0 : _b.logError);
|
|
26
|
+
this.nativeNavigationAndTitleService = new native_navigation_and_title_service_1.NativeNavigationAndTitleService(this.nativeParamsService, (_c = this.options) === null || _c === void 0 ? void 0 : _c.browserHistoryApiWrappers, (_d = this.options) === null || _d === void 0 ? void 0 : _d.logError);
|
|
30
27
|
}
|
|
31
28
|
/**
|
|
32
29
|
* Схема NA.
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { type PdfType } from '../types';
|
|
2
|
-
import { type NativeLogService } from './native-log-service';
|
|
1
|
+
import { type LogError, type PdfType } from '../types';
|
|
3
2
|
import { type NativeParamsService } from './native-params-service';
|
|
4
3
|
/**
|
|
5
4
|
* Сервис, предоставляющий методы для открытия внешних для текущего WA экранов
|
|
@@ -7,9 +6,9 @@ import { type NativeParamsService } from './native-params-service';
|
|
|
7
6
|
*/
|
|
8
7
|
export declare class ExternalLinksService {
|
|
9
8
|
private nativeParamsService;
|
|
10
|
-
private
|
|
9
|
+
private logError?;
|
|
11
10
|
private navigationByNativeAppInProgress;
|
|
12
|
-
constructor(nativeParamsService: NativeParamsService,
|
|
11
|
+
constructor(nativeParamsService: NativeParamsService, logError?: LogError | undefined);
|
|
13
12
|
handleNativeDeeplink(deeplink: string, closeWebviewBeforeCallNativeDeeplinkHandler?: boolean): void;
|
|
14
13
|
getHrefToOpenInBrowser(link: string): string;
|
|
15
14
|
openInBrowser(link: string): void;
|
|
@@ -12,9 +12,9 @@ const QUERY_OPEN_IN_BROWSER_VALUE = 'true';
|
|
|
12
12
|
* и связанных с этим действий.
|
|
13
13
|
*/
|
|
14
14
|
class ExternalLinksService {
|
|
15
|
-
constructor(nativeParamsService,
|
|
15
|
+
constructor(nativeParamsService, logError) {
|
|
16
16
|
this.nativeParamsService = nativeParamsService;
|
|
17
|
-
this.
|
|
17
|
+
this.logError = logError;
|
|
18
18
|
this.navigationByNativeAppInProgress = false;
|
|
19
19
|
}
|
|
20
20
|
handleNativeDeeplink(deeplink, closeWebviewBeforeCallNativeDeeplinkHandler = false) {
|
|
@@ -28,40 +28,22 @@ class ExternalLinksService {
|
|
|
28
28
|
: originalNativeUrl;
|
|
29
29
|
if (closeWebviewBeforeCallNativeDeeplinkHandler &&
|
|
30
30
|
this.nativeParamsService.canUseNativeFeature('savedBackStack')) {
|
|
31
|
-
|
|
31
|
+
(0, utils_1.closeWebviewUtil)();
|
|
32
32
|
// Проверено, ОС получает диплинк и передаёт его NA, не смотря на то,
|
|
33
33
|
// что это происходит в следующей макрозадаче после команды на закрытие WV.
|
|
34
|
-
|
|
35
|
-
setTimeout(() => window.location.replace(preparedNativeUrl), 0);
|
|
36
|
-
}, { payload: { deeplink: preparedNativeUrl } });
|
|
34
|
+
setTimeout(() => window.location.replace(preparedNativeUrl), 0);
|
|
37
35
|
return;
|
|
38
36
|
}
|
|
39
|
-
|
|
40
|
-
const { fromVersion } = constants_1.NATIVE_FEATURES_FROM_VERSION[this.nativeParamsService.environment].savedBackStack;
|
|
41
|
-
if (this.nativeParamsService.environment === 'android' &&
|
|
42
|
-
!this.nativeParamsService.isCurrentVersionHigherOrEqual(fromVersion)) {
|
|
43
|
-
featureContext = {
|
|
44
|
-
feature: 'savedBackStack',
|
|
45
|
-
fallbackReason: 'Открытие нового webview в Android приведет к закрытию текущего',
|
|
46
|
-
};
|
|
47
|
-
}
|
|
48
|
-
this.nativeLogService.execute('nativeDeeplink', () => this.navigateByNativeApp(preparedNativeUrl), {
|
|
49
|
-
payload: { deeplink: preparedNativeUrl },
|
|
50
|
-
featureContext: featureContext !== null && featureContext !== void 0 ? featureContext : null,
|
|
51
|
-
});
|
|
37
|
+
this.navigateByNativeApp(preparedNativeUrl);
|
|
52
38
|
}
|
|
53
39
|
getHrefToOpenInBrowser(link) {
|
|
54
40
|
if (!this.nativeParamsService.canUseNativeFeature('linksInBrowser')) {
|
|
55
|
-
if ((this, this.nativeParamsService.environment === 'android')) {
|
|
56
|
-
this.nativeLogService.logFeatureFallback({
|
|
57
|
-
feature: 'linksInBrowser',
|
|
58
|
-
fallbackReason: 'Открытие в браузере технически недоступно, будет открыто в новом webview',
|
|
59
|
-
payload: { link },
|
|
60
|
-
});
|
|
61
|
-
}
|
|
62
41
|
return `${this.nativeParamsService.appId}://webFeature?type=recommendation&url=${encodeURIComponent(link)}`;
|
|
63
42
|
}
|
|
64
|
-
const url =
|
|
43
|
+
const url = (0, utils_1.validateUrl)(link, this.logError);
|
|
44
|
+
if (!url) {
|
|
45
|
+
throw new Error(`invalid url: ${link}`);
|
|
46
|
+
}
|
|
65
47
|
url.searchParams.append(QUERY_OPEN_IN_BROWSER_KEY, QUERY_OPEN_IN_BROWSER_VALUE);
|
|
66
48
|
return url.href;
|
|
67
49
|
}
|
|
@@ -70,24 +52,21 @@ class ExternalLinksService {
|
|
|
70
52
|
return;
|
|
71
53
|
}
|
|
72
54
|
if (!this.nativeParamsService.canUseNativeFeature('linksInBrowser')) {
|
|
73
|
-
if ((this, this.nativeParamsService.environment === 'android')) {
|
|
74
|
-
this.nativeLogService.logFeatureFallback({
|
|
75
|
-
feature: 'linksInBrowser',
|
|
76
|
-
fallbackReason: 'Открытие в браузере технически недоступно, будет открыто в новом webview',
|
|
77
|
-
payload: { link },
|
|
78
|
-
});
|
|
79
|
-
}
|
|
80
55
|
this.openInNewWebview(link);
|
|
81
56
|
return;
|
|
82
57
|
}
|
|
83
|
-
const url =
|
|
58
|
+
const url = (0, utils_1.validateUrl)(link, this.logError);
|
|
59
|
+
if (!url) {
|
|
60
|
+
throw new Error(`invalid url: ${link}`);
|
|
61
|
+
}
|
|
84
62
|
url.searchParams.append(QUERY_OPEN_IN_BROWSER_KEY, QUERY_OPEN_IN_BROWSER_VALUE);
|
|
85
|
-
this.
|
|
86
|
-
payload: { url: url.href },
|
|
87
|
-
});
|
|
63
|
+
this.navigateByNativeApp(url.href);
|
|
88
64
|
}
|
|
89
65
|
openInNewWebview(link, nativeTitle = '', closeCurrentWebview = false) {
|
|
90
|
-
const url =
|
|
66
|
+
const url = (0, utils_1.validateUrl)(link, this.logError);
|
|
67
|
+
if (!url) {
|
|
68
|
+
throw new Error(`invalid url: ${link}`);
|
|
69
|
+
}
|
|
91
70
|
if (nativeTitle) {
|
|
92
71
|
url.searchParams.set(query_and_headers_keys_1.QUERY_B2N_TITLE, nativeTitle);
|
|
93
72
|
}
|
|
@@ -112,9 +91,7 @@ class ExternalLinksService {
|
|
|
112
91
|
this.nativeParamsService.environment === 'ios'
|
|
113
92
|
? (0, utils_1.appendFromCurrentQueryParamForIos)(replaceUrl)
|
|
114
93
|
: replaceUrl;
|
|
115
|
-
this.
|
|
116
|
-
payload: { replaceUrl },
|
|
117
|
-
});
|
|
94
|
+
this.navigateByNativeApp(replaceUrl);
|
|
118
95
|
}
|
|
119
96
|
navigateByNativeApp(url) {
|
|
120
97
|
this.navigationByNativeAppInProgress = true;
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { type BrowserHistoryApiWrappers, type HistoryPushStateParams, type LocationAssignParam, type LogError } from '../types';
|
|
2
|
-
import { type NativeLogService } from './native-log-service';
|
|
3
2
|
import { type NativeParamsService } from './native-params-service';
|
|
4
3
|
/**
|
|
5
4
|
* Сервис, отвечающий за взаимодействие WA с WV компонентами NA —
|
|
@@ -10,7 +9,6 @@ import { type NativeParamsService } from './native-params-service';
|
|
|
10
9
|
*/
|
|
11
10
|
export declare class NativeNavigationAndTitleService {
|
|
12
11
|
private nativeParamsService;
|
|
13
|
-
private nativeLogService;
|
|
14
12
|
private browserHistoryApiWrappers?;
|
|
15
13
|
private logError?;
|
|
16
14
|
private lastSetPageSettingsParams;
|
|
@@ -18,7 +16,7 @@ export declare class NativeNavigationAndTitleService {
|
|
|
18
16
|
private numOfBackSteps;
|
|
19
17
|
private isGoBackLocked;
|
|
20
18
|
private isNavigateServerSideLocked;
|
|
21
|
-
constructor(nativeParamsService: NativeParamsService,
|
|
19
|
+
constructor(nativeParamsService: NativeParamsService, browserHistoryApiWrappers?: BrowserHistoryApiWrappers | undefined, logError?: LogError | undefined);
|
|
22
20
|
closeWebview(): void;
|
|
23
21
|
goBack(): void;
|
|
24
22
|
goBackAFewSteps(stepsNumber: number, autoCloseWebview?: boolean): void;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
/* eslint max-lines: ["error", {"max": 360, "skipComments": true}] */
|
|
2
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
4
|
exports.NativeNavigationAndTitleService = void 0;
|
|
4
|
-
/* eslint max-lines: ["error", {"max": 360, "skipComments": true}] */
|
|
5
5
|
const query_and_headers_keys_1 = require("../../query-and-headers-keys");
|
|
6
6
|
const utils_1 = require("./utils");
|
|
7
7
|
const NativeHistoryStackStub = 0;
|
|
@@ -13,9 +13,8 @@ const NativeHistoryStackStub = 0;
|
|
|
13
13
|
* см. в документе {@link ./NAVIGATION_SCENARIOS.md}.
|
|
14
14
|
*/
|
|
15
15
|
class NativeNavigationAndTitleService {
|
|
16
|
-
constructor(nativeParamsService,
|
|
16
|
+
constructor(nativeParamsService, browserHistoryApiWrappers, logError) {
|
|
17
17
|
this.nativeParamsService = nativeParamsService;
|
|
18
|
-
this.nativeLogService = nativeLogService;
|
|
19
18
|
this.browserHistoryApiWrappers = browserHistoryApiWrappers;
|
|
20
19
|
this.logError = logError;
|
|
21
20
|
// Здесь сохраняются параметры, которые в последний раз были отправлены
|
|
@@ -89,11 +88,22 @@ class NativeNavigationAndTitleService {
|
|
|
89
88
|
this.syncHistoryWithNative();
|
|
90
89
|
}
|
|
91
90
|
navigateServerSide(link, nativeTitle = '') {
|
|
91
|
+
var _a;
|
|
92
92
|
if (this.isNavigateServerSideLocked) {
|
|
93
93
|
return;
|
|
94
94
|
}
|
|
95
95
|
this.isNavigateServerSideLocked = true;
|
|
96
|
-
|
|
96
|
+
let url;
|
|
97
|
+
try {
|
|
98
|
+
url = link instanceof URL ? link : new URL(link);
|
|
99
|
+
}
|
|
100
|
+
catch (error) {
|
|
101
|
+
(_a = this.logError) === null || _a === void 0 ? void 0 : _a.call(this, 'navigateServerSide: URL creating error', {
|
|
102
|
+
link,
|
|
103
|
+
error,
|
|
104
|
+
});
|
|
105
|
+
throw error;
|
|
106
|
+
}
|
|
97
107
|
this.nativeHistoryStack.push(nativeTitle || '');
|
|
98
108
|
if (nativeTitle) {
|
|
99
109
|
url.searchParams.set(query_and_headers_keys_1.QUERY_B2N_TITLE, nativeTitle);
|
|
@@ -272,12 +282,13 @@ class NativeNavigationAndTitleService {
|
|
|
272
282
|
* с `nativeHistoryStack`.
|
|
273
283
|
*/
|
|
274
284
|
syncHistoryWithNative() {
|
|
285
|
+
var _a;
|
|
275
286
|
const { pageId, pageTitle } = this.getNativePageIdAndTitle();
|
|
276
287
|
if (this.nativeParamsService.environment === 'android') {
|
|
277
288
|
const narrowedPageId = pageId !== null && pageId !== void 0 ? pageId : 1;
|
|
278
289
|
const paramsToSend = JSON.stringify({ pageId: narrowedPageId, pageTitle });
|
|
279
290
|
if (this.lastSetPageSettingsParams !== paramsToSend) {
|
|
280
|
-
|
|
291
|
+
(_a = this.nativeParamsService.AndroidBridge) === null || _a === void 0 ? void 0 : _a.setPageSettings(paramsToSend);
|
|
281
292
|
this.lastSetPageSettingsParams = paramsToSend;
|
|
282
293
|
}
|
|
283
294
|
}
|
|
@@ -286,7 +297,7 @@ class NativeNavigationAndTitleService {
|
|
|
286
297
|
const pageIdStr = pageId ? `&pageId=${pageId}` : '';
|
|
287
298
|
const paramsToSend = `ios:setPageSettings/${pageTitleStr + pageIdStr}`;
|
|
288
299
|
if (this.lastSetPageSettingsParams !== paramsToSend) {
|
|
289
|
-
|
|
300
|
+
window.location.replace(paramsToSend);
|
|
290
301
|
this.lastSetPageSettingsParams = paramsToSend;
|
|
291
302
|
}
|
|
292
303
|
}
|
|
@@ -1,10 +1,8 @@
|
|
|
1
|
-
import { type Environment, type
|
|
2
|
-
import { type LogError, type NativeFeatureKey, type Theme } from '../types';
|
|
1
|
+
import { type Environment, type LogError, type NativeFeatureKey, type Theme } from '../types';
|
|
3
2
|
/**
|
|
4
3
|
* Сервис, аккумулирующий детали о NA и предоставляющий методы, связанные с этим.
|
|
5
4
|
*/
|
|
6
5
|
export declare class NativeParamsService {
|
|
7
|
-
private noop?;
|
|
8
6
|
private logError?;
|
|
9
7
|
AndroidBridge: {
|
|
10
8
|
setPageSettings: (params: string) => void;
|
|
@@ -18,12 +16,10 @@ export declare class NativeParamsService {
|
|
|
18
16
|
theme: Theme;
|
|
19
17
|
title: string;
|
|
20
18
|
webviewLaunchTime: number | null;
|
|
21
|
-
constructor(
|
|
19
|
+
constructor(logError?: LogError | undefined);
|
|
22
20
|
canUseNativeFeature(feature: NativeFeatureKey): boolean;
|
|
23
21
|
isCurrentVersionHigherOrEqual(versionToCompare: string): boolean;
|
|
24
22
|
private static isValidVersionFormat;
|
|
25
23
|
private getAppId;
|
|
26
24
|
private readNativeParamsCookie;
|
|
27
|
-
private resolveEnvironment;
|
|
28
|
-
private resolveAppVersion;
|
|
29
25
|
}
|
|
@@ -7,14 +7,15 @@ const constants_1 = require("../constants");
|
|
|
7
7
|
* Сервис, аккумулирующий детали о NA и предоставляющий методы, связанные с этим.
|
|
8
8
|
*/
|
|
9
9
|
class NativeParamsService {
|
|
10
|
-
constructor(
|
|
11
|
-
this.noop = noop;
|
|
10
|
+
constructor(logError) {
|
|
12
11
|
this.logError = logError;
|
|
13
12
|
this.AndroidBridge = window.Android;
|
|
13
|
+
this.environment = window.Android ? 'android' : 'ios';
|
|
14
14
|
this.nativeParamsReadErrorFlag = false;
|
|
15
15
|
const nativeParams = this.readNativeParamsCookie();
|
|
16
|
-
this.
|
|
17
|
-
|
|
16
|
+
this.appVersion = NativeParamsService.isValidVersionFormat(nativeParams === null || nativeParams === void 0 ? void 0 : nativeParams.appVersion)
|
|
17
|
+
? nativeParams.appVersion
|
|
18
|
+
: '0.0.0';
|
|
18
19
|
this.appId = this.getAppId(nativeParams === null || nativeParams === void 0 ? void 0 : nativeParams.iosAppId);
|
|
19
20
|
this.nextPageId = (nativeParams === null || nativeParams === void 0 ? void 0 : nativeParams.nextPageId) || null;
|
|
20
21
|
this.originalWebviewParams = (nativeParams === null || nativeParams === void 0 ? void 0 : nativeParams.originalWebviewParams) || null;
|
|
@@ -75,21 +76,5 @@ class NativeParamsService {
|
|
|
75
76
|
return null;
|
|
76
77
|
}
|
|
77
78
|
}
|
|
78
|
-
resolveEnvironment() {
|
|
79
|
-
var _a;
|
|
80
|
-
if (((_a = this.noop) === null || _a === void 0 ? void 0 : _a.enabled) && this.noop.environment) {
|
|
81
|
-
return this.noop.environment;
|
|
82
|
-
}
|
|
83
|
-
return window.Android ? 'android' : 'ios';
|
|
84
|
-
}
|
|
85
|
-
resolveAppVersion(versionFromCookie) {
|
|
86
|
-
var _a;
|
|
87
|
-
if (((_a = this.noop) === null || _a === void 0 ? void 0 : _a.enabled) && this.noop.appVersion) {
|
|
88
|
-
return this.noop.appVersion;
|
|
89
|
-
}
|
|
90
|
-
return NativeParamsService.isValidVersionFormat(versionFromCookie)
|
|
91
|
-
? versionFromCookie
|
|
92
|
-
: '0.0.0';
|
|
93
|
-
}
|
|
94
79
|
}
|
|
95
80
|
exports.NativeParamsService = NativeParamsService;
|
|
@@ -1,2 +1,4 @@
|
|
|
1
|
+
import { type LogError } from '../types';
|
|
1
2
|
export declare function appendFromCurrentQueryParamForIos(nativeUrl: string): string;
|
|
2
3
|
export declare const closeWebviewUtil: () => void;
|
|
4
|
+
export declare const validateUrl: (link: URL | string, logError?: LogError) => URL | null;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.closeWebviewUtil = void 0;
|
|
3
|
+
exports.validateUrl = exports.closeWebviewUtil = void 0;
|
|
4
4
|
exports.appendFromCurrentQueryParamForIos = appendFromCurrentQueryParamForIos;
|
|
5
5
|
const QUERY_CLOSE_WEBVIEW_KEY = 'closeWebView';
|
|
6
6
|
const QUERY_CLOSE_WEBVIEW_VALUE = 'true';
|
|
@@ -23,3 +23,18 @@ const closeWebviewUtil = () => {
|
|
|
23
23
|
window.location.href = originalPageUrl.toString();
|
|
24
24
|
};
|
|
25
25
|
exports.closeWebviewUtil = closeWebviewUtil;
|
|
26
|
+
const validateUrl = (link, logError) => {
|
|
27
|
+
let url;
|
|
28
|
+
try {
|
|
29
|
+
url = link instanceof URL ? link : new URL(link);
|
|
30
|
+
}
|
|
31
|
+
catch (error) {
|
|
32
|
+
logError === null || logError === void 0 ? void 0 : logError('validateUrl: URL parsing error', {
|
|
33
|
+
error,
|
|
34
|
+
link,
|
|
35
|
+
});
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
return url;
|
|
39
|
+
};
|
|
40
|
+
exports.validateUrl = validateUrl;
|
package/client/types.d.ts
CHANGED
|
@@ -3,15 +3,12 @@ export type BrowserHistoryApiWrappers = {
|
|
|
3
3
|
go?: (delta: number) => void;
|
|
4
4
|
replace?: (url: HistoryReplaceStateParams[2], state: HistoryReplaceStateParams[0]) => void;
|
|
5
5
|
};
|
|
6
|
+
export type Environment = 'android' | 'ios';
|
|
6
7
|
export type HistoryPushStateParams = Parameters<typeof window.history.pushState>;
|
|
7
8
|
export type HistoryReplaceStateParams = Parameters<typeof window.history.replaceState>;
|
|
8
9
|
export type LocationAssignParam = Parameters<typeof window.location.assign>[0];
|
|
9
10
|
export type LogError = (b2nErrorMessage: string, originalError: unknown) => void;
|
|
10
11
|
export type NativeFeatureKey = 'geolocation' | 'linksInBrowser' | 'savedBackStack';
|
|
11
|
-
export type NativeFeatureContext = {
|
|
12
|
-
feature: NativeFeatureKey;
|
|
13
|
-
fallbackReason?: string;
|
|
14
|
-
};
|
|
15
12
|
type NativeFeaturesParams = Readonly<Record<NativeFeatureKey, {
|
|
16
13
|
fromVersion: string;
|
|
17
14
|
}>>;
|
package/package.json
CHANGED
|
@@ -1,121 +1,121 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
},
|
|
10
|
-
"repository": {
|
|
11
|
-
"type": "git",
|
|
12
|
-
"url": "git+https://github.com/core-ds/bridge-to-native.git"
|
|
13
|
-
},
|
|
14
|
-
"exports": {
|
|
15
|
-
"./client": {
|
|
16
|
-
"import": "./client/index.js",
|
|
17
|
-
"require": "./client/index.js",
|
|
18
|
-
"types": "./client/index.d.ts"
|
|
2
|
+
"name": "@alfalab/bridge-to-native",
|
|
3
|
+
"version": "1.4.2",
|
|
4
|
+
"license": "MIT",
|
|
5
|
+
"description": "Утилита для удобной работы веб приложения внутри нативного приложения и коммуникации с ним.",
|
|
6
|
+
"engines": {
|
|
7
|
+
"node": ">=20.19.2",
|
|
8
|
+
"npm": "please-use-yarn"
|
|
19
9
|
},
|
|
20
|
-
"
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
"types": "./server/index.d.ts"
|
|
24
|
-
}
|
|
25
|
-
},
|
|
26
|
-
"sideEffects": false,
|
|
27
|
-
"bugs": {
|
|
28
|
-
"url": "https://github.com/core-ds/bridge-to-native/issues"
|
|
29
|
-
},
|
|
30
|
-
"scripts": {
|
|
31
|
-
"build": "yarn build:clean && yarn build:ts",
|
|
32
|
-
"build:clean": "shx rm -rf .publish",
|
|
33
|
-
"build:copy-package-json": "shx cp package.json .publish/package.json",
|
|
34
|
-
"build:ts": "tsc --build",
|
|
35
|
-
"format": "arui-presets-lint format",
|
|
36
|
-
"format:check": "arui-presets-lint format:check",
|
|
37
|
-
"lint": "yarn lint:scripts && yarn format:check",
|
|
38
|
-
"lint:fix": "yarn lint:scripts --fix && yarn format",
|
|
39
|
-
"lint:scripts": "arui-presets-lint scripts",
|
|
40
|
-
"pub": "npm publish .publish --userconfig \"../.npmrc\" --tag \"$TAG\"",
|
|
41
|
-
"release": "yarn build && yarn build:copy-package-json && yarn pub",
|
|
42
|
-
"test": "arui-scripts test --silent --collect-coverage"
|
|
43
|
-
},
|
|
44
|
-
"devDependencies": {
|
|
45
|
-
"@happy-dom/jest-environment": "18.0.1",
|
|
46
|
-
"@types/jest": "29.5.14",
|
|
47
|
-
"@types/node": "20.19.1",
|
|
48
|
-
"arui-presets-lint": "8.7.0",
|
|
49
|
-
"arui-scripts": "19.0.7",
|
|
50
|
-
"copyfiles": "2.4.1",
|
|
51
|
-
"jest-junit": "10.0.0",
|
|
52
|
-
"lint-staged": "^12.5.0",
|
|
53
|
-
"promisify-child-process": "4.1.1",
|
|
54
|
-
"shx": "0.3.4",
|
|
55
|
-
"typescript": "5.5.4"
|
|
56
|
-
},
|
|
57
|
-
"commitlint": {
|
|
58
|
-
"extends": "./node_modules/arui-presets-lint/commitlint"
|
|
59
|
-
},
|
|
60
|
-
"eslintConfig": {
|
|
61
|
-
"extends": "./node_modules/arui-presets-lint/eslint",
|
|
62
|
-
"parserOptions": {
|
|
63
|
-
"project": [
|
|
64
|
-
"./__tests__/tsconfig.json",
|
|
65
|
-
"./src/client/tsconfig.json",
|
|
66
|
-
"./src/server/tsconfig.json"
|
|
67
|
-
]
|
|
10
|
+
"repository": {
|
|
11
|
+
"type": "git",
|
|
12
|
+
"url": "git+https://github.com/core-ds/bridge-to-native.git"
|
|
68
13
|
},
|
|
69
|
-
"
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
14
|
+
"exports": {
|
|
15
|
+
"./client": {
|
|
16
|
+
"import": "./client/index.js",
|
|
17
|
+
"require": "./client/index.js",
|
|
18
|
+
"types": "./client/index.d.ts"
|
|
19
|
+
},
|
|
20
|
+
"./server": {
|
|
21
|
+
"import": "./server/index.js",
|
|
22
|
+
"require": "./server/index.js",
|
|
23
|
+
"types": "./server/index.d.ts"
|
|
76
24
|
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
"
|
|
84
|
-
"
|
|
85
|
-
"
|
|
86
|
-
|
|
25
|
+
},
|
|
26
|
+
"sideEffects": false,
|
|
27
|
+
"bugs": {
|
|
28
|
+
"url": "https://github.com/core-ds/bridge-to-native/issues"
|
|
29
|
+
},
|
|
30
|
+
"scripts": {
|
|
31
|
+
"build": "yarn build:clean && yarn build:ts",
|
|
32
|
+
"build:clean": "shx rm -rf .publish",
|
|
33
|
+
"build:copy-package-json": "shx cp package.json .publish/package.json",
|
|
34
|
+
"build:ts": "tsc --build",
|
|
35
|
+
"format": "arui-presets-lint format",
|
|
36
|
+
"format:check": "arui-presets-lint format:check",
|
|
37
|
+
"lint": "yarn lint:scripts && yarn format:check",
|
|
38
|
+
"lint:fix": "yarn lint:scripts --fix && yarn format",
|
|
39
|
+
"lint:scripts": "arui-presets-lint scripts",
|
|
40
|
+
"pub": "npm publish .publish --userconfig \"../.npmrc\" --tag \"$TAG\"",
|
|
41
|
+
"release": "yarn build && yarn build:copy-package-json && yarn pub",
|
|
42
|
+
"test": "arui-scripts test --silent --collect-coverage"
|
|
43
|
+
},
|
|
44
|
+
"devDependencies": {
|
|
45
|
+
"@happy-dom/jest-environment": "18.0.1",
|
|
46
|
+
"@types/jest": "29.5.14",
|
|
47
|
+
"@types/node": "20.19.1",
|
|
48
|
+
"arui-presets-lint": "8.7.0",
|
|
49
|
+
"arui-scripts": "19.0.7",
|
|
50
|
+
"copyfiles": "2.4.1",
|
|
51
|
+
"jest-junit": "10.0.0",
|
|
52
|
+
"lint-staged": "^12.5.0",
|
|
53
|
+
"promisify-child-process": "4.1.1",
|
|
54
|
+
"shx": "0.3.4",
|
|
55
|
+
"typescript": "5.5.4"
|
|
56
|
+
},
|
|
57
|
+
"commitlint": {
|
|
58
|
+
"extends": "./node_modules/arui-presets-lint/commitlint"
|
|
59
|
+
},
|
|
60
|
+
"eslintConfig": {
|
|
61
|
+
"extends": "./node_modules/arui-presets-lint/eslint",
|
|
62
|
+
"parserOptions": {
|
|
63
|
+
"project": [
|
|
64
|
+
"./__tests__/tsconfig.json",
|
|
65
|
+
"./src/client/tsconfig.json",
|
|
66
|
+
"./src/server/tsconfig.json"
|
|
67
|
+
]
|
|
68
|
+
},
|
|
69
|
+
"overrides": [
|
|
70
|
+
{
|
|
71
|
+
"files": [
|
|
72
|
+
"__tests__/**/*"
|
|
73
|
+
],
|
|
74
|
+
"rules": {
|
|
75
|
+
"max-lines": "off"
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
]
|
|
79
|
+
},
|
|
80
|
+
"jest": {
|
|
81
|
+
"projects": [
|
|
82
|
+
{
|
|
83
|
+
"displayName": "client-tests",
|
|
84
|
+
"testEnvironment": "@happy-dom/jest-environment",
|
|
85
|
+
"testPathIgnorePatterns": [
|
|
86
|
+
"/__tests__/server/"
|
|
87
|
+
]
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
"displayName": "server-tests",
|
|
91
|
+
"testEnvironment": "node",
|
|
92
|
+
"testPathIgnorePatterns": [
|
|
93
|
+
"/__tests__/client/"
|
|
94
|
+
]
|
|
95
|
+
}
|
|
96
|
+
],
|
|
97
|
+
"testRegex": [
|
|
98
|
+
"__tests__/.*\\.test\\.ts"
|
|
99
|
+
],
|
|
100
|
+
"coveragePathIgnorePatterns": [
|
|
101
|
+
"/node_modules/",
|
|
102
|
+
"/src/(client|server)/index.ts"
|
|
103
|
+
],
|
|
104
|
+
"reporters": [
|
|
105
|
+
"default",
|
|
106
|
+
"jest-junit"
|
|
87
107
|
]
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
"
|
|
92
|
-
"
|
|
93
|
-
|
|
108
|
+
},
|
|
109
|
+
"prettier": "arui-presets-lint/prettier",
|
|
110
|
+
"stylelint": {
|
|
111
|
+
"extends": "arui-presets-lint/stylelint",
|
|
112
|
+
"ignoreFiles": [
|
|
113
|
+
"coverage/**/*.js",
|
|
114
|
+
".yarn/releases/*"
|
|
94
115
|
]
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
"coveragePathIgnorePatterns": [
|
|
101
|
-
"/node_modules/",
|
|
102
|
-
"/src/(client|server)/index.ts"
|
|
103
|
-
],
|
|
104
|
-
"reporters": [
|
|
105
|
-
"default",
|
|
106
|
-
"jest-junit"
|
|
107
|
-
]
|
|
108
|
-
},
|
|
109
|
-
"prettier": "arui-presets-lint/prettier",
|
|
110
|
-
"stylelint": {
|
|
111
|
-
"extends": "arui-presets-lint/stylelint",
|
|
112
|
-
"ignoreFiles": [
|
|
113
|
-
"coverage/**/*.js",
|
|
114
|
-
".yarn/releases/*"
|
|
115
|
-
]
|
|
116
|
-
},
|
|
117
|
-
"publishConfig": {
|
|
118
|
-
"registry": "https://registry.npmjs.org"
|
|
119
|
-
},
|
|
120
|
-
"packageManager": "yarn@4.12.0"
|
|
116
|
+
},
|
|
117
|
+
"publishConfig": {
|
|
118
|
+
"registry": "https://registry.npmjs.org"
|
|
119
|
+
},
|
|
120
|
+
"packageManager": "yarn@4.12.0"
|
|
121
121
|
}
|
|
@@ -11,8 +11,6 @@ exports.HEADER_KEY_USER_AGENT = 'user-agent';
|
|
|
11
11
|
*/
|
|
12
12
|
// Ключ cookie, с помощью которого серверная часть B2N передаст на клиент информацию об NA.
|
|
13
13
|
exports.COOKIE_KEY_BRIDGE_TO_NATIVE_DATA = 'bridgeToNativeData';
|
|
14
|
-
// Ключ cookie, с помощью которого серверная часть B2N передаст на клиент информацию об NA.
|
|
15
|
-
// export const B2N_MODE = 'b2n_mode';
|
|
16
14
|
// NA на обеих платформах подмешивает этот заголовок к запросу за HTML.
|
|
17
15
|
// TODO:
|
|
18
16
|
// * Исследовать, делает ли оно это при запросах к прочим ресурсам;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type NativeParams
|
|
1
|
+
import { type NativeParams } from '../types';
|
|
2
2
|
import { type UniversalRequest } from './types';
|
|
3
3
|
/**
|
|
4
4
|
* Парсит запрос, доставая из него данные о нативном приложении,
|
|
@@ -11,4 +11,4 @@ import { type UniversalRequest } from './types';
|
|
|
11
11
|
* Нужно передать функцию, которая средствами используемого веб-сервера добавит заголовок в ответ.
|
|
12
12
|
* b2native с её помощью добавит `Set-Cookie` заголовок с некоторыми данными для своего клиентского кода.
|
|
13
13
|
*/
|
|
14
|
-
export declare function prepareNativeAppDetailsForClient(request: UniversalRequest, setResponseHeader: (headerKey: string, headerValue: string) => void
|
|
14
|
+
export declare function prepareNativeAppDetailsForClient(request: UniversalRequest, setResponseHeader: (headerKey: string, headerValue: string) => void): Partial<NativeParams>;
|
|
@@ -16,17 +16,15 @@ const utils_1 = require("./utils");
|
|
|
16
16
|
* Нужно передать функцию, которая средствами используемого веб-сервера добавит заголовок в ответ.
|
|
17
17
|
* b2native с её помощью добавит `Set-Cookie` заголовок с некоторыми данными для своего клиентского кода.
|
|
18
18
|
*/
|
|
19
|
-
function prepareNativeAppDetailsForClient(request, setResponseHeader
|
|
19
|
+
function prepareNativeAppDetailsForClient(request, setResponseHeader) {
|
|
20
20
|
// Поскольку вебвью модули имеют особенность сохранять сессионную куку подолгу,
|
|
21
21
|
// даже после перезагрузки устройства или обновления приложения/ОС, ее значение
|
|
22
22
|
// актуализируется при каждом запросе на сервер.
|
|
23
23
|
const cookieHeader = (0, utils_1.getHeaderValue)(request, query_and_headers_keys_1.HEADER_KEY_COOKIE);
|
|
24
24
|
const nativeParamsFromCookie = (0, utils_1.readNativeParamsFromCookie)(cookieHeader);
|
|
25
25
|
const nativeParams = buildNativeParams(request, nativeParamsFromCookie);
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
setResponseHeader('Set-Cookie', `${query_and_headers_keys_1.COOKIE_KEY_BRIDGE_TO_NATIVE_DATA}=${serializedNativeParams}; Path=/`);
|
|
29
|
-
}
|
|
26
|
+
const serializedNativeParams = encodeURIComponent(JSON.stringify(nativeParams));
|
|
27
|
+
setResponseHeader('Set-Cookie', `${query_and_headers_keys_1.COOKIE_KEY_BRIDGE_TO_NATIVE_DATA}=${serializedNativeParams}; Path=/`);
|
|
30
28
|
return nativeParams;
|
|
31
29
|
}
|
|
32
30
|
function buildNativeParams(request, nativeParamsFromCookie) {
|
package/server/utils.js
CHANGED
|
@@ -74,8 +74,6 @@ const getBridgeToNativeDataCookie = (cookieHeader) => {
|
|
|
74
74
|
return undefined;
|
|
75
75
|
};
|
|
76
76
|
exports.getBridgeToNativeDataCookie = getBridgeToNativeDataCookie;
|
|
77
|
-
// export const getBridgeToNativeDataCookie = (cookieHeader: string | null) =>
|
|
78
|
-
// getCookieValue(cookieHeader, COOKIE_KEY_BRIDGE_TO_NATIVE_DATA);
|
|
79
77
|
/**
|
|
80
78
|
* Возвращает десериализованные данные из `bridgeToNativeData` cookie.
|
|
81
79
|
*/
|
|
@@ -91,10 +89,3 @@ function readNativeParamsFromCookie(cookieHeader) {
|
|
|
91
89
|
return null;
|
|
92
90
|
}
|
|
93
91
|
}
|
|
94
|
-
// export function readModeFromCookie(cookieHeader: string | null) {
|
|
95
|
-
// const mode = getCookieValue(cookieHeader, B2N_MODE);
|
|
96
|
-
// if (!mode) {
|
|
97
|
-
// return null;
|
|
98
|
-
// }
|
|
99
|
-
// return mode as 'noop' | 'native';
|
|
100
|
-
// }
|
package/types.d.ts
CHANGED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import { type Environment, type NoopOptions } from '../../types';
|
|
2
|
-
import { type NativeFeatureContext, type NativeFeatureKey } from '../types';
|
|
3
|
-
/**
|
|
4
|
-
* Обёртка для выполнения нативных вызовов с noop-режимом и логированием версионных фич
|
|
5
|
-
*/
|
|
6
|
-
export declare class NativeLogService {
|
|
7
|
-
private environment;
|
|
8
|
-
private appVersion;
|
|
9
|
-
private isNoop?;
|
|
10
|
-
constructor(environment: Environment, appVersion: string, isNoop?: NoopOptions["enabled"] | undefined);
|
|
11
|
-
/**
|
|
12
|
-
* Метод для вывода в консоль информации о недоступности фич,
|
|
13
|
-
* перечисленных в `NATIVE_FEATURES_FROM_VERSION` src/client/constants.ts
|
|
14
|
-
*/
|
|
15
|
-
logFeatureFallback(params: {
|
|
16
|
-
feature: NativeFeatureKey;
|
|
17
|
-
fallbackReason: string;
|
|
18
|
-
payload?: unknown;
|
|
19
|
-
}): void;
|
|
20
|
-
/**
|
|
21
|
-
* Метод подменяющий нативный вызов и логирующий его, для работы в noop режиме
|
|
22
|
-
*/
|
|
23
|
-
execute(action: string, fn: () => void, meta?: {
|
|
24
|
-
featureContext?: NativeFeatureContext | null;
|
|
25
|
-
payload?: unknown;
|
|
26
|
-
}): void;
|
|
27
|
-
}
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.NativeLogService = void 0;
|
|
4
|
-
const constants_1 = require("../constants");
|
|
5
|
-
/**
|
|
6
|
-
* Обёртка для выполнения нативных вызовов с noop-режимом и логированием версионных фич
|
|
7
|
-
*/
|
|
8
|
-
class NativeLogService {
|
|
9
|
-
constructor(environment, appVersion, isNoop) {
|
|
10
|
-
this.environment = environment;
|
|
11
|
-
this.appVersion = appVersion;
|
|
12
|
-
this.isNoop = isNoop;
|
|
13
|
-
}
|
|
14
|
-
/**
|
|
15
|
-
* Метод для вывода в консоль информации о недоступности фич,
|
|
16
|
-
* перечисленных в `NATIVE_FEATURES_FROM_VERSION` src/client/constants.ts
|
|
17
|
-
*/
|
|
18
|
-
logFeatureFallback(params) {
|
|
19
|
-
if (!this.isNoop)
|
|
20
|
-
return;
|
|
21
|
-
const { fromVersion } = constants_1.NATIVE_FEATURES_FROM_VERSION[this.environment][params.feature];
|
|
22
|
-
console.info([
|
|
23
|
-
`[B2N noop][${this.environment}][v${this.appVersion}]`,
|
|
24
|
-
`Feature: ${params.feature}`,
|
|
25
|
-
`${params.fallbackReason}`,
|
|
26
|
-
`Будет исправлено в версии: ${fromVersion}`,
|
|
27
|
-
].join('\n'), params.payload);
|
|
28
|
-
}
|
|
29
|
-
/**
|
|
30
|
-
* Метод подменяющий нативный вызов и логирующий его, для работы в noop режиме
|
|
31
|
-
*/
|
|
32
|
-
execute(action, fn, meta) {
|
|
33
|
-
var _a;
|
|
34
|
-
if (this.isNoop) {
|
|
35
|
-
if (meta === null || meta === void 0 ? void 0 : meta.featureContext) {
|
|
36
|
-
this.logFeatureFallback({
|
|
37
|
-
feature: meta.featureContext.feature,
|
|
38
|
-
fallbackReason: (_a = meta.featureContext.fallbackReason) !== null && _a !== void 0 ? _a : '',
|
|
39
|
-
payload: meta.payload,
|
|
40
|
-
});
|
|
41
|
-
}
|
|
42
|
-
else {
|
|
43
|
-
console.info(`[B2N noop][${this.environment}][v${this.appVersion}] ${action}`, ...((meta === null || meta === void 0 ? void 0 : meta.payload) !== undefined ? [meta.payload] : []));
|
|
44
|
-
}
|
|
45
|
-
return;
|
|
46
|
-
}
|
|
47
|
-
fn();
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
exports.NativeLogService = NativeLogService;
|