@ihazz/bitrix24 1.1.2 → 1.1.4
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 +5 -0
- package/dist/index.d.ts +30 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +55 -0
- package/dist/index.js.map +1 -0
- package/dist/src/access-control.d.ts +43 -0
- package/dist/src/access-control.d.ts.map +1 -0
- package/dist/src/access-control.js +128 -0
- package/dist/src/access-control.js.map +1 -0
- package/dist/src/api.d.ts +161 -0
- package/dist/src/api.d.ts.map +1 -0
- package/dist/src/api.js +357 -0
- package/dist/src/api.js.map +1 -0
- package/dist/src/bot-avatar.d.ts +7 -0
- package/dist/src/bot-avatar.d.ts.map +1 -0
- package/dist/src/bot-avatar.js +7 -0
- package/dist/src/bot-avatar.js.map +1 -0
- package/dist/src/channel.d.ts +216 -0
- package/dist/src/channel.d.ts.map +1 -0
- package/dist/src/channel.js +2324 -0
- package/dist/src/channel.js.map +1 -0
- package/dist/src/commands.d.ts +22 -0
- package/dist/src/commands.d.ts.map +1 -0
- package/dist/src/commands.js +160 -0
- package/dist/src/commands.js.map +1 -0
- package/dist/src/config-schema.d.ts +356 -0
- package/dist/src/config-schema.d.ts.map +1 -0
- package/dist/src/config-schema.js +43 -0
- package/dist/src/config-schema.js.map +1 -0
- package/dist/src/config.d.ts +11 -0
- package/dist/src/config.d.ts.map +1 -0
- package/dist/src/config.js +50 -0
- package/dist/src/config.js.map +1 -0
- package/dist/src/dedup.d.ts +22 -0
- package/dist/src/dedup.d.ts.map +1 -0
- package/dist/src/dedup.js +49 -0
- package/dist/src/dedup.js.map +1 -0
- package/dist/src/group-access.d.ts +52 -0
- package/dist/src/group-access.d.ts.map +1 -0
- package/dist/src/group-access.js +180 -0
- package/dist/src/group-access.js.map +1 -0
- package/dist/src/history-cache.d.ts +41 -0
- package/dist/src/history-cache.d.ts.map +1 -0
- package/dist/src/history-cache.js +82 -0
- package/dist/src/history-cache.js.map +1 -0
- package/dist/src/i18n.d.ts +22 -0
- package/dist/src/i18n.d.ts.map +1 -0
- package/dist/src/i18n.js +175 -0
- package/dist/src/i18n.js.map +1 -0
- package/dist/src/inbound-handler.d.ts +92 -0
- package/dist/src/inbound-handler.d.ts.map +1 -0
- package/dist/src/inbound-handler.js +417 -0
- package/dist/src/inbound-handler.js.map +1 -0
- package/dist/src/media-service.d.ts +52 -0
- package/dist/src/media-service.d.ts.map +1 -0
- package/dist/src/media-service.js +423 -0
- package/dist/src/media-service.js.map +1 -0
- package/dist/src/message-utils.d.ts +34 -0
- package/dist/src/message-utils.d.ts.map +1 -0
- package/dist/src/message-utils.js +392 -0
- package/dist/src/message-utils.js.map +1 -0
- package/dist/src/polling-service.d.ts +39 -0
- package/dist/src/polling-service.d.ts.map +1 -0
- package/dist/src/polling-service.js +204 -0
- package/dist/src/polling-service.js.map +1 -0
- package/dist/src/rate-limiter.d.ts +22 -0
- package/dist/src/rate-limiter.d.ts.map +1 -0
- package/dist/src/rate-limiter.js +72 -0
- package/dist/src/rate-limiter.js.map +1 -0
- package/dist/src/runtime.d.ts +106 -0
- package/dist/src/runtime.d.ts.map +1 -0
- package/dist/src/runtime.js +11 -0
- package/dist/src/runtime.js.map +1 -0
- package/dist/src/send-service.d.ts +66 -0
- package/dist/src/send-service.d.ts.map +1 -0
- package/dist/src/send-service.js +177 -0
- package/dist/src/send-service.js.map +1 -0
- package/dist/src/state-paths.d.ts +3 -0
- package/dist/src/state-paths.d.ts.map +1 -0
- package/dist/src/state-paths.js +23 -0
- package/dist/src/state-paths.js.map +1 -0
- package/dist/src/types.d.ts +381 -0
- package/dist/src/types.d.ts.map +1 -0
- package/dist/src/types.js +3 -0
- package/dist/src/types.js.map +1 -0
- package/dist/src/utils.d.ts +60 -0
- package/dist/src/utils.d.ts.map +1 -0
- package/dist/src/utils.js +131 -0
- package/dist/src/utils.js.map +1 -0
- package/index.ts +1 -1
- package/openclaw.plugin.json +278 -1
- package/package.json +11 -2
- package/src/api.ts +0 -3
- package/src/channel.ts +76 -73
- package/src/config-schema.ts +1 -2
- package/src/config.ts +6 -8
- package/src/group-access.ts +1 -8
- package/src/inbound-handler.ts +128 -15
- package/src/media-service.ts +160 -45
- package/src/polling-service.ts +2 -3
- package/src/send-service.ts +4 -3
- package/src/state-paths.ts +4 -0
- package/src/types.ts +1 -2
- package/src/utils.ts +31 -4
|
@@ -0,0 +1,392 @@
|
|
|
1
|
+
// ─── Placeholder helpers ──────────────────────────────────────────────────────
|
|
2
|
+
const PH_ESC = '\x00ESC'; // escape sequences
|
|
3
|
+
const PH_FCODE = '\x00FC'; // fenced code blocks
|
|
4
|
+
const PH_ICODE = '\x00IC'; // inline code
|
|
5
|
+
const PH_HR = '\x00HR'; // horizontal rules
|
|
6
|
+
const PH_TSEP = '\x00TS'; // table separators
|
|
7
|
+
const INLINE_ACCENT_COLOR = '#7A1F3D';
|
|
8
|
+
/**
|
|
9
|
+
* Convert Markdown (CommonMark + GFM subset) to Bitrix24 BB-code chat format.
|
|
10
|
+
*
|
|
11
|
+
* 4-phase pipeline:
|
|
12
|
+
* 1. Protect literals — escape sequences, fenced code, inline code → placeholders
|
|
13
|
+
* 2. Block rules — indented code, setext headings, horizontal rules, ATX headings,
|
|
14
|
+
* blockquotes, unordered lists
|
|
15
|
+
* 3. Inline rules — images, bold+italic, bold, italic, strikethrough, HTML inline
|
|
16
|
+
* formatting, links, autolinks
|
|
17
|
+
* 4. Restore — placeholders → BB-code equivalents
|
|
18
|
+
*/
|
|
19
|
+
export function markdownToBbCode(md) {
|
|
20
|
+
let text = md;
|
|
21
|
+
// ── Phase 1: Protect literals ─────────────────────────────────────────────
|
|
22
|
+
// 1a. Escape sequences: \* \# \_ etc. → placeholders
|
|
23
|
+
const escapes = [];
|
|
24
|
+
text = text.replace(/\\([\\`*_{}[\]()#+\-.!~|>])/g, (_match, ch) => {
|
|
25
|
+
escapes.push(ch);
|
|
26
|
+
return `${PH_ESC}${escapes.length - 1}\x00`;
|
|
27
|
+
});
|
|
28
|
+
// 1b. Fenced code blocks (backticks and tildes)
|
|
29
|
+
const fencedBlocks = [];
|
|
30
|
+
text = text.replace(/^(`{3,})[^\n`]*\n([\s\S]*?)^\1[ \t]*$/gm, (_match, _fence, code) => {
|
|
31
|
+
fencedBlocks.push(code.replace(/\n$/, ''));
|
|
32
|
+
return `${PH_FCODE}${fencedBlocks.length - 1}\x00`;
|
|
33
|
+
});
|
|
34
|
+
text = text.replace(/^(~{3,})[^\n~]*\n([\s\S]*?)^\1[ \t]*$/gm, (_match, _fence, code) => {
|
|
35
|
+
fencedBlocks.push(code.replace(/\n$/, ''));
|
|
36
|
+
return `${PH_FCODE}${fencedBlocks.length - 1}\x00`;
|
|
37
|
+
});
|
|
38
|
+
// 1c. Inline code (backticks) — single and double backtick
|
|
39
|
+
const inlineCodes = [];
|
|
40
|
+
text = text.replace(/``([^`]+)``/g, (_match, code) => {
|
|
41
|
+
inlineCodes.push(code);
|
|
42
|
+
return `${PH_ICODE}${inlineCodes.length - 1}\x00`;
|
|
43
|
+
});
|
|
44
|
+
text = text.replace(/`([^`\n]+)`/g, (_match, code) => {
|
|
45
|
+
inlineCodes.push(code);
|
|
46
|
+
return `${PH_ICODE}${inlineCodes.length - 1}\x00`;
|
|
47
|
+
});
|
|
48
|
+
const tableSeparators = [];
|
|
49
|
+
// ── Phase 2: Block rules (line-level, order matters) ──────────────────────
|
|
50
|
+
// 2a. Indented code blocks (4 spaces or 1 tab after a blank line)
|
|
51
|
+
// Collect consecutive indented lines preceded by a blank line
|
|
52
|
+
text = text.replace(/(?:^|\n)\n((?:(?: |\t).+\n?)+)/g, (_match, block) => {
|
|
53
|
+
const code = block.replace(/^(?: |\t)/gm, '').replace(/\n$/, '');
|
|
54
|
+
fencedBlocks.push(code);
|
|
55
|
+
return `\n${PH_FCODE}${fencedBlocks.length - 1}\x00`;
|
|
56
|
+
});
|
|
57
|
+
// 2b. Setext headings (BEFORE horizontal rules — `---` under text is H2, not HR)
|
|
58
|
+
text = text.replace(/^([^\n]+)\n={2,}[ \t]*$/gm, '[SIZE=24][B]$1[/B][/SIZE]');
|
|
59
|
+
text = text.replace(/^([^\n]+)\n-{2,}[ \t]*$/gm, '[SIZE=20][B]$1[/B][/SIZE]');
|
|
60
|
+
// 2c. Horizontal rules: ---, ***, ___, - - -, * * * (on their own line)
|
|
61
|
+
// Use placeholder to prevent underscores from being caught by bold/italic rules
|
|
62
|
+
text = text.replace(/^[ \t]*([-*_])[ \t]*\1[ \t]*\1(?:[ \t]*\1)*[ \t]*$/gm, `${PH_HR}\x00`);
|
|
63
|
+
text = text.replace(/^[ \t]*[-*_](?:[ \t]+[-*_]){2,}[ \t]*$/gm, `${PH_HR}\x00`);
|
|
64
|
+
// 2d. ATX headings: # through ######
|
|
65
|
+
text = text.replace(/^######\s+(.+?)(?:\s+#+)?$/gm, '[SIZE=16][B]$1[/B][/SIZE]');
|
|
66
|
+
text = text.replace(/^#####\s+(.+?)(?:\s+#+)?$/gm, '[SIZE=16][B]$1[/B][/SIZE]');
|
|
67
|
+
text = text.replace(/^####\s+(.+?)(?:\s+#+)?$/gm, '[SIZE=16][B]$1[/B][/SIZE]');
|
|
68
|
+
text = text.replace(/^###\s+(.+?)(?:\s+#+)?$/gm, '[SIZE=18][B]$1[/B][/SIZE]');
|
|
69
|
+
text = text.replace(/^##\s+(.+?)(?:\s+#+)?$/gm, '[SIZE=20][B]$1[/B][/SIZE]');
|
|
70
|
+
text = text.replace(/^#\s+(.+?)(?:\s+#+)?$/gm, '[SIZE=24][B]$1[/B][/SIZE]');
|
|
71
|
+
// 2e. Blockquotes: > text → >>text
|
|
72
|
+
// Nested quotes are flattened into Bitrix-compatible quote blocks with separators.
|
|
73
|
+
text = convertBlockquotes(text);
|
|
74
|
+
// 2f. Task lists (GFM): - [x] done / - [ ] todo → emoji checkboxes
|
|
75
|
+
// Must run BEFORE generic list rules to avoid double-processing
|
|
76
|
+
text = text.replace(/^([ \t]*)[-*+]\s+\[x\]\s+(.*)$/gmi, (_m, indent, content) => {
|
|
77
|
+
const depth = Math.floor(indent.replace(/\t/g, ' ').length / 2);
|
|
78
|
+
return '\t'.repeat(depth) + '✅ ' + content;
|
|
79
|
+
});
|
|
80
|
+
text = text.replace(/^([ \t]*)[-*+]\s+\[ \]\s+(.*)$/gm, (_m, indent, content) => {
|
|
81
|
+
const depth = Math.floor(indent.replace(/\t/g, ' ').length / 2);
|
|
82
|
+
return '\t'.repeat(depth) + '☑️ ' + content;
|
|
83
|
+
});
|
|
84
|
+
// 2g. Ordered lists: 1. item / 2. item → number with dot
|
|
85
|
+
// Handle nested lists with tab indentation
|
|
86
|
+
text = text.replace(/^([ \t]*)(\d+)\.\s+(.*)$/gm, (_m, indent, num, content) => {
|
|
87
|
+
const depth = Math.floor(indent.replace(/\t/g, ' ').length / 2);
|
|
88
|
+
return '\t'.repeat(depth) + num + '. ' + content;
|
|
89
|
+
});
|
|
90
|
+
// 2h. Unordered lists: - item / * item / + item → • item
|
|
91
|
+
// Handle nested lists with tab indentation
|
|
92
|
+
text = text.replace(/^([ \t]*)[-*+]\s+(.*)$/gm, (_m, indent, content) => {
|
|
93
|
+
const depth = Math.floor(indent.replace(/\t/g, ' ').length / 2);
|
|
94
|
+
return '\t'.repeat(depth) + '• ' + content;
|
|
95
|
+
});
|
|
96
|
+
// 2i. GFM tables → simplified plain-text tables
|
|
97
|
+
text = convertGfmTables(text, (separator) => {
|
|
98
|
+
tableSeparators.push(separator);
|
|
99
|
+
return `${PH_TSEP}${tableSeparators.length - 1}\x00`;
|
|
100
|
+
});
|
|
101
|
+
// ── Phase 3: Inline rules (order matters) ─────────────────────────────────
|
|
102
|
+
// 3a. Images:  → [img size=medium]url [/img]
|
|
103
|
+
text = text.replace(/!\[[^\]]*\]\(([\s\S]*?)\)/g, (_match, rawTarget) => {
|
|
104
|
+
const imageUrl = extractMarkdownTarget(rawTarget);
|
|
105
|
+
return `[img size=medium]${normalizeBitrixImageUrl(imageUrl)} [/img]`;
|
|
106
|
+
});
|
|
107
|
+
// 3b. Bold+Italic combined: ***text*** or ___text___ → [B][I]text[/I][/B]
|
|
108
|
+
text = text.replace(/\*\*\*(.+?)\*\*\*/g, '[B][I]$1[/I][/B]');
|
|
109
|
+
text = text.replace(/___(.+?)___/g, '[B][I]$1[/I][/B]');
|
|
110
|
+
// 3c. Bold: **text** or __text__
|
|
111
|
+
text = text.replace(/\*\*(.+?)\*\*/g, '[B]$1[/B]');
|
|
112
|
+
text = text.replace(/__(.+?)__/g, '[B]$1[/B]');
|
|
113
|
+
// 3d. Italic: *text* or _text_ (word boundaries to avoid false positives)
|
|
114
|
+
text = text.replace(/(?<!\w)\*([^*]+?)\*(?!\w)/g, '[I]$1[/I]');
|
|
115
|
+
text = text.replace(/(?<!\w)_([^_]+?)_(?!\w)/g, '[I]$1[/I]');
|
|
116
|
+
// 3e. Strikethrough: ~~text~~
|
|
117
|
+
text = text.replace(/~~(.+?)~~/g, '[S]$1[/S]');
|
|
118
|
+
// 3f. HTML inline formatting tags
|
|
119
|
+
text = text.replace(/<u>([\s\S]*?)<\/u>/gi, '[U]$1[/U]');
|
|
120
|
+
text = text.replace(/<b>([\s\S]*?)<\/b>/gi, '[B]$1[/B]');
|
|
121
|
+
text = text.replace(/<strong>([\s\S]*?)<\/strong>/gi, '[B]$1[/B]');
|
|
122
|
+
text = text.replace(/<i>([\s\S]*?)<\/i>/gi, '[I]$1[/I]');
|
|
123
|
+
text = text.replace(/<em>([\s\S]*?)<\/em>/gi, '[I]$1[/I]');
|
|
124
|
+
text = text.replace(/<s>([\s\S]*?)<\/s>/gi, '[S]$1[/S]');
|
|
125
|
+
text = text.replace(/<del>([\s\S]*?)<\/del>/gi, '[S]$1[/S]');
|
|
126
|
+
text = text.replace(/<strike>([\s\S]*?)<\/strike>/gi, '[S]$1[/S]');
|
|
127
|
+
// 3g. Links: [text](url) → [URL=url]text[/URL]
|
|
128
|
+
text = text.replace(/\[([^\]]+)\]\(([^)]+)\)/g, '[URL=$2]$1[/URL]');
|
|
129
|
+
// 3h. Autolink URL: <https://...> → [URL]https://...[/URL]
|
|
130
|
+
text = text.replace(/<(https?:\/\/[^>]+)>/g, '[URL]$1[/URL]');
|
|
131
|
+
// 3i. Autolink email: <user@example.com> → [URL]mailto:user@example.com[/URL]
|
|
132
|
+
text = text.replace(/<([a-zA-Z0-9._%+\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,})>/g, '[URL]mailto:$1[/URL]');
|
|
133
|
+
// ── Phase 4: Restore placeholders ─────────────────────────────────────────
|
|
134
|
+
// 4a. Horizontal rules → visual separator
|
|
135
|
+
text = text.replace(new RegExp(`${PH_HR.replace(/\x00/g, '\\x00')}\\x00`, 'g'), '____________');
|
|
136
|
+
// 4aa. Table separators → underscore rows
|
|
137
|
+
text = text.replace(new RegExp(`${PH_TSEP.replace(/\x00/g, '\\x00')}(\\d+)\\x00`, 'g'), (_m, idx) => {
|
|
138
|
+
const value = tableSeparators[Number(idx)];
|
|
139
|
+
return value != null ? value : _m;
|
|
140
|
+
});
|
|
141
|
+
// 4b. Inline code → [CODE]...[/CODE]
|
|
142
|
+
text = text.replace(new RegExp(`${PH_ICODE.replace(/\x00/g, '\\x00')}(\\d+)\\x00`, 'g'), (_m, idx) => {
|
|
143
|
+
const value = inlineCodes[Number(idx)];
|
|
144
|
+
if (value == null)
|
|
145
|
+
return _m;
|
|
146
|
+
return isInlineAccentToken(value)
|
|
147
|
+
? `[B][COLOR=${INLINE_ACCENT_COLOR}]${value}[/COLOR][/B]`
|
|
148
|
+
: `[CODE]${value}[/CODE]`;
|
|
149
|
+
});
|
|
150
|
+
// 4b. Fenced/indented code blocks → [CODE]...[/CODE]
|
|
151
|
+
text = text.replace(new RegExp(`${PH_FCODE.replace(/\x00/g, '\\x00')}(\\d+)\\x00`, 'g'), (_m, idx) => {
|
|
152
|
+
const value = fencedBlocks[Number(idx)];
|
|
153
|
+
return value != null ? `[CODE]${value}[/CODE]` : _m;
|
|
154
|
+
});
|
|
155
|
+
// 4c. Escape sequences → literal characters
|
|
156
|
+
text = text.replace(new RegExp(`${PH_ESC.replace(/\x00/g, '\\x00')}(\\d+)\\x00`, 'g'), (_m, idx) => {
|
|
157
|
+
const value = escapes[Number(idx)];
|
|
158
|
+
return value != null ? value : _m;
|
|
159
|
+
});
|
|
160
|
+
return text;
|
|
161
|
+
}
|
|
162
|
+
function isInlineAccentToken(value) {
|
|
163
|
+
const trimmed = value.trim();
|
|
164
|
+
if (!trimmed || /\s/.test(trimmed))
|
|
165
|
+
return false;
|
|
166
|
+
if (/^\/[a-z0-9][a-z0-9._:-]*$/i.test(trimmed)) {
|
|
167
|
+
return true;
|
|
168
|
+
}
|
|
169
|
+
return /^[A-Z][A-Z0-9+._/-]{1,15}$/.test(trimmed);
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Split a long message into chunks respecting B24's 20000 char limit.
|
|
173
|
+
* Tries to split at line boundaries.
|
|
174
|
+
*/
|
|
175
|
+
export function splitMessage(text, maxLen = 20000) {
|
|
176
|
+
if (text.length <= maxLen)
|
|
177
|
+
return [text];
|
|
178
|
+
const chunks = [];
|
|
179
|
+
let remaining = text;
|
|
180
|
+
while (remaining.length > 0) {
|
|
181
|
+
if (remaining.length <= maxLen) {
|
|
182
|
+
chunks.push(remaining);
|
|
183
|
+
break;
|
|
184
|
+
}
|
|
185
|
+
// Find the last newline within the limit
|
|
186
|
+
let splitAt = remaining.lastIndexOf('\n', maxLen);
|
|
187
|
+
if (splitAt <= 0) {
|
|
188
|
+
// No newline found, split at the limit
|
|
189
|
+
splitAt = maxLen;
|
|
190
|
+
}
|
|
191
|
+
chunks.push(remaining.slice(0, splitAt));
|
|
192
|
+
remaining = remaining.slice(splitAt).replace(/^\n/, '');
|
|
193
|
+
}
|
|
194
|
+
return chunks;
|
|
195
|
+
}
|
|
196
|
+
function convertGfmTables(text, registerSeparator) {
|
|
197
|
+
const lines = text.split('\n');
|
|
198
|
+
const result = [];
|
|
199
|
+
for (let index = 0; index < lines.length; index++) {
|
|
200
|
+
const currentLine = lines[index];
|
|
201
|
+
const nextLine = lines[index + 1];
|
|
202
|
+
if (looksLikeMarkdownTableRow(currentLine) && isMarkdownTableSeparator(nextLine)) {
|
|
203
|
+
const rows = [splitMarkdownTableRow(currentLine)];
|
|
204
|
+
let rowIndex = index + 2;
|
|
205
|
+
while (rowIndex < lines.length && looksLikeMarkdownTableRow(lines[rowIndex])) {
|
|
206
|
+
rows.push(splitMarkdownTableRow(lines[rowIndex]));
|
|
207
|
+
rowIndex += 1;
|
|
208
|
+
}
|
|
209
|
+
result.push(formatPlainTextTable(rows, registerSeparator));
|
|
210
|
+
index = rowIndex - 1;
|
|
211
|
+
continue;
|
|
212
|
+
}
|
|
213
|
+
result.push(currentLine);
|
|
214
|
+
}
|
|
215
|
+
return result.join('\n');
|
|
216
|
+
}
|
|
217
|
+
function convertBlockquotes(text) {
|
|
218
|
+
const lines = text.split('\n');
|
|
219
|
+
const result = [];
|
|
220
|
+
for (let index = 0; index < lines.length; index++) {
|
|
221
|
+
const currentQuoteLine = parseMarkdownBlockquoteLine(lines[index]);
|
|
222
|
+
if (!currentQuoteLine) {
|
|
223
|
+
result.push(lines[index]);
|
|
224
|
+
continue;
|
|
225
|
+
}
|
|
226
|
+
const quoteRun = [currentQuoteLine];
|
|
227
|
+
let nextIndex = index + 1;
|
|
228
|
+
while (nextIndex < lines.length) {
|
|
229
|
+
const nextQuoteLine = parseMarkdownBlockquoteLine(lines[nextIndex]);
|
|
230
|
+
if (!nextQuoteLine) {
|
|
231
|
+
break;
|
|
232
|
+
}
|
|
233
|
+
quoteRun.push(nextQuoteLine);
|
|
234
|
+
nextIndex += 1;
|
|
235
|
+
}
|
|
236
|
+
const hasNestedQuote = quoteRun.some((line) => line.depth > 1);
|
|
237
|
+
const normalizedQuoteRun = hasNestedQuote
|
|
238
|
+
? quoteRun.filter((line) => line.content.trim().length > 0)
|
|
239
|
+
: quoteRun;
|
|
240
|
+
for (const line of normalizedQuoteRun) {
|
|
241
|
+
result.push(`>>${line.content}`);
|
|
242
|
+
if (hasNestedQuote) {
|
|
243
|
+
result.push('>>------------------------------------------------------');
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
index = nextIndex - 1;
|
|
247
|
+
}
|
|
248
|
+
return result.join('\n');
|
|
249
|
+
}
|
|
250
|
+
function parseMarkdownBlockquoteLine(line) {
|
|
251
|
+
const indentMatch = /^[ \t]{0,3}/.exec(line);
|
|
252
|
+
let rest = line.slice(indentMatch?.[0].length ?? 0);
|
|
253
|
+
if (!rest.startsWith('>')) {
|
|
254
|
+
return null;
|
|
255
|
+
}
|
|
256
|
+
let depth = 0;
|
|
257
|
+
while (rest.startsWith('>')) {
|
|
258
|
+
depth += 1;
|
|
259
|
+
rest = rest.slice(1);
|
|
260
|
+
if (rest.startsWith(' ')) {
|
|
261
|
+
rest = rest.slice(1);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
return {
|
|
265
|
+
depth,
|
|
266
|
+
content: rest,
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
function looksLikeMarkdownTableRow(line) {
|
|
270
|
+
if (typeof line !== 'string')
|
|
271
|
+
return false;
|
|
272
|
+
const trimmed = line.trim();
|
|
273
|
+
if (!trimmed.includes('|'))
|
|
274
|
+
return false;
|
|
275
|
+
const cells = splitMarkdownTableRow(trimmed);
|
|
276
|
+
return cells.length >= 2 && cells.some((cell) => cell.length > 0);
|
|
277
|
+
}
|
|
278
|
+
function isMarkdownTableSeparator(line) {
|
|
279
|
+
if (typeof line !== 'string')
|
|
280
|
+
return false;
|
|
281
|
+
const trimmed = line.trim();
|
|
282
|
+
if (!trimmed.includes('|'))
|
|
283
|
+
return false;
|
|
284
|
+
const cells = splitMarkdownTableRow(trimmed);
|
|
285
|
+
return cells.length >= 2 && cells.every((cell) => /^:?-{3,}:?$/.test(cell));
|
|
286
|
+
}
|
|
287
|
+
function splitMarkdownTableRow(line) {
|
|
288
|
+
let normalized = line.trim();
|
|
289
|
+
if (normalized.startsWith('|')) {
|
|
290
|
+
normalized = normalized.slice(1);
|
|
291
|
+
}
|
|
292
|
+
if (normalized.endsWith('|')) {
|
|
293
|
+
normalized = normalized.slice(0, -1);
|
|
294
|
+
}
|
|
295
|
+
return normalized.split('|').map((cell) => cell.trim());
|
|
296
|
+
}
|
|
297
|
+
function formatPlainTextTable(rows, registerSeparator) {
|
|
298
|
+
const columnCount = Math.max(...rows.map((row) => row.length));
|
|
299
|
+
const normalizedRows = rows.map((row) => {
|
|
300
|
+
const cells = [...row];
|
|
301
|
+
while (cells.length < columnCount) {
|
|
302
|
+
cells.push('');
|
|
303
|
+
}
|
|
304
|
+
return cells;
|
|
305
|
+
});
|
|
306
|
+
const columnWidths = Array.from({ length: columnCount }, (_, columnIndex) => {
|
|
307
|
+
return Math.max(...normalizedRows.map((row) => row[columnIndex].length));
|
|
308
|
+
});
|
|
309
|
+
const formattedRows = normalizedRows.map((row) => {
|
|
310
|
+
return row
|
|
311
|
+
.map((cell, columnIndex) => cell.padEnd(columnWidths[columnIndex]))
|
|
312
|
+
.join(' | ')
|
|
313
|
+
.trimEnd();
|
|
314
|
+
});
|
|
315
|
+
const separator = registerSeparator('_'.repeat(Math.max(formattedRows[0]?.length ?? 0, 3)));
|
|
316
|
+
return [formattedRows[0], separator, ...formattedRows.slice(1)].join('\n');
|
|
317
|
+
}
|
|
318
|
+
function extractMarkdownTarget(rawTarget) {
|
|
319
|
+
const trimmed = rawTarget.trim();
|
|
320
|
+
if (!trimmed)
|
|
321
|
+
return '';
|
|
322
|
+
if (trimmed.startsWith('<')) {
|
|
323
|
+
const closingIndex = trimmed.indexOf('>');
|
|
324
|
+
if (closingIndex > 1) {
|
|
325
|
+
return trimmed.slice(1, closingIndex);
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
let depth = 0;
|
|
329
|
+
for (let index = 0; index < trimmed.length; index++) {
|
|
330
|
+
const char = trimmed[index];
|
|
331
|
+
if (char === '(') {
|
|
332
|
+
depth += 1;
|
|
333
|
+
continue;
|
|
334
|
+
}
|
|
335
|
+
if (char === ')') {
|
|
336
|
+
depth = Math.max(0, depth - 1);
|
|
337
|
+
continue;
|
|
338
|
+
}
|
|
339
|
+
if (/\s/.test(char) && depth === 0) {
|
|
340
|
+
return trimmed.slice(0, index);
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
return trimmed;
|
|
344
|
+
}
|
|
345
|
+
function normalizeBitrixImageUrl(rawUrl) {
|
|
346
|
+
const trimmed = rawUrl.trim();
|
|
347
|
+
if (!trimmed)
|
|
348
|
+
return trimmed;
|
|
349
|
+
try {
|
|
350
|
+
const url = new URL(trimmed);
|
|
351
|
+
if (hasSupportedBitrixImageExtension(`${url.pathname}${url.hash}`)) {
|
|
352
|
+
return url.toString();
|
|
353
|
+
}
|
|
354
|
+
url.hash = 'image.jpg';
|
|
355
|
+
return url.toString();
|
|
356
|
+
}
|
|
357
|
+
catch {
|
|
358
|
+
if (hasSupportedBitrixImageExtension(trimmed)) {
|
|
359
|
+
return trimmed;
|
|
360
|
+
}
|
|
361
|
+
return `${trimmed}#image.jpg`;
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
function hasSupportedBitrixImageExtension(value) {
|
|
365
|
+
return /\.(jpe?g|png|gif)(?:$|[?#])/i.test(value);
|
|
366
|
+
}
|
|
367
|
+
/**
|
|
368
|
+
* Build a KEYBOARD array for imbot.v2.Chat.Message.send.
|
|
369
|
+
*
|
|
370
|
+
* @param rows - Array of button rows. Each row is an array of buttons.
|
|
371
|
+
*/
|
|
372
|
+
export function buildKeyboard(rows) {
|
|
373
|
+
const keyboard = [];
|
|
374
|
+
for (let i = 0; i < rows.length; i++) {
|
|
375
|
+
for (const btn of rows[i]) {
|
|
376
|
+
keyboard.push({
|
|
377
|
+
TEXT: btn.text,
|
|
378
|
+
...(btn.command ? { COMMAND: btn.command, COMMAND_PARAMS: btn.commandParams ?? '' } : {}),
|
|
379
|
+
...(btn.link ? { LINK: btn.link } : {}),
|
|
380
|
+
BG_COLOR: btn.bgColor ?? '#29619b',
|
|
381
|
+
TEXT_COLOR: btn.textColor ?? '#fff',
|
|
382
|
+
DISPLAY: btn.fullWidth ? 'LINE' : 'BLOCK',
|
|
383
|
+
BLOCK: btn.disableAfterClick ? 'Y' : 'N',
|
|
384
|
+
});
|
|
385
|
+
}
|
|
386
|
+
if (i < rows.length - 1) {
|
|
387
|
+
keyboard.push({ TYPE: 'NEWLINE' });
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
return keyboard;
|
|
391
|
+
}
|
|
392
|
+
//# sourceMappingURL=message-utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"message-utils.js","sourceRoot":"","sources":["../../src/message-utils.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { Bitrix24Api, BotContext } from './api.js';
|
|
2
|
+
import type { B24V2FetchEventItem, Logger } from './types.js';
|
|
3
|
+
export interface PollingServiceOptions {
|
|
4
|
+
api: Bitrix24Api;
|
|
5
|
+
webhookUrl: string;
|
|
6
|
+
bot: BotContext;
|
|
7
|
+
accountId: string;
|
|
8
|
+
pollingIntervalMs: number;
|
|
9
|
+
pollingFastIntervalMs: number;
|
|
10
|
+
withUserEvents?: boolean;
|
|
11
|
+
onEvent: (event: B24V2FetchEventItem) => Promise<void>;
|
|
12
|
+
abortSignal: AbortSignal;
|
|
13
|
+
logger: Logger;
|
|
14
|
+
}
|
|
15
|
+
export declare class PollingService {
|
|
16
|
+
private readonly api;
|
|
17
|
+
private readonly webhookUrl;
|
|
18
|
+
private readonly bot;
|
|
19
|
+
private readonly accountId;
|
|
20
|
+
private readonly pollingIntervalMs;
|
|
21
|
+
private readonly pollingFastIntervalMs;
|
|
22
|
+
private readonly withUserEvents;
|
|
23
|
+
private readonly onEvent;
|
|
24
|
+
private readonly abortSignal;
|
|
25
|
+
private readonly logger;
|
|
26
|
+
private readonly offsetPath;
|
|
27
|
+
private offset;
|
|
28
|
+
private rateLimitStreak;
|
|
29
|
+
constructor(opts: PollingServiceOptions);
|
|
30
|
+
/**
|
|
31
|
+
* Start the blocking polling loop.
|
|
32
|
+
* Uses imbot.v2.Event.get which returns { events, lastEventId, hasMore }.
|
|
33
|
+
*/
|
|
34
|
+
start(): Promise<void>;
|
|
35
|
+
private loadOffset;
|
|
36
|
+
private persistOffset;
|
|
37
|
+
private sleepWithAbort;
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=polling-service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"polling-service.d.ts","sourceRoot":"","sources":["../../src/polling-service.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AACxD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAG9D,MAAM,WAAW,qBAAqB;IACpC,GAAG,EAAE,WAAW,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,GAAG,EAAE,UAAU,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,qBAAqB,EAAE,MAAM,CAAC;IAC9B,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,OAAO,EAAE,CAAC,KAAK,EAAE,mBAAmB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACvD,WAAW,EAAE,WAAW,CAAC;IACzB,MAAM,EAAE,MAAM,CAAC;CAChB;AA6CD,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAc;IAClC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAa;IACjC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAS;IAC3C,OAAO,CAAC,QAAQ,CAAC,qBAAqB,CAAS;IAC/C,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAU;IACzC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAgD;IACxE,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAc;IAC1C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IAEpC,OAAO,CAAC,MAAM,CAAK;IACnB,OAAO,CAAC,eAAe,CAAK;gBAEhB,IAAI,EAAE,qBAAqB;IAevC;;;OAGG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;YAwFd,UAAU;YAgBV,aAAa;IAsB3B,OAAO,CAAC,cAAc;CAiBvB"}
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
import { writeFile, readFile, mkdir, rename } from 'node:fs/promises';
|
|
2
|
+
import { join, dirname } from 'node:path';
|
|
3
|
+
import { randomBytes } from 'node:crypto';
|
|
4
|
+
import { resolvePollingStateDir } from './state-paths.js';
|
|
5
|
+
import { Bitrix24ApiError } from './utils.js';
|
|
6
|
+
/** Exponential backoff with jitter for recoverable errors. */
|
|
7
|
+
class ExponentialBackoff {
|
|
8
|
+
initialMs;
|
|
9
|
+
maxMs;
|
|
10
|
+
factor;
|
|
11
|
+
jitter;
|
|
12
|
+
currentMs;
|
|
13
|
+
constructor(initialMs = 2000, maxMs = 30000, factor = 1.8, jitter = 0.25) {
|
|
14
|
+
this.initialMs = initialMs;
|
|
15
|
+
this.maxMs = maxMs;
|
|
16
|
+
this.factor = factor;
|
|
17
|
+
this.jitter = jitter;
|
|
18
|
+
this.currentMs = initialMs;
|
|
19
|
+
}
|
|
20
|
+
next() {
|
|
21
|
+
const base = this.currentMs;
|
|
22
|
+
const jitterRange = base * this.jitter;
|
|
23
|
+
const delay = base + (Math.random() * 2 - 1) * jitterRange;
|
|
24
|
+
this.currentMs = Math.min(this.currentMs * this.factor, this.maxMs);
|
|
25
|
+
return Math.max(delay, 0);
|
|
26
|
+
}
|
|
27
|
+
reset() {
|
|
28
|
+
this.currentMs = this.initialMs;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
/** Fatal errors that should stop the polling loop. */
|
|
32
|
+
const FATAL_ERROR_CODES = new Set([
|
|
33
|
+
'ACCESS_DENIED',
|
|
34
|
+
'BOT_NOT_FOUND',
|
|
35
|
+
'BOT_OWNERSHIP_ERROR',
|
|
36
|
+
'AUTH_ERROR',
|
|
37
|
+
'SCOPE_ERROR',
|
|
38
|
+
]);
|
|
39
|
+
/** Errors that indicate B24 rate limiting. */
|
|
40
|
+
const RATE_LIMIT_CODE = 'QUERY_LIMIT_EXCEEDED';
|
|
41
|
+
export class PollingService {
|
|
42
|
+
api;
|
|
43
|
+
webhookUrl;
|
|
44
|
+
bot;
|
|
45
|
+
accountId;
|
|
46
|
+
pollingIntervalMs;
|
|
47
|
+
pollingFastIntervalMs;
|
|
48
|
+
withUserEvents;
|
|
49
|
+
onEvent;
|
|
50
|
+
abortSignal;
|
|
51
|
+
logger;
|
|
52
|
+
offsetPath;
|
|
53
|
+
offset = 0;
|
|
54
|
+
rateLimitStreak = 0;
|
|
55
|
+
constructor(opts) {
|
|
56
|
+
this.api = opts.api;
|
|
57
|
+
this.webhookUrl = opts.webhookUrl;
|
|
58
|
+
this.bot = opts.bot;
|
|
59
|
+
this.accountId = opts.accountId;
|
|
60
|
+
this.pollingIntervalMs = opts.pollingIntervalMs;
|
|
61
|
+
this.pollingFastIntervalMs = opts.pollingFastIntervalMs;
|
|
62
|
+
this.withUserEvents = Boolean(opts.withUserEvents);
|
|
63
|
+
this.onEvent = opts.onEvent;
|
|
64
|
+
this.abortSignal = opts.abortSignal;
|
|
65
|
+
this.logger = opts.logger;
|
|
66
|
+
this.offsetPath = join(resolvePollingStateDir(), `poll-offset-${this.accountId}.json`);
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Start the blocking polling loop.
|
|
70
|
+
* Uses imbot.v2.Event.get which returns { events, lastEventId, hasMore }.
|
|
71
|
+
*/
|
|
72
|
+
async start() {
|
|
73
|
+
this.offset = await this.loadOffset();
|
|
74
|
+
this.logger.info(`Polling started (botId=${this.bot.botId}, offset=${this.offset})`);
|
|
75
|
+
const backoff = new ExponentialBackoff();
|
|
76
|
+
while (!this.abortSignal.aborted) {
|
|
77
|
+
try {
|
|
78
|
+
const result = await this.api.fetchEvents(this.webhookUrl, this.bot, {
|
|
79
|
+
offset: this.offset,
|
|
80
|
+
limit: 100,
|
|
81
|
+
withUserEvents: this.withUserEvents,
|
|
82
|
+
});
|
|
83
|
+
// Successful fetch — reset backoff and rate limit streak
|
|
84
|
+
backoff.reset();
|
|
85
|
+
this.rateLimitStreak = 0;
|
|
86
|
+
const { events, lastEventId, hasMore } = result;
|
|
87
|
+
let nextOffset = this.offset;
|
|
88
|
+
// Process events sequentially
|
|
89
|
+
for (const event of events) {
|
|
90
|
+
if (this.abortSignal.aborted)
|
|
91
|
+
break;
|
|
92
|
+
try {
|
|
93
|
+
await this.onEvent(event);
|
|
94
|
+
nextOffset = Math.max(nextOffset, event.eventId + 1);
|
|
95
|
+
}
|
|
96
|
+
catch (err) {
|
|
97
|
+
if (nextOffset > this.offset) {
|
|
98
|
+
this.offset = nextOffset;
|
|
99
|
+
await this.persistOffset(this.offset);
|
|
100
|
+
}
|
|
101
|
+
throw err;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
// Advance offset only for events that were processed successfully.
|
|
105
|
+
if (events.length > 0 && nextOffset > this.offset) {
|
|
106
|
+
this.offset = nextOffset;
|
|
107
|
+
await this.persistOffset(this.offset);
|
|
108
|
+
}
|
|
109
|
+
else if (events.length > 0 && lastEventId < this.offset) {
|
|
110
|
+
this.logger.warn('Polling: lastEventId regressed', {
|
|
111
|
+
lastEventId,
|
|
112
|
+
currentOffset: this.offset,
|
|
113
|
+
eventCount: events.length,
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
// If there are more events, fetch again quickly
|
|
117
|
+
if (hasMore) {
|
|
118
|
+
await this.sleepWithAbort(this.pollingFastIntervalMs);
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
await this.sleepWithAbort(this.pollingIntervalMs);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
catch (err) {
|
|
125
|
+
if (this.abortSignal.aborted)
|
|
126
|
+
break;
|
|
127
|
+
// Handle B24 API errors
|
|
128
|
+
if (err instanceof Bitrix24ApiError) {
|
|
129
|
+
// Fatal errors — stop polling
|
|
130
|
+
if (FATAL_ERROR_CODES.has(err.code)) {
|
|
131
|
+
this.logger.error(`Fatal polling error (${err.code}): ${err.description} — stopping`);
|
|
132
|
+
throw err;
|
|
133
|
+
}
|
|
134
|
+
// Rate limit — short pause without exponential backoff
|
|
135
|
+
if (err.code === RATE_LIMIT_CODE) {
|
|
136
|
+
this.rateLimitStreak++;
|
|
137
|
+
const pauseMs = this.rateLimitStreak >= 3 ? 5000 : 2000;
|
|
138
|
+
this.logger.warn(`Rate limited (streak=${this.rateLimitStreak}), pausing ${pauseMs}ms`);
|
|
139
|
+
await this.sleepWithAbort(pauseMs);
|
|
140
|
+
continue;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
// HTTP errors and network errors — recoverable with backoff
|
|
144
|
+
const delayMs = backoff.next();
|
|
145
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
146
|
+
this.logger.warn(`Polling error, retrying in ${Math.round(delayMs)}ms: ${errMsg}`);
|
|
147
|
+
await this.sleepWithAbort(delayMs);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
this.logger.info('Polling stopped');
|
|
151
|
+
}
|
|
152
|
+
// ─── Offset persistence ──────────────────────────────────────────────
|
|
153
|
+
async loadOffset() {
|
|
154
|
+
try {
|
|
155
|
+
const raw = await readFile(this.offsetPath, 'utf-8');
|
|
156
|
+
const state = JSON.parse(raw);
|
|
157
|
+
if (typeof state.offset === 'number' && state.offset >= 0) {
|
|
158
|
+
this.logger.info(`Loaded saved offset: ${state.offset}`);
|
|
159
|
+
return state.offset;
|
|
160
|
+
}
|
|
161
|
+
this.logger.debug('Saved offset invalid, starting from 0', { raw: state });
|
|
162
|
+
}
|
|
163
|
+
catch (err) {
|
|
164
|
+
// File doesn't exist or is corrupted — start from 0
|
|
165
|
+
this.logger.debug('Failed to load saved offset, starting from 0', err);
|
|
166
|
+
}
|
|
167
|
+
return 0;
|
|
168
|
+
}
|
|
169
|
+
async persistOffset(offset) {
|
|
170
|
+
try {
|
|
171
|
+
const dir = dirname(this.offsetPath);
|
|
172
|
+
await mkdir(dir, { recursive: true });
|
|
173
|
+
const state = {
|
|
174
|
+
offset,
|
|
175
|
+
updatedAt: new Date().toISOString(),
|
|
176
|
+
};
|
|
177
|
+
const data = JSON.stringify(state, null, 2);
|
|
178
|
+
// Atomic write: tmp file + rename
|
|
179
|
+
const tmpPath = `${this.offsetPath}.${randomBytes(4).toString('hex')}.tmp`;
|
|
180
|
+
await writeFile(tmpPath, data, 'utf-8');
|
|
181
|
+
await rename(tmpPath, this.offsetPath);
|
|
182
|
+
}
|
|
183
|
+
catch (err) {
|
|
184
|
+
this.logger.warn('Failed to persist offset', err);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
// ─── Sleep with abort ────────────────────────────────────────────────
|
|
188
|
+
sleepWithAbort(ms) {
|
|
189
|
+
if (this.abortSignal.aborted)
|
|
190
|
+
return Promise.resolve();
|
|
191
|
+
return new Promise((resolve) => {
|
|
192
|
+
const timer = setTimeout(() => {
|
|
193
|
+
this.abortSignal.removeEventListener('abort', onAbort);
|
|
194
|
+
resolve();
|
|
195
|
+
}, ms);
|
|
196
|
+
const onAbort = () => {
|
|
197
|
+
clearTimeout(timer);
|
|
198
|
+
resolve();
|
|
199
|
+
};
|
|
200
|
+
this.abortSignal.addEventListener('abort', onAbort, { once: true });
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
//# sourceMappingURL=polling-service.js.map
|