@andrey4emk/npm-app-back-b24 3.4.0 → 3.5.0
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/README.md +30 -1
- package/bitrix24/b24.ts +15 -6
- package/package.json +4 -2
- package/utils/fetchRetry.ts +24 -1
package/README.md
CHANGED
|
@@ -26,6 +26,24 @@
|
|
|
26
26
|
npm install @andrey4emk/npm-app-back-b24
|
|
27
27
|
```
|
|
28
28
|
|
|
29
|
+
### Точки входа
|
|
30
|
+
|
|
31
|
+
| Импорт | Что отдаёт | Поднимает OAuth-модуль |
|
|
32
|
+
| --------------------------------------------- | ----------------------------- | ---------------------- |
|
|
33
|
+
| `@andrey4emk/npm-app-back-b24` | всё | да |
|
|
34
|
+
| `@andrey4emk/npm-app-back-b24/logs` | `logs` | нет |
|
|
35
|
+
| `@andrey4emk/npm-app-back-b24/fetchRetry` | `fetchRetry`, `isNetworkError`, `maskUrl` | нет |
|
|
36
|
+
|
|
37
|
+
Корневой импорт — barrel: он тянет модуль OAuth, который при загрузке читает `authB24.json` и, если приложение авторизовано, запускает таймер проактивного обновления токена. Проектам, которые ходят в B24 по **входящему вебхуку** или берут из пакета только логгер и `fetchRetry`, удобнее импортировать по подпутям — тогда OAuth-модуль не загружается вообще.
|
|
38
|
+
|
|
39
|
+
```js
|
|
40
|
+
// Проект без OAuth: ничего лишнего не поднимается
|
|
41
|
+
import { logs } from "@andrey4emk/npm-app-back-b24/logs";
|
|
42
|
+
import { fetchRetry, maskUrl } from "@andrey4emk/npm-app-back-b24/fetchRetry";
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Корневой импорт при этом остаётся безопасным: если `APP_B24_CLIENT_ID` и `APP_B24_CLIENT_SECRET` не заданы, пакет считает, что OAuth в проекте не используется, молча выставляет `$b24 = null` и пишет об этом только в `debug`.
|
|
46
|
+
|
|
29
47
|
## Использование
|
|
30
48
|
|
|
31
49
|
```js
|
|
@@ -46,6 +64,7 @@ import {
|
|
|
46
64
|
logs,
|
|
47
65
|
fetchRetry,
|
|
48
66
|
isNetworkError,
|
|
67
|
+
maskUrl,
|
|
49
68
|
} from "@andrey4emk/npm-app-back-b24";
|
|
50
69
|
|
|
51
70
|
// $b24 — готовый экземпляр B24OAuth (или null, если токены не настроены)
|
|
@@ -116,6 +135,7 @@ const response = await fetchRetry("https://api.example.com/data", { method: "GET
|
|
|
116
135
|
**Особенности:**
|
|
117
136
|
- При обновлении токенов SDK автоматически сохраняет их в файл через callback `setCallbackRefreshAuth`.
|
|
118
137
|
- Окружение (`DEV`/`PROD`) определяется переменной `APP_ENV` — используется как ключ секции в конфиге авторизации.
|
|
138
|
+
- Признак того, что проект использует OAuth, — заданные `APP_B24_CLIENT_ID` и `APP_B24_CLIENT_SECRET`. Если их нет, `$b24` молча становится `null` (уровень `debug`). Если они заданы, но токенов в `authB24.json` не хватает, пишется `error` — это уже настоящая проблема конфигурации.
|
|
119
139
|
|
|
120
140
|
**Retry при сетевых ошибках:**
|
|
121
141
|
|
|
@@ -633,6 +653,15 @@ const response = await fetchRetry("https://api.example.com/data", { method: "GET
|
|
|
633
653
|
|
|
634
654
|
- **`fetchRetry(url, options?, retries?, delay?)`** — обёртка над `fetch` с повторными попытками при сетевых ошибках. HTTP-ошибки (4xx, 5xx) **не** вызывают повторных попыток — повторяются только сетевые сбои (TypeError, ECONNRESET, ETIMEDOUT и т.д.).
|
|
635
655
|
|
|
656
|
+
- **`maskUrl(url)`** — маскирует секреты в адресе перед записью в лог. URL входящего вебхука B24 содержит секрет прямо в пути (`/rest/1/<секрет>/method.json`), а токен авторизации может приходить в query-параметрах (`auth`, `access_token`, `refresh_token`, `token`). Хост и имя метода сохраняются, тело секрета заменяется на `***`. Используется внутри `fetchRetry`; применяйте в своём коде везде, где логируете адреса запросов к B24.
|
|
657
|
+
|
|
658
|
+
```js
|
|
659
|
+
import { maskUrl } from "@andrey4emk/npm-app-back-b24";
|
|
660
|
+
|
|
661
|
+
logs.add(`Запрос не прошёл — ${maskUrl(url)}`, "warn");
|
|
662
|
+
// https://portal.bitrix24.ru/rest/1/***/crm.deal.get.json
|
|
663
|
+
```
|
|
664
|
+
|
|
636
665
|
- **`isNetworkError(error)`** — проверяет, является ли ошибка сетевой (стоит повторить запрос). Используется внутри `fetchRetry` и retry-обёртки `$b24`. Можно использовать в своём коде для аналогичных проверок.
|
|
637
666
|
|
|
638
667
|
```js
|
|
@@ -661,7 +690,7 @@ const response = await fetchRetry("https://api.example.com/data", { method: "GET
|
|
|
661
690
|
- **Обрабатываемые сетевые ошибки:**
|
|
662
691
|
`ECONNRESET`, `ECONNREFUSED`, `ETIMEDOUT`, `ENOTFOUND`, `ENETUNREACH`, `EAI_AGAIN`, `UND_ERR_CONNECT_TIMEOUT`, `UND_ERR_SOCKET`, `TypeError`, а также ошибки с сообщениями `fetch failed`, `network`, `socket`.
|
|
663
692
|
|
|
664
|
-
- **Логирование:** при каждой неудачной попытке записывает сообщение через `logs.add()` с уровнем `
|
|
693
|
+
- **Логирование:** при каждой неудачной попытке записывает сообщение через `logs.add()` с уровнем `warn`. Адрес запроса перед записью пропускается через `maskUrl()`, поэтому секрет вебхука в лог не попадает.
|
|
665
694
|
|
|
666
695
|
```js
|
|
667
696
|
import { fetchRetry } from "@andrey4emk/npm-app-back-b24";
|
package/bitrix24/b24.ts
CHANGED
|
@@ -86,11 +86,12 @@ export function getResultData<T = any>(response: AjaxResult, methodName: string)
|
|
|
86
86
|
// ==================== Создание экземпляра B24OAuth ====================
|
|
87
87
|
|
|
88
88
|
function createB24Instance(): B24OAuth | null {
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
89
|
+
// Проект вообще не использует OAuth: ходит в B24 по входящему вебхуку либо берёт
|
|
90
|
+
// из пакета только logs/fetchRetry. Отсутствие авторизации для него — норма, а не
|
|
91
|
+
// ошибка, поэтому уровень debug: иначе ложная строка попадает в мониторинг.
|
|
92
|
+
// Признак «OAuth задуман» — наличие credentials приложения в .env.
|
|
93
|
+
if (!CLIENT_ID && !CLIENT_SECRET) {
|
|
94
|
+
logs.add("OAuth Bitrix24 не настроен (APP_B24_CLIENT_ID и APP_B24_CLIENT_SECRET не заданы), $b24 = null", "debug");
|
|
94
95
|
return null;
|
|
95
96
|
}
|
|
96
97
|
|
|
@@ -99,6 +100,14 @@ function createB24Instance(): B24OAuth | null {
|
|
|
99
100
|
return null;
|
|
100
101
|
}
|
|
101
102
|
|
|
103
|
+
const store = confAuthB24.store as Record<string, AuthData>;
|
|
104
|
+
const authConfig = store[APP_ENV];
|
|
105
|
+
|
|
106
|
+
if (!authConfig?.domain || !authConfig?.access_token || !authConfig?.refresh_token) {
|
|
107
|
+
logs.add("В конфиге authB24 не хватает данных для авторизации. Сохрани токены через клиент и перезагрузи докер", "error");
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
|
|
102
111
|
const domain = cleanDomain(authConfig.domain);
|
|
103
112
|
|
|
104
113
|
const authParams: B24OAuthParams = {
|
|
@@ -410,7 +419,7 @@ export async function reinitializeB24(): Promise<SaveResult> {
|
|
|
410
419
|
$b24 = _b24Raw ? wrapB24WithRetry(_b24Raw) : null;
|
|
411
420
|
|
|
412
421
|
if (!_b24Raw || !$b24) {
|
|
413
|
-
return { error: true, message: "Не удалось пересоздать $b24 — проверь authB24.json" };
|
|
422
|
+
return { error: true, message: "Не удалось пересоздать $b24 — проверь authB24.json и APP_B24_CLIENT_ID/APP_B24_CLIENT_SECRET" };
|
|
414
423
|
}
|
|
415
424
|
|
|
416
425
|
setupRefreshCallback(_b24Raw);
|
package/package.json
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@andrey4emk/npm-app-back-b24",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.5.0",
|
|
4
4
|
"description": "Bitrix24 OAuth helpers for Node.js projects",
|
|
5
5
|
"main": "index.ts",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"exports": {
|
|
8
|
-
".": "./index.ts"
|
|
8
|
+
".": "./index.ts",
|
|
9
|
+
"./logs": "./logs/logs.ts",
|
|
10
|
+
"./fetchRetry": "./utils/fetchRetry.ts"
|
|
9
11
|
},
|
|
10
12
|
"scripts": {
|
|
11
13
|
"test": "echo \"No tests\" && exit 0",
|
package/utils/fetchRetry.ts
CHANGED
|
@@ -32,6 +32,29 @@ export function isNetworkError(error: unknown): boolean {
|
|
|
32
32
|
return false;
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
+
/**
|
|
36
|
+
* Маскирует секреты в URL перед записью в лог.
|
|
37
|
+
*
|
|
38
|
+
* URL входящего вебхука B24 содержит секрет прямо в пути
|
|
39
|
+
* (`https://портал.bitrix24.ru/rest/1/<секрет>/method.json`), а токен авторизации
|
|
40
|
+
* может приходить в query-параметрах. Хост и имя метода сохраняются — они нужны
|
|
41
|
+
* для диагностики, тело секрета заменяется на `***`.
|
|
42
|
+
*
|
|
43
|
+
* @param url — адрес запроса в любом виде, принимаемом fetch
|
|
44
|
+
* @returns строка URL, пригодная для логирования
|
|
45
|
+
*/
|
|
46
|
+
export function maskUrl(url: string | URL | Request): string {
|
|
47
|
+
const raw = typeof url === "string" ? url : url instanceof URL ? url.href : url.url;
|
|
48
|
+
|
|
49
|
+
return (
|
|
50
|
+
raw
|
|
51
|
+
// Секрет входящего вебхука: /rest/<id пользователя>/<секрет>/
|
|
52
|
+
.replace(/(\/rest\/\d+\/)[^/?#]+/gi, "$1***")
|
|
53
|
+
// Токены в query-параметрах
|
|
54
|
+
.replace(/([?&](?:auth|access_token|refresh_token|token)=)[^&#]+/gi, "$1***")
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
|
|
35
58
|
/**
|
|
36
59
|
* Обёртка над fetch с повторными попытками при сетевых ошибках.
|
|
37
60
|
* Повторяет запрос только при проблемах с сетью (TypeError, ECONNRESET и т.д.),
|
|
@@ -63,7 +86,7 @@ export async function fetchRetry(
|
|
|
63
86
|
}
|
|
64
87
|
|
|
65
88
|
logs.add(
|
|
66
|
-
`fetchRetry: попытка ${attempt}/${retries} не удалась (${lastError.message}), повтор через ${delay}мс — ${
|
|
89
|
+
`fetchRetry: попытка ${attempt}/${retries} не удалась (${lastError.message}), повтор через ${delay}мс — ${maskUrl(url)}`,
|
|
67
90
|
"warn"
|
|
68
91
|
);
|
|
69
92
|
|