@alfalab/bridge-to-native 1.0.0 → 1.0.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/client/services-and-utils/native-navigation-and-title-service.js +2 -0
- package/package.json +1 -1
- package/query-and-headers-keys.d.ts +1 -0
- package/query-and-headers-keys.js +5 -1
- package/server/is-webview-env.js +2 -1
- package/server/prepare-native-app-details-for-client.d.ts +2 -1
- package/server/prepare-native-app-details-for-client.js +35 -10
- package/server/utils.d.ts +2 -1
- package/server/utils.js +13 -4
|
@@ -79,6 +79,8 @@ class NativeNavigationAndTitleService {
|
|
|
79
79
|
reload() {
|
|
80
80
|
this.nativeHistoryStack.push(1 /* NativeHistoryStackSpecialValues.TemporaryReloadStub */); // небольшой костыль, чтобы переиспользовать server-side сценарий
|
|
81
81
|
this.saveNativeHistoryStack();
|
|
82
|
+
// информация для серверной стороны B2N, что происходит `reload` и парсить запрос на предмет NA параметров не нужно (в нем их скорее всего не будет)
|
|
83
|
+
document.cookie = `${query_and_headers_keys_1.COOKIE_KEY_BRIDGE_TO_NATIVE_RELOAD}=true; Path=/`;
|
|
82
84
|
}
|
|
83
85
|
setInitialView(nativeTitle = '') {
|
|
84
86
|
this.nativeHistoryStack = [nativeTitle];
|
package/package.json
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export declare const HEADER_KEY_COOKIE = "cookie";
|
|
2
2
|
export declare const HEADER_KEY_USER_AGENT = "user-agent";
|
|
3
3
|
export declare const COOKIE_KEY_BRIDGE_TO_NATIVE_DATA = "bridgeToNativeData";
|
|
4
|
+
export declare const COOKIE_KEY_BRIDGE_TO_NATIVE_RELOAD = "bridgeToNativeReload";
|
|
4
5
|
export declare const HEADER_KEY_NATIVE_APPVERSION = "app-version";
|
|
5
6
|
export declare const QUERY_B2N_NEXT_PAGEID = "b2n-next-page-id";
|
|
6
7
|
export declare const QUERY_B2N_TITLE = "b2n-title";
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Ключи стандартных заголовков.
|
|
4
4
|
*/
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.SS_KEY_BRIDGE_TO_NATIVE_HISTORY_STACK = exports.QUERY_NATIVE_THEME = exports.QUERY_NATIVE_IOS_APPVERSION = exports.QUERY_NATIVE_IOS_APPID = exports.QUERY_B2N_TITLE_DEPRECATED = exports.QUERY_B2N_TITLE = exports.QUERY_B2N_NEXT_PAGEID = exports.HEADER_KEY_NATIVE_APPVERSION = exports.COOKIE_KEY_BRIDGE_TO_NATIVE_DATA = exports.HEADER_KEY_USER_AGENT = exports.HEADER_KEY_COOKIE = void 0;
|
|
6
|
+
exports.SS_KEY_BRIDGE_TO_NATIVE_HISTORY_STACK = exports.QUERY_NATIVE_THEME = exports.QUERY_NATIVE_IOS_APPVERSION = exports.QUERY_NATIVE_IOS_APPID = exports.QUERY_B2N_TITLE_DEPRECATED = exports.QUERY_B2N_TITLE = exports.QUERY_B2N_NEXT_PAGEID = exports.HEADER_KEY_NATIVE_APPVERSION = exports.COOKIE_KEY_BRIDGE_TO_NATIVE_RELOAD = exports.COOKIE_KEY_BRIDGE_TO_NATIVE_DATA = exports.HEADER_KEY_USER_AGENT = exports.HEADER_KEY_COOKIE = void 0;
|
|
7
7
|
exports.HEADER_KEY_COOKIE = 'cookie';
|
|
8
8
|
exports.HEADER_KEY_USER_AGENT = 'user-agent';
|
|
9
9
|
/*
|
|
@@ -11,6 +11,10 @@ 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, указывающий, что запрос выполнен после вызова `bridgeToNative.reload()`.
|
|
15
|
+
// Используется для предотвращения перезаписи cookie bridgeToNativeData, чтобы сохранить
|
|
16
|
+
// актуальные параметры нативного приложения
|
|
17
|
+
exports.COOKIE_KEY_BRIDGE_TO_NATIVE_RELOAD = 'bridgeToNativeReload';
|
|
14
18
|
// Нативное приложение на обеих платформах подмешивает этот заголовок к запросу за HTML.
|
|
15
19
|
// TODO:
|
|
16
20
|
// * Исследовать, делает ли оно это при запросах к прочим ресурсам;
|
package/server/is-webview-env.js
CHANGED
|
@@ -11,7 +11,8 @@ const utils_1 = require("./utils");
|
|
|
11
11
|
*/
|
|
12
12
|
function isWebviewEnv(request) {
|
|
13
13
|
// Выставленная ранее кука — однозначный индикатор вебвью окружения.
|
|
14
|
-
|
|
14
|
+
const cookieHeader = (0, utils_1.getHeaderValue)(request, query_and_headers_keys_1.HEADER_KEY_COOKIE);
|
|
15
|
+
if ((0, utils_1.hasBridgeToNativeDataCookie)(cookieHeader)) {
|
|
15
16
|
return true;
|
|
16
17
|
}
|
|
17
18
|
const appVersion = (0, utils_1.getHeaderValue)(request, query_and_headers_keys_1.HEADER_KEY_NATIVE_APPVERSION);
|
|
@@ -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):
|
|
14
|
+
export declare function prepareNativeAppDetailsForClient(request: UniversalRequest, setResponseHeader: (headerKey: string, headerValue: string) => void): Partial<NativeParams>;
|
|
@@ -17,17 +17,27 @@ const utils_1 = require("./utils");
|
|
|
17
17
|
* b2native с её помощью добавит `Set-Cookie` заголовок с некоторыми данными для своего клиентского кода.
|
|
18
18
|
*/
|
|
19
19
|
function prepareNativeAppDetailsForClient(request, setResponseHeader) {
|
|
20
|
-
//
|
|
21
|
-
//
|
|
22
|
-
//
|
|
23
|
-
//
|
|
24
|
-
//
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
20
|
+
// Проверяем наличие куки bridgeToNativeData в запросе. Если куки нет — устанавливаем её.
|
|
21
|
+
// Также сверяем тему из query-параметров с темой, сохранённой в куке, потому что
|
|
22
|
+
// при повторном открытии WebView сессионная кука может сохраниться, и если тема приложения
|
|
23
|
+
// изменилась между сессиями, WebView и нативное приложение будут не синхронизированы.
|
|
24
|
+
// В таком случае обновляем куку актуальными данными из query-параметров
|
|
25
|
+
// Для случая когда передан флаг `reload` куку перезаписывать не нужно, потому что:
|
|
26
|
+
// 1) Данных NA в запросе с большой вероятностью не будет;
|
|
27
|
+
// 2) клиентская сторона сохранит всё, что нужно в SessionStorage
|
|
28
|
+
const cookieHeader = (0, utils_1.getHeaderValue)(request, query_and_headers_keys_1.HEADER_KEY_COOKIE);
|
|
28
29
|
const nativeParams = parseRequest(request);
|
|
29
|
-
const
|
|
30
|
-
|
|
30
|
+
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
|
+
if (hasReloadFlag) {
|
|
38
|
+
setResponseHeader('Set-Cookie', `${query_and_headers_keys_1.COOKIE_KEY_BRIDGE_TO_NATIVE_RELOAD}=false; Max-Age=0; Path=/`);
|
|
39
|
+
}
|
|
40
|
+
return nativeParams;
|
|
31
41
|
}
|
|
32
42
|
function parseRequest(request) {
|
|
33
43
|
// Прихраним «сервисные» query-параметры от нативного приложения,
|
|
@@ -76,3 +86,18 @@ function parseRequest(request) {
|
|
|
76
86
|
}
|
|
77
87
|
return nativeParams;
|
|
78
88
|
}
|
|
89
|
+
// Возвращает результат сравнения темы полученной, из query-параметров
|
|
90
|
+
// с темой, полученной из cookie
|
|
91
|
+
function isSameTheme(request, cookies) {
|
|
92
|
+
if (!cookies)
|
|
93
|
+
return false;
|
|
94
|
+
const [themeFromQuery] = (0, utils_1.getQueryValues)(request, [query_and_headers_keys_1.QUERY_NATIVE_THEME]);
|
|
95
|
+
const parsedCookies = (0, utils_1.parseCookies)(cookies);
|
|
96
|
+
const bridgeCookie = parsedCookies[query_and_headers_keys_1.COOKIE_KEY_BRIDGE_TO_NATIVE_DATA];
|
|
97
|
+
try {
|
|
98
|
+
return JSON.parse(bridgeCookie || '{}').theme === themeFromQuery;
|
|
99
|
+
}
|
|
100
|
+
catch (_) {
|
|
101
|
+
return false;
|
|
102
|
+
}
|
|
103
|
+
}
|
package/server/utils.d.ts
CHANGED
|
@@ -21,4 +21,5 @@ export declare function getQueryValues(request: UniversalRequest, queryKeys: str
|
|
|
21
21
|
*
|
|
22
22
|
* @param request Объект запроса (Request или IncomingMessage).
|
|
23
23
|
*/
|
|
24
|
-
export declare function hasBridgeToNativeDataCookie(
|
|
24
|
+
export declare function hasBridgeToNativeDataCookie(cookieHeader: string | null): boolean;
|
|
25
|
+
export declare function parseCookies(cookieHeader: string): Record<string, string>;
|
package/server/utils.js
CHANGED
|
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.getHeaderValue = getHeaderValue;
|
|
4
4
|
exports.getQueryValues = getQueryValues;
|
|
5
5
|
exports.hasBridgeToNativeDataCookie = hasBridgeToNativeDataCookie;
|
|
6
|
-
|
|
6
|
+
exports.parseCookies = parseCookies;
|
|
7
7
|
const regexp_patterns_1 = require("./regexp-patterns");
|
|
8
8
|
/**
|
|
9
9
|
* На основе объекта запроса любого типа возвращает
|
|
@@ -38,7 +38,16 @@ function getQueryValues(request, queryKeys) {
|
|
|
38
38
|
*
|
|
39
39
|
* @param request Объект запроса (Request или IncomingMessage).
|
|
40
40
|
*/
|
|
41
|
-
function hasBridgeToNativeDataCookie(
|
|
42
|
-
|
|
43
|
-
|
|
41
|
+
function hasBridgeToNativeDataCookie(cookieHeader) {
|
|
42
|
+
return Boolean(cookieHeader && regexp_patterns_1.bridgeToNativeDataCookieExistencePattern.test(cookieHeader));
|
|
43
|
+
}
|
|
44
|
+
function parseCookies(cookieHeader) {
|
|
45
|
+
return cookieHeader.split(';').reduce((acc, part) => {
|
|
46
|
+
const [key, ...rest] = part.split('=');
|
|
47
|
+
const trimmedKey = key.trim();
|
|
48
|
+
if (!trimmedKey)
|
|
49
|
+
return acc;
|
|
50
|
+
acc[trimmedKey] = decodeURIComponent(rest.join('=').trim());
|
|
51
|
+
return acc;
|
|
52
|
+
}, {});
|
|
44
53
|
}
|