@ihazz/bitrix24 1.1.12 → 1.1.13
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 +77 -4
- package/dist/src/api.d.ts +10 -5
- package/dist/src/api.d.ts.map +1 -1
- package/dist/src/api.js +42 -8
- package/dist/src/api.js.map +1 -1
- package/dist/src/channel.d.ts +18 -1
- package/dist/src/channel.d.ts.map +1 -1
- package/dist/src/channel.js +1253 -42
- package/dist/src/channel.js.map +1 -1
- package/dist/src/i18n.js +68 -68
- package/dist/src/i18n.js.map +1 -1
- package/dist/src/inbound-handler.js +85 -7
- package/dist/src/inbound-handler.js.map +1 -1
- package/dist/src/media-service.d.ts +2 -0
- package/dist/src/media-service.d.ts.map +1 -1
- package/dist/src/media-service.js +117 -14
- package/dist/src/media-service.js.map +1 -1
- package/dist/src/message-utils.d.ts.map +1 -1
- package/dist/src/message-utils.js +73 -3
- package/dist/src/message-utils.js.map +1 -1
- package/dist/src/runtime.d.ts +1 -0
- package/dist/src/runtime.d.ts.map +1 -1
- package/dist/src/runtime.js.map +1 -1
- package/dist/src/send-service.d.ts +1 -0
- package/dist/src/send-service.d.ts.map +1 -1
- package/dist/src/send-service.js +26 -3
- package/dist/src/send-service.js.map +1 -1
- package/dist/src/state-paths.d.ts +1 -0
- package/dist/src/state-paths.d.ts.map +1 -1
- package/dist/src/state-paths.js +9 -0
- package/dist/src/state-paths.js.map +1 -1
- package/dist/src/types.d.ts +92 -0
- package/dist/src/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/api.ts +62 -13
- package/src/channel.ts +1734 -76
- package/src/i18n.ts +68 -68
- package/src/inbound-handler.ts +110 -7
- package/src/media-service.ts +146 -15
- package/src/message-utils.ts +90 -3
- package/src/runtime.ts +1 -0
- package/src/send-service.ts +40 -2
- package/src/state-paths.ts +11 -0
- package/src/types.ts +122 -0
package/src/message-utils.ts
CHANGED
|
@@ -149,6 +149,7 @@ export function markdownToBbCode(md: string): string {
|
|
|
149
149
|
text = text.replace(/~~(.+?)~~/g, '[S]$1[/S]');
|
|
150
150
|
|
|
151
151
|
// 3f. HTML inline formatting tags
|
|
152
|
+
text = text.replace(/<br\s*\/?>/gi, '[BR]');
|
|
152
153
|
text = text.replace(/<u>([\s\S]*?)<\/u>/gi, '[U]$1[/U]');
|
|
153
154
|
text = text.replace(/<b>([\s\S]*?)<\/b>/gi, '[B]$1[/B]');
|
|
154
155
|
text = text.replace(/<strong>([\s\S]*?)<\/strong>/gi, '[B]$1[/B]');
|
|
@@ -158,13 +159,18 @@ export function markdownToBbCode(md: string): string {
|
|
|
158
159
|
text = text.replace(/<del>([\s\S]*?)<\/del>/gi, '[S]$1[/S]');
|
|
159
160
|
text = text.replace(/<strike>([\s\S]*?)<\/strike>/gi, '[S]$1[/S]');
|
|
160
161
|
|
|
161
|
-
// 3g. Links: [text](url) →
|
|
162
|
-
text = text.replace(/\[([^\]]+)\]\(([
|
|
162
|
+
// 3g. Links: [text](url) → Bitrix BB-code links and action links
|
|
163
|
+
text = text.replace(/\[([^\]]+)\]\(([\s\S]*?)\)/g, (_match, label: string, rawTarget: string) => {
|
|
164
|
+
return convertMarkdownLink(label, rawTarget);
|
|
165
|
+
});
|
|
163
166
|
|
|
164
167
|
// 3h. Autolink URL: <https://...> → [URL]https://...[/URL]
|
|
165
168
|
text = text.replace(/<(https?:\/\/[^>]+)>/g, '[URL]$1[/URL]');
|
|
166
169
|
|
|
167
|
-
// 3i. Autolink
|
|
170
|
+
// 3i. Autolink tel URI: <tel:+79991234567> → [CALL]+79991234567[/CALL]
|
|
171
|
+
text = text.replace(/<tel:([^>]+)>/gi, '[CALL]$1[/CALL]');
|
|
172
|
+
|
|
173
|
+
// 3j. Autolink email: <user@example.com> → [URL]mailto:user@example.com[/URL]
|
|
168
174
|
text = text.replace(/<([a-zA-Z0-9._%+\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,})>/g, '[URL]mailto:$1[/URL]');
|
|
169
175
|
|
|
170
176
|
// ── Phase 4: Restore placeholders ─────────────────────────────────────────
|
|
@@ -645,6 +651,87 @@ function extractMarkdownTarget(rawTarget: string): string {
|
|
|
645
651
|
return trimmed;
|
|
646
652
|
}
|
|
647
653
|
|
|
654
|
+
function convertMarkdownLink(label: string, rawTarget: string): string {
|
|
655
|
+
const target = extractMarkdownTarget(rawTarget);
|
|
656
|
+
const normalizedTarget = target.trim();
|
|
657
|
+
|
|
658
|
+
if (!normalizedTarget) {
|
|
659
|
+
return label;
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
const sendMatch = normalizedTarget.match(/^send:(.+)$/i);
|
|
663
|
+
if (sendMatch) {
|
|
664
|
+
const payload = normalizeActionLinkPayload(sendMatch[1]);
|
|
665
|
+
return payload ? `[SEND=${payload}]${label}[/SEND]` : `[SEND]${label}[/SEND]`;
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
const putMatch = normalizedTarget.match(/^put:(.+)$/i);
|
|
669
|
+
if (putMatch) {
|
|
670
|
+
const payload = normalizeActionLinkPayload(putMatch[1]);
|
|
671
|
+
return payload ? `[PUT=${payload}]${label}[/PUT]` : `[PUT]${label}[/PUT]`;
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
const callMatch = normalizedTarget.match(/^(?:call|tel):(.+)$/i);
|
|
675
|
+
if (callMatch) {
|
|
676
|
+
const phone = callMatch[1].trim();
|
|
677
|
+
return phone ? `[CALL=${phone}]${label}[/CALL]` : `[CALL]${label}[/CALL]`;
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
const userMatch = normalizedTarget.match(/^user:(.+)$/i);
|
|
681
|
+
if (userMatch) {
|
|
682
|
+
return `[USER=${userMatch[1].trim()}]${label}[/USER]`;
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
const chatMatch = normalizedTarget.match(/^chat:(.+)$/i);
|
|
686
|
+
if (chatMatch) {
|
|
687
|
+
return `[CHAT=${chatMatch[1].trim()}]${label}[/CHAT]`;
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
const contextMatch = normalizedTarget.match(/^context:(.+)$/i);
|
|
691
|
+
if (contextMatch) {
|
|
692
|
+
return `[context=${contextMatch[1].trim()}]${label}[/context]`;
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
const diskMatch = normalizedTarget.match(/^disk:(.+)$/i);
|
|
696
|
+
if (diskMatch) {
|
|
697
|
+
return `[disk=${diskMatch[1].trim()}]`;
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
const timestampMatch = normalizedTarget.match(/^timestamp:(.+)$/i);
|
|
701
|
+
if (timestampMatch) {
|
|
702
|
+
const timestampMarkup = buildTimestampBbCode(timestampMatch[1].trim());
|
|
703
|
+
if (timestampMarkup) {
|
|
704
|
+
return timestampMarkup;
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
return `[URL=${normalizedTarget}]${label}[/URL]`;
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
function normalizeActionLinkPayload(value: string): string {
|
|
712
|
+
return value.trim().replace(/^\/\//, '/');
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
function buildTimestampBbCode(value: string): string {
|
|
716
|
+
if (!value) {
|
|
717
|
+
return '';
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
const [timestamp, rawQuery = ''] = value.split('?', 2);
|
|
721
|
+
const normalizedTimestamp = timestamp.trim();
|
|
722
|
+
if (!normalizedTimestamp) {
|
|
723
|
+
return '';
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
const params = new URLSearchParams(rawQuery);
|
|
727
|
+
const format = params.get('format')?.trim();
|
|
728
|
+
if (format) {
|
|
729
|
+
return `[timestamp=${normalizedTimestamp} format=${format}]`;
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
return `[timestamp=${normalizedTimestamp}]`;
|
|
733
|
+
}
|
|
734
|
+
|
|
648
735
|
function normalizeBitrixImageUrl(rawUrl: string): string {
|
|
649
736
|
const trimmed = rawUrl.trim();
|
|
650
737
|
if (!trimmed) return trimmed;
|
package/src/runtime.ts
CHANGED
package/src/send-service.ts
CHANGED
|
@@ -41,6 +41,7 @@ export class SendService {
|
|
|
41
41
|
options?: {
|
|
42
42
|
keyboard?: B24Keyboard;
|
|
43
43
|
convertMarkdown?: boolean;
|
|
44
|
+
replyToMessageId?: number;
|
|
44
45
|
forwardMessages?: number[];
|
|
45
46
|
system?: boolean;
|
|
46
47
|
},
|
|
@@ -49,8 +50,41 @@ export class SendService {
|
|
|
49
50
|
? markdownToBbCode(text)
|
|
50
51
|
: text;
|
|
51
52
|
|
|
52
|
-
const chunks = splitMessage(convertedText);
|
|
53
|
-
if (chunks.length === 0)
|
|
53
|
+
const chunks = convertedText.length > 0 ? splitMessage(convertedText) : [];
|
|
54
|
+
if (chunks.length === 0) {
|
|
55
|
+
if (!options?.forwardMessages?.length) {
|
|
56
|
+
return { ok: true };
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const msgOptions: {
|
|
60
|
+
forwardMessages?: number[];
|
|
61
|
+
replyToMessageId?: number;
|
|
62
|
+
system?: boolean;
|
|
63
|
+
} = {
|
|
64
|
+
forwardMessages: options.forwardMessages,
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
if (options?.replyToMessageId) {
|
|
68
|
+
msgOptions.replyToMessageId = options.replyToMessageId;
|
|
69
|
+
}
|
|
70
|
+
if (options?.system !== undefined) {
|
|
71
|
+
msgOptions.system = options.system;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
try {
|
|
75
|
+
const messageId = await this.api.sendMessage(
|
|
76
|
+
ctx.webhookUrl,
|
|
77
|
+
ctx.bot,
|
|
78
|
+
ctx.dialogId,
|
|
79
|
+
null,
|
|
80
|
+
msgOptions,
|
|
81
|
+
);
|
|
82
|
+
return { ok: true, messageId };
|
|
83
|
+
} catch (error) {
|
|
84
|
+
this.logger.error('Failed to send forwarded message without text', { error: serializeError(error) });
|
|
85
|
+
throw error;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
54
88
|
let lastMessageId: number | undefined;
|
|
55
89
|
|
|
56
90
|
for (let i = 0; i < chunks.length; i++) {
|
|
@@ -58,6 +92,7 @@ export class SendService {
|
|
|
58
92
|
const isLast = i === chunks.length - 1;
|
|
59
93
|
const msgOptions: {
|
|
60
94
|
keyboard?: B24Keyboard;
|
|
95
|
+
replyToMessageId?: number;
|
|
61
96
|
forwardMessages?: number[];
|
|
62
97
|
system?: boolean;
|
|
63
98
|
} = {};
|
|
@@ -65,6 +100,9 @@ export class SendService {
|
|
|
65
100
|
if (isLast && options?.keyboard) {
|
|
66
101
|
msgOptions.keyboard = options.keyboard;
|
|
67
102
|
}
|
|
103
|
+
if (isFirst && options?.replyToMessageId) {
|
|
104
|
+
msgOptions.replyToMessageId = options.replyToMessageId;
|
|
105
|
+
}
|
|
68
106
|
if (isFirst && options?.forwardMessages?.length) {
|
|
69
107
|
msgOptions.forwardMessages = options.forwardMessages;
|
|
70
108
|
}
|
package/src/state-paths.ts
CHANGED
|
@@ -23,6 +23,17 @@ export function resolveManagedMediaDir(env: NodeJS.ProcessEnv = process.env): st
|
|
|
23
23
|
return join(resolveOpenClawStateDir(env), 'media', 'bitrix24');
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
+
export function resolveTrustedWorkspaceDirs(env: NodeJS.ProcessEnv = process.env): string[] {
|
|
27
|
+
const roots = [
|
|
28
|
+
env.OPENCLAW_WORKSPACE_DIR?.trim(),
|
|
29
|
+
env.CLAWDBOT_WORKSPACE_DIR?.trim(),
|
|
30
|
+
join(resolveOpenClawStateDir(env), 'workspace'),
|
|
31
|
+
join(resolveHomeDir(env), 'workspace'),
|
|
32
|
+
].filter((value): value is string => Boolean(value));
|
|
33
|
+
|
|
34
|
+
return [...new Set(roots.map((root) => resolvePath(root)))];
|
|
35
|
+
}
|
|
36
|
+
|
|
26
37
|
export function resolvePollingStateDir(env: NodeJS.ProcessEnv = process.env): string {
|
|
27
38
|
return join(resolveOpenClawStateDir(env), 'state', 'bitrix24');
|
|
28
39
|
}
|
package/src/types.ts
CHANGED
|
@@ -346,12 +346,134 @@ export interface KeyboardNewline {
|
|
|
346
346
|
/** B24 keyboard: flat array with NEWLINE separators between rows */
|
|
347
347
|
export type B24Keyboard = (KeyboardButton | KeyboardNewline)[];
|
|
348
348
|
|
|
349
|
+
export type B24AttachColorToken = 'primary' | 'secondary' | 'alert' | 'base';
|
|
350
|
+
|
|
351
|
+
export interface B24AttachMessageBlock {
|
|
352
|
+
MESSAGE: string;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
export interface B24AttachLinkValue {
|
|
356
|
+
LINK: string;
|
|
357
|
+
NAME?: string;
|
|
358
|
+
DESC?: string;
|
|
359
|
+
HTML?: string;
|
|
360
|
+
PREVIEW?: string;
|
|
361
|
+
WIDTH?: number;
|
|
362
|
+
HEIGHT?: number;
|
|
363
|
+
USER_ID?: number;
|
|
364
|
+
CHAT_ID?: number;
|
|
365
|
+
NETWORK_ID?: string;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
export interface B24AttachLinkBlock {
|
|
369
|
+
LINK: B24AttachLinkValue;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
export interface B24AttachImageItem {
|
|
373
|
+
LINK: string;
|
|
374
|
+
NAME?: string;
|
|
375
|
+
PREVIEW?: string;
|
|
376
|
+
WIDTH?: number;
|
|
377
|
+
HEIGHT?: number;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
export interface B24AttachImageBlock {
|
|
381
|
+
IMAGE: B24AttachImageItem | B24AttachImageItem[];
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
export interface B24AttachFileItem {
|
|
385
|
+
LINK: string;
|
|
386
|
+
NAME?: string;
|
|
387
|
+
SIZE?: number;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
export interface B24AttachFileBlock {
|
|
391
|
+
FILE: B24AttachFileItem | B24AttachFileItem[];
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
export interface B24AttachDelimiterValue {
|
|
395
|
+
SIZE?: number;
|
|
396
|
+
COLOR?: string;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
export interface B24AttachDelimiterBlock {
|
|
400
|
+
DELIMITER: B24AttachDelimiterValue;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
export type B24AttachGridDisplay = 'BLOCK' | 'LINE' | 'ROW' | 'TABLE';
|
|
404
|
+
|
|
405
|
+
export interface B24AttachGridItem {
|
|
406
|
+
DISPLAY: B24AttachGridDisplay;
|
|
407
|
+
NAME?: string;
|
|
408
|
+
VALUE?: string;
|
|
409
|
+
WIDTH?: number;
|
|
410
|
+
HEIGHT?: number;
|
|
411
|
+
COLOR_TOKEN?: B24AttachColorToken;
|
|
412
|
+
COLOR?: string;
|
|
413
|
+
LINK?: string;
|
|
414
|
+
USER_ID?: number;
|
|
415
|
+
CHAT_ID?: number;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
export interface B24AttachGridBlock {
|
|
419
|
+
GRID: B24AttachGridItem[];
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
export interface B24AttachUserValue {
|
|
423
|
+
NAME?: string;
|
|
424
|
+
AVATAR?: string;
|
|
425
|
+
LINK?: string;
|
|
426
|
+
USER_ID?: number;
|
|
427
|
+
NETWORK_ID?: string;
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
export interface B24AttachUserBlock {
|
|
431
|
+
USER: B24AttachUserValue;
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
export type B24AttachBlock =
|
|
435
|
+
| B24AttachMessageBlock
|
|
436
|
+
| B24AttachLinkBlock
|
|
437
|
+
| B24AttachImageBlock
|
|
438
|
+
| B24AttachFileBlock
|
|
439
|
+
| B24AttachDelimiterBlock
|
|
440
|
+
| B24AttachGridBlock
|
|
441
|
+
| B24AttachUserBlock;
|
|
442
|
+
|
|
443
|
+
export interface B24AttachEnvelope {
|
|
444
|
+
ID?: number;
|
|
445
|
+
COLOR_TOKEN?: B24AttachColorToken;
|
|
446
|
+
COLOR?: string;
|
|
447
|
+
BLOCKS: B24AttachBlock[];
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
export type B24Attach = B24AttachEnvelope | B24AttachBlock[];
|
|
451
|
+
|
|
349
452
|
export interface SendMessageResult {
|
|
350
453
|
ok: boolean;
|
|
351
454
|
messageId?: number;
|
|
352
455
|
error?: string;
|
|
353
456
|
}
|
|
354
457
|
|
|
458
|
+
// ─── Message Action Discovery ────────────────────────────────────────────────
|
|
459
|
+
|
|
460
|
+
export interface ChannelMessageToolSchemaContribution {
|
|
461
|
+
properties: Record<string, unknown>;
|
|
462
|
+
visibility?: 'current-channel' | 'all-configured';
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
export interface ChannelMessageToolDiscovery {
|
|
466
|
+
actions: string[];
|
|
467
|
+
capabilities: string[];
|
|
468
|
+
schema: ChannelMessageToolSchemaContribution | ChannelMessageToolSchemaContribution[] | null;
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
export interface ExtractedToolSendTarget {
|
|
472
|
+
to: string;
|
|
473
|
+
accountId?: string;
|
|
474
|
+
threadId?: string;
|
|
475
|
+
}
|
|
476
|
+
|
|
355
477
|
// ─── FETCH Mode Context ─────────────────────────────────────────────────────
|
|
356
478
|
|
|
357
479
|
/** Context passed from PollingService to InboundHandler for FETCH events */
|