@alfalab/bridge-to-native 1.2.1 → 1.3.2-beta.0084dcb

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.
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ExternalLinksService = void 0;
4
4
  const query_and_headers_keys_1 = require("../../query-and-headers-keys");
5
5
  const constants_1 = require("../constants");
6
- const close_webview_util_1 = require("./close-webview-util");
6
+ const utils_1 = require("./utils");
7
7
  const QUERY_OPEN_IN_BROWSER_KEY = 'openInBrowser';
8
8
  const QUERY_OPEN_IN_BROWSER_VALUE = 'true';
9
9
  /**
@@ -16,15 +16,19 @@ class ExternalLinksService {
16
16
  }
17
17
  handleNativeDeeplink(deeplink, closeWebviewBeforeCallNativeDeeplinkHandler = false) {
18
18
  const clearedDeeplinkPath = deeplink.replace(constants_1.DEEP_LINK_PATTERN, '');
19
+ const nativeUrl = `${this.nativeParamsService.appId}://${clearedDeeplinkPath}`;
20
+ const replaceUrl = this.nativeParamsService.environment === 'ios'
21
+ ? (0, utils_1.appendFromCurrentQueryParamForIos)(nativeUrl)
22
+ : nativeUrl;
19
23
  if (closeWebviewBeforeCallNativeDeeplinkHandler &&
20
24
  this.nativeParamsService.canUseNativeFeature('savedBackStack')) {
21
- (0, close_webview_util_1.closeWebviewUtil)();
25
+ (0, utils_1.closeWebviewUtil)();
22
26
  // Проверено, ОС получает диплинк и передаёт его NA, не смотря на то,
23
27
  // что это происходит в следующей макрозадаче после команды на закрытие WV.
24
- setTimeout(() => window.location.replace(`${this.nativeParamsService.appId}://${clearedDeeplinkPath}`), 0);
28
+ setTimeout(() => window.location.replace(replaceUrl), 0);
25
29
  return;
26
30
  }
27
- window.location.replace(`${this.nativeParamsService.appId}://${clearedDeeplinkPath}`);
31
+ window.location.replace(replaceUrl);
28
32
  }
29
33
  getHrefToOpenInBrowser(link) {
30
34
  if (!this.nativeParamsService.canUseNativeFeature('linksInBrowser')) {
@@ -50,6 +50,7 @@ export declare class NativeNavigationAndTitleService {
50
50
  * экзепляра B2N следующей страницы текущего WA
51
51
  */
52
52
  private prepareExternalLinkBeforeOpen;
53
+ private static shouldInitializeFromNextPageId;
53
54
  /**
54
55
  * Читает сохраннённый в sessionStorage `nativeHistoryStack`,
55
56
  * снова сохраняет его в sessionStorage, уменьшая список на одну запись,
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
4
  exports.NativeNavigationAndTitleService = void 0;
5
5
  const query_and_headers_keys_1 = require("../../query-and-headers-keys");
6
- const close_webview_util_1 = require("./close-webview-util");
6
+ const utils_1 = require("./utils");
7
7
  /**
8
8
  * Сервис, отвечающий за взаимодействие WA с WV компонентами NA —
9
9
  * «заголовком» и кнопкой «назад».
@@ -24,7 +24,7 @@ class NativeNavigationAndTitleService {
24
24
  }
25
25
  // eslint-disable-next-line class-methods-use-this -- удобней использовать метод в контексте экземпляра.
26
26
  closeWebview() {
27
- (0, close_webview_util_1.closeWebviewUtil)();
27
+ (0, utils_1.closeWebviewUtil)();
28
28
  }
29
29
  goBack() {
30
30
  this.goBackAFewStepsClientSide(-1, true);
@@ -38,7 +38,7 @@ class NativeNavigationAndTitleService {
38
38
  const maxStepsToBack = this.nativeHistoryStack.length - 1;
39
39
  if (stepsToBack > maxStepsToBack) {
40
40
  if (autoCloseWebview) {
41
- (0, close_webview_util_1.closeWebviewUtil)();
41
+ (0, utils_1.closeWebviewUtil)();
42
42
  return;
43
43
  }
44
44
  this.numOfBackSteps = maxStepsToBack;
@@ -119,7 +119,7 @@ class NativeNavigationAndTitleService {
119
119
  this.nativeHistoryStack = this.nativeHistoryStack.slice(0, -this.numOfBackSteps);
120
120
  this.numOfBackSteps = 1;
121
121
  if (this.nativeHistoryStack.length < 1) {
122
- (0, close_webview_util_1.closeWebviewUtil)();
122
+ (0, utils_1.closeWebviewUtil)();
123
123
  return;
124
124
  }
125
125
  this.syncHistoryWithNative();
@@ -135,9 +135,12 @@ class NativeNavigationAndTitleService {
135
135
  */
