@alfalab/bridge-to-native 1.2.0 → 1.2.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alfalab/bridge-to-native",
3
- "version": "1.2.0",
3
+ "version": "1.2.1",
4
4
  "license": "MIT",
5
5
  "description": "Утилита для удобной работы веб приложения внутри нативного приложения и коммуникации с ним.",
6
6
  "engines": {
@@ -1,4 +1,3 @@
1
- import { type NativeParams } from '../types';
2
1
  import { type UniversalRequest } from './types';
3
2
  /**
4
3
  * Парсит запрос, доставая из него данные о нативном приложении,
@@ -11,4 +10,4 @@ import { type UniversalRequest } from './types';
11
10
  * Нужно передать функцию, которая средствами используемого веб-сервера добавит заголовок в ответ.
12
11
  * b2native с её помощью добавит `Set-Cookie` заголовок с некоторыми данными для своего клиентского кода.
13
12
  */
14
- export declare function prepareNativeAppDetailsForClient(request: UniversalRequest, setResponseHeader: (headerKey: string, headerValue: string) => void): Partial<NativeParams>;
13
+ export declare function prepareNativeAppDetailsForClient(request: UniversalRequest, setResponseHeader: (headerKey: string, headerValue: string) => void): any;
@@ -17,26 +17,30 @@ const utils_1 = require("./utils");
17
17
  * b2native с её помощью добавит `Set-Cookie` заголовок с некоторыми данными для своего клиентского кода.
18
18
  */
19
19
  function prepareNativeAppDetailsForClient(request, setResponseHeader) {
20
- // Проверяем наличие куки bridgeToNativeData в запросе. Если куки нет — устанавливаем её.
21
- // Также сверяем тему из query-параметров с темой, сохранённой в куке, потому что
22
- // при повторном открытии WebView сессионная кука может сохраниться, и если тема приложения
23
- // изменилась между сессиями, WebView и нативное приложение будут не синхронизированы.
24
- // В таком случае обновляем куку актуальными данными из query-параметров
25
- // Для случая когда передан флаг `reload` куку перезаписывать не нужно, потому что:
20
+ // Поскольку вебвью модули имеют особенность сохранять сессионную куку подолгу,
21
+ // даже после перезагрузки устройства или обновления приложения/ОС, ее значение
22
+ // актуализируется при каждом запросе на сервер. Исключением является вызов `reload()`.
23
+ // В этом случае функция возвращает объект с параметрами, полученными из
24
+ // ранее сохраненной куки, но перезаписываться кука не будет, потому что:
26
25
  // 1) Данных NA в запросе с большой вероятностью не будет;
27
26
  // 2) клиентская сторона сохранит всё, что нужно в SessionStorage
28
27
  const cookieHeader = (0, utils_1.getHeaderValue)(request, query_and_headers_keys_1.HEADER_KEY_COOKIE);
29
- const nativeParams = parseRequest(request);
30
28
  const hasReloadFlag = cookieHeader?.includes(`${query_and_headers_keys_1.COOKIE_KEY_BRIDGE_TO_NATIVE_RELOAD}=true`);
31
- const shouldUpdateCookie = !(0, utils_1.hasBridgeToNativeDataCookie)(cookieHeader) || !isSameTheme(request, cookieHeader);
32
- if (!hasReloadFlag && shouldUpdateCookie) {
33
- const serializedNativeParams = encodeURIComponent(JSON.stringify(nativeParams));
34
- setResponseHeader('Set-Cookie', `${query_and_headers_keys_1.COOKIE_KEY_BRIDGE_TO_NATIVE_DATA}=${serializedNativeParams}; Path=/`);
35
- return nativeParams;
36
- }
37
29
  if (hasReloadFlag) {
38
30
  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
+ }
39
+ }
39
40
  }
41
+ const nativeParams = parseRequest(request);
42
+ const serializedNativeParams = encodeURIComponent(JSON.stringify(nativeParams));
43
+ setResponseHeader('Set-Cookie', `${query_and_headers_keys_1.COOKIE_KEY_BRIDGE_TO_NATIVE_DATA}=${serializedNativeParams}; Path=/`);
40
44
  return nativeParams;
41
45
  }
42
46
  function parseRequest(request) {
@@ -90,18 +94,3 @@ function parseRequest(request) {
90
94
  }
91
95
  return nativeParams;
92
96
  }
