@alfalab/bridge-to-native 1.4.2 → 1.5.1-beta.50a07d1

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.
@@ -1,5 +1,5 @@
1
1
 
2
- import { type BrowserHistoryApiWrappers, type HistoryPushStateParams, type HistoryReplaceStateParams, type LocationAssignParam, type LogError, type NativeFeatureKey, type PdfType } from './types';
2
+ import { type BrowserHistoryApiWrappers, type HistoryPushStateParams, type HistoryReplaceStateParams, type LocationAssignParam, type LogError, type NativeFeatureKey, type NoopOptions, type PdfType } from './types';
3
3
  /**
4
4
  * Сервис, предоставляет методы для WA, работающего внутри NA.
5
5
  */
@@ -13,12 +13,15 @@ export declare class BridgeToNative {
13
13
  * будут использованы стандартные `History: pushState()` и `History: go()`.
14
14
  * @param options.logError Функция с помощью которой B2N может залогировать ошибку,
15
15
  * если не передать, B2N не будет логировать ошибки.
16
+ * @param options.noop ....
16
17
  */
17
18
  constructor(options?: {
18
19
  browserHistoryApiWrappers?: BrowserHistoryApiWrappers;
19
20
  logError?: LogError;
21
+ noop?: NoopOptions;
20
22
  } | undefined);
21
23
  private nativeParamsService;
24
+ private nativeLogService;
22
25
  private externalLinksService;
23
26
  private nativeNavigationAndTitleService;
24
27
  /**
@@ -3,6 +3,7 @@
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");
6
7
  const native_navigation_and_title_service_1 = require("./services-and-utils/native-navigation-and-title-service");
7
8
  const native_params_service_1 = require("./services-and-utils/native-params-service");
8
9
  /**
@@ -17,13 +18,15 @@ class BridgeToNative {
17
18
  * будут использованы стандартные `History: pushState()` и `History: go()`.
18
19
  * @param options.logError Функция с помощью которой B2N может залогировать ошибку,
19
20
  * если не передать, B2N не будет логировать ошибки.
21
+ * @param options.noop ....
20
22
  */
21
23
  constructor(options) {
22
- var _a, _b, _c, _d;
24
+ var _a, _b, _c, _d, _e, _f, _g;
23
25
  this.options = options;
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);
26
+ this.nativeParamsService = new native_params_service_1.NativeParamsService((_a = this.options) === null || _a === void 0 ? void 0 : _a.noop, (_b = this.options) === null || _b === void 0 ? void 0 : _b.logError);
27
+ this.nativeLogService = new native_log_service_1.NativeLogService(this.nativeParamsService.environment, this.nativeParamsService.appVersion, (_d = (_c = this.options) === null || _c === void 0 ? void 0 : _c.noop) === null || _d === void 0 ? void 0 : _d.enabled);
28
+ this.externalLinksService = new external_links_service_1.ExternalLinksService(this.nativeParamsService, this.nativeLogService, (_e = this.options) === null || _e === void 0 ? void 0 : _e.logError);
29
+ this.nativeNavigationAndTitleService = new native_navigation_and_title_service_1.NativeNavigationAndTitleService(this.nativeParamsService, this.nativeLogService, (_f = this.options) === null || _f === void 0 ? void 0 : _f.browserHistoryApiWrappers, (_g = this.options) === null || _g === void 0 ? void 0 : _g.logError);
27
30
  }
