@ihazz/bitrix24 0.2.4 → 1.0.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 +118 -164
- package/index.ts +46 -11
- package/openclaw.plugin.json +1 -0
- package/package.json +1 -1
- package/skills/bitrix24/SKILL.md +70 -0
- package/src/access-control.ts +102 -46
- package/src/api.ts +434 -232
- package/src/channel.ts +1486 -393
- package/src/commands.ts +169 -31
- package/src/config-schema.ts +8 -3
- package/src/config.ts +11 -0
- package/src/dedup.ts +4 -0
- package/src/i18n.ts +127 -0
- package/src/inbound-handler.ts +306 -110
- package/src/media-service.ts +218 -65
- package/src/message-utils.ts +252 -10
- package/src/polling-service.ts +240 -0
- package/src/rate-limiter.ts +11 -6
- package/src/send-service.ts +140 -60
- package/src/types.ts +279 -185
- package/src/utils.ts +54 -3
- package/tests/access-control.test.ts +174 -58
- package/tests/api.test.ts +95 -0
- package/tests/channel.test.ts +279 -61
- package/tests/commands.test.ts +57 -0
- package/tests/config.test.ts +5 -1
- package/tests/i18n.test.ts +47 -0
- package/tests/inbound-handler.test.ts +554 -69
- package/tests/index.test.ts +94 -0
- package/tests/media-service.test.ts +146 -51
- package/tests/message-utils.test.ts +64 -0
- package/tests/polling-service.test.ts +77 -0
- package/tests/rate-limiter.test.ts +2 -2
- package/tests/send-service.test.ts +145 -0
package/src/types.ts
CHANGED
|
@@ -1,187 +1,215 @@
|
|
|
1
|
-
// ───
|
|
1
|
+
// ─── Shared Logger interface ─────────────────────────────────────────────────
|
|
2
2
|
|
|
3
|
-
/**
|
|
4
|
-
export interface
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
client_endpoint: string;
|
|
10
|
-
member_id: string;
|
|
11
|
-
user_id: number;
|
|
12
|
-
application_token: string;
|
|
3
|
+
/** Logger interface used across all plugin modules. */
|
|
4
|
+
export interface Logger {
|
|
5
|
+
info: (...args: unknown[]) => void;
|
|
6
|
+
warn: (...args: unknown[]) => void;
|
|
7
|
+
error: (...args: unknown[]) => void;
|
|
8
|
+
debug: (...args: unknown[]) => void;
|
|
13
9
|
}
|
|
14
10
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
11
|
+
// ─── Bitrix24 V2 Event Entity Types (camelCase) ─────────────────────────────
|
|
12
|
+
|
|
13
|
+
/** Bot entity from V2 events (FETCH mode — full format) */
|
|
14
|
+
export interface B24V2Bot {
|
|
15
|
+
id: number;
|
|
16
|
+
code: string;
|
|
17
|
+
type: string;
|
|
18
|
+
isHidden: boolean;
|
|
19
|
+
isSupportOpenline: boolean;
|
|
20
|
+
isReactionsEnabled: boolean;
|
|
21
|
+
backgroundId: string | null;
|
|
22
|
+
language: string;
|
|
23
|
+
moduleId?: string;
|
|
24
|
+
appId?: string;
|
|
25
|
+
eventMode?: string;
|
|
26
|
+
countMessage?: number;
|
|
27
|
+
countCommand?: number;
|
|
28
|
+
countChat?: number;
|
|
29
|
+
countUser?: number;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** Bot entity from V2 webhook events (simplified format with auth) */
|
|
33
|
+
export interface B24V2WebhookBot {
|
|
34
|
+
id: number;
|
|
35
|
+
code: string;
|
|
36
|
+
auth: {
|
|
37
|
+
access_token: string;
|
|
38
|
+
refresh_token: string;
|
|
39
|
+
[key: string]: unknown;
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** User entity from V2 events */
|
|
44
|
+
export interface B24V2User {
|
|
45
|
+
id: number;
|
|
46
|
+
active: boolean;
|
|
47
|
+
name: string;
|
|
48
|
+
firstName: string;
|
|
49
|
+
lastName: string;
|
|
50
|
+
workPosition: string;
|
|
51
|
+
color: string;
|
|
52
|
+
avatar: string;
|
|
53
|
+
gender: string;
|
|
54
|
+
birthday: string;
|
|
55
|
+
extranet: boolean;
|
|
56
|
+
bot: boolean;
|
|
57
|
+
connector: boolean;
|
|
58
|
+
externalAuthId: string;
|
|
59
|
+
status: string;
|
|
60
|
+
idle: string | false;
|
|
61
|
+
lastActivityDate: string | false;
|
|
62
|
+
absent: string | false;
|
|
63
|
+
departments: number[];
|
|
64
|
+
phones: Record<string, string> | false;
|
|
65
|
+
type: string;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/** Message entity from V2 events */
|
|
69
|
+
export interface B24V2Message {
|
|
47
70
|
id: number;
|
|
48
71
|
chatId: number;
|
|
49
|
-
|
|
72
|
+
authorId: number;
|
|
73
|
+
date: string | null;
|
|
74
|
+
text: string;
|
|
75
|
+
isSystem: boolean;
|
|
76
|
+
uuid: string;
|
|
77
|
+
forward: { id: number; userId: number; chatId: number; date: string } | null;
|
|
78
|
+
params: Record<string, unknown>;
|
|
79
|
+
viewedByOthers: boolean;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/** Chat entity from V2 events */
|
|
83
|
+
export interface B24V2Chat {
|
|
84
|
+
id: number;
|
|
85
|
+
dialogId: string;
|
|
86
|
+
type: string;
|
|
87
|
+
name: string;
|
|
88
|
+
messageType?: string;
|
|
89
|
+
entityType: string;
|
|
90
|
+
owner: number;
|
|
91
|
+
avatar: string;
|
|
92
|
+
color: string;
|
|
93
|
+
description?: string;
|
|
94
|
+
extranet?: boolean;
|
|
95
|
+
diskFolderId?: number | null;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/** Command entity from V2 ONIMBOTV2COMMANDADD events */
|
|
99
|
+
export interface B24V2Command {
|
|
100
|
+
id: number;
|
|
101
|
+
command: string;
|
|
102
|
+
params: string;
|
|
103
|
+
context: 'textarea' | 'keyboard' | 'menu';
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/** File entity from V2 responses */
|
|
107
|
+
export interface B24V2File {
|
|
108
|
+
id: number;
|
|
109
|
+
chatId: number;
|
|
110
|
+
date: string | null;
|
|
50
111
|
type: string;
|
|
51
112
|
name: string;
|
|
52
113
|
extension: string;
|
|
53
114
|
size: number;
|
|
54
|
-
image: number;
|
|
55
|
-
status: string;
|
|
56
|
-
progress: number;
|
|
115
|
+
image: { height: number; width: number } | false;
|
|
57
116
|
authorId: number;
|
|
58
117
|
authorName: string;
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
viewerAttrs?: {
|
|
63
|
-
viewer: string;
|
|
64
|
-
viewerType: string;
|
|
65
|
-
src: string;
|
|
66
|
-
objectId: number;
|
|
67
|
-
title: string;
|
|
68
|
-
};
|
|
118
|
+
isTranscribable?: boolean;
|
|
119
|
+
isVideoNote?: boolean;
|
|
120
|
+
isVoiceNote?: boolean;
|
|
69
121
|
}
|
|
70
122
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
TO_USER_ID: number;
|
|
81
|
-
MESSAGE_ID: number;
|
|
82
|
-
CHAT_TYPE: string;
|
|
83
|
-
LANGUAGE?: string;
|
|
84
|
-
PLATFORM_CONTEXT?: string;
|
|
85
|
-
CHAT_USER_COUNT?: number;
|
|
86
|
-
PARAMS?: {
|
|
87
|
-
FILE_ID?: number[];
|
|
88
|
-
[key: string]: unknown;
|
|
89
|
-
};
|
|
90
|
-
FILES?: Record<string, B24File>;
|
|
91
|
-
[key: string]: unknown;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
/** Full ONIMBOTMESSAGEADD event payload */
|
|
95
|
-
export interface B24MessageEvent {
|
|
96
|
-
event: 'ONIMBOTMESSAGEADD';
|
|
97
|
-
event_handler_id?: number;
|
|
98
|
-
data: {
|
|
99
|
-
BOT: Record<string, B24BotEntry>;
|
|
100
|
-
PARAMS: B24MessageParams;
|
|
101
|
-
USER: B24User;
|
|
102
|
-
};
|
|
103
|
-
ts: number;
|
|
104
|
-
auth: B24Auth;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
/** ONIMBOTJOINCHAT event payload */
|
|
108
|
-
export interface B24JoinChatEvent {
|
|
109
|
-
event: 'ONIMBOTJOINCHAT';
|
|
110
|
-
event_handler_id?: number;
|
|
111
|
-
data: {
|
|
112
|
-
BOT: Record<string, B24BotEntry>;
|
|
113
|
-
PARAMS: {
|
|
114
|
-
CHAT_TYPE: string;
|
|
115
|
-
MESSAGE_TYPE: string;
|
|
116
|
-
BOT_ID: number;
|
|
117
|
-
USER_ID: number;
|
|
118
|
-
DIALOG_ID: string;
|
|
119
|
-
LANGUAGE?: string;
|
|
120
|
-
[key: string]: unknown;
|
|
121
|
-
};
|
|
122
|
-
USER: B24User;
|
|
123
|
-
};
|
|
124
|
-
ts: number;
|
|
125
|
-
auth: B24Auth;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
/** Command entry in data.COMMAND map — keyed by COMMAND_ID */
|
|
129
|
-
export interface B24CommandEntry {
|
|
130
|
-
access_token: string;
|
|
131
|
-
BOT_ID: number;
|
|
132
|
-
BOT_CODE: string;
|
|
133
|
-
COMMAND: string;
|
|
134
|
-
COMMAND_ID: number;
|
|
135
|
-
COMMAND_PARAMS: string;
|
|
136
|
-
COMMAND_CONTEXT: 'TEXTAREA' | 'KEYBOARD';
|
|
137
|
-
MESSAGE_ID: number;
|
|
138
|
-
[key: string]: unknown;
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
/** ONIMCOMMANDADD event payload */
|
|
142
|
-
export interface B24CommandEvent {
|
|
143
|
-
event: 'ONIMCOMMANDADD';
|
|
144
|
-
event_handler_id?: number;
|
|
145
|
-
data: {
|
|
146
|
-
COMMAND: Record<string, B24CommandEntry>;
|
|
147
|
-
PARAMS: {
|
|
148
|
-
MESSAGE: string;
|
|
149
|
-
FROM_USER_ID: number;
|
|
150
|
-
DIALOG_ID: string;
|
|
151
|
-
TO_CHAT_ID: number;
|
|
152
|
-
MESSAGE_ID: number;
|
|
153
|
-
CHAT_TYPE: string;
|
|
154
|
-
[key: string]: unknown;
|
|
155
|
-
};
|
|
156
|
-
USER: B24User;
|
|
157
|
-
};
|
|
158
|
-
ts: number;
|
|
159
|
-
auth: B24Auth;
|
|
123
|
+
// ─── V2 Event Data Structures ───────────────────────────────────────────────
|
|
124
|
+
|
|
125
|
+
/** ONIMBOTV2MESSAGEADD / ONIMBOTV2MESSAGEUPDATE data */
|
|
126
|
+
export interface B24V2MessageEventData {
|
|
127
|
+
bot: B24V2Bot | B24V2WebhookBot;
|
|
128
|
+
message: B24V2Message;
|
|
129
|
+
chat: B24V2Chat;
|
|
130
|
+
user: B24V2User;
|
|
131
|
+
language: string;
|
|
160
132
|
}
|
|
161
133
|
|
|
162
|
-
/**
|
|
163
|
-
export interface
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
134
|
+
/** ONIMBOTV2MESSAGEDELETE data */
|
|
135
|
+
export interface B24V2MessageDeleteEventData {
|
|
136
|
+
bot: B24V2Bot | B24V2WebhookBot;
|
|
137
|
+
messageId: number;
|
|
138
|
+
chat: B24V2Chat;
|
|
139
|
+
user: B24V2User;
|
|
140
|
+
language: string;
|
|
168
141
|
}
|
|
169
142
|
|
|
170
|
-
/**
|
|
171
|
-
export interface
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
143
|
+
/** ONIMBOTV2JOINCHAT data */
|
|
144
|
+
export interface B24V2JoinChatEventData {
|
|
145
|
+
bot: B24V2Bot | B24V2WebhookBot;
|
|
146
|
+
dialogId: string;
|
|
147
|
+
chat: B24V2Chat;
|
|
148
|
+
user: B24V2User;
|
|
149
|
+
language: string;
|
|
176
150
|
}
|
|
177
151
|
|
|
178
|
-
/**
|
|
179
|
-
export
|
|
180
|
-
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
152
|
+
/** ONIMBOTV2COMMANDADD data */
|
|
153
|
+
export interface B24V2CommandEventData {
|
|
154
|
+
bot: B24V2Bot | B24V2WebhookBot;
|
|
155
|
+
command: B24V2Command;
|
|
156
|
+
message: B24V2Message;
|
|
157
|
+
chat: B24V2Chat;
|
|
158
|
+
user: B24V2User;
|
|
159
|
+
language: string;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/** ONIMBOTV2DELETE data */
|
|
163
|
+
export interface B24V2DeleteEventData {
|
|
164
|
+
bot: B24V2Bot | B24V2WebhookBot;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/** ONIMBOTV2REACTIONCHANGE data */
|
|
168
|
+
export interface B24V2ReactionEventData {
|
|
169
|
+
bot: B24V2Bot | B24V2WebhookBot;
|
|
170
|
+
reaction: string;
|
|
171
|
+
action: 'set' | 'delete';
|
|
172
|
+
message: B24V2Message;
|
|
173
|
+
chat: B24V2Chat;
|
|
174
|
+
user: B24V2User;
|
|
175
|
+
language: string;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/** Union of V2 event data */
|
|
179
|
+
export type B24V2EventData =
|
|
180
|
+
| B24V2MessageEventData
|
|
181
|
+
| B24V2MessageDeleteEventData
|
|
182
|
+
| B24V2JoinChatEventData
|
|
183
|
+
| B24V2CommandEventData
|
|
184
|
+
| B24V2DeleteEventData
|
|
185
|
+
| B24V2ReactionEventData;
|
|
186
|
+
|
|
187
|
+
// ─── V2 FETCH Event Types ───────────────────────────────────────────────────
|
|
188
|
+
|
|
189
|
+
/** Single event item from imbot.v2.Event.get */
|
|
190
|
+
export interface B24V2FetchEventItem {
|
|
191
|
+
eventId: number;
|
|
192
|
+
type: string;
|
|
193
|
+
date: string;
|
|
194
|
+
data: B24V2EventData;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/** Response from imbot.v2.Event.get */
|
|
198
|
+
export interface B24V2EventGetResult {
|
|
199
|
+
events: B24V2FetchEventItem[];
|
|
200
|
+
lastEventId: number;
|
|
201
|
+
hasMore: boolean;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// ─── V2 Webhook Event (incoming POST) ──────────────────────────────────────
|
|
205
|
+
|
|
206
|
+
/** V2 webhook event payload (POST to webhookUrl) */
|
|
207
|
+
export interface B24V2WebhookEvent {
|
|
208
|
+
event: string;
|
|
209
|
+
data: B24V2EventData;
|
|
210
|
+
ts?: number;
|
|
211
|
+
auth?: Record<string, unknown>;
|
|
212
|
+
}
|
|
185
213
|
|
|
186
214
|
// ─── Bitrix24 API Response Types ─────────────────────────────────────────────
|
|
187
215
|
|
|
@@ -191,7 +219,7 @@ export interface B24ApiResult<T = unknown> {
|
|
|
191
219
|
start: number;
|
|
192
220
|
finish: number;
|
|
193
221
|
duration: number;
|
|
194
|
-
processing
|
|
222
|
+
processing?: number;
|
|
195
223
|
date_start: string;
|
|
196
224
|
date_finish: string;
|
|
197
225
|
};
|
|
@@ -199,9 +227,72 @@ export interface B24ApiResult<T = unknown> {
|
|
|
199
227
|
error_description?: string;
|
|
200
228
|
}
|
|
201
229
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
230
|
+
// ─── V2 API Response Types ──────────────────────────────────────────────────
|
|
231
|
+
|
|
232
|
+
/** Response from imbot.v2.Bot.register / Bot.update */
|
|
233
|
+
export interface B24V2BotResult {
|
|
234
|
+
bot: B24V2Bot;
|
|
235
|
+
users: B24V2User[];
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/** Response from imbot.v2.Bot.list */
|
|
239
|
+
export interface B24V2BotListResult {
|
|
240
|
+
bots: B24V2Bot[];
|
|
241
|
+
users: B24V2User[];
|
|
242
|
+
hasNextPage: boolean;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/** Response from imbot.v2.Chat.Message.send */
|
|
246
|
+
export interface B24V2SendMessageResult {
|
|
247
|
+
id: number;
|
|
248
|
+
uuidMap: Record<string, number>;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/** Available status codes for imbot.v2.Chat.InputAction.notify */
|
|
252
|
+
export type B24InputActionStatusCode =
|
|
253
|
+
| 'IMBOT_AGENT_ACTION_THINKING'
|
|
254
|
+
| 'IMBOT_AGENT_ACTION_SEARCHING'
|
|
255
|
+
| 'IMBOT_AGENT_ACTION_GENERATING'
|
|
256
|
+
| 'IMBOT_AGENT_ACTION_ANALYZING'
|
|
257
|
+
| 'IMBOT_AGENT_ACTION_PROCESSING'
|
|
258
|
+
| 'IMBOT_AGENT_ACTION_TRANSLATING'
|
|
259
|
+
| 'IMBOT_AGENT_ACTION_CONNECTING'
|
|
260
|
+
| 'IMBOT_AGENT_ACTION_CHECKING'
|
|
261
|
+
| 'IMBOT_AGENT_ACTION_CALCULATING'
|
|
262
|
+
| 'IMBOT_AGENT_ACTION_READING_DOCS'
|
|
263
|
+
| 'IMBOT_AGENT_ACTION_COMPOSING';
|
|
264
|
+
|
|
265
|
+
/** Response from imbot.v2.Chat.Message.read */
|
|
266
|
+
export interface B24V2ReadMessageResult {
|
|
267
|
+
chatId: number;
|
|
268
|
+
lastId: number;
|
|
269
|
+
counter: number;
|
|
270
|
+
viewedMessages: number[];
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/** Response from imbot.v2.Command.register */
|
|
274
|
+
export interface B24V2CommandResult {
|
|
275
|
+
command: {
|
|
276
|
+
id: number;
|
|
277
|
+
botId: number;
|
|
278
|
+
command: string;
|
|
279
|
+
common: boolean;
|
|
280
|
+
hidden: boolean;
|
|
281
|
+
extranetSupport: boolean;
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/** Response from imbot.v2.File.upload */
|
|
286
|
+
export interface B24V2FileUploadResult {
|
|
287
|
+
file: B24V2File;
|
|
288
|
+
messageId: number;
|
|
289
|
+
chatId: number;
|
|
290
|
+
dialogId: string;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/** Response from imbot.v2.File.download */
|
|
294
|
+
export interface B24V2FileDownloadResult {
|
|
295
|
+
downloadUrl: string;
|
|
205
296
|
}
|
|
206
297
|
|
|
207
298
|
// ─── Outbound Message Types ──────────────────────────────────────────────────
|
|
@@ -229,31 +320,37 @@ export interface KeyboardNewline {
|
|
|
229
320
|
/** B24 keyboard: flat array with NEWLINE separators between rows */
|
|
230
321
|
export type B24Keyboard = (KeyboardButton | KeyboardNewline)[];
|
|
231
322
|
|
|
232
|
-
export interface SendMessageOptions {
|
|
233
|
-
ATTACH?: unknown;
|
|
234
|
-
KEYBOARD?: B24Keyboard;
|
|
235
|
-
MENU?: unknown;
|
|
236
|
-
SYSTEM?: 'Y' | 'N';
|
|
237
|
-
URL_PREVIEW?: 'Y' | 'N';
|
|
238
|
-
}
|
|
239
|
-
|
|
240
323
|
export interface SendMessageResult {
|
|
241
324
|
ok: boolean;
|
|
242
325
|
messageId?: number;
|
|
243
326
|
error?: string;
|
|
244
327
|
}
|
|
245
328
|
|
|
329
|
+
// ─── FETCH Mode Context ─────────────────────────────────────────────────────
|
|
330
|
+
|
|
331
|
+
/** Context passed from PollingService to InboundHandler for FETCH events */
|
|
332
|
+
export interface FetchContext {
|
|
333
|
+
webhookUrl: string;
|
|
334
|
+
botId: number;
|
|
335
|
+
botToken: string;
|
|
336
|
+
}
|
|
337
|
+
|
|
246
338
|
// ─── Plugin Config Types ─────────────────────────────────────────────────────
|
|
247
339
|
|
|
248
340
|
export interface Bitrix24AccountConfig {
|
|
249
341
|
enabled?: boolean;
|
|
250
342
|
webhookUrl?: string;
|
|
343
|
+
botToken?: string;
|
|
251
344
|
botName?: string;
|
|
252
345
|
botCode?: string;
|
|
253
346
|
botAvatar?: string;
|
|
254
|
-
callbackUrl?: string;
|
|
255
|
-
dmPolicy?: 'open' | 'allowlist' | 'pairing';
|
|
256
347
|
allowFrom?: string[];
|
|
348
|
+
callbackUrl?: string;
|
|
349
|
+
eventMode?: 'fetch' | 'webhook';
|
|
350
|
+
agentMode?: boolean;
|
|
351
|
+
pollingIntervalMs?: number;
|
|
352
|
+
pollingFastIntervalMs?: number;
|
|
353
|
+
dmPolicy?: 'pairing' | 'webhookUser';
|
|
257
354
|
showTyping?: boolean;
|
|
258
355
|
streamUpdates?: boolean;
|
|
259
356
|
updateIntervalMs?: number;
|
|
@@ -273,16 +370,15 @@ export interface B24MsgContext {
|
|
|
273
370
|
chatId: string;
|
|
274
371
|
chatInternalId: string;
|
|
275
372
|
messageId: string;
|
|
373
|
+
replyToMessageId?: string;
|
|
374
|
+
isForwarded?: boolean;
|
|
276
375
|
text: string;
|
|
277
376
|
isDm: boolean;
|
|
278
377
|
isGroup: boolean;
|
|
279
378
|
media: B24MediaItem[];
|
|
280
379
|
platform?: string;
|
|
281
380
|
language?: string;
|
|
282
|
-
raw:
|
|
283
|
-
botToken: string;
|
|
284
|
-
userToken: string;
|
|
285
|
-
clientEndpoint: string;
|
|
381
|
+
raw: B24V2FetchEventItem | B24V2WebhookEvent;
|
|
286
382
|
botId: number;
|
|
287
383
|
memberId: string;
|
|
288
384
|
}
|
|
@@ -302,6 +398,4 @@ export interface PortalState {
|
|
|
302
398
|
botId: number;
|
|
303
399
|
memberId: string;
|
|
304
400
|
domain: string;
|
|
305
|
-
clientEndpoint: string;
|
|
306
|
-
applicationToken: string;
|
|
307
401
|
}
|
package/src/utils.ts
CHANGED
|
@@ -6,6 +6,46 @@ export function maskToken(token: string): string {
|
|
|
6
6
|
return `${token.slice(0, 4)}...${token.slice(-4)}`;
|
|
7
7
|
}
|
|
8
8
|
|
|
9
|
+
/**
|
|
10
|
+
* Mask Bitrix24 webhook credentials in a REST URL before logging it.
|
|
11
|
+
*/
|
|
12
|
+
export function maskWebhookUrl(webhookUrl: string): string {
|
|
13
|
+
try {
|
|
14
|
+
const url = new URL(webhookUrl);
|
|
15
|
+
const pathParts = url.pathname.split('/').filter(Boolean);
|
|
16
|
+
|
|
17
|
+
if (pathParts[0] === 'rest' && pathParts.length >= 3) {
|
|
18
|
+
pathParts[1] = '***';
|
|
19
|
+
pathParts[2] = '***';
|
|
20
|
+
url.pathname = `/${pathParts.join('/')}`;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
url.username = '';
|
|
24
|
+
url.password = '';
|
|
25
|
+
url.search = '';
|
|
26
|
+
return url.toString();
|
|
27
|
+
} catch {
|
|
28
|
+
return '[masked webhook url]';
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Convert an unknown error into a log-friendly plain object.
|
|
34
|
+
*/
|
|
35
|
+
export function serializeError(error: unknown): Record<string, unknown> {
|
|
36
|
+
if (error instanceof Error) {
|
|
37
|
+
return {
|
|
38
|
+
name: error.name,
|
|
39
|
+
message: error.message,
|
|
40
|
+
stack: error.stack,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return {
|
|
45
|
+
message: String(error),
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
9
49
|
/**
|
|
10
50
|
* Retry a function with exponential backoff.
|
|
11
51
|
*/
|
|
@@ -23,12 +63,10 @@ export async function withRetry<T>(
|
|
|
23
63
|
const maxDelayMs = opts.maxDelayMs ?? 10000;
|
|
24
64
|
const shouldRetry = opts.shouldRetry ?? (() => true);
|
|
25
65
|
|
|
26
|
-
let lastError: unknown;
|
|
27
66
|
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
28
67
|
try {
|
|
29
68
|
return await fn();
|
|
30
69
|
} catch (error) {
|
|
31
|
-
lastError = error;
|
|
32
70
|
if (attempt >= maxRetries || !shouldRetry(error)) {
|
|
33
71
|
throw error;
|
|
34
72
|
}
|
|
@@ -37,7 +75,8 @@ export async function withRetry<T>(
|
|
|
37
75
|
await new Promise((r) => setTimeout(r, jitter));
|
|
38
76
|
}
|
|
39
77
|
}
|
|
40
|
-
|
|
78
|
+
// Unreachable: loop always returns or throws
|
|
79
|
+
throw new Error('withRetry: unexpected end of retry loop');
|
|
41
80
|
}
|
|
42
81
|
|
|
43
82
|
/**
|
|
@@ -63,6 +102,18 @@ export class Bitrix24ApiError extends Error {
|
|
|
63
102
|
}
|
|
64
103
|
}
|
|
65
104
|
|
|
105
|
+
/**
|
|
106
|
+
* Regex matching the channel prefix variants: "bitrix24:", "b24:", "bx24:".
|
|
107
|
+
*/
|
|
108
|
+
export const CHANNEL_PREFIX_RE = /^(bitrix24|b24|bx24):/i;
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Strip channel prefix from an identifier (e.g. "bitrix24:42" → "42").
|
|
112
|
+
*/
|
|
113
|
+
export function stripChannelPrefix(id: string): string {
|
|
114
|
+
return id.replace(CHANNEL_PREFIX_RE, '');
|
|
115
|
+
}
|
|
116
|
+
|
|
66
117
|
/**
|
|
67
118
|
* Simple console logger fallback.
|
|
68
119
|
*/
|