@andrey4emk/npm-app-back-b24 3.7.0 → 3.7.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/README.md +12 -0
- package/package.json +8 -8
- package/sendMessage/chatApp.ts +41 -6
package/README.md
CHANGED
|
@@ -44,6 +44,12 @@ import { fetchRetry, maskUrl } from "@andrey4emk/npm-app-back-b24/fetchRetry";
|
|
|
44
44
|
|
|
45
45
|
Корневой импорт при этом остаётся безопасным: если `APP_B24_CLIENT_ID` и `APP_B24_CLIENT_SECRET` не заданы, пакет считает, что OAuth в проекте не используется, молча выставляет `$b24 = null` и пишет об этом только в `debug`.
|
|
46
46
|
|
|
47
|
+
### Строгость типов
|
|
48
|
+
|
|
49
|
+
Пакет публикуется исходниками на TypeScript и компилируется **в программе потребителя** — значит его код проверяется настройками потребителя, а не нашими. Поэтому сам пакет собирается с `strict` и `noUncheckedIndexedAccess`: на настройках Nuxt (где оба флага включены) штатный `nuxt typecheck` проходит по коду пакета без обходных скриптов и без `skipLibCheck`-заплаток.
|
|
50
|
+
|
|
51
|
+
Практическое следствие: индексация массива внутри пакета всегда сопровождается проверкой на `undefined`. Если в своём проекте эти флаги включены — ошибок из `node_modules/@andrey4emk/npm-app-back-b24` быть не должно.
|
|
52
|
+
|
|
47
53
|
## Использование
|
|
48
54
|
|
|
49
55
|
```js
|
|
@@ -493,6 +499,10 @@ const response = await fetchRetry("https://api.example.com/data", { method: "GET
|
|
|
493
499
|
);
|
|
494
500
|
```
|
|
495
501
|
|
|
502
|
+
Конструктор сразу разрешает тип мессенджера для `whatsApp` и `telegram` — берёт `messenger[0].type` и держит в полях, вместо того чтобы индексировать массив при каждой отправке. Если конфига нет или список `messenger` пуст, тип остаётся неразрешённым, и **методы этого мессенджера возвращают** `{ error: true, message: "ChatApp: не разрешён тип мессенджера whatsApp (нет конфига или пуст messenger)", data: null }` — вместо запроса на URL с `undefined` в пути. Конструктор при этом **не бросает**: экземпляр обычно создаётся на уровне модуля, и бросок уронил бы загрузку всего модуля отправки вместе с соседними каналами.
|
|
503
|
+
|
|
504
|
+
Отказ локальный: пустой `whatsApp` не мешает `telegram`. Но конфиг всё равно нужен для **обоих** мессенджеров, даже если проект пользуется одним — иначе второй канал молча перестанет работать, и узнать об этом можно будет только по `res.error` в логе.
|
|
505
|
+
|
|
496
506
|
**Методы:**
|
|
497
507
|
|
|
498
508
|
- **`makeTokenChatApp()`** — получить токены доступа для ChatApp API.
|
|
@@ -629,6 +639,8 @@ const response = await fetchRetry("https://api.example.com/data", { method: "GET
|
|
|
629
639
|
- **Особенности:**
|
|
630
640
|
- SMTP-сервер: `smtp.yandex.ru:465` (SMTPS).
|
|
631
641
|
- Копия письма автоматически отправляется на адрес отправителя.
|
|
642
|
+
- Транспорт — `nodemailer` `^9` (диапазон, а не точная версия: иначе патч безопасности нельзя было бы применить на стороне потребителя).
|
|
643
|
+
- Вложения передаются готовым `Buffer` — файл по `fileUrl` пакет скачивает сам. Поля `path` и `href` намеренно не поддерживаются: nodemailer не должен ходить по URL.
|
|
632
644
|
|
|
633
645
|
### Wappi
|
|
634
646
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@andrey4emk/npm-app-back-b24",
|
|
3
|
-
"version": "3.7.
|
|
3
|
+
"version": "3.7.1",
|
|
4
4
|
"description": "Bitrix24 OAuth helpers for Node.js projects",
|
|
5
5
|
"main": "index.ts",
|
|
6
6
|
"type": "module",
|
|
@@ -39,12 +39,12 @@
|
|
|
39
39
|
"dependencies": {
|
|
40
40
|
"@bitrix24/b24jssdk": "2.0.0",
|
|
41
41
|
"@types/express": "5.0.6",
|
|
42
|
-
"@types/luxon": "3.7.
|
|
43
|
-
"@types/node": "25.
|
|
44
|
-
"@types/nodemailer": "
|
|
45
|
-
"conf": "15.0
|
|
46
|
-
"dotenv": "17.2
|
|
47
|
-
"luxon": "3.
|
|
48
|
-
"nodemailer": "
|
|
42
|
+
"@types/luxon": "3.7.4",
|
|
43
|
+
"@types/node": "25.9.5",
|
|
44
|
+
"@types/nodemailer": "8.0.1",
|
|
45
|
+
"conf": "15.1.0",
|
|
46
|
+
"dotenv": "17.4.2",
|
|
47
|
+
"luxon": "3.7.2",
|
|
48
|
+
"nodemailer": "^9.0.5"
|
|
49
49
|
}
|
|
50
50
|
}
|
package/sendMessage/chatApp.ts
CHANGED
|
@@ -57,12 +57,32 @@ export class ChatApp {
|
|
|
57
57
|
private auth: ChatAppAuthParam;
|
|
58
58
|
private type: ChatAppTypeParam;
|
|
59
59
|
private updateToken: boolean;
|
|
60
|
+
private readonly whatsAppType: string | null;
|
|
61
|
+
private readonly telegramType: string | null;
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Тип мессенджера из конфига. Массив приходит из внешнего источника
|
|
65
|
+
* (config/chatApp.json обновляется данными API ChatApp), поэтому проверяем:
|
|
66
|
+
* пустой messenger дал бы URL с undefined и «отправку в никуда».
|
|
67
|
+
* Не бросаем: экземпляр создаётся на уровне модуля, и бросок уронил бы
|
|
68
|
+
* импорт всего модуля отправки вместе с остальными каналами. Отказ локальный —
|
|
69
|
+
* его возвращают методы того мессенджера, который не разрешился.
|
|
70
|
+
*/
|
|
71
|
+
private static resolveMessengerType(config: MessengerConfig | undefined): string | null {
|
|
72
|
+
const first = config?.messenger?.[0];
|
|
73
|
+
if (typeof first?.type !== "string" || !first.type.trim()) {
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
return first.type;
|
|
77
|
+
}
|
|
60
78
|
|
|
61
79
|
constructor(makeParam: ChatAppMakeParam, authParam: ChatAppAuthParam, typeParam: ChatAppTypeParam) {
|
|
62
80
|
this.make = makeParam;
|
|
63
81
|
this.auth = authParam;
|
|
64
82
|
this.type = typeParam;
|
|
65
83
|
this.updateToken = false;
|
|
84
|
+
this.whatsAppType = ChatApp.resolveMessengerType(typeParam?.whatsApp);
|
|
85
|
+
this.telegramType = ChatApp.resolveMessengerType(typeParam?.telegram);
|
|
66
86
|
}
|
|
67
87
|
|
|
68
88
|
async sendMessageChatApp(messangerType: MessengerType, messageData: MessageData): Promise<ChatAppResult> {
|
|
@@ -73,6 +93,11 @@ export class ChatApp {
|
|
|
73
93
|
if (!messageData.phone || !messageData.message) {
|
|
74
94
|
return { error: true, message: "Отсутствует phone или message", data: null };
|
|
75
95
|
}
|
|
96
|
+
// Тип мессенджера не разрешился из конфига — отправлять некуда
|
|
97
|
+
const resolvedType = messangerType === "whatsApp" ? this.whatsAppType : this.telegramType;
|
|
98
|
+
if (!resolvedType) {
|
|
99
|
+
return { error: true, message: `ChatApp: не разрешён тип мессенджера ${messangerType} (нет конфига или пуст messenger)`, data: null };
|
|
100
|
+
}
|
|
76
101
|
|
|
77
102
|
const check = await this.checkTokenChatApp();
|
|
78
103
|
if (check.error) {
|
|
@@ -84,10 +109,10 @@ export class ChatApp {
|
|
|
84
109
|
|
|
85
110
|
let url: string | undefined;
|
|
86
111
|
if (messangerType === "whatsApp") {
|
|
87
|
-
url = `https://api.chatapp.online/v1/licenses/${this.type.whatsApp.licenseId}/messengers/${
|
|
112
|
+
url = `https://api.chatapp.online/v1/licenses/${this.type.whatsApp.licenseId}/messengers/${resolvedType}/chats/${phone}/messages/text`;
|
|
88
113
|
}
|
|
89
114
|
if (messangerType === "telegram") {
|
|
90
|
-
url = `https://api.chatapp.online/v1/licenses/${this.type.telegram.licenseId}/messengers/${
|
|
115
|
+
url = `https://api.chatapp.online/v1/licenses/${this.type.telegram.licenseId}/messengers/${resolvedType}/chats/${phone}/messages/text`;
|
|
91
116
|
}
|
|
92
117
|
|
|
93
118
|
const res = await fetch(url!, {
|
|
@@ -123,6 +148,11 @@ export class ChatApp {
|
|
|
123
148
|
if (!messageData.phone || !messageData.message) {
|
|
124
149
|
return { error: true, message: "Отсутствует phone или message", data: null };
|
|
125
150
|
}
|
|
151
|
+
// Тип мессенджера не разрешился из конфига — отправлять некуда
|
|
152
|
+
const resolvedType = messangerType === "whatsApp" ? this.whatsAppType : this.telegramType;
|
|
153
|
+
if (!resolvedType) {
|
|
154
|
+
return { error: true, message: `ChatApp: не разрешён тип мессенджера ${messangerType} (нет конфига или пуст messenger)`, data: null };
|
|
155
|
+
}
|
|
126
156
|
|
|
127
157
|
const check = await this.checkTokenChatApp();
|
|
128
158
|
if (check.error) {
|
|
@@ -136,10 +166,10 @@ export class ChatApp {
|
|
|
136
166
|
|
|
137
167
|
let url: string | undefined;
|
|
138
168
|
if (messangerType === "whatsApp") {
|
|
139
|
-
url = `https://api.chatapp.online/v1/licenses/${this.type.whatsApp.licenseId}/messengers/${
|
|
169
|
+
url = `https://api.chatapp.online/v1/licenses/${this.type.whatsApp.licenseId}/messengers/${resolvedType}/chats/${phone}/messages/file`;
|
|
140
170
|
}
|
|
141
171
|
if (messangerType === "telegram") {
|
|
142
|
-
url = `https://api.chatapp.online/v1/licenses/${this.type.telegram.licenseId}/messengers/${
|
|
172
|
+
url = `https://api.chatapp.online/v1/licenses/${this.type.telegram.licenseId}/messengers/${resolvedType}/chats/${phone}/messages/file`;
|
|
143
173
|
}
|
|
144
174
|
|
|
145
175
|
const res = await fetch(url!, {
|
|
@@ -171,6 +201,11 @@ export class ChatApp {
|
|
|
171
201
|
if (!["whatsApp", "telegram"].includes(messangerType)) {
|
|
172
202
|
return { error: true, message: "Неверный тип мессенджера", data: null };
|
|
173
203
|
}
|
|
204
|
+
// Тип мессенджера не разрешился из конфига — проверять телефон негде
|
|
205
|
+
const resolvedType = messangerType === "whatsApp" ? this.whatsAppType : this.telegramType;
|
|
206
|
+
if (!resolvedType) {
|
|
207
|
+
return { error: true, message: `ChatApp: не разрешён тип мессенджера ${messangerType} (нет конфига или пуст messenger)`, data: null };
|
|
208
|
+
}
|
|
174
209
|
|
|
175
210
|
const check = await this.checkTokenChatApp();
|
|
176
211
|
if (check.error) {
|
|
@@ -179,10 +214,10 @@ export class ChatApp {
|
|
|
179
214
|
|
|
180
215
|
let url: string | undefined;
|
|
181
216
|
if (messangerType === "whatsApp") {
|
|
182
|
-
url = `https://api.chatapp.online/v1/licenses/${this.type.whatsApp.licenseId}/messengers/${
|
|
217
|
+
url = `https://api.chatapp.online/v1/licenses/${this.type.whatsApp.licenseId}/messengers/${resolvedType}/phones/${phone}/check`;
|
|
183
218
|
}
|
|
184
219
|
if (messangerType === "telegram") {
|
|
185
|
-
url = `https://api.chatapp.online/v1/licenses/${this.type.telegram.licenseId}/messengers/${
|
|
220
|
+
url = `https://api.chatapp.online/v1/licenses/${this.type.telegram.licenseId}/messengers/${resolvedType}/phones/${phone}/check`;
|
|
186
221
|
}
|
|
187
222
|
|
|
188
223
|
const res = await fetch(url!, {
|