28
31
  /**
29
32
  * Схема NA.
package/client/index.d.ts CHANGED
@@ -1 +1,3 @@
1
1
  export { BridgeToNative } from './bridge-to-native';
2
+ export { canUseNativeFeature, isVersionHigherOrEqual, prepareNativeDeeplinkUrl, prepareOpenInBrowserUrl, prepareOpenInNewWebviewDeeplink, preparePdfUrl, } from './primitives';
3
+ 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.isVersionHigherOrEqual = 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 primitives_1 = require("./primitives");
7
+ Object.defineProperty(exports, "canUseNativeFeature", { enumerable: true, get: function () { return primitives_1.canUseNativeFeature; } });
8
+ Object.defineProperty(exports, "isVersionHigherOrEqual", { enumerable: true, get: function () { return primitives_1.isVersionHigherOrEqual; } });
9
+ Object.defineProperty(exports, "prepareNativeDeeplinkUrl", { enumerable: true, get: function () { return primitives_1.prepareNativeDeeplinkUrl; } });
10
+ Object.defineProperty(exports, "prepareOpenInBrowserUrl", { enumerable: true, get: function () { return primitives_1.prepareOpenInBrowserUrl; } });
11
+ Object.defineProperty(exports, "prepareOpenInNewWebviewDeeplink", { enumerable: true, get: function () { return primitives_1.prepareOpenInNewWebviewDeeplink; } });
12
+ Object.defineProperty(exports, "preparePdfUrl", { enumerable: true, get: function () { return primitives_1.preparePdfUrl; } });
@@ -0,0 +1,3 @@
1
+ export { canUseNativeFeature, isVersionHigherOrEqual } from './services-and-utils/native-features';
2
+ export { prepareNativeDeeplinkUrl, prepareOpenInBrowserUrl, prepareOpenInNewWebviewDeeplink, preparePdfUrl, } from './services-and-utils/native-links';
3
+ export type { Environment, NativeAppTarget, NativeFeatureKey, PdfType } from './types';
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.preparePdfUrl = exports.prepareOpenInNewWebviewDeeplink = exports.prepareOpenInBrowserUrl = exports.prepareNativeDeeplinkUrl = exports.isVersionHigherOrEqual = exports.canUseNativeFeature = void 0;
4
+ var native_features_1 = require("./services-and-utils/native-features");
5
+ Object.defineProperty(exports, "canUseNativeFeature", { enumerable: true, get: function () { return native_features_1.canUseNativeFeature; } });
6
+ Object.defineProperty(exports, "isVersionHigherOrEqual", { enumerable: true, get: function () { return native_features_1.isVersionHigherOrEqual; } });
7
+ var native_links_1 = require("./services-and-utils/native-links");
8
+ Object.defineProperty(exports, "prepareNativeDeeplinkUrl", { enumerable: true, get: function () { return native_links_1.prepareNativeDeeplinkUrl; } });
9
+ Object.defineProperty(exports, "prepareOpenInBrowserUrl", { enumerable: true, get: function () { return native_links_1.prepareOpenInBrowserUrl; } });
10
+ Object.defineProperty(exports, "prepareOpenInNewWebviewDeeplink", { enumerable: true, get: function () { return native_links_1.prepareOpenInNewWebviewDeeplink; } });
11
+ Object.defineProperty(exports, "preparePdfUrl", { enumerable: true, get: function () { return native_links_1.preparePdfUrl; } });
@@ -1,4 +1,5 @@
1
1
  import { type LogError, type PdfType } from '../types';
2
+ import { type NativeLogService } from './native-log-service';
2
3
  import { type NativeParamsService } from './native-params-service';
3
4
  /**
4
5
  * Сервис, предоставляющий методы для открытия внешних для текущего WA экранов
@@ -6,13 +7,21 @@ import { type NativeParamsService } from './native-params-service';
6
7
  */
7
8
  export declare class ExternalLinksService {
8
9
  private nativeParamsService;
10
+ private nativeLogService;
9
11
  private logError?;
10
12
  private navigationByNativeAppInProgress;
11
- constructor(nativeParamsService: NativeParamsService, logError?: LogError | undefined);
13
+ constructor(nativeParamsService: NativeParamsService, nativeLogService: NativeLogService, logError?: LogError | undefined);
12
14
  handleNativeDeeplink(deeplink: string, closeWebviewBeforeCallNativeDeeplinkHandler?: boolean): void;
13
15
  getHrefToOpenInBrowser(link: string): string;
14
16
  openInBrowser(link: string): void;
15
17
  openInNewWebview(link: string, nativeTitle?: string, closeCurrentWebview?: boolean): void;
16
18
  openPdf(url: string, type?: PdfType, title?: string): void;
19
+ private get nativeAppTarget();
20
+ /**
21
+ * Логирует невалидный URL через `logError` и бросает ошибку.
22
+ * Чистые функции сборки URL бросают ту же ошибку, но без логирования.
23
+ */
24
+ private validateUrlOrThrow;
25
+ private logBrowserFallback;
17
26
  private navigateByNativeApp;
18
27
  }
@@ -1,19 +1,17 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ExternalLinksService = void 0;
4
- const query_and_headers_keys_1 = require("../../query-and-headers-keys");
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
  * и связанных с этим действий.
13
10
  */
