@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,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):
|
|
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
|
-
//
|
|
21
|
-
//
|
|
22
|
-
// при
|
|
23
|
-
//
|
|
24
|
-
//
|
|
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;
|