136
136
  initializeNativeHistoryStack() {
137
137
  const { nextPageId, title } = this.nativeParamsService;
138
- if (nextPageId) {
138
+ if (nextPageId &&
139
+ NativeNavigationAndTitleService.shouldInitializeFromNextPageId(nextPageId)) {
139
140
  // Сценарий 2 – `nextPageId` ставит метод `this.navigateServerSide`,
140
141
  // т.е. это инициализация сразу после перехода server-side навигацией.
142
+ // Если в sessionStorage уже есть стек, используем `nextPageId` только для прямого
143
+ // перехода "вперёд", когда он на 1 больше сохранённой глубины истории.
141
144
  this.nativeHistoryStack = new Array(nextPageId).fill(0 /* NativeHistoryStackSpecialValues.ServerSideNavigationStub */);
142
145
  this.nativeHistoryStack[this.nativeHistoryStack.length - 1] = title;
143
146
  }
@@ -168,11 +171,38 @@ class NativeNavigationAndTitleService {
168
171
  */
169
172
  prepareExternalLinkBeforeOpen(url) {
170
173
  const currentPageId = this.nativeHistoryStack.length;
171
- const divider = new URL(url).searchParams.toString() ? '&' : '?';
172
- const modifiedUrl = new URL(`${url}${divider}${this.nativeParamsService.originalWebviewParams}`);
174
+ const modifiedUrl = new URL(url);
175
+ const { originalWebviewParams, appVersion } = this.nativeParamsService;
176
+ if (originalWebviewParams) {
177
+ const originalWebviewSearchParams = new URLSearchParams(originalWebviewParams);
178
+ originalWebviewSearchParams.forEach((value, key) => {
179
+ modifiedUrl.searchParams.set(key, value);
180
+ });
181
+ }
182
+ // Явно добавляем query-параметр `device_app_version` используемый NA на iOS, чтобы он был и в Android окружении.
183
+ // Таким образом гарантируется, что версию приложения будет видеть следующее WA
184
+ // (заголовок `app-version` может отсутствовать при server-side переходах).
185
+ modifiedUrl.searchParams.set(query_and_headers_keys_1.QUERY_NATIVE_IOS_APPVERSION, appVersion);
173
186
  modifiedUrl.searchParams.set(query_and_headers_keys_1.QUERY_B2N_NEXT_PAGEID, (currentPageId + 1).toString());
174
187
  return modifiedUrl;
175
188
  }
189
+ static shouldInitializeFromNextPageId(nextPageId) {
190
+ if (!NativeNavigationAndTitleService.hasSavedHistoryStack()) {
191
+ return true;
192
+ }
193
+ try {
194
+ const serializedNativeHistoryStack = sessionStorage.getItem(query_and_headers_keys_1.SS_KEY_BRIDGE_TO_NATIVE_HISTORY_STACK);
195
+ if (!serializedNativeHistoryStack) {
196
+ return true;
197
+ }
198
+ return (nextPageId ===
199
+ JSON.parse(serializedNativeHistoryStack).length +
200
+ 1);
201
+ }
202
+ catch (_a) {
203
+ return true;
204
+ }
205
+ }
176
206
  /**
177
207
  * Читает сохраннённый в sessionStorage `nativeHistoryStack`,
178
208
  * снова сохраняет его в sessionStorage, уменьшая список на одну запись,
@@ -0,0 +1,2 @@
1
+ export declare function appendFromCurrentQueryParamForIos(nativeUrl: string): string;
2
+ export declare const closeWebviewUtil: () => void;
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.closeWebviewUtil = void 0;
4
+ exports.appendFromCurrentQueryParamForIos = appendFromCurrentQueryParamForIos;
5
+ const QUERY_CLOSE_WEBVIEW_KEY = 'closeWebView';
6
+ const QUERY_CLOSE_WEBVIEW_VALUE = 'true';
7
+ const QUERY_FROM_CURRENT_KEY = 'fromCurrent';
8
+ const QUERY_FROM_CURRENT_VALUE = 'true';
9
+ function appendFromCurrentQueryParamForIos(nativeUrl) {
10
+ const qIndex = nativeUrl.indexOf('?');
11
+ if (qIndex === -1) {
12
+ return `${nativeUrl}?${QUERY_FROM_CURRENT_KEY}=${QUERY_FROM_CURRENT_VALUE}`;
13
+ }
14
+ const base = nativeUrl.slice(0, qIndex);
15
+ const query = nativeUrl.slice(qIndex + 1);
16
+ const params = new URLSearchParams(query);
17
+ params.set(QUERY_FROM_CURRENT_KEY, QUERY_FROM_CURRENT_VALUE);
18
+ return `${base}?${params.toString()}`;
19
+ }
20
+ const closeWebviewUtil = () => {
21
+ const originalPageUrl = new URL(window.location.href);
22
+ originalPageUrl.searchParams.set(QUERY_CLOSE_WEBVIEW_KEY, QUERY_CLOSE_WEBVIEW_VALUE);
23
+ window.location.href = originalPageUrl.toString();
24
+ };
25
+ exports.closeWebviewUtil = closeWebviewUtil;
package/package.json CHANGED
@@ -1,122 +1,121 @@
1
1
  {
2
- "name": "@alfalab/bridge-to-native",
3
- "version": "1.2.1",
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.3.2-beta.0084dcb",
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
+ "./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
+ ]
13
68
  },
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
- "changelog": "bash bin/fill-changelog-file-and-notify-github.sh",
36
- "format": "arui-presets-lint format",
37
- "format:check": "arui-presets-lint format:check",
38
- "lint": "yarn lint:scripts && yarn format:check",
39
- "lint:fix": "yarn lint:scripts --fix && yarn format",
40
- "lint:scripts": "arui-presets-lint scripts",
41
- "pub": "npm publish .publish --userconfig \"../.npmrc\" --tag \"$TAG\"",
42
- "release": "yarn build && npm version \"$VERSION\" --no-git-tag-version && yarn build:copy-package-json && yarn pub",
43
- "test": "arui-scripts test --silent --collect-coverage"
44
- },
45
- "devDependencies": {
46
- "@happy-dom/jest-environment": "18.0.1",
47
- "@types/jest": "29.5.14",
48
- "@types/node": "20.19.1",
49
- "arui-presets-lint": "8.7.0",
50
- "arui-scripts": "19.0.7",
51
- "copyfiles": "2.4.1",
52
- "jest-junit": "10.0.0",
53
- "lint-staged": "^12.5.0",
54
- "promisify-child-process": "4.1.1",
55
- "shx": "0.3.4",
56
- "typescript": "5.5.4"
57
- },
58
- "commitlint": {
59
- "extends": "./node_modules/arui-presets-lint/commitlint"
60
- },
61
- "eslintConfig": {
62
- "extends": "./node_modules/arui-presets-lint/eslint",
63
- "parserOptions": {
64
- "project": [
65
- "./__tests__/tsconfig.json",
66
- "./src/client/tsconfig.json",
67
- "./src/server/tsconfig.json"
68
- ]
69
- },
70
- "overrides": [
71
- {
72
- "files": [
73
- "__tests__/**/*"
74
- ],
75
- "rules": {
76
- "max-lines": "off"
77
- }
78
- }
79
- ]
80
- },
81
- "jest": {
82
- "projects": [
83
- {
84
- "displayName": "client-tests",
85
- "testEnvironment": "@happy-dom/jest-environment",
86
- "testPathIgnorePatterns": [
87
- "/__tests__/server/"
88
- ]
89
- },
90
- {
91
- "displayName": "server-tests",
92
- "testEnvironment": "node",
93
- "testPathIgnorePatterns": [
94
- "/__tests__/client/"
95
- ]
96
- }
97
- ],
98
- "testRegex": [
99
- "__tests__/.*\\.test\\.ts"
69
+ "overrides": [
70
+ {
71
+ "files": [
72
+ "__tests__/**/*"
100
73
  ],
101
- "coveragePathIgnorePatterns": [
102
- "/node_modules/",
103
- "/src/(client|server)/index.ts"
104
- ],
105
- "reporters": [
106
- "default",
107
- "jest-junit"
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/"
108
87
  ]
109
- },
110
- "prettier": "arui-presets-lint/prettier",
111
- "stylelint": {
112
- "extends": "arui-presets-lint/stylelint",
113
- "ignoreFiles": [
114
- "coverage/**/*.js",
115
- ".yarn/releases/*"
88
+ },
89
+ {
90
+ "displayName": "server-tests",
91
+ "testEnvironment": "node",
92
+ "testPathIgnorePatterns": [
93
+ "/__tests__/client/"
116
94
  ]
117
- },
118
- "publishConfig": {
119
- "registry": "https://registry.npmjs.org"
120
- },
121
- "packageManager": "yarn@4.12.0"
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"
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"
122
121
  }
@@ -34,7 +34,7 @@ exports.QUERY_B2N_TITLE = 'b2n-title';
34
34
  // (т.к. `title` часто может использоваться самим веб-приложением).
35
35
  // Игнорируется, если указан 'b2n-title'.
36
36
  exports.QUERY_B2N_TITLE_DEPRECATED = 'title';
37
- // NA на iOS приложение передаёт в этом параметре схему,
37
+ // NA на iOS передаёт в этом параметре схему,
38
38
  // под которым оно зарегистрировано в OS.
39
39
  // Известные проблемы:
40
40
  // * В старых версиях отсутствует, клиентский код использует хардкод (см. `src/client/constants.ts`);
@@ -42,7 +42,9 @@ exports.QUERY_B2N_TITLE_DEPRECATED = 'title';
42
42
  // и схемой, которая приходит в этом параметре.
43
43
  // Нужно просить iOS разработчика собрать сборку нормально.
44
44
  exports.QUERY_NATIVE_IOS_APPID = 'applicationId';
45
- // NA на iOS приложение передаёт в этом параметре свою версию.
45
+ // Исторически NA на iOS передаёт в этом параметре свою версию.
46
+ // B2N сознательно переиспользует этот query и для server-side переходов в Android,
47
+ // чтобы не вводить отдельный служебный параметр только для переноса версии между WA.
46
48
  exports.QUERY_NATIVE_IOS_APPVERSION = 'device_app_version';
47
49
  // NA на обеих платформах в этом параметре передаёт активную тему (светлая/тёмная).
48
50
  exports.QUERY_NATIVE_THEME = 'theme';
@@ -1,3 +1,4 @@
1
+ import { type NativeParams } from '../types';
1
2
  import { type UniversalRequest } from './types';
2
3
  /**
3
4
  * Парсит запрос, доставая из него данные о нативном приложении,
@@ -10,4 +11,4 @@ import { type UniversalRequest } from './types';
10
11
  * Нужно передать функцию, которая средствами используемого веб-сервера добавит заголовок в ответ.
11
12
  * b2native с её помощью добавит `Set-Cookie` заголовок с некоторыми данными для своего клиентского кода.
12
13
  */
13
- export declare function prepareNativeAppDetailsForClient(request: UniversalRequest, setResponseHeader: (headerKey: string, headerValue: string) => void): any;
14
+ export declare function prepareNativeAppDetailsForClient(request: UniversalRequest, setResponseHeader: (headerKey: string, headerValue: string) => void): Partial<NativeParams>;
@@ -25,25 +25,21 @@ function prepareNativeAppDetailsForClient(request, setResponseHeader) {
25
25
  // 1) Данных NA в запросе с большой вероятностью не будет;
26
26
  // 2) клиентская сторона сохранит всё, что нужно в SessionStorage
27
27
  const cookieHeader = (0, utils_1.getHeaderValue)(request, query_and_headers_keys_1.HEADER_KEY_COOKIE);
28
+ const nativeParamsFromCookie = (0, utils_1.readNativeParamsFromCookie)(cookieHeader);
28
29
  const hasReloadFlag = cookieHeader?.includes(`${query_and_headers_keys_1.COOKIE_KEY_BRIDGE_TO_NATIVE_RELOAD}=true`);
29
30
  if (hasReloadFlag) {
30
31
  setResponseHeader('Set-Cookie', `${query_and_headers_keys_1.COOKIE_KEY_BRIDGE_TO_NATIVE_RELOAD}=false; Max-Age=0; Path=/`);
31
- const cookieData = (0, utils_1.getBridgeToNativeDataCookie)(cookieHeader);
32
- if (cookieData) {
33
- try {
34
- return JSON.parse(decodeURIComponent(cookieData));
35
- }
36
- catch {
37
- return parseRequest(request);
38
- }
32
+ if (nativeParamsFromCookie) {
33
+ return nativeParamsFromCookie;
39
34
  }
35
+ return buildNativeParams(request);
40
36
  }
41
- const nativeParams = parseRequest(request);
37
+ const nativeParams = buildNativeParams(request, nativeParamsFromCookie);
42
38
  const serializedNativeParams = encodeURIComponent(JSON.stringify(nativeParams));
43
39
  setResponseHeader('Set-Cookie', `${query_and_headers_keys_1.COOKIE_KEY_BRIDGE_TO_NATIVE_DATA}=${serializedNativeParams}; Path=/`);
44
40
  return nativeParams;
45
41
  }
46
- function parseRequest(request) {
42
+ function buildNativeParams(request, nativeParamsFromCookie) {
47
43
  // Прихраним «сервисные» query-параметры от нативного приложения,
48
44
  // чтобы подмешать их к URL при переходе в другое веб-приложение
49
45
  // в рамках одной вебвью-сессии.
@@ -70,6 +66,9 @@ function parseRequest(request) {
70
66
  const [, appIdSubsting] = iosAppIdQuery.match(regexp_patterns_1.iosAppIdPattern); // кастинг ок — в условии блока регулярка проверена
71
67
  nativeParams.iosAppId = appIdSubsting;
72
68
  }
69
+ // Версия приложения может приехать прямо в текущем request (в query-параметре `device_app_version`
70
+ // или заголовке `app-version`), а при server-side переходах / возврате назад может уже не приехать.
71
+ // В таких сценариях берём `appVersion` фолбэком из куки `bridgeToNativeData`.
73
72
  if (iosAppVersionQuery && regexp_patterns_1.versionPattern.test(iosAppVersionQuery)) {
74
73
  nativeParams.appVersion = iosAppVersionQuery;
75
74
  }
@@ -77,6 +76,11 @@ function parseRequest(request) {
77
76
  const [, versionSubstring] = appVersionFromHeaders.match(regexp_patterns_1.versionPattern); // кастинг ок — в условии блока регулярка проверена
78
77
  nativeParams.appVersion = versionSubstring;
79
78
  }
79
+ else if (nativeParamsFromCookie?.appVersion &&
80
+ regexp_patterns_1.versionPattern.test(nativeParamsFromCookie.appVersion)) {
81
+ const [, versionSubstring] = nativeParamsFromCookie.appVersion.match(regexp_patterns_1.versionPattern);
82
+ nativeParams.appVersion = versionSubstring;
83
+ }
80
84
  else {
81
85
  nativeParams.appVersion = '0.0.0';
82
86
  }
package/server/utils.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { type NativeParams } from '../types';
1
2
  import { type UniversalRequest } from './types';
2
3
  /**
3
4
  * На основе объекта запроса любого типа возвращает
@@ -31,6 +32,10 @@ export declare function parseHeaderTimestamp(headerValue: string | number | null
31
32
  /**
32
33
  * Возвращает значение для нужной куки
33
34
  *
34
- * @param cookieName Имя куки
35
+ * @param cookieHeader Имя куки
35
36
  */
36
- export declare const getBridgeToNativeDataCookie: (cookieName: string | null) => string | undefined;
37
+ export declare const getBridgeToNativeDataCookie: (cookieHeader: string | null) => string | undefined;
38
+ /**
39
+ * Возвращает десериализованные данные из `bridgeToNativeData` cookie.
40
+ */
41
+ export declare function readNativeParamsFromCookie(cookieHeader: string | null): Partial<NativeParams> | null;
package/server/utils.js CHANGED
@@ -5,6 +5,7 @@ exports.getHeaderValue = getHeaderValue;
5
5
  exports.getQueryValues = getQueryValues;
6
6
  exports.hasBridgeToNativeDataCookie = hasBridgeToNativeDataCookie;
7
7
  exports.parseHeaderTimestamp = parseHeaderTimestamp;
8
+ exports.readNativeParamsFromCookie = readNativeParamsFromCookie;
8
9
  const query_and_headers_keys_1 = require("../query-and-headers-keys");
9
10
  const regexp_patterns_1 = require("./regexp-patterns");
10
11
  /**
@@ -57,13 +58,13 @@ function parseHeaderTimestamp(headerValue) {
57
58
  /**
58
59
  * Возвращает значение для нужной куки
59
60
  *
60
- * @param cookieName Имя куки
61
+ * @param cookieHeader Имя куки
61
62
  */
62
- const getBridgeToNativeDataCookie = (cookieName) => {
63
- if (!cookieName) {
63
+ const getBridgeToNativeDataCookie = (cookieHeader) => {
64
+ if (!cookieHeader) {
64
65
  return undefined;
65
66
  }
66
- const cookies = cookieName.split(';');
67
+ const cookies = cookieHeader.split(';');
67
68
  for (const cookie of cookies) {
68
69
  const [key, value] = cookie.trim().split('=');
69
70
  if (key === query_and_headers_keys_1.COOKIE_KEY_BRIDGE_TO_NATIVE_DATA) {
@@ -73,3 +74,18 @@ const getBridgeToNativeDataCookie = (cookieName) => {
73
74
  return undefined;
74
75
  };
75
76
  exports.getBridgeToNativeDataCookie = getBridgeToNativeDataCookie;
77
+ /**
78
+ * Возвращает десериализованные данные из `bridgeToNativeData` cookie.
79
+ */
80
+ function readNativeParamsFromCookie(cookieHeader) {
81
+ const cookieData = (0, exports.getBridgeToNativeDataCookie)(cookieHeader);
82
+ if (!cookieData) {
83
+ return null;
84
+ }
85
+ try {
86
+ return JSON.parse(decodeURIComponent(cookieData));
87
+ }
88
+ catch {
89
+ return null;
90
+ }
91
+ }
@@ -1 +0,0 @@
1
- export declare const closeWebviewUtil: () => void;
@@ -1,11 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.closeWebviewUtil = void 0;
4
- const QUERY_CLOSE_WEBVIEW_KEY = 'closeWebView';
5
- const QUERY_CLOSE_WEBVIEW_VALUE = 'true';
6
- const closeWebviewUtil = () => {
7
- const originalPageUrl = new URL(window.location.href);
8
- originalPageUrl.searchParams.set(QUERY_CLOSE_WEBVIEW_KEY, QUERY_CLOSE_WEBVIEW_VALUE);
9
- window.location.href = originalPageUrl.toString();
10
- };
11
- exports.closeWebviewUtil = closeWebviewUtil;