93
- // Возвращает результат сравнения темы полученной, из query-параметров
94
- // с темой, полученной из cookie
95
- function isSameTheme(request, cookies) {
96
- if (!cookies)
97
- return false;
98
- const [themeFromQuery] = (0, utils_1.getQueryValues)(request, [query_and_headers_keys_1.QUERY_NATIVE_THEME]);
99
- const parsedCookies = (0, utils_1.parseCookies)(cookies);
100
- const bridgeCookie = parsedCookies[query_and_headers_keys_1.COOKIE_KEY_BRIDGE_TO_NATIVE_DATA];
101
- try {
102
- return JSON.parse(bridgeCookie || '{}').theme === themeFromQuery;
103
- }
104
- catch (_) {
105
- return false;
106
- }
107
- }
package/server/utils.d.ts CHANGED
@@ -22,10 +22,15 @@ export declare function getQueryValues(request: UniversalRequest, queryKeys: str
22
22
  * @param request Объект запроса (Request или IncomingMessage).
23
23
  */
24
24
  export declare function hasBridgeToNativeDataCookie(cookieHeader: string | null): boolean;
25
- export declare function parseCookies(cookieHeader: string): Record<string, string>;
26
25
  /**
27
26
  * Преобразует значение из заголовка в timestamp
28
27
  *
29
28
  * @param headerValue Значение заголовка
30
29
  */
31
30
  export declare function parseHeaderTimestamp(headerValue: string | number | null): number | null;
31
+ /**
32
+ * Возвращает значение для нужной куки
33
+ *
34
+ * @param cookieName Имя куки
35
+ */
36
+ export declare const getBridgeToNativeDataCookie: (cookieName: string | null) => string | undefined;
package/server/utils.js CHANGED
@@ -1,10 +1,11 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getBridgeToNativeDataCookie = void 0;
3
4
  exports.getHeaderValue = getHeaderValue;
4
5
  exports.getQueryValues = getQueryValues;
5
6
  exports.hasBridgeToNativeDataCookie = hasBridgeToNativeDataCookie;
6
- exports.parseCookies = parseCookies;
7
7
  exports.parseHeaderTimestamp = parseHeaderTimestamp;
8
+ const query_and_headers_keys_1 = require("../query-and-headers-keys");
8
9
  const regexp_patterns_1 = require("./regexp-patterns");
9
10
  /**
10
11
  * На основе объекта запроса любого типа возвращает
@@ -42,16 +43,6 @@ function getQueryValues(request, queryKeys) {
42
43
  function hasBridgeToNativeDataCookie(cookieHeader) {
43
44
  return Boolean(cookieHeader && regexp_patterns_1.bridgeToNativeDataCookieExistencePattern.test(cookieHeader));
44
45
  }
45
- function parseCookies(cookieHeader) {
46
- return cookieHeader.split(';').reduce((acc, part) => {
47
- const [key, ...rest] = part.split('=');
48
- const trimmedKey = key.trim();
49
- if (!trimmedKey)
50
- return acc;
51
- acc[trimmedKey] = decodeURIComponent(rest.join('=').trim());
52
- return acc;
53
- }, {});
54
- }
55
46
  /**
56
47
  * Преобразует значение из заголовка в timestamp
57
48
  *
@@ -63,3 +54,22 @@ function parseHeaderTimestamp(headerValue) {
63
54
  const timestamp = Number(headerValue);
64
55
  return Number.isFinite(timestamp) ? timestamp : null;
65
56
  }
57
+ /**
58
+ * Возвращает значение для нужной куки
59
+ *
60
+ * @param cookieName Имя куки
61
+ */
62
+ const getBridgeToNativeDataCookie = (cookieName) => {
63
+ if (!cookieName) {
64
+ return undefined;
65
+ }
66
+ const cookies = cookieName.split(';');
67
+ for (const cookie of cookies) {
68
+ const [key, value] = cookie.trim().split('=');
69
+ if (key === query_and_headers_keys_1.COOKIE_KEY_BRIDGE_TO_NATIVE_DATA) {
70
+ return value;
71
+ }
72
+ }
73
+ return undefined;
74
+ };
75
+ exports.getBridgeToNativeDataCookie = getBridgeToNativeDataCookie;