@pocketping/sdk-node 1.3.0 → 1.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 +13 -0
- package/dist/index.cjs +175 -14
- package/dist/index.d.cts +13 -5
- package/dist/index.d.ts +13 -5
- package/dist/index.js +175 -14
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -209,6 +209,12 @@ pp.addBridge(DiscordBridge.withBot({ ... }));
|
|
|
209
209
|
pp.addBridge(SlackBridge.withWebhook({ ... }));
|
|
210
210
|
```
|
|
211
211
|
|
|
212
|
+
### Reply Behavior
|
|
213
|
+
|
|
214
|
+
- **Telegram:** uses native replies when `replyTo` is set and the Telegram message ID is available.
|
|
215
|
+
- **Discord:** uses native replies via `message_reference` when the Discord message ID is available.
|
|
216
|
+
- **Slack:** renders a quoted block (left bar) in the thread.
|
|
217
|
+
|
|
212
218
|
## Architecture Options
|
|
213
219
|
|
|
214
220
|
### 1. Embedded Mode with Built-in Bridges (Simple)
|
|
@@ -255,6 +261,7 @@ const webhookHandler = new WebhookHandler({
|
|
|
255
261
|
telegramBotToken: process.env.TELEGRAM_BOT_TOKEN,
|
|
256
262
|
slackBotToken: process.env.SLACK_BOT_TOKEN,
|
|
257
263
|
discordBotToken: process.env.DISCORD_BOT_TOKEN,
|
|
264
|
+
allowedBotIds: process.env.BRIDGE_TEST_BOT_IDS?.split(',').map((id) => id.trim()).filter(Boolean),
|
|
258
265
|
onOperatorMessage: async (sessionId, content, operatorName, source, attachments) => {
|
|
259
266
|
console.log(`Message from ${operatorName} via ${source}: ${content}`);
|
|
260
267
|
|
|
@@ -267,6 +274,12 @@ const webhookHandler = new WebhookHandler({
|
|
|
267
274
|
// att.data contains the file bytes
|
|
268
275
|
}
|
|
269
276
|
},
|
|
277
|
+
onOperatorMessageEdit: async (sessionId, bridgeMessageId, content, source) => {
|
|
278
|
+
console.log(`Edited message ${bridgeMessageId} via ${source}: ${content}`);
|
|
279
|
+
},
|
|
280
|
+
onOperatorMessageDelete: async (sessionId, bridgeMessageId, source) => {
|
|
281
|
+
console.log(`Deleted message ${bridgeMessageId} via ${source}`);
|
|
282
|
+
},
|
|
270
283
|
});
|
|
271
284
|
|
|
272
285
|
// Mount webhook routes
|
package/dist/index.cjs
CHANGED
|
@@ -1212,8 +1212,67 @@ var WebhookHandler = class {
|
|
|
1212
1212
|
try {
|
|
1213
1213
|
const body = await this.parseBody(req);
|
|
1214
1214
|
const update = body;
|
|
1215
|
+
if (update.edited_message) {
|
|
1216
|
+
const msg = update.edited_message;
|
|
1217
|
+
if (msg.text?.startsWith("/")) {
|
|
1218
|
+
this.writeOK(res);
|
|
1219
|
+
return;
|
|
1220
|
+
}
|
|
1221
|
+
const text = msg.text ?? msg.caption ?? "";
|
|
1222
|
+
if (!text) {
|
|
1223
|
+
this.writeOK(res);
|
|
1224
|
+
return;
|
|
1225
|
+
}
|
|
1226
|
+
const topicId = msg.message_thread_id;
|
|
1227
|
+
if (!topicId) {
|
|
1228
|
+
this.writeOK(res);
|
|
1229
|
+
return;
|
|
1230
|
+
}
|
|
1231
|
+
if (this.config.onOperatorMessageEdit) {
|
|
1232
|
+
const editedAt = msg.edit_date ? new Date(msg.edit_date * 1e3).toISOString() : (/* @__PURE__ */ new Date()).toISOString();
|
|
1233
|
+
await this.config.onOperatorMessageEdit(
|
|
1234
|
+
String(topicId),
|
|
1235
|
+
msg.message_id,
|
|
1236
|
+
text,
|
|
1237
|
+
"telegram",
|
|
1238
|
+
editedAt
|
|
1239
|
+
);
|
|
1240
|
+
}
|
|
1241
|
+
this.writeOK(res);
|
|
1242
|
+
return;
|
|
1243
|
+
}
|
|
1244
|
+
if (update.message_reaction) {
|
|
1245
|
+
const reaction = update.message_reaction;
|
|
1246
|
+
const emoji = reaction.new_reaction?.[0]?.emoji;
|
|
1247
|
+
const topicId = reaction.message_thread_id;
|
|
1248
|
+
if (emoji && emoji.includes("\u{1F5D1}") && topicId && this.config.onOperatorMessageDelete) {
|
|
1249
|
+
const deletedAt = reaction.date ? new Date(reaction.date * 1e3).toISOString() : (/* @__PURE__ */ new Date()).toISOString();
|
|
1250
|
+
await this.config.onOperatorMessageDelete(
|
|
1251
|
+
String(topicId),
|
|
1252
|
+
reaction.message_id,
|
|
1253
|
+
"telegram",
|
|
1254
|
+
deletedAt
|
|
1255
|
+
);
|
|
1256
|
+
}
|
|
1257
|
+
this.writeOK(res);
|
|
1258
|
+
return;
|
|
1259
|
+
}
|
|
1215
1260
|
if (update.message) {
|
|
1216
1261
|
const msg = update.message;
|
|
1262
|
+
if (msg.text && /^\/delete(@\w+)?(\s|$)/.test(msg.text)) {
|
|
1263
|
+
const topicId2 = msg.message_thread_id;
|
|
1264
|
+
const replyToId = msg.reply_to_message?.message_id;
|
|
1265
|
+
if (topicId2 && replyToId && this.config.onOperatorMessageDelete) {
|
|
1266
|
+
await this.config.onOperatorMessageDelete(
|
|
1267
|
+
String(topicId2),
|
|
1268
|
+
replyToId,
|
|
1269
|
+
"telegram",
|
|
1270
|
+
(/* @__PURE__ */ new Date()).toISOString()
|
|
1271
|
+
);
|
|
1272
|
+
}
|
|
1273
|
+
this.writeOK(res);
|
|
1274
|
+
return;
|
|
1275
|
+
}
|
|
1217
1276
|
if (msg.text?.startsWith("/")) {
|
|
1218
1277
|
this.writeOK(res);
|
|
1219
1278
|
return;
|
|
@@ -1267,6 +1326,7 @@ var WebhookHandler = class {
|
|
|
1267
1326
|
return;
|
|
1268
1327
|
}
|
|
1269
1328
|
const operatorName = msg.from?.first_name ?? "Operator";
|
|
1329
|
+
const replyToBridgeMessageId = msg.reply_to_message?.message_id ?? null;
|
|
1270
1330
|
const attachments = [];
|
|
1271
1331
|
if (media) {
|
|
1272
1332
|
const data = await this.downloadTelegramFile(media.fileId);
|
|
@@ -1285,7 +1345,9 @@ var WebhookHandler = class {
|
|
|
1285
1345
|
text,
|
|
1286
1346
|
operatorName,
|
|
1287
1347
|
"telegram",
|
|
1288
|
-
attachments
|
|
1348
|
+
attachments,
|
|
1349
|
+
replyToBridgeMessageId,
|
|
1350
|
+
msg.message_id
|
|
1289
1351
|
);
|
|
1290
1352
|
}
|
|
1291
1353
|
this.writeOK(res);
|
|
@@ -1316,7 +1378,56 @@ var WebhookHandler = class {
|
|
|
1316
1378
|
}
|
|
1317
1379
|
if (payload.type === "event_callback" && payload.event) {
|
|
1318
1380
|
const event = payload.event;
|
|
1319
|
-
const
|
|
1381
|
+
const isAllowedBot = (botId) => !!botId && (this.config.allowedBotIds?.includes(botId) ?? false);
|
|
1382
|
+
if (event.subtype === "message_changed") {
|
|
1383
|
+
if (!this.config.onOperatorMessageEdit) {
|
|
1384
|
+
this.writeOK(res);
|
|
1385
|
+
return;
|
|
1386
|
+
}
|
|
1387
|
+
const botId = event.message?.bot_id ?? event.previous_message?.bot_id ?? event.bot_id;
|
|
1388
|
+
if (botId && !isAllowedBot(botId)) {
|
|
1389
|
+
this.writeOK(res);
|
|
1390
|
+
return;
|
|
1391
|
+
}
|
|
1392
|
+
const threadTs = event.message?.thread_ts ?? event.previous_message?.thread_ts;
|
|
1393
|
+
const messageTs = event.message?.ts ?? event.previous_message?.ts;
|
|
1394
|
+
const text = event.message?.text ?? "";
|
|
1395
|
+
if (threadTs && messageTs) {
|
|
1396
|
+
await this.config.onOperatorMessageEdit(
|
|
1397
|
+
threadTs,
|
|
1398
|
+
messageTs,
|
|
1399
|
+
text,
|
|
1400
|
+
"slack",
|
|
1401
|
+
(/* @__PURE__ */ new Date()).toISOString()
|
|
1402
|
+
);
|
|
1403
|
+
}
|
|
1404
|
+
this.writeOK(res);
|
|
1405
|
+
return;
|
|
1406
|
+
}
|
|
1407
|
+
if (event.subtype === "message_deleted") {
|
|
1408
|
+
if (!this.config.onOperatorMessageDelete) {
|
|
1409
|
+
this.writeOK(res);
|
|
1410
|
+
return;
|
|
1411
|
+
}
|
|
1412
|
+
const botId = event.previous_message?.bot_id ?? event.bot_id;
|
|
1413
|
+
if (botId && !isAllowedBot(botId)) {
|
|
1414
|
+
this.writeOK(res);
|
|
1415
|
+
return;
|
|
1416
|
+
}
|
|
1417
|
+
const threadTs = event.previous_message?.thread_ts;
|
|
1418
|
+
const messageTs = event.deleted_ts ?? event.previous_message?.ts;
|
|
1419
|
+
if (threadTs && messageTs) {
|
|
1420
|
+
await this.config.onOperatorMessageDelete(
|
|
1421
|
+
threadTs,
|
|
1422
|
+
messageTs,
|
|
1423
|
+
"slack",
|
|
1424
|
+
(/* @__PURE__ */ new Date()).toISOString()
|
|
1425
|
+
);
|
|
1426
|
+
}
|
|
1427
|
+
this.writeOK(res);
|
|
1428
|
+
return;
|
|
1429
|
+
}
|
|
1430
|
+
const hasContent = event.type === "message" && event.thread_ts && (!event.bot_id || isAllowedBot(event.bot_id)) && !event.subtype;
|
|
1320
1431
|
const hasFiles = event.files && event.files.length > 0;
|
|
1321
1432
|
if (hasContent && (event.text || hasFiles)) {
|
|
1322
1433
|
const threadTs = event.thread_ts;
|
|
@@ -1346,7 +1457,9 @@ var WebhookHandler = class {
|
|
|
1346
1457
|
text,
|
|
1347
1458
|
operatorName,
|
|
1348
1459
|
"slack",
|
|
1349
|
-
attachments
|
|
1460
|
+
attachments,
|
|
1461
|
+
null,
|
|
1462
|
+
event.ts ?? null
|
|
1350
1463
|
);
|
|
1351
1464
|
}
|
|
1352
1465
|
}
|
|
@@ -1384,7 +1497,8 @@ var WebhookHandler = class {
|
|
|
1384
1497
|
content,
|
|
1385
1498
|
operatorName,
|
|
1386
1499
|
"discord",
|
|
1387
|
-
[]
|
|
1500
|
+
[],
|
|
1501
|
+
null
|
|
1388
1502
|
);
|
|
1389
1503
|
res.setHeader("Content-Type", "application/json");
|
|
1390
1504
|
res.end(
|
|
@@ -1496,7 +1610,8 @@ var TelegramBridge = class {
|
|
|
1496
1610
|
/**
|
|
1497
1611
|
* Initialize the bridge (optional setup)
|
|
1498
1612
|
*/
|
|
1499
|
-
async init(
|
|
1613
|
+
async init(pocketping) {
|
|
1614
|
+
this.pocketping = pocketping;
|
|
1500
1615
|
try {
|
|
1501
1616
|
const response = await fetch(`${this.baseUrl}/getMe`);
|
|
1502
1617
|
const data = await response.json();
|
|
@@ -1525,8 +1640,18 @@ var TelegramBridge = class {
|
|
|
1525
1640
|
*/
|
|
1526
1641
|
async onVisitorMessage(message, session) {
|
|
1527
1642
|
const text = this.formatVisitorMessage(session.visitorId, message.content);
|
|
1643
|
+
let replyToMessageId;
|
|
1644
|
+
if (message.replyTo) {
|
|
1645
|
+
const storage = this.pocketping?.getStorage();
|
|
1646
|
+
if (storage?.getBridgeMessageIds) {
|
|
1647
|
+
const ids = await storage.getBridgeMessageIds(message.replyTo);
|
|
1648
|
+
if (ids?.telegramMessageId) {
|
|
1649
|
+
replyToMessageId = ids.telegramMessageId;
|
|
1650
|
+
}
|
|
1651
|
+
}
|
|
1652
|
+
}
|
|
1528
1653
|
try {
|
|
1529
|
-
const messageId = await this.sendMessage(text);
|
|
1654
|
+
const messageId = await this.sendMessage(text, replyToMessageId);
|
|
1530
1655
|
return { messageId };
|
|
1531
1656
|
} catch (error) {
|
|
1532
1657
|
console.error("[TelegramBridge] Failed to send visitor message:", error);
|
|
@@ -1663,7 +1788,7 @@ ${dataStr}
|
|
|
1663
1788
|
/**
|
|
1664
1789
|
* Send a message to the Telegram chat
|
|
1665
1790
|
*/
|
|
1666
|
-
async sendMessage(text) {
|
|
1791
|
+
async sendMessage(text, replyToMessageId) {
|
|
1667
1792
|
const response = await fetch(`${this.baseUrl}/sendMessage`, {
|
|
1668
1793
|
method: "POST",
|
|
1669
1794
|
headers: { "Content-Type": "application/json" },
|
|
@@ -1671,7 +1796,8 @@ ${dataStr}
|
|
|
1671
1796
|
chat_id: this.chatId,
|
|
1672
1797
|
text,
|
|
1673
1798
|
parse_mode: this.parseMode,
|
|
1674
|
-
disable_notification: this.disableNotification
|
|
1799
|
+
disable_notification: this.disableNotification,
|
|
1800
|
+
...replyToMessageId ? { reply_to_message_id: replyToMessageId } : {}
|
|
1675
1801
|
})
|
|
1676
1802
|
});
|
|
1677
1803
|
const data = await response.json();
|
|
@@ -1768,7 +1894,8 @@ var DiscordBridge = class _DiscordBridge {
|
|
|
1768
1894
|
/**
|
|
1769
1895
|
* Initialize the bridge (optional setup)
|
|
1770
1896
|
*/
|
|
1771
|
-
async init(
|
|
1897
|
+
async init(pocketping) {
|
|
1898
|
+
this.pocketping = pocketping;
|
|
1772
1899
|
if (this.mode === "bot" && this.botToken) {
|
|
1773
1900
|
try {
|
|
1774
1901
|
const response = await fetch("https://discord.com/api/v10/users/@me", {
|
|
@@ -1818,8 +1945,18 @@ var DiscordBridge = class _DiscordBridge {
|
|
|
1818
1945
|
// Green
|
|
1819
1946
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
1820
1947
|
};
|
|
1948
|
+
let replyToMessageId;
|
|
1949
|
+
if (message.replyTo) {
|
|
1950
|
+
const storage = this.pocketping?.getStorage();
|
|
1951
|
+
if (storage?.getBridgeMessageIds) {
|
|
1952
|
+
const ids = await storage.getBridgeMessageIds(message.replyTo);
|
|
1953
|
+
if (ids?.discordMessageId) {
|
|
1954
|
+
replyToMessageId = ids.discordMessageId;
|
|
1955
|
+
}
|
|
1956
|
+
}
|
|
1957
|
+
}
|
|
1821
1958
|
try {
|
|
1822
|
-
const messageId = await this.sendEmbed(embed);
|
|
1959
|
+
const messageId = await this.sendEmbed(embed, replyToMessageId);
|
|
1823
1960
|
return { messageId };
|
|
1824
1961
|
} catch (error) {
|
|
1825
1962
|
console.error("[DiscordBridge] Failed to send visitor message:", error);
|
|
@@ -2009,7 +2146,7 @@ ${JSON.stringify(event.data, null, 2)}
|
|
|
2009
2146
|
/**
|
|
2010
2147
|
* Send an embed to Discord
|
|
2011
2148
|
*/
|
|
2012
|
-
async sendEmbed(embed) {
|
|
2149
|
+
async sendEmbed(embed, replyToMessageId) {
|
|
2013
2150
|
const body = {
|
|
2014
2151
|
embeds: [embed]
|
|
2015
2152
|
};
|
|
@@ -2020,6 +2157,9 @@ ${JSON.stringify(event.data, null, 2)}
|
|
|
2020
2157
|
body.avatar_url = this.avatarUrl;
|
|
2021
2158
|
}
|
|
2022
2159
|
if (this.mode === "webhook" && this.webhookUrl) {
|
|
2160
|
+
if (replyToMessageId) {
|
|
2161
|
+
body.message_reference = { message_id: replyToMessageId };
|
|
2162
|
+
}
|
|
2023
2163
|
const response = await fetch(`${this.webhookUrl}?wait=true`, {
|
|
2024
2164
|
method: "POST",
|
|
2025
2165
|
headers: { "Content-Type": "application/json" },
|
|
@@ -2032,6 +2172,9 @@ ${JSON.stringify(event.data, null, 2)}
|
|
|
2032
2172
|
const data = await response.json();
|
|
2033
2173
|
return data.id;
|
|
2034
2174
|
} else if (this.mode === "bot" && this.channelId) {
|
|
2175
|
+
if (replyToMessageId) {
|
|
2176
|
+
body.message_reference = { message_id: replyToMessageId };
|
|
2177
|
+
}
|
|
2035
2178
|
const response = await fetch(
|
|
2036
2179
|
`https://discord.com/api/v10/channels/${this.channelId}/messages`,
|
|
2037
2180
|
{
|
|
@@ -2094,7 +2237,8 @@ var SlackBridge = class _SlackBridge {
|
|
|
2094
2237
|
/**
|
|
2095
2238
|
* Initialize the bridge (optional setup)
|
|
2096
2239
|
*/
|
|
2097
|
-
async init(
|
|
2240
|
+
async init(pocketping) {
|
|
2241
|
+
this.pocketping = pocketping;
|
|
2098
2242
|
if (this.mode === "bot" && this.botToken) {
|
|
2099
2243
|
try {
|
|
2100
2244
|
const response = await fetch("https://slack.com/api/auth.test", {
|
|
@@ -2154,7 +2298,24 @@ ${url}`
|
|
|
2154
2298
|
* Returns the Slack message timestamp for edit/delete sync.
|
|
2155
2299
|
*/
|
|
2156
2300
|
async onVisitorMessage(message, session) {
|
|
2157
|
-
const blocks = [
|
|
2301
|
+
const blocks = [];
|
|
2302
|
+
if (message.replyTo && this.pocketping?.getStorage().getMessage) {
|
|
2303
|
+
const replyTarget = await this.pocketping.getStorage().getMessage(message.replyTo);
|
|
2304
|
+
if (replyTarget) {
|
|
2305
|
+
const senderLabel = replyTarget.sender === "visitor" ? "Visitor" : replyTarget.sender === "operator" ? "Support" : "AI";
|
|
2306
|
+
const rawPreview = replyTarget.deletedAt ? "Message deleted" : replyTarget.content || "Message";
|
|
2307
|
+
const preview = rawPreview.length > 140 ? `${rawPreview.slice(0, 140)}...` : rawPreview;
|
|
2308
|
+
const quoted = `> *${this.escapeSlack(senderLabel)}* \u2014 ${this.escapeSlack(preview)}`;
|
|
2309
|
+
blocks.push({
|
|
2310
|
+
type: "section",
|
|
2311
|
+
text: {
|
|
2312
|
+
type: "mrkdwn",
|
|
2313
|
+
text: quoted
|
|
2314
|
+
}
|
|
2315
|
+
});
|
|
2316
|
+
}
|
|
2317
|
+
}
|
|
2318
|
+
blocks.push(
|
|
2158
2319
|
{
|
|
2159
2320
|
type: "section",
|
|
2160
2321
|
text: {
|
|
@@ -2172,7 +2333,7 @@ ${this.escapeSlack(message.content)}`
|
|
|
2172
2333
|
}
|
|
2173
2334
|
]
|
|
2174
2335
|
}
|
|
2175
|
-
|
|
2336
|
+
);
|
|
2176
2337
|
try {
|
|
2177
2338
|
const messageId = await this.sendBlocks(blocks);
|
|
2178
2339
|
return { messageId };
|
package/dist/index.d.cts
CHANGED
|
@@ -594,13 +594,18 @@ interface OperatorAttachment {
|
|
|
594
594
|
bridgeFileId?: string;
|
|
595
595
|
}
|
|
596
596
|
/** Callback when operator sends a message from a bridge */
|
|
597
|
-
type OperatorMessageCallback = (sessionId: string, content: string, operatorName: string, sourceBridge: 'telegram' | 'discord' | 'slack', attachments: OperatorAttachment[]) => void | Promise<void>;
|
|
597
|
+
type OperatorMessageCallback = (sessionId: string, content: string, operatorName: string, sourceBridge: 'telegram' | 'discord' | 'slack', attachments: OperatorAttachment[], replyToBridgeMessageId?: number | null, bridgeMessageId?: number | string | null) => void | Promise<void>;
|
|
598
|
+
type OperatorMessageEditCallback = (sessionId: string, bridgeMessageId: number | string, content: string, sourceBridge: 'telegram' | 'discord' | 'slack', editedAt?: string) => void | Promise<void>;
|
|
599
|
+
type OperatorMessageDeleteCallback = (sessionId: string, bridgeMessageId: number | string, sourceBridge: 'telegram' | 'discord' | 'slack', deletedAt?: string) => void | Promise<void>;
|
|
598
600
|
/** Webhook handler configuration */
|
|
599
601
|
interface WebhookConfig {
|
|
600
602
|
telegramBotToken?: string;
|
|
601
603
|
slackBotToken?: string;
|
|
602
604
|
discordBotToken?: string;
|
|
605
|
+
allowedBotIds?: string[];
|
|
603
606
|
onOperatorMessage: OperatorMessageCallback;
|
|
607
|
+
onOperatorMessageEdit?: OperatorMessageEditCallback;
|
|
608
|
+
onOperatorMessageDelete?: OperatorMessageDeleteCallback;
|
|
604
609
|
}
|
|
605
610
|
declare class WebhookHandler {
|
|
606
611
|
private config;
|
|
@@ -655,6 +660,7 @@ interface TelegramBridgeOptions {
|
|
|
655
660
|
*/
|
|
656
661
|
declare class TelegramBridge implements Bridge {
|
|
657
662
|
readonly name = "telegram";
|
|
663
|
+
private pocketping?;
|
|
658
664
|
private readonly botToken;
|
|
659
665
|
private readonly chatId;
|
|
660
666
|
private readonly parseMode;
|
|
@@ -664,7 +670,7 @@ declare class TelegramBridge implements Bridge {
|
|
|
664
670
|
/**
|
|
665
671
|
* Initialize the bridge (optional setup)
|
|
666
672
|
*/
|
|
667
|
-
init(
|
|
673
|
+
init(pocketping: PocketPing): Promise<void>;
|
|
668
674
|
/**
|
|
669
675
|
* Called when a new chat session is created
|
|
670
676
|
*/
|
|
@@ -770,6 +776,7 @@ interface DiscordBotOptions {
|
|
|
770
776
|
*/
|
|
771
777
|
declare class DiscordBridge implements Bridge {
|
|
772
778
|
readonly name = "discord";
|
|
779
|
+
private pocketping?;
|
|
773
780
|
private readonly mode;
|
|
774
781
|
private readonly webhookUrl?;
|
|
775
782
|
private readonly botToken?;
|
|
@@ -788,7 +795,7 @@ declare class DiscordBridge implements Bridge {
|
|
|
788
795
|
/**
|
|
789
796
|
* Initialize the bridge (optional setup)
|
|
790
797
|
*/
|
|
791
|
-
init(
|
|
798
|
+
init(pocketping: PocketPing): Promise<void>;
|
|
792
799
|
/**
|
|
793
800
|
* Called when a new chat session is created
|
|
794
801
|
*/
|
|
@@ -878,6 +885,7 @@ interface SlackBotOptions {
|
|
|
878
885
|
*/
|
|
879
886
|
declare class SlackBridge implements Bridge {
|
|
880
887
|
readonly name = "slack";
|
|
888
|
+
private pocketping?;
|
|
881
889
|
private readonly mode;
|
|
882
890
|
private readonly webhookUrl?;
|
|
883
891
|
private readonly botToken?;
|
|
@@ -897,7 +905,7 @@ declare class SlackBridge implements Bridge {
|
|
|
897
905
|
/**
|
|
898
906
|
* Initialize the bridge (optional setup)
|
|
899
907
|
*/
|
|
900
|
-
init(
|
|
908
|
+
init(pocketping: PocketPing): Promise<void>;
|
|
901
909
|
/**
|
|
902
910
|
* Called when a new chat session is created
|
|
903
911
|
*/
|
|
@@ -946,4 +954,4 @@ declare class SlackBridge implements Bridge {
|
|
|
946
954
|
private escapeSlack;
|
|
947
955
|
}
|
|
948
956
|
|
|
949
|
-
export { type AIProvider, type Bridge, type BridgeMessageIds, type BridgeMessageResult, type ConnectRequest, type ConnectResponse, type CustomEvent, type CustomEventHandler, type DeleteMessageRequest, type DeleteMessageResponse, type DiscordBotOptions, DiscordBridge, type DiscordWebhookOptions, type EditMessageRequest, type EditMessageResponse, MemoryStorage, type Message, type OperatorAttachment, type OperatorMessageCallback, PocketPing, type PocketPingConfig, type PresenceResponse, type SendMessageRequest, type SendMessageResponse, type Session, type SlackBotOptions, SlackBridge, type SlackWebhookOptions, type Storage, TelegramBridge, type TelegramBridgeOptions, type TrackedElement, type TriggerOptions, type WebhookConfig, WebhookHandler, type WebhookPayload };
|
|
957
|
+
export { type AIProvider, type Bridge, type BridgeMessageIds, type BridgeMessageResult, type ConnectRequest, type ConnectResponse, type CustomEvent, type CustomEventHandler, type DeleteMessageRequest, type DeleteMessageResponse, type DiscordBotOptions, DiscordBridge, type DiscordWebhookOptions, type EditMessageRequest, type EditMessageResponse, MemoryStorage, type Message, type OperatorAttachment, type OperatorMessageCallback, type OperatorMessageDeleteCallback, type OperatorMessageEditCallback, PocketPing, type PocketPingConfig, type PresenceResponse, type SendMessageRequest, type SendMessageResponse, type Session, type SlackBotOptions, SlackBridge, type SlackWebhookOptions, type Storage, TelegramBridge, type TelegramBridgeOptions, type TrackedElement, type TriggerOptions, type WebhookConfig, WebhookHandler, type WebhookPayload };
|
package/dist/index.d.ts
CHANGED
|
@@ -594,13 +594,18 @@ interface OperatorAttachment {
|
|
|
594
594
|
bridgeFileId?: string;
|
|
595
595
|
}
|
|
596
596
|
/** Callback when operator sends a message from a bridge */
|
|
597
|
-
type OperatorMessageCallback = (sessionId: string, content: string, operatorName: string, sourceBridge: 'telegram' | 'discord' | 'slack', attachments: OperatorAttachment[]) => void | Promise<void>;
|
|
597
|
+
type OperatorMessageCallback = (sessionId: string, content: string, operatorName: string, sourceBridge: 'telegram' | 'discord' | 'slack', attachments: OperatorAttachment[], replyToBridgeMessageId?: number | null, bridgeMessageId?: number | string | null) => void | Promise<void>;
|
|
598
|
+
type OperatorMessageEditCallback = (sessionId: string, bridgeMessageId: number | string, content: string, sourceBridge: 'telegram' | 'discord' | 'slack', editedAt?: string) => void | Promise<void>;
|
|
599
|
+
type OperatorMessageDeleteCallback = (sessionId: string, bridgeMessageId: number | string, sourceBridge: 'telegram' | 'discord' | 'slack', deletedAt?: string) => void | Promise<void>;
|
|
598
600
|
/** Webhook handler configuration */
|
|
599
601
|
interface WebhookConfig {
|
|
600
602
|
telegramBotToken?: string;
|
|
601
603
|
slackBotToken?: string;
|
|
602
604
|
discordBotToken?: string;
|
|
605
|
+
allowedBotIds?: string[];
|
|
603
606
|
onOperatorMessage: OperatorMessageCallback;
|
|
607
|
+
onOperatorMessageEdit?: OperatorMessageEditCallback;
|
|
608
|
+
onOperatorMessageDelete?: OperatorMessageDeleteCallback;
|
|
604
609
|
}
|
|
605
610
|
declare class WebhookHandler {
|
|
606
611
|
private config;
|
|
@@ -655,6 +660,7 @@ interface TelegramBridgeOptions {
|
|
|
655
660
|
*/
|
|
656
661
|
declare class TelegramBridge implements Bridge {
|
|
657
662
|
readonly name = "telegram";
|
|
663
|
+
private pocketping?;
|
|
658
664
|
private readonly botToken;
|
|
659
665
|
private readonly chatId;
|
|
660
666
|
private readonly parseMode;
|
|
@@ -664,7 +670,7 @@ declare class TelegramBridge implements Bridge {
|
|
|
664
670
|
/**
|
|
665
671
|
* Initialize the bridge (optional setup)
|
|
666
672
|
*/
|
|
667
|
-
init(
|
|
673
|
+
init(pocketping: PocketPing): Promise<void>;
|
|
668
674
|
/**
|
|
669
675
|
* Called when a new chat session is created
|
|
670
676
|
*/
|
|
@@ -770,6 +776,7 @@ interface DiscordBotOptions {
|
|
|
770
776
|
*/
|
|
771
777
|
declare class DiscordBridge implements Bridge {
|
|
772
778
|
readonly name = "discord";
|
|
779
|
+
private pocketping?;
|
|
773
780
|
private readonly mode;
|
|
774
781
|
private readonly webhookUrl?;
|
|
775
782
|
private readonly botToken?;
|
|
@@ -788,7 +795,7 @@ declare class DiscordBridge implements Bridge {
|
|
|
788
795
|
/**
|
|
789
796
|
* Initialize the bridge (optional setup)
|
|
790
797
|
*/
|
|
791
|
-
init(
|
|
798
|
+
init(pocketping: PocketPing): Promise<void>;
|
|
792
799
|
/**
|
|
793
800
|
* Called when a new chat session is created
|
|
794
801
|
*/
|
|
@@ -878,6 +885,7 @@ interface SlackBotOptions {
|
|
|
878
885
|
*/
|
|
879
886
|
declare class SlackBridge implements Bridge {
|
|
880
887
|
readonly name = "slack";
|
|
888
|
+
private pocketping?;
|
|
881
889
|
private readonly mode;
|
|
882
890
|
private readonly webhookUrl?;
|
|
883
891
|
private readonly botToken?;
|
|
@@ -897,7 +905,7 @@ declare class SlackBridge implements Bridge {
|
|
|
897
905
|
/**
|
|
898
906
|
* Initialize the bridge (optional setup)
|
|
899
907
|
*/
|
|
900
|
-
init(
|
|
908
|
+
init(pocketping: PocketPing): Promise<void>;
|
|
901
909
|
/**
|
|
902
910
|
* Called when a new chat session is created
|
|
903
911
|
*/
|
|
@@ -946,4 +954,4 @@ declare class SlackBridge implements Bridge {
|
|
|
946
954
|
private escapeSlack;
|
|
947
955
|
}
|
|
948
956
|
|
|
949
|
-
export { type AIProvider, type Bridge, type BridgeMessageIds, type BridgeMessageResult, type ConnectRequest, type ConnectResponse, type CustomEvent, type CustomEventHandler, type DeleteMessageRequest, type DeleteMessageResponse, type DiscordBotOptions, DiscordBridge, type DiscordWebhookOptions, type EditMessageRequest, type EditMessageResponse, MemoryStorage, type Message, type OperatorAttachment, type OperatorMessageCallback, PocketPing, type PocketPingConfig, type PresenceResponse, type SendMessageRequest, type SendMessageResponse, type Session, type SlackBotOptions, SlackBridge, type SlackWebhookOptions, type Storage, TelegramBridge, type TelegramBridgeOptions, type TrackedElement, type TriggerOptions, type WebhookConfig, WebhookHandler, type WebhookPayload };
|
|
957
|
+
export { type AIProvider, type Bridge, type BridgeMessageIds, type BridgeMessageResult, type ConnectRequest, type ConnectResponse, type CustomEvent, type CustomEventHandler, type DeleteMessageRequest, type DeleteMessageResponse, type DiscordBotOptions, DiscordBridge, type DiscordWebhookOptions, type EditMessageRequest, type EditMessageResponse, MemoryStorage, type Message, type OperatorAttachment, type OperatorMessageCallback, type OperatorMessageDeleteCallback, type OperatorMessageEditCallback, PocketPing, type PocketPingConfig, type PresenceResponse, type SendMessageRequest, type SendMessageResponse, type Session, type SlackBotOptions, SlackBridge, type SlackWebhookOptions, type Storage, TelegramBridge, type TelegramBridgeOptions, type TrackedElement, type TriggerOptions, type WebhookConfig, WebhookHandler, type WebhookPayload };
|
package/dist/index.js
CHANGED
|
@@ -1181,8 +1181,67 @@ var WebhookHandler = class {
|
|
|
1181
1181
|
try {
|
|
1182
1182
|
const body = await this.parseBody(req);
|
|
1183
1183
|
const update = body;
|
|
1184
|
+
if (update.edited_message) {
|
|
1185
|
+
const msg = update.edited_message;
|
|
1186
|
+
if (msg.text?.startsWith("/")) {
|
|
1187
|
+
this.writeOK(res);
|
|
1188
|
+
return;
|
|
1189
|
+
}
|
|
1190
|
+
const text = msg.text ?? msg.caption ?? "";
|
|
1191
|
+
if (!text) {
|
|
1192
|
+
this.writeOK(res);
|
|
1193
|
+
return;
|
|
1194
|
+
}
|
|
1195
|
+
const topicId = msg.message_thread_id;
|
|
1196
|
+
if (!topicId) {
|
|
1197
|
+
this.writeOK(res);
|
|
1198
|
+
return;
|
|
1199
|
+
}
|
|
1200
|
+
if (this.config.onOperatorMessageEdit) {
|
|
1201
|
+
const editedAt = msg.edit_date ? new Date(msg.edit_date * 1e3).toISOString() : (/* @__PURE__ */ new Date()).toISOString();
|
|
1202
|
+
await this.config.onOperatorMessageEdit(
|
|
1203
|
+
String(topicId),
|
|
1204
|
+
msg.message_id,
|
|
1205
|
+
text,
|
|
1206
|
+
"telegram",
|
|
1207
|
+
editedAt
|
|
1208
|
+
);
|
|
1209
|
+
}
|
|
1210
|
+
this.writeOK(res);
|
|
1211
|
+
return;
|
|
1212
|
+
}
|
|
1213
|
+
if (update.message_reaction) {
|
|
1214
|
+
const reaction = update.message_reaction;
|
|
1215
|
+
const emoji = reaction.new_reaction?.[0]?.emoji;
|
|
1216
|
+
const topicId = reaction.message_thread_id;
|
|
1217
|
+
if (emoji && emoji.includes("\u{1F5D1}") && topicId && this.config.onOperatorMessageDelete) {
|
|
1218
|
+
const deletedAt = reaction.date ? new Date(reaction.date * 1e3).toISOString() : (/* @__PURE__ */ new Date()).toISOString();
|
|
1219
|
+
await this.config.onOperatorMessageDelete(
|
|
1220
|
+
String(topicId),
|
|
1221
|
+
reaction.message_id,
|
|
1222
|
+
"telegram",
|
|
1223
|
+
deletedAt
|
|
1224
|
+
);
|
|
1225
|
+
}
|
|
1226
|
+
this.writeOK(res);
|
|
1227
|
+
return;
|
|
1228
|
+
}
|
|
1184
1229
|
if (update.message) {
|
|
1185
1230
|
const msg = update.message;
|
|
1231
|
+
if (msg.text && /^\/delete(@\w+)?(\s|$)/.test(msg.text)) {
|
|
1232
|
+
const topicId2 = msg.message_thread_id;
|
|
1233
|
+
const replyToId = msg.reply_to_message?.message_id;
|
|
1234
|
+
if (topicId2 && replyToId && this.config.onOperatorMessageDelete) {
|
|
1235
|
+
await this.config.onOperatorMessageDelete(
|
|
1236
|
+
String(topicId2),
|
|
1237
|
+
replyToId,
|
|
1238
|
+
"telegram",
|
|
1239
|
+
(/* @__PURE__ */ new Date()).toISOString()
|
|
1240
|
+
);
|
|
1241
|
+
}
|
|
1242
|
+
this.writeOK(res);
|
|
1243
|
+
return;
|
|
1244
|
+
}
|
|
1186
1245
|
if (msg.text?.startsWith("/")) {
|
|
1187
1246
|
this.writeOK(res);
|
|
1188
1247
|
return;
|
|
@@ -1236,6 +1295,7 @@ var WebhookHandler = class {
|
|
|
1236
1295
|
return;
|
|
1237
1296
|
}
|
|
1238
1297
|
const operatorName = msg.from?.first_name ?? "Operator";
|
|
1298
|
+
const replyToBridgeMessageId = msg.reply_to_message?.message_id ?? null;
|
|
1239
1299
|
const attachments = [];
|
|
1240
1300
|
if (media) {
|
|
1241
1301
|
const data = await this.downloadTelegramFile(media.fileId);
|
|
@@ -1254,7 +1314,9 @@ var WebhookHandler = class {
|
|
|
1254
1314
|
text,
|
|
1255
1315
|
operatorName,
|
|
1256
1316
|
"telegram",
|
|
1257
|
-
attachments
|
|
1317
|
+
attachments,
|
|
1318
|
+
replyToBridgeMessageId,
|
|
1319
|
+
msg.message_id
|
|
1258
1320
|
);
|
|
1259
1321
|
}
|
|
1260
1322
|
this.writeOK(res);
|
|
@@ -1285,7 +1347,56 @@ var WebhookHandler = class {
|
|
|
1285
1347
|
}
|
|
1286
1348
|
if (payload.type === "event_callback" && payload.event) {
|
|
1287
1349
|
const event = payload.event;
|
|
1288
|
-
const
|
|
1350
|
+
const isAllowedBot = (botId) => !!botId && (this.config.allowedBotIds?.includes(botId) ?? false);
|
|
1351
|
+
if (event.subtype === "message_changed") {
|
|
1352
|
+
if (!this.config.onOperatorMessageEdit) {
|
|
1353
|
+
this.writeOK(res);
|
|
1354
|
+
return;
|
|
1355
|
+
}
|
|
1356
|
+
const botId = event.message?.bot_id ?? event.previous_message?.bot_id ?? event.bot_id;
|
|
1357
|
+
if (botId && !isAllowedBot(botId)) {
|
|
1358
|
+
this.writeOK(res);
|
|
1359
|
+
return;
|
|
1360
|
+
}
|
|
1361
|
+
const threadTs = event.message?.thread_ts ?? event.previous_message?.thread_ts;
|
|
1362
|
+
const messageTs = event.message?.ts ?? event.previous_message?.ts;
|
|
1363
|
+
const text = event.message?.text ?? "";
|
|
1364
|
+
if (threadTs && messageTs) {
|
|
1365
|
+
await this.config.onOperatorMessageEdit(
|
|
1366
|
+
threadTs,
|
|
1367
|
+
messageTs,
|
|
1368
|
+
text,
|
|
1369
|
+
"slack",
|
|
1370
|
+
(/* @__PURE__ */ new Date()).toISOString()
|
|
1371
|
+
);
|
|
1372
|
+
}
|
|
1373
|
+
this.writeOK(res);
|
|
1374
|
+
return;
|
|
1375
|
+
}
|
|
1376
|
+
if (event.subtype === "message_deleted") {
|
|
1377
|
+
if (!this.config.onOperatorMessageDelete) {
|
|
1378
|
+
this.writeOK(res);
|
|
1379
|
+
return;
|
|
1380
|
+
}
|
|
1381
|
+
const botId = event.previous_message?.bot_id ?? event.bot_id;
|
|
1382
|
+
if (botId && !isAllowedBot(botId)) {
|
|
1383
|
+
this.writeOK(res);
|
|
1384
|
+
return;
|
|
1385
|
+
}
|
|
1386
|
+
const threadTs = event.previous_message?.thread_ts;
|
|
1387
|
+
const messageTs = event.deleted_ts ?? event.previous_message?.ts;
|
|
1388
|
+
if (threadTs && messageTs) {
|
|
1389
|
+
await this.config.onOperatorMessageDelete(
|
|
1390
|
+
threadTs,
|
|
1391
|
+
messageTs,
|
|
1392
|
+
"slack",
|
|
1393
|
+
(/* @__PURE__ */ new Date()).toISOString()
|
|
1394
|
+
);
|
|
1395
|
+
}
|
|
1396
|
+
this.writeOK(res);
|
|
1397
|
+
return;
|
|
1398
|
+
}
|
|
1399
|
+
const hasContent = event.type === "message" && event.thread_ts && (!event.bot_id || isAllowedBot(event.bot_id)) && !event.subtype;
|
|
1289
1400
|
const hasFiles = event.files && event.files.length > 0;
|
|
1290
1401
|
if (hasContent && (event.text || hasFiles)) {
|
|
1291
1402
|
const threadTs = event.thread_ts;
|
|
@@ -1315,7 +1426,9 @@ var WebhookHandler = class {
|
|
|
1315
1426
|
text,
|
|
1316
1427
|
operatorName,
|
|
1317
1428
|
"slack",
|
|
1318
|
-
attachments
|
|
1429
|
+
attachments,
|
|
1430
|
+
null,
|
|
1431
|
+
event.ts ?? null
|
|
1319
1432
|
);
|
|
1320
1433
|
}
|
|
1321
1434
|
}
|
|
@@ -1353,7 +1466,8 @@ var WebhookHandler = class {
|
|
|
1353
1466
|
content,
|
|
1354
1467
|
operatorName,
|
|
1355
1468
|
"discord",
|
|
1356
|
-
[]
|
|
1469
|
+
[],
|
|
1470
|
+
null
|
|
1357
1471
|
);
|
|
1358
1472
|
res.setHeader("Content-Type", "application/json");
|
|
1359
1473
|
res.end(
|
|
@@ -1465,7 +1579,8 @@ var TelegramBridge = class {
|
|
|
1465
1579
|
/**
|
|
1466
1580
|
* Initialize the bridge (optional setup)
|
|
1467
1581
|
*/
|
|
1468
|
-
async init(
|
|
1582
|
+
async init(pocketping) {
|
|
1583
|
+
this.pocketping = pocketping;
|
|
1469
1584
|
try {
|
|
1470
1585
|
const response = await fetch(`${this.baseUrl}/getMe`);
|
|
1471
1586
|
const data = await response.json();
|
|
@@ -1494,8 +1609,18 @@ var TelegramBridge = class {
|
|
|
1494
1609
|
*/
|
|
1495
1610
|
async onVisitorMessage(message, session) {
|
|
1496
1611
|
const text = this.formatVisitorMessage(session.visitorId, message.content);
|
|
1612
|
+
let replyToMessageId;
|
|
1613
|
+
if (message.replyTo) {
|
|
1614
|
+
const storage = this.pocketping?.getStorage();
|
|
1615
|
+
if (storage?.getBridgeMessageIds) {
|
|
1616
|
+
const ids = await storage.getBridgeMessageIds(message.replyTo);
|
|
1617
|
+
if (ids?.telegramMessageId) {
|
|
1618
|
+
replyToMessageId = ids.telegramMessageId;
|
|
1619
|
+
}
|
|
1620
|
+
}
|
|
1621
|
+
}
|
|
1497
1622
|
try {
|
|
1498
|
-
const messageId = await this.sendMessage(text);
|
|
1623
|
+
const messageId = await this.sendMessage(text, replyToMessageId);
|
|
1499
1624
|
return { messageId };
|
|
1500
1625
|
} catch (error) {
|
|
1501
1626
|
console.error("[TelegramBridge] Failed to send visitor message:", error);
|
|
@@ -1632,7 +1757,7 @@ ${dataStr}
|
|
|
1632
1757
|
/**
|
|
1633
1758
|
* Send a message to the Telegram chat
|
|
1634
1759
|
*/
|
|
1635
|
-
async sendMessage(text) {
|
|
1760
|
+
async sendMessage(text, replyToMessageId) {
|
|
1636
1761
|
const response = await fetch(`${this.baseUrl}/sendMessage`, {
|
|
1637
1762
|
method: "POST",
|
|
1638
1763
|
headers: { "Content-Type": "application/json" },
|
|
@@ -1640,7 +1765,8 @@ ${dataStr}
|
|
|
1640
1765
|
chat_id: this.chatId,
|
|
1641
1766
|
text,
|
|
1642
1767
|
parse_mode: this.parseMode,
|
|
1643
|
-
disable_notification: this.disableNotification
|
|
1768
|
+
disable_notification: this.disableNotification,
|
|
1769
|
+
...replyToMessageId ? { reply_to_message_id: replyToMessageId } : {}
|
|
1644
1770
|
})
|
|
1645
1771
|
});
|
|
1646
1772
|
const data = await response.json();
|
|
@@ -1737,7 +1863,8 @@ var DiscordBridge = class _DiscordBridge {
|
|
|
1737
1863
|
/**
|
|
1738
1864
|
* Initialize the bridge (optional setup)
|
|
1739
1865
|
*/
|
|
1740
|
-
async init(
|
|
1866
|
+
async init(pocketping) {
|
|
1867
|
+
this.pocketping = pocketping;
|
|
1741
1868
|
if (this.mode === "bot" && this.botToken) {
|
|
1742
1869
|
try {
|
|
1743
1870
|
const response = await fetch("https://discord.com/api/v10/users/@me", {
|
|
@@ -1787,8 +1914,18 @@ var DiscordBridge = class _DiscordBridge {
|
|
|
1787
1914
|
// Green
|
|
1788
1915
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
1789
1916
|
};
|
|
1917
|
+
let replyToMessageId;
|
|
1918
|
+
if (message.replyTo) {
|
|
1919
|
+
const storage = this.pocketping?.getStorage();
|
|
1920
|
+
if (storage?.getBridgeMessageIds) {
|
|
1921
|
+
const ids = await storage.getBridgeMessageIds(message.replyTo);
|
|
1922
|
+
if (ids?.discordMessageId) {
|
|
1923
|
+
replyToMessageId = ids.discordMessageId;
|
|
1924
|
+
}
|
|
1925
|
+
}
|
|
1926
|
+
}
|
|
1790
1927
|
try {
|
|
1791
|
-
const messageId = await this.sendEmbed(embed);
|
|
1928
|
+
const messageId = await this.sendEmbed(embed, replyToMessageId);
|
|
1792
1929
|
return { messageId };
|
|
1793
1930
|
} catch (error) {
|
|
1794
1931
|
console.error("[DiscordBridge] Failed to send visitor message:", error);
|
|
@@ -1978,7 +2115,7 @@ ${JSON.stringify(event.data, null, 2)}
|
|
|
1978
2115
|
/**
|
|
1979
2116
|
* Send an embed to Discord
|
|
1980
2117
|
*/
|
|
1981
|
-
async sendEmbed(embed) {
|
|
2118
|
+
async sendEmbed(embed, replyToMessageId) {
|
|
1982
2119
|
const body = {
|
|
1983
2120
|
embeds: [embed]
|
|
1984
2121
|
};
|
|
@@ -1989,6 +2126,9 @@ ${JSON.stringify(event.data, null, 2)}
|
|
|
1989
2126
|
body.avatar_url = this.avatarUrl;
|
|
1990
2127
|
}
|
|
1991
2128
|
if (this.mode === "webhook" && this.webhookUrl) {
|
|
2129
|
+
if (replyToMessageId) {
|
|
2130
|
+
body.message_reference = { message_id: replyToMessageId };
|
|
2131
|
+
}
|
|
1992
2132
|
const response = await fetch(`${this.webhookUrl}?wait=true`, {
|
|
1993
2133
|
method: "POST",
|
|
1994
2134
|
headers: { "Content-Type": "application/json" },
|
|
@@ -2001,6 +2141,9 @@ ${JSON.stringify(event.data, null, 2)}
|
|
|
2001
2141
|
const data = await response.json();
|
|
2002
2142
|
return data.id;
|
|
2003
2143
|
} else if (this.mode === "bot" && this.channelId) {
|
|
2144
|
+
if (replyToMessageId) {
|
|
2145
|
+
body.message_reference = { message_id: replyToMessageId };
|
|
2146
|
+
}
|
|
2004
2147
|
const response = await fetch(
|
|
2005
2148
|
`https://discord.com/api/v10/channels/${this.channelId}/messages`,
|
|
2006
2149
|
{
|
|
@@ -2063,7 +2206,8 @@ var SlackBridge = class _SlackBridge {
|
|
|
2063
2206
|
/**
|
|
2064
2207
|
* Initialize the bridge (optional setup)
|
|
2065
2208
|
*/
|
|
2066
|
-
async init(
|
|
2209
|
+
async init(pocketping) {
|
|
2210
|
+
this.pocketping = pocketping;
|
|
2067
2211
|
if (this.mode === "bot" && this.botToken) {
|
|
2068
2212
|
try {
|
|
2069
2213
|
const response = await fetch("https://slack.com/api/auth.test", {
|
|
@@ -2123,7 +2267,24 @@ ${url}`
|
|
|
2123
2267
|
* Returns the Slack message timestamp for edit/delete sync.
|
|
2124
2268
|
*/
|
|
2125
2269
|
async onVisitorMessage(message, session) {
|
|
2126
|
-
const blocks = [
|
|
2270
|
+
const blocks = [];
|
|
2271
|
+
if (message.replyTo && this.pocketping?.getStorage().getMessage) {
|
|
2272
|
+
const replyTarget = await this.pocketping.getStorage().getMessage(message.replyTo);
|
|
2273
|
+
if (replyTarget) {
|
|
2274
|
+
const senderLabel = replyTarget.sender === "visitor" ? "Visitor" : replyTarget.sender === "operator" ? "Support" : "AI";
|
|
2275
|
+
const rawPreview = replyTarget.deletedAt ? "Message deleted" : replyTarget.content || "Message";
|
|
2276
|
+
const preview = rawPreview.length > 140 ? `${rawPreview.slice(0, 140)}...` : rawPreview;
|
|
2277
|
+
const quoted = `> *${this.escapeSlack(senderLabel)}* \u2014 ${this.escapeSlack(preview)}`;
|
|
2278
|
+
blocks.push({
|
|
2279
|
+
type: "section",
|
|
2280
|
+
text: {
|
|
2281
|
+
type: "mrkdwn",
|
|
2282
|
+
text: quoted
|
|
2283
|
+
}
|
|
2284
|
+
});
|
|
2285
|
+
}
|
|
2286
|
+
}
|
|
2287
|
+
blocks.push(
|
|
2127
2288
|
{
|
|
2128
2289
|
type: "section",
|
|
2129
2290
|
text: {
|
|
@@ -2141,7 +2302,7 @@ ${this.escapeSlack(message.content)}`
|
|
|
2141
2302
|
}
|
|
2142
2303
|
]
|
|
2143
2304
|
}
|
|
2144
|
-
|
|
2305
|
+
);
|
|
2145
2306
|
try {
|
|
2146
2307
|
const messageId = await this.sendBlocks(blocks);
|
|
2147
2308
|
return { messageId };
|