14
11
  class ExternalLinksService {
15
- constructor(nativeParamsService, logError) {
12
+ constructor(nativeParamsService, nativeLogService, logError) {
16
13
  this.nativeParamsService = nativeParamsService;
14
+ this.nativeLogService = nativeLogService;
17
15
  this.logError = logError;
18
16
  this.navigationByNativeAppInProgress = false;
19
17
  }
@@ -21,84 +19,86 @@ class ExternalLinksService {
21
19
  if (this.navigationByNativeAppInProgress) {
22
20
  return;
23
21
  }
24
- const clearedDeeplinkPath = deeplink.replace(constants_1.DEEP_LINK_PATTERN, '');
25
- const originalNativeUrl = `${this.nativeParamsService.appId}://${clearedDeeplinkPath}`;
26
- const preparedNativeUrl = this.nativeParamsService.environment === 'ios'
27
- ? (0, utils_1.appendFromCurrentQueryParamForIos)(originalNativeUrl)
28
- : originalNativeUrl;
22
+ const preparedNativeUrl = (0, native_links_1.prepareNativeDeeplinkUrl)(this.nativeAppTarget, deeplink);
29
23
  if (closeWebviewBeforeCallNativeDeeplinkHandler &&
30
24
  this.nativeParamsService.canUseNativeFeature('savedBackStack')) {
31
- (0, utils_1.closeWebviewUtil)();
25
+ this.nativeLogService.execute('closeWebview', () => (0, utils_1.closeWebviewUtil)());
32
26
  // Проверено, ОС получает диплинк и передаёт его NA, не смотря на то,
33
27
  // что это происходит в следующей макрозадаче после команды на закрытие WV.
34
- setTimeout(() => window.location.replace(preparedNativeUrl), 0);
28
+ this.nativeLogService.execute('nativeDeeplink', () => {
29
+ setTimeout(() => window.location.replace(preparedNativeUrl), 0);
30
+ }, { payload: { deeplink: preparedNativeUrl } });
35
31
  return;
36
32
  }
37
- this.navigateByNativeApp(preparedNativeUrl);
33
+ this.navigateByNativeApp(preparedNativeUrl, 'nativeDeeplink');
38
34
  }
39
35
  getHrefToOpenInBrowser(link) {
40
36
  if (!this.nativeParamsService.canUseNativeFeature('linksInBrowser')) {
37
+ this.logBrowserFallback(link);
41
38
  return `${this.nativeParamsService.appId}://webFeature?type=recommendation&url=${encodeURIComponent(link)}`;
42
39
  }
43
- const url = (0, utils_1.validateUrl)(link, this.logError);
44
- if (!url) {
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;
40
+ this.validateUrlOrThrow(link);
41
+ return (0, native_links_1.prepareOpenInBrowserUrl)(this.nativeAppTarget, link, true);
49
42
  }
50
43
  openInBrowser(link) {
51
44
  if (this.navigationByNativeAppInProgress) {
52
45
  return;
53
46
  }
54
- if (!this.nativeParamsService.canUseNativeFeature('linksInBrowser')) {
55
- this.openInNewWebview(link);
56
- return;
57
- }
58
- const url = (0, utils_1.validateUrl)(link, this.logError);
59
- if (!url) {
60
- throw new Error(`invalid url: ${link}`);
47
+ this.validateUrlOrThrow(link);
48
+ const linksInBrowser = this.nativeParamsService.canUseNativeFeature('linksInBrowser');
49
+ if (!linksInBrowser) {
50
+ this.logBrowserFallback(link);
61
51
  }
62
- url.searchParams.append(QUERY_OPEN_IN_BROWSER_KEY, QUERY_OPEN_IN_BROWSER_VALUE);
63
- this.navigateByNativeApp(url.href);
52
+ this.navigateByNativeApp((0, native_links_1.prepareOpenInBrowserUrl)(this.nativeAppTarget, link, linksInBrowser), 'openInBrowser');
64
53
  }
65
54
  openInNewWebview(link, nativeTitle = '', closeCurrentWebview = false) {
66
- const url = (0, utils_1.validateUrl)(link, this.logError);
67
- if (!url) {
68
- throw new Error(`invalid url: ${link}`);
69
- }
70
- if (nativeTitle) {
71
- url.searchParams.set(query_and_headers_keys_1.QUERY_B2N_TITLE, nativeTitle);
55
+ this.validateUrlOrThrow(link);
56
+ if (this.nativeParamsService.environment === 'android' &&
57
+ !this.nativeParamsService.canUseNativeFeature('savedBackStack')) {
58
+ this.nativeLogService.logFeatureFallback({
59
+ feature: 'savedBackStack',
60
+ fallbackReason: 'Открытие нового webview в Android приведет к закрытию текущего',
61
+ payload: { link },
62
+ });
72
63
  }
73
- this.handleNativeDeeplink(`/webFeature?type=recommendation&url=${encodeURIComponent(url.toString())}`, closeCurrentWebview);
64
+ this.handleNativeDeeplink((0, native_links_1.prepareOpenInNewWebviewDeeplink)(link, nativeTitle), closeCurrentWebview);
74
65
  }
75
66
  openPdf(url, type = 'pdfFile', title) {
76
67
  if (this.navigationByNativeAppInProgress) {
77
68
  return;
78
69
  }
79
- let replaceUrl = url;
80
- if (this.nativeParamsService.environment === 'ios') {
81
- const params = new URLSearchParams();
82
- params.append('type', type);
83
- params.append('url', decodeURIComponent(url));
84
- if (title) {
85
- params.append('title', title.replace(/\s/g, '_'));
86
- }
87
- const paramsStr = params.toString();
88
- replaceUrl = `${this.nativeParamsService.appId}:///dashboard/pdf_viewer?${paramsStr}`;
70
+ this.navigateByNativeApp((0, native_links_1.preparePdfUrl)(this.nativeAppTarget, url, type, title), 'openPdf');
71
+ }
72
+ get nativeAppTarget() {
73
+ return {
74
+ platform: this.nativeParamsService.environment,
75
+ appId: this.nativeParamsService.appId,
76
+ };
77
+ }
78
+ /**
79
+ * Логирует невалидный URL через `logError` и бросает ошибку.
80
+ * Чистые функции сборки URL бросают ту же ошибку, но без логирования.
81
+ */
82
+ validateUrlOrThrow(link) {
83
+ if (!(0, utils_1.validateUrl)(link, this.logError)) {
84
+ throw new Error(`invalid url: ${link}`);
89
85
  }
90
- replaceUrl =
91
- this.nativeParamsService.environment === 'ios'
92
- ? (0, utils_1.appendFromCurrentQueryParamForIos)(replaceUrl)
93
- : replaceUrl;
94
- this.navigateByNativeApp(replaceUrl);
95
86
  }
96
- navigateByNativeApp(url) {
97
- this.navigationByNativeAppInProgress = true;
98
- window.location.replace(url);
99
- setTimeout(() => {
100
- this.navigationByNativeAppInProgress = false;
101
- }, CANCEL_NEW_CALLS_TO_NA_TIME);
87
+ logBrowserFallback(link) {
88
+ this.nativeLogService.logFeatureFallback({
89
+ feature: 'linksInBrowser',
90
+ fallbackReason: 'Открытие в браузере технически недоступно, будет открыто в новом webview',
91
+ payload: { link },
92
+ });
93
+ }
94
+ navigateByNativeApp(url, action) {
95
+ this.nativeLogService.execute(action, () => {
96
+ this.navigationByNativeAppInProgress = true;
97
+ window.location.replace(url);
98
+ setTimeout(() => {
99
+ this.navigationByNativeAppInProgress = false;
100
+ }, CANCEL_NEW_CALLS_TO_NA_TIME);
101
+ }, { payload: { url } });
102
102
  }
103
103
  }
104
104
  exports.ExternalLinksService = ExternalLinksService;
@@ -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;
@@ -0,0 +1,26 @@
1
+ import { type Environment, type NativeFeatureContext, type NativeFeatureKey, type NoopOptions } from '../types';
2
+ /**
3
+ * Обёртка для выполнения нативных вызовов с noop-режимом и логированием версионных фич
4
+ */
5
+ export declare class NativeLogService {
6
+ private environment;
7
+ private appVersion;
8
+ private isNoop?;
9
+ constructor(environment: Environment, appVersion: string, isNoop?: NoopOptions["enabled"] | undefined);
10
+ /**
11
+ * Метод для вывода в консоль информации о недоступности фич,
12
+ * перечисленных в `NATIVE_FEATURES_FROM_VERSION` src/client/constants.ts
13
+ */
14
+ logFeatureFallback(params: {
15
+ feature: NativeFeatureKey;
16
+ fallbackReason: string;
17
+ payload?: unknown;
18
+ }): void;
19
+ /**
20
+ * Метод подменяющий нативный вызов и логирующий его, для работы в noop режиме
21
+ */
22
+ execute(action: string, fn: () => void, meta?: {
23
+ featureContext?: NativeFeatureContext | null;
24
+ payload?: unknown;
25
+ }): void;
26
+ }
@@ -0,0 +1,50 @@
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;
@@ -1,4 +1,5 @@
1
1
  import { type BrowserHistoryApiWrappers, type HistoryPushStateParams, type LocationAssignParam, type LogError } from '../types';
2
+ import { type NativeLogService } from './native-log-service';
2
3
  import { type NativeParamsService } from './native-params-service';
3
4
  /**
4
5
  * Сервис, отвечающий за взаимодействие WA с WV компонентами NA —
@@ -9,6 +10,7 @@ import { type NativeParamsService } from './native-params-service';
9
10
  */
10
11
  export declare class NativeNavigationAndTitleService {
11
12
  private nativeParamsService;
13
+ private nativeLogService;
12
14
  private browserHistoryApiWrappers?;
13
15
  private logError?;
14
16
  private lastSetPageSettingsParams;
@@ -16,7 +18,7 @@ export declare class NativeNavigationAndTitleService {
16
18
  private numOfBackSteps;
17
19
  private isGoBackLocked;
18
20
  private isNavigateServerSideLocked;
19
- constructor(nativeParamsService: NativeParamsService, browserHistoryApiWrappers?: BrowserHistoryApiWrappers | undefined, logError?: LogError | undefined);
21
+ constructor(nativeParamsService: NativeParamsService, nativeLogService: NativeLogService, browserHistoryApiWrappers?: BrowserHistoryApiWrappers | undefined, logError?: LogError | undefined);
20
22
  closeWebview(): void;
21
23
  goBack(): void;
22
24
  goBackAFewSteps(stepsNumber: number, autoCloseWebview?: boolean): void;
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
- /* eslint max-lines: ["error", {"max": 360, "skipComments": true}] */
3
2
  Object.defineProperty(exports, "__esModule", { value: true });
4
3
  exports.NativeNavigationAndTitleService = void 0;
4
+ /* eslint max-lines: ["error", {"max": 370, "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,8 +13,9 @@ const NativeHistoryStackStub = 0;
13
13
  * см. в документе {@link ./NAVIGATION_SCENARIOS.md}.
14
14
  */
15
15
  class NativeNavigationAndTitleService {
16
- constructor(nativeParamsService, browserHistoryApiWrappers, logError) {
16
+ constructor(nativeParamsService, nativeLogService, browserHistoryApiWrappers, logError) {
17
17
  this.nativeParamsService = nativeParamsService;
18
+ this.nativeLogService = nativeLogService;
18
19
  this.browserHistoryApiWrappers = browserHistoryApiWrappers;
19
20
  this.logError = logError;
20
21
  // Здесь сохраняются параметры, которые в последний раз были отправлены
@@ -39,7 +40,7 @@ class NativeNavigationAndTitleService {
39
40
  }
40
41
  // eslint-disable-next-line class-methods-use-this -- удобней использовать метод в контексте экземпляра.
41
42
  closeWebview() {
42
- (0, utils_1.closeWebviewUtil)();
43
+ this.nativeLogService.execute('closeWebview', () => (0, utils_1.closeWebviewUtil)());
43
44
  }
44
45
  goBack() {
45
46
  if (this.isGoBackLocked) {
@@ -57,7 +58,7 @@ class NativeNavigationAndTitleService {
57
58
  const maxStepsToBack = this.nativeHistoryStack.length - 1;
58
59
  if (stepsToBack > maxStepsToBack) {
59
60
  if (autoCloseWebview) {
60
- (0, utils_1.closeWebviewUtil)();
61
+ this.nativeLogService.execute('closeWebview', () => (0, utils_1.closeWebviewUtil)());
61
62
  return;
62
63
  }
63
64
  this.numOfBackSteps = maxStepsToBack;
@@ -165,7 +166,7 @@ class NativeNavigationAndTitleService {
165
166
  }
166
167
  this.numOfBackSteps = 1;
167
168
  if (this.nativeHistoryStack.length < 1) {
168
- (0, utils_1.closeWebviewUtil)();
169
+ this.nativeLogService.execute('closeWebview', () => (0, utils_1.closeWebviewUtil)());
169
170
  return;
170
171
  }
171
172
  this.saveNativeHistoryStack();
@@ -282,13 +283,12 @@ class NativeNavigationAndTitleService {
282
283
  * с `nativeHistoryStack`.
283
284
  */
284
285
  syncHistoryWithNative() {
285
- var _a;
286
286
  const { pageId, pageTitle } = this.getNativePageIdAndTitle();
287
287
  if (this.nativeParamsService.environment === 'android') {
288
288
  const narrowedPageId = pageId !== null && pageId !== void 0 ? pageId : 1;
289
289
  const paramsToSend = JSON.stringify({ pageId: narrowedPageId, pageTitle });
290
290
  if (this.lastSetPageSettingsParams !== paramsToSend) {
291
- (_a = this.nativeParamsService.AndroidBridge) === null || _a === void 0 ? void 0 : _a.setPageSettings(paramsToSend);
291
+ this.nativeLogService.execute('syncHistoryWithNative', () => { var _a; return (_a = this.nativeParamsService.AndroidBridge) === null || _a === void 0 ? void 0 : _a.setPageSettings(paramsToSend); }, { payload: paramsToSend });
292
292
  this.lastSetPageSettingsParams = paramsToSend;
293
293
  }
294
294
  }
@@ -297,7 +297,7 @@ class NativeNavigationAndTitleService {
297
297
  const pageIdStr = pageId ? `&pageId=${pageId}` : '';
298
298
  const paramsToSend = `ios:setPageSettings/${pageTitleStr + pageIdStr}`;
299
299
  if (this.lastSetPageSettingsParams !== paramsToSend) {
300
- window.location.replace(paramsToSend);
300
+ this.nativeLogService.execute('syncHistoryWithNative', () => window.location.replace(paramsToSend), { payload: paramsToSend });
301
301
  this.lastSetPageSettingsParams = paramsToSend;
302
302
  }
303
303
  }
@@ -1,8 +1,9 @@
1
- import { type Environment, type LogError, type NativeFeatureKey, type Theme } from '../types';
1
+ import { type Environment, type LogError, type NativeFeatureKey, type NoopOptions, type Theme } from '../types';
2
2
  /**
3
3
  * Сервис, аккумулирующий детали о NA и предоставляющий методы, связанные с этим.
4
4
  */
5
5
  export declare class NativeParamsService {
6
+ private noop?;
6
7
  private logError?;
7
8
  AndroidBridge: {
8
9
  setPageSettings: (params: string) => void;
@@ -16,10 +17,12 @@ export declare class NativeParamsService {
16
17
  theme: Theme;
17
18
  title: string;
18
19
  webviewLaunchTime: number | null;
19
- constructor(logError?: LogError | undefined);
20
+ constructor(noop?: NoopOptions | undefined, logError?: LogError | undefined);
20
21
  canUseNativeFeature(feature: NativeFeatureKey): boolean;
21
22
  isCurrentVersionHigherOrEqual(versionToCompare: string): boolean;
22
23
  private static isValidVersionFormat;
23
24
  private getAppId;
24
25
  private readNativeParamsCookie;
26
+ private resolveEnvironment;
27
+ private resolveAppVersion;
25
28
  }
@@ -3,19 +3,19 @@ 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
  */
9
10
  class NativeParamsService {
10
- constructor(logError) {
11
+ constructor(noop, logError) {
12
+ this.noop = noop;
11
13
  this.logError = logError;
12
14
  this.AndroidBridge = window.Android;
13
- this.environment = window.Android ? 'android' : 'ios';
14
15
  this.nativeParamsReadErrorFlag = false;
15
16
  const nativeParams = this.readNativeParamsCookie();
16
- this.appVersion = NativeParamsService.isValidVersionFormat(nativeParams === null || nativeParams === void 0 ? void 0 : nativeParams.appVersion)
17
- ? nativeParams.appVersion
18
- : '0.0.0';
17
+ this.environment = this.resolveEnvironment();
18
+ this.appVersion = this.resolveAppVersion(nativeParams === null || nativeParams === void 0 ? void 0 : nativeParams.appVersion);
19
19
  this.appId = this.getAppId(nativeParams === null || nativeParams === void 0 ? void 0 : nativeParams.iosAppId);
20
20
  this.nextPageId = (nativeParams === null || nativeParams === void 0 ? void 0 : nativeParams.nextPageId) || null;
21
21
  this.originalWebviewParams = (nativeParams === null || nativeParams === void 0 ? void 0 : nativeParams.originalWebviewParams) || null;
@@ -24,28 +24,13 @@ class NativeParamsService {
24
24
  this.webviewLaunchTime = (nativeParams === null || nativeParams === void 0 ? void 0 : nativeParams.webviewLaunchTime) || null;
25
25
  }
26
26
  canUseNativeFeature(feature) {
27
- const { fromVersion } = constants_1.NATIVE_FEATURES_FROM_VERSION[this.environment][feature];
28
- return this.isCurrentVersionHigherOrEqual(fromVersion);
27
+ return (0, native_features_1.canUseNativeFeature)(this.environment, this.appVersion, feature);
29
28
  }
30
29
  isCurrentVersionHigherOrEqual(versionToCompare) {
31
- if (!NativeParamsService.isValidVersionFormat(versionToCompare)) {
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;
30
+ return (0, native_features_1.isVersionHigherOrEqual)(this.appVersion, versionToCompare);
43
31
  }
44
32
  static isValidVersionFormat(version) {
45
- if (!version)
46
- return false;
47
- const versionPattern = /^\d+\.\d+\.\d+$/;
48
- return versionPattern.test(version);
33
+ return (0, native_features_1.isValidVersionFormat)(version);
49
34
  }
50
35
  getAppId(knownIosAppId) {
51
36
  if (this.environment !== 'ios') {
@@ -76,5 +61,21 @@ class NativeParamsService {
76
61
  return null;
77
62
  }
78
63
  }
64
+ resolveEnvironment() {
65
+ var _a;
66
+ if (((_a = this.noop) === null || _a === void 0 ? void 0 : _a.enabled) && this.noop.environment) {
67
+ return this.noop.environment;
68
+ }
69
+ return window.Android ? 'android' : 'ios';
70
+ }
71
+ resolveAppVersion(versionFromCookie) {
72
+ var _a;
73
+ if (((_a = this.noop) === null || _a === void 0 ? void 0 : _a.enabled) && NativeParamsService.isValidVersionFormat(this.noop.appVersion)) {
74
+ return this.noop.appVersion;
75
+ }
76
+ return NativeParamsService.isValidVersionFormat(versionFromCookie)
77
+ ? versionFromCookie
78
+ : '0.0.0';
79
+ }
79
80
  }
80
81
  exports.NativeParamsService = NativeParamsService;
@@ -26,7 +26,7 @@ exports.closeWebviewUtil = closeWebviewUtil;
26
26
  const validateUrl = (link, logError) => {
27
27
  let url;
28
28
  try {
29
- url = link instanceof URL ? link : new URL(link);
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,11 +4,19 @@ 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];
10
14
  export type LogError = (b2nErrorMessage: string, originalError: unknown) => void;
11
15
  export type NativeFeatureKey = 'geolocation' | 'linksInBrowser' | 'savedBackStack';
16
+ export type NativeFeatureContext = {
17
+ feature: NativeFeatureKey;
18
+ fallbackReason?: string;
19
+ };
12
20
  type NativeFeaturesParams = Readonly<Record<NativeFeatureKey, {
13
21
  fromVersion: string;
14
22
  }>>;
@@ -18,4 +26,9 @@ export type NativeFeaturesFromVersion = Readonly<{
18
26
  }>;
19
27
  export type PdfType = 'pdfFile' | 'base64' | 'binary';
20
28
  export type Theme = 'light' | 'dark';
29
+ export type NoopOptions = {
30
+ enabled: boolean;
31
+ environment?: Environment;
32
+ appVersion?: string;
33
+ };
21
34
  export {};
package/package.json CHANGED
@@ -1,121 +1,127 @@
1
1
  {
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"
2
+ "name": "@alfalab/bridge-to-native",
3
+ "version": "1.5.1-beta.50a07d1",
4
+ "license": "MIT",
5
+ "description": "Утилита для удобной работы веб приложения внутри нативного приложения и коммуникации с ним.",
6
+ "engines": {
7
+ "node": ">=20.19.2",
8
+ "npm": "please-use-yarn"
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"
9
19
  },
10
- "repository": {
11
- "type": "git",
12
- "url": "git+https://github.com/core-ds/bridge-to-native.git"
20
+ "./client/primitives": {
21
+ "import": "./client/primitives.js",
22
+ "require": "./client/primitives.js",
23
+ "types": "./client/primitives.d.ts"
13
24
  },
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"
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
- ]
68
- },
69
- "overrides": [
70
- {
71
- "files": [
72
- "__tests__/**/*"
73
- ],
74
- "rules": {
75
- "max-lines": "off"
76
- }
77
- }
78
- ]
25
+ "./server": {
26
+ "import": "./server/index.js",
27
+ "require": "./server/index.js",
28
+ "types": "./server/index.d.ts"
29
+ }
30
+ },
31
+ "sideEffects": false,
32
+ "bugs": {
33
+ "url": "https://github.com/core-ds/bridge-to-native/issues"
34
+ },
35
+ "scripts": {
36
+ "build": "yarn build:clean && yarn build:ts",
37
+ "build:clean": "shx rm -rf .publish",
38
+ "build:copy-package-json": "shx cp package.json .publish/package.json",
39
+ "build:ts": "tsc --build",
40
+ "format": "arui-presets-lint format",
41
+ "format:check": "arui-presets-lint format:check",
42
+ "lint": "yarn lint:scripts && yarn format:check",
43
+ "lint:fix": "yarn lint:scripts --fix && yarn format",
44
+ "lint:scripts": "arui-presets-lint scripts",
45
+ "pub": "npm publish .publish --userconfig \"../.npmrc\" --tag \"$TAG\"",
46
+ "release": "yarn build && yarn build:copy-package-json && yarn pub",
47
+ "test": "arui-scripts test --silent --collect-coverage"
48
+ },
49
+ "devDependencies": {
50
+ "@happy-dom/jest-environment": "18.0.1",
51
+ "@types/jest": "29.5.14",
52
+ "@types/node": "20.19.1",
53
+ "arui-presets-lint": "8.7.0",
54
+ "arui-scripts": "19.0.7",
55
+ "copyfiles": "2.4.1",
56
+ "jest-junit": "10.0.0",
57
+ "lint-staged": "^12.5.0",
58
+ "promisify-child-process": "4.1.1",
59
+ "shx": "0.3.4",
60
+ "typescript": "5.5.4"
61
+ },
62
+ "commitlint": {
63
+ "extends": "./node_modules/arui-presets-lint/commitlint"
64
+ },
65
+ "eslintConfig": {
66
+ "extends": "./node_modules/arui-presets-lint/eslint",
67
+ "parserOptions": {
68
+ "project": [
69
+ "./__tests__/tsconfig.json",
70
+ "./src/client/tsconfig.json",
71
+ "./src/server/tsconfig.json"
72
+ ]
79
73
  },
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
- }
74
+ "overrides": [
75
+ {
76
+ "files": [
77
+ "__tests__/**/*"
96
78
  ],
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"
79
+ "rules": {
80
+ "max-lines": "off"
81
+ }
82
+ }
83
+ ]
84
+ },
85
+ "jest": {
86
+ "projects": [
87
+ {
88
+ "displayName": "client-tests",
89
+ "testEnvironment": "@happy-dom/jest-environment",
90
+ "testPathIgnorePatterns": [
91
+ "/__tests__/server/"
107
92
  ]
108
- },
109
- "prettier": "arui-presets-lint/prettier",
110
- "stylelint": {
111
- "extends": "arui-presets-lint/stylelint",
112
- "ignoreFiles": [
113
- "coverage/**/*.js",
114
- ".yarn/releases/*"
93
+ },
94
+ {
95
+ "displayName": "server-tests",
96
+ "testEnvironment": "node",
97
+ "testPathIgnorePatterns": [
98
+ "/__tests__/client/"
115
99
  ]
116
- },
117
- "publishConfig": {
118
- "registry": "https://registry.npmjs.org"
119
- },
120
- "packageManager": "yarn@4.12.0"
100
+ }
101
+ ],
102
+ "testRegex": [
103
+ "__tests__/.*\\.test\\.ts"
104
+ ],
105
+ "coveragePathIgnorePatterns": [
106
+ "/node_modules/",
107
+ "/src/(client|server)/index.ts",
108
+ "/src/client/primitives.ts"
109
+ ],
110
+ "reporters": [
111
+ "default",
112
+ "jest-junit"
113
+ ]
114
+ },
115
+ "prettier": "arui-presets-lint/prettier",
116
+ "stylelint": {
117
+ "extends": "arui-presets-lint/stylelint",
118
+ "ignoreFiles": [
119
+ "coverage/**/*.js",
120
+ ".yarn/releases/*"
121
+ ]
122
+ },
123
+ "publishConfig": {
124
+ "registry": "https://registry.npmjs.org"
125
+ },
126
+ "packageManager": "yarn@4.12.0"
121
127
  }
@@ -11,6 +11,8 @@ 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';
14
16
  // NA на обеих платформах подмешивает этот заголовок к запросу за HTML.
15
17
  // TODO:
16
18
  // * Исследовать, делает ли оно это при запросах к прочим ресурсам;