@odience-network/paperclip-plugin-telegram-enhanced 0.2.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/LICENSE +21 -0
- package/README.md +215 -0
- package/dist/acp-bridge.d.ts +35 -0
- package/dist/acp-bridge.js +891 -0
- package/dist/acp-bridge.js.map +1 -0
- package/dist/adapter.d.ts +35 -0
- package/dist/adapter.js +75 -0
- package/dist/adapter.js.map +1 -0
- package/dist/agent-labels.d.ts +12 -0
- package/dist/agent-labels.js +96 -0
- package/dist/agent-labels.js.map +1 -0
- package/dist/allowlist.d.ts +27 -0
- package/dist/allowlist.js +34 -0
- package/dist/allowlist.js.map +1 -0
- package/dist/approval-routing.d.ts +2 -0
- package/dist/approval-routing.js +7 -0
- package/dist/approval-routing.js.map +1 -0
- package/dist/command-registry.d.ts +3 -0
- package/dist/command-registry.js +268 -0
- package/dist/command-registry.js.map +1 -0
- package/dist/commands.d.ts +11 -0
- package/dist/commands.js +516 -0
- package/dist/commands.js.map +1 -0
- package/dist/constants.d.ts +76 -0
- package/dist/constants.js +71 -0
- package/dist/constants.js.map +1 -0
- package/dist/escalation.d.ts +42 -0
- package/dist/escalation.js +252 -0
- package/dist/escalation.js.map +1 -0
- package/dist/file-routing.d.ts +51 -0
- package/dist/file-routing.js +212 -0
- package/dist/file-routing.js.map +1 -0
- package/dist/formatters.d.ts +31 -0
- package/dist/formatters.js +336 -0
- package/dist/formatters.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -0
- package/dist/interaction-delivery.d.ts +90 -0
- package/dist/interaction-delivery.js +142 -0
- package/dist/interaction-delivery.js.map +1 -0
- package/dist/manifest.d.ts +3 -0
- package/dist/manifest.js +111 -0
- package/dist/manifest.js.map +1 -0
- package/dist/media-pipeline.d.ts +47 -0
- package/dist/media-pipeline.js +162 -0
- package/dist/media-pipeline.js.map +1 -0
- package/dist/notification-filters.d.ts +23 -0
- package/dist/notification-filters.js +93 -0
- package/dist/notification-filters.js.map +1 -0
- package/dist/paperclip-api.d.ts +25 -0
- package/dist/paperclip-api.js +69 -0
- package/dist/paperclip-api.js.map +1 -0
- package/dist/polling-offset.d.ts +22 -0
- package/dist/polling-offset.js +68 -0
- package/dist/polling-offset.js.map +1 -0
- package/dist/secret-ref-validation.d.ts +7 -0
- package/dist/secret-ref-validation.js +49 -0
- package/dist/secret-ref-validation.js.map +1 -0
- package/dist/telegram-api.d.ts +40 -0
- package/dist/telegram-api.js +251 -0
- package/dist/telegram-api.js.map +1 -0
- package/dist/topic-projects.d.ts +2 -0
- package/dist/topic-projects.js +45 -0
- package/dist/topic-projects.js.map +1 -0
- package/dist/ui/index.d.ts +2 -0
- package/dist/ui/index.js +1446 -0
- package/dist/ui/index.js.map +1 -0
- package/dist/watch-registry.d.ts +9 -0
- package/dist/watch-registry.js +272 -0
- package/dist/watch-registry.js.map +1 -0
- package/dist/worker.d.ts +162 -0
- package/dist/worker.js +1520 -0
- package/dist/worker.js.map +1 -0
- package/package.json +59 -0
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
export const TELEGRAM_LAST_UPDATE_ID_STATE_KEY = "telegram-last-update-id";
|
|
2
|
+
export async function getPersistedTelegramUpdateOffset(ctx) {
|
|
3
|
+
const saved = await ctx.state.get({
|
|
4
|
+
scopeKind: "instance",
|
|
5
|
+
stateKey: TELEGRAM_LAST_UPDATE_ID_STATE_KEY,
|
|
6
|
+
});
|
|
7
|
+
const updateId = typeof saved === "number"
|
|
8
|
+
? saved
|
|
9
|
+
: typeof saved === "string"
|
|
10
|
+
? Number.parseInt(saved, 10)
|
|
11
|
+
: null;
|
|
12
|
+
return updateId !== null && Number.isSafeInteger(updateId) && updateId >= 0
|
|
13
|
+
? updateId
|
|
14
|
+
: 0;
|
|
15
|
+
}
|
|
16
|
+
export async function persistTelegramUpdateOffset(ctx, updateId) {
|
|
17
|
+
if (!Number.isSafeInteger(updateId) || updateId < 0)
|
|
18
|
+
return;
|
|
19
|
+
await ctx.state.set({
|
|
20
|
+
scopeKind: "instance",
|
|
21
|
+
stateKey: TELEGRAM_LAST_UPDATE_ID_STATE_KEY,
|
|
22
|
+
}, updateId);
|
|
23
|
+
}
|
|
24
|
+
export async function handleTelegramUpdateThenPersistOffset(options) {
|
|
25
|
+
const { updateId, lastUpdateId, handleUpdate, persistOffset, logger } = options;
|
|
26
|
+
try {
|
|
27
|
+
await handleUpdate();
|
|
28
|
+
}
|
|
29
|
+
catch (err) {
|
|
30
|
+
logger.error("Telegram update handling failed", {
|
|
31
|
+
updateId,
|
|
32
|
+
error: String(err),
|
|
33
|
+
});
|
|
34
|
+
return lastUpdateId;
|
|
35
|
+
}
|
|
36
|
+
const nextUpdateId = Math.max(lastUpdateId, updateId);
|
|
37
|
+
if (nextUpdateId <= lastUpdateId)
|
|
38
|
+
return lastUpdateId;
|
|
39
|
+
try {
|
|
40
|
+
await persistOffset(nextUpdateId);
|
|
41
|
+
}
|
|
42
|
+
catch (err) {
|
|
43
|
+
logger.error("Failed to persist Telegram polling offset", {
|
|
44
|
+
updateId: nextUpdateId,
|
|
45
|
+
error: String(err),
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
return nextUpdateId;
|
|
49
|
+
}
|
|
50
|
+
export async function processTelegramUpdateBatch(options) {
|
|
51
|
+
const { updates, handleUpdate, persistOffset, logger } = options;
|
|
52
|
+
let lastUpdateId = options.lastUpdateId;
|
|
53
|
+
for (const update of updates) {
|
|
54
|
+
const nextUpdateId = await handleTelegramUpdateThenPersistOffset({
|
|
55
|
+
updateId: update.update_id,
|
|
56
|
+
lastUpdateId,
|
|
57
|
+
handleUpdate: () => handleUpdate(update),
|
|
58
|
+
persistOffset,
|
|
59
|
+
logger,
|
|
60
|
+
});
|
|
61
|
+
if (nextUpdateId === lastUpdateId && update.update_id > lastUpdateId) {
|
|
62
|
+
break;
|
|
63
|
+
}
|
|
64
|
+
lastUpdateId = nextUpdateId;
|
|
65
|
+
}
|
|
66
|
+
return lastUpdateId;
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=polling-offset.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"polling-offset.js","sourceRoot":"","sources":["../src/polling-offset.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,iCAAiC,GAAG,yBAAyB,CAAC;AAE3E,MAAM,CAAC,KAAK,UAAU,gCAAgC,CAAC,GAAkB;IACvE,MAAM,KAAK,GAAG,MAAM,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC;QAChC,SAAS,EAAE,UAAU;QACrB,QAAQ,EAAE,iCAAiC;KAC5C,CAAC,CAAC;IAEH,MAAM,QAAQ,GACZ,OAAO,KAAK,KAAK,QAAQ;QACvB,CAAC,CAAC,KAAK;QACP,CAAC,CAAC,OAAO,KAAK,KAAK,QAAQ;YACzB,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,EAAE,EAAE,CAAC;YAC5B,CAAC,CAAC,IAAI,CAAC;IAEb,OAAO,QAAQ,KAAK,IAAI,IAAI,MAAM,CAAC,aAAa,CAAC,QAAQ,CAAC,IAAI,QAAQ,IAAI,CAAC;QACzE,CAAC,CAAC,QAAQ;QACV,CAAC,CAAC,CAAC,CAAC;AACR,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,2BAA2B,CAC/C,GAAkB,EAClB,QAAgB;IAEhB,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,QAAQ,CAAC,IAAI,QAAQ,GAAG,CAAC;QAAE,OAAO;IAE5D,MAAM,GAAG,CAAC,KAAK,CAAC,GAAG,CACjB;QACE,SAAS,EAAE,UAAU;QACrB,QAAQ,EAAE,iCAAiC;KAC5C,EACD,QAAQ,CACT,CAAC;AACJ,CAAC;AAID,MAAM,CAAC,KAAK,UAAU,qCAAqC,CAAC,OAM3D;IACC,MAAM,EAAE,QAAQ,EAAE,YAAY,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC;IAEhF,IAAI,CAAC;QACH,MAAM,YAAY,EAAE,CAAC;IACvB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,CAAC,KAAK,CAAC,iCAAiC,EAAE;YAC9C,QAAQ;YACR,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC;SACnB,CAAC,CAAC;QACH,OAAO,YAAY,CAAC;IACtB,CAAC;IAED,MAAM,YAAY,GAAG,IAAI,CAAC,GAAG,CAAC,YAAY,EAAE,QAAQ,CAAC,CAAC;IACtD,IAAI,YAAY,IAAI,YAAY;QAAE,OAAO,YAAY,CAAC;IAEtD,IAAI,CAAC;QACH,MAAM,aAAa,CAAC,YAAY,CAAC,CAAC;IACpC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,CAAC,KAAK,CAAC,2CAA2C,EAAE;YACxD,QAAQ,EAAE,YAAY;YACtB,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC;SACnB,CAAC,CAAC;IACL,CAAC;IAED,OAAO,YAAY,CAAC;AACtB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,0BAA0B,CAAwC,OAMvF;IACC,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC;IACjE,IAAI,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC;IAExC,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,MAAM,YAAY,GAAG,MAAM,qCAAqC,CAAC;YAC/D,QAAQ,EAAE,MAAM,CAAC,SAAS;YAC1B,YAAY;YACZ,YAAY,EAAE,GAAG,EAAE,CAAC,YAAY,CAAC,MAAM,CAAC;YACxC,aAAa;YACb,MAAM;SACP,CAAC,CAAC;QAEH,IAAI,YAAY,KAAK,YAAY,IAAI,MAAM,CAAC,SAAS,GAAG,YAAY,EAAE,CAAC;YACrE,MAAM;QACR,CAAC;QAED,YAAY,GAAG,YAAY,CAAC;IAC9B,CAAC;IAED,OAAO,YAAY,CAAC;AACtB,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export type SecretRefConfig = {
|
|
2
|
+
telegramBotTokenRef?: unknown;
|
|
3
|
+
paperclipBoardApiTokenRef?: unknown;
|
|
4
|
+
transcriptionApiKeyRef?: unknown;
|
|
5
|
+
};
|
|
6
|
+
export declare function isValidSecretRef(value: unknown): value is string;
|
|
7
|
+
export declare function validateSecretRefFields(config: SecretRefConfig): string[];
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
2
|
+
const FIELDS = [
|
|
3
|
+
{ key: "telegramBotTokenRef", required: true },
|
|
4
|
+
{ key: "paperclipBoardApiTokenRef", required: false },
|
|
5
|
+
{ key: "transcriptionApiKeyRef", required: false },
|
|
6
|
+
];
|
|
7
|
+
export function isValidSecretRef(value) {
|
|
8
|
+
return typeof value === "string" && UUID_RE.test(value.trim());
|
|
9
|
+
}
|
|
10
|
+
function describeBadValue(value) {
|
|
11
|
+
if (value === undefined || value === null)
|
|
12
|
+
return "<empty>";
|
|
13
|
+
if (typeof value !== "string")
|
|
14
|
+
return `<${typeof value}>`;
|
|
15
|
+
const trimmed = value.trim();
|
|
16
|
+
if (trimmed.length === 0)
|
|
17
|
+
return "<empty string>";
|
|
18
|
+
// Truncate to avoid leaking long pasted secrets into error logs.
|
|
19
|
+
const sample = trimmed.length > 16 ? `${trimmed.slice(0, 12)}…` : trimmed;
|
|
20
|
+
return `"${sample}"`;
|
|
21
|
+
}
|
|
22
|
+
function fieldError(key, value) {
|
|
23
|
+
return [
|
|
24
|
+
`${key} must be the UUID of a Paperclip secret`,
|
|
25
|
+
`(format 8-4-4-4-12, e.g. "12f7ed4a-1234-4d0c-9abc-bd58d44d15e1").`,
|
|
26
|
+
`Got ${describeBadValue(value)}.`,
|
|
27
|
+
`Create the secret first via POST /api/companies/{id}/secrets and paste the returned "id" value here —`,
|
|
28
|
+
`not the raw token, the whole JSON response, or any other identifier.`,
|
|
29
|
+
].join(" ");
|
|
30
|
+
}
|
|
31
|
+
export function validateSecretRefFields(config) {
|
|
32
|
+
const errors = [];
|
|
33
|
+
for (const { key, required } of FIELDS) {
|
|
34
|
+
const value = config[key];
|
|
35
|
+
const isMissing = value === undefined ||
|
|
36
|
+
value === null ||
|
|
37
|
+
(typeof value === "string" && value.trim().length === 0);
|
|
38
|
+
if (isMissing) {
|
|
39
|
+
if (required)
|
|
40
|
+
errors.push(`${key} is required.`);
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
if (!isValidSecretRef(value)) {
|
|
44
|
+
errors.push(fieldError(key, value));
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return errors;
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=secret-ref-validation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"secret-ref-validation.js","sourceRoot":"","sources":["../src/secret-ref-validation.ts"],"names":[],"mappings":"AAMA,MAAM,OAAO,GAAG,iEAAiE,CAAC;AAElF,MAAM,MAAM,GAAG;IACb,EAAE,GAAG,EAAE,qBAAqB,EAAE,QAAQ,EAAE,IAAI,EAAE;IAC9C,EAAE,GAAG,EAAE,2BAA2B,EAAE,QAAQ,EAAE,KAAK,EAAE;IACrD,EAAE,GAAG,EAAE,wBAAwB,EAAE,QAAQ,EAAE,KAAK,EAAE;CAC1C,CAAC;AAEX,MAAM,UAAU,gBAAgB,CAAC,KAAc;IAC7C,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;AACjE,CAAC;AAED,SAAS,gBAAgB,CAAC,KAAc;IACtC,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,SAAS,CAAC;IAC5D,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,IAAI,OAAO,KAAK,GAAG,CAAC;IAC1D,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;IAC7B,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,gBAAgB,CAAC;IAClD,iEAAiE;IACjE,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC;IAC1E,OAAO,IAAI,MAAM,GAAG,CAAC;AACvB,CAAC;AAED,SAAS,UAAU,CAAC,GAAW,EAAE,KAAc;IAC7C,OAAO;QACL,GAAG,GAAG,yCAAyC;QAC/C,mEAAmE;QACnE,OAAO,gBAAgB,CAAC,KAAK,CAAC,GAAG;QACjC,uGAAuG;QACvG,sEAAsE;KACvE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACd,CAAC;AAED,MAAM,UAAU,uBAAuB,CAAC,MAAuB;IAC7D,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,KAAK,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,MAAM,EAAE,CAAC;QACvC,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;QAC1B,MAAM,SAAS,GACb,KAAK,KAAK,SAAS;YACnB,KAAK,KAAK,IAAI;YACd,CAAC,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC;QAE3D,IAAI,SAAS,EAAE,CAAC;YACd,IAAI,QAAQ;gBAAE,MAAM,CAAC,IAAI,CAAC,GAAG,GAAG,eAAe,CAAC,CAAC;YACjD,SAAS;QACX,CAAC;QAED,IAAI,CAAC,gBAAgB,CAAC,KAAK,CAAC,EAAE,CAAC;YAC7B,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC;QACtC,CAAC;IACH,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { PluginContext } from "@paperclipai/plugin-sdk";
|
|
2
|
+
type InlineButton = {
|
|
3
|
+
text: string;
|
|
4
|
+
callback_data?: string;
|
|
5
|
+
url?: string;
|
|
6
|
+
};
|
|
7
|
+
type InlineKeyboard = InlineButton[][];
|
|
8
|
+
export type SendMessageOptions = {
|
|
9
|
+
parseMode?: "MarkdownV2" | "HTML";
|
|
10
|
+
replyToMessageId?: number;
|
|
11
|
+
messageThreadId?: number;
|
|
12
|
+
inlineKeyboard?: InlineKeyboard;
|
|
13
|
+
disableNotification?: boolean;
|
|
14
|
+
};
|
|
15
|
+
export type SendDocumentOptions = {
|
|
16
|
+
filename: string;
|
|
17
|
+
caption?: string;
|
|
18
|
+
parseMode?: "MarkdownV2" | "HTML";
|
|
19
|
+
replyToMessageId?: number;
|
|
20
|
+
messageThreadId?: number;
|
|
21
|
+
disableNotification?: boolean;
|
|
22
|
+
};
|
|
23
|
+
export declare function sendMessage(ctx: PluginContext, token: string, chatId: string, text: string, options?: SendMessageOptions): Promise<number | null>;
|
|
24
|
+
export declare function sendDocument(ctx: PluginContext, token: string, chatId: string, markdownContent: string, options: SendDocumentOptions): Promise<number | null>;
|
|
25
|
+
export declare function editMessage(ctx: PluginContext, token: string, chatId: string, messageId: number, text: string, options?: {
|
|
26
|
+
parseMode?: "MarkdownV2" | "HTML";
|
|
27
|
+
inlineKeyboard?: InlineKeyboard;
|
|
28
|
+
}): Promise<boolean>;
|
|
29
|
+
export declare function answerCallbackQuery(ctx: PluginContext, token: string, callbackQueryId: string, text: string): Promise<void>;
|
|
30
|
+
export declare function setMyCommands(ctx: PluginContext, token: string, commands: Array<{
|
|
31
|
+
command: string;
|
|
32
|
+
description: string;
|
|
33
|
+
}>): Promise<boolean>;
|
|
34
|
+
export declare function sendChatAction(ctx: PluginContext, token: string, chatId: string, action?: "typing"): Promise<void>;
|
|
35
|
+
export declare function isForum(ctx: PluginContext, token: string, chatId: string): Promise<boolean>;
|
|
36
|
+
/** General topic thread ID for forum groups. */
|
|
37
|
+
export declare const GENERAL_TOPIC_THREAD_ID = 1;
|
|
38
|
+
export declare function escapeMarkdownV2(text: string): string;
|
|
39
|
+
export declare function truncateAtWord(text: string, maxLen: number): string;
|
|
40
|
+
export {};
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
import { METRIC_NAMES } from "./constants.js";
|
|
2
|
+
const TELEGRAM_API = "https://api.telegram.org";
|
|
3
|
+
export async function sendMessage(ctx, token, chatId, text, options = {}) {
|
|
4
|
+
const body = {
|
|
5
|
+
chat_id: chatId,
|
|
6
|
+
text,
|
|
7
|
+
};
|
|
8
|
+
if (options.parseMode)
|
|
9
|
+
body.parse_mode = options.parseMode;
|
|
10
|
+
if (options.replyToMessageId)
|
|
11
|
+
body.reply_to_message_id = options.replyToMessageId;
|
|
12
|
+
if (options.messageThreadId)
|
|
13
|
+
body.message_thread_id = options.messageThreadId;
|
|
14
|
+
if (options.disableNotification)
|
|
15
|
+
body.disable_notification = true;
|
|
16
|
+
if (options.inlineKeyboard) {
|
|
17
|
+
body.reply_markup = {
|
|
18
|
+
inline_keyboard: options.inlineKeyboard,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
for (let attempt = 0; attempt < 3; attempt++) {
|
|
22
|
+
try {
|
|
23
|
+
const res = await ctx.http.fetch(`${TELEGRAM_API}/bot${token}/sendMessage`, {
|
|
24
|
+
method: "POST",
|
|
25
|
+
headers: { "Content-Type": "application/json" },
|
|
26
|
+
body: JSON.stringify(body),
|
|
27
|
+
});
|
|
28
|
+
const data = (await res.json());
|
|
29
|
+
if (!data.ok) {
|
|
30
|
+
if (data.parameters?.retry_after && attempt < 2) {
|
|
31
|
+
const wait = data.parameters.retry_after * 1000;
|
|
32
|
+
ctx.logger.warn("Telegram rate limited, retrying", { retryAfter: data.parameters.retry_after, attempt });
|
|
33
|
+
await new Promise((r) => setTimeout(r, wait));
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
if (options.parseMode === "MarkdownV2") {
|
|
37
|
+
ctx.logger.warn("MarkdownV2 send failed, retrying as plain text", {
|
|
38
|
+
error: data.description,
|
|
39
|
+
});
|
|
40
|
+
return sendMessage(ctx, token, chatId, stripMarkdown(text), {
|
|
41
|
+
...options,
|
|
42
|
+
parseMode: undefined,
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
ctx.logger.error("Telegram sendMessage failed", { error: data.description });
|
|
46
|
+
await ctx.metrics.write(METRIC_NAMES.failed, 1);
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
await ctx.metrics.write(METRIC_NAMES.sent, 1);
|
|
50
|
+
return data.result?.message_id ?? null;
|
|
51
|
+
}
|
|
52
|
+
catch (err) {
|
|
53
|
+
ctx.logger.error("Telegram API error", { error: String(err) });
|
|
54
|
+
await ctx.metrics.write(METRIC_NAMES.failed, 1);
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
// Ported from ant013/paperclip-plugin-telegram (TEL-8, commits 0b57865/a6f5037):
|
|
61
|
+
// "send markdown documents with native upload fallback".
|
|
62
|
+
export async function sendDocument(ctx, token, chatId, markdownContent, options) {
|
|
63
|
+
for (let attempt = 0; attempt < 3; attempt++) {
|
|
64
|
+
try {
|
|
65
|
+
const data = await postTelegramDocument(ctx, token, chatId, markdownContent, options);
|
|
66
|
+
if (!data.ok) {
|
|
67
|
+
if (data.parameters?.retry_after && attempt < 2) {
|
|
68
|
+
const wait = data.parameters.retry_after * 1000;
|
|
69
|
+
ctx.logger.warn("Telegram rate limited, retrying file send", {
|
|
70
|
+
retryAfter: data.parameters.retry_after,
|
|
71
|
+
attempt,
|
|
72
|
+
});
|
|
73
|
+
await new Promise((r) => setTimeout(r, wait));
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
if (options.parseMode === "MarkdownV2" && options.caption) {
|
|
77
|
+
ctx.logger.warn("MarkdownV2 file caption failed, retrying as plain text", {
|
|
78
|
+
error: data.description,
|
|
79
|
+
});
|
|
80
|
+
return sendDocument(ctx, token, chatId, markdownContent, {
|
|
81
|
+
...options,
|
|
82
|
+
caption: stripMarkdown(options.caption),
|
|
83
|
+
parseMode: undefined,
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
ctx.logger.error("Telegram document send failed", { error: data.description });
|
|
87
|
+
await ctx.metrics.write(METRIC_NAMES.failed, 1);
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
await ctx.metrics.write(METRIC_NAMES.sent, 1);
|
|
91
|
+
return data.result?.message_id ?? null;
|
|
92
|
+
}
|
|
93
|
+
catch (err) {
|
|
94
|
+
ctx.logger.error("Telegram document API error", { error: String(err) });
|
|
95
|
+
await ctx.metrics.write(METRIC_NAMES.failed, 1);
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
function buildDocumentFormData(chatId, markdownContent, options) {
|
|
102
|
+
const body = new FormData();
|
|
103
|
+
body.append("chat_id", chatId);
|
|
104
|
+
body.append("document", new Blob([markdownContent], { type: "text/markdown; charset=utf-8" }), options.filename);
|
|
105
|
+
if (options.caption)
|
|
106
|
+
body.append("caption", options.caption);
|
|
107
|
+
if (options.parseMode)
|
|
108
|
+
body.append("parse_mode", options.parseMode);
|
|
109
|
+
if (options.replyToMessageId)
|
|
110
|
+
body.append("reply_to_message_id", String(options.replyToMessageId));
|
|
111
|
+
if (options.messageThreadId)
|
|
112
|
+
body.append("message_thread_id", String(options.messageThreadId));
|
|
113
|
+
if (options.disableNotification)
|
|
114
|
+
body.append("disable_notification", "true");
|
|
115
|
+
return body;
|
|
116
|
+
}
|
|
117
|
+
async function postTelegramDocument(ctx, token, chatId, markdownContent, options) {
|
|
118
|
+
const url = `${TELEGRAM_API}/bot${token}/sendDocument`;
|
|
119
|
+
const proxied = await ctx.http.fetch(url, {
|
|
120
|
+
method: "POST",
|
|
121
|
+
body: buildDocumentFormData(chatId, markdownContent, options),
|
|
122
|
+
});
|
|
123
|
+
const data = await proxied.json();
|
|
124
|
+
if (data.ok || data.description !== "Bad Request: there is no document in the request") {
|
|
125
|
+
return data;
|
|
126
|
+
}
|
|
127
|
+
// Paperclip's HTTP bridge can lose multipart file parts while serializing FormData.
|
|
128
|
+
// Retry from the worker process with native fetch so Telegram receives the Blob.
|
|
129
|
+
ctx.logger.warn("Telegram document proxy upload failed, retrying with native fetch", {
|
|
130
|
+
error: data.description,
|
|
131
|
+
});
|
|
132
|
+
const direct = await fetch(url, {
|
|
133
|
+
method: "POST",
|
|
134
|
+
body: buildDocumentFormData(chatId, markdownContent, options),
|
|
135
|
+
});
|
|
136
|
+
return await direct.json();
|
|
137
|
+
}
|
|
138
|
+
export async function editMessage(ctx, token, chatId, messageId, text, options = {}) {
|
|
139
|
+
const body = {
|
|
140
|
+
chat_id: chatId,
|
|
141
|
+
message_id: messageId,
|
|
142
|
+
text,
|
|
143
|
+
};
|
|
144
|
+
if (options.parseMode)
|
|
145
|
+
body.parse_mode = options.parseMode;
|
|
146
|
+
if (options.inlineKeyboard) {
|
|
147
|
+
body.reply_markup = { inline_keyboard: options.inlineKeyboard };
|
|
148
|
+
}
|
|
149
|
+
else {
|
|
150
|
+
body.reply_markup = { inline_keyboard: [] };
|
|
151
|
+
}
|
|
152
|
+
try {
|
|
153
|
+
const res = await ctx.http.fetch(`${TELEGRAM_API}/bot${token}/editMessageText`, {
|
|
154
|
+
method: "POST",
|
|
155
|
+
headers: { "Content-Type": "application/json" },
|
|
156
|
+
body: JSON.stringify(body),
|
|
157
|
+
});
|
|
158
|
+
const data = (await res.json());
|
|
159
|
+
return data.ok;
|
|
160
|
+
}
|
|
161
|
+
catch (err) {
|
|
162
|
+
ctx.logger.error("Telegram editMessage failed", { error: String(err) });
|
|
163
|
+
return false;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
export async function answerCallbackQuery(ctx, token, callbackQueryId, text) {
|
|
167
|
+
try {
|
|
168
|
+
await ctx.http.fetch(`${TELEGRAM_API}/bot${token}/answerCallbackQuery`, {
|
|
169
|
+
method: "POST",
|
|
170
|
+
headers: { "Content-Type": "application/json" },
|
|
171
|
+
body: JSON.stringify({
|
|
172
|
+
callback_query_id: callbackQueryId,
|
|
173
|
+
text,
|
|
174
|
+
}),
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
catch (err) {
|
|
178
|
+
ctx.logger.error("Telegram answerCallbackQuery failed", { error: String(err) });
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
export async function setMyCommands(ctx, token, commands) {
|
|
182
|
+
try {
|
|
183
|
+
const res = await ctx.http.fetch(`${TELEGRAM_API}/bot${token}/setMyCommands`, {
|
|
184
|
+
method: "POST",
|
|
185
|
+
headers: { "Content-Type": "application/json" },
|
|
186
|
+
body: JSON.stringify({ commands }),
|
|
187
|
+
});
|
|
188
|
+
const data = (await res.json());
|
|
189
|
+
return data.ok;
|
|
190
|
+
}
|
|
191
|
+
catch (err) {
|
|
192
|
+
ctx.logger.error("Telegram setMyCommands failed", { error: String(err) });
|
|
193
|
+
return false;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
export async function sendChatAction(ctx, token, chatId, action = "typing") {
|
|
197
|
+
try {
|
|
198
|
+
await ctx.http.fetch(`${TELEGRAM_API}/bot${token}/sendChatAction`, {
|
|
199
|
+
method: "POST",
|
|
200
|
+
headers: { "Content-Type": "application/json" },
|
|
201
|
+
body: JSON.stringify({ chat_id: chatId, action }),
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
catch {
|
|
205
|
+
// Typing indicator failures are non-critical
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Check if a chat is a forum (has topics enabled).
|
|
210
|
+
* Caches the result per chatId for the lifetime of the process.
|
|
211
|
+
*/
|
|
212
|
+
const forumCache = new Map();
|
|
213
|
+
export async function isForum(ctx, token, chatId) {
|
|
214
|
+
const cached = forumCache.get(chatId);
|
|
215
|
+
if (cached !== undefined)
|
|
216
|
+
return cached;
|
|
217
|
+
try {
|
|
218
|
+
const res = await ctx.http.fetch(`${TELEGRAM_API}/bot${token}/getChat`, {
|
|
219
|
+
method: "POST",
|
|
220
|
+
headers: { "Content-Type": "application/json" },
|
|
221
|
+
body: JSON.stringify({ chat_id: chatId }),
|
|
222
|
+
});
|
|
223
|
+
const data = (await res.json());
|
|
224
|
+
const result = data.ok && data.result?.is_forum === true;
|
|
225
|
+
forumCache.set(chatId, result);
|
|
226
|
+
return result;
|
|
227
|
+
}
|
|
228
|
+
catch {
|
|
229
|
+
return false;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
/** General topic thread ID for forum groups. */
|
|
233
|
+
export const GENERAL_TOPIC_THREAD_ID = 1;
|
|
234
|
+
// MarkdownV2 requires escaping these characters
|
|
235
|
+
const MD_ESCAPE_CHARS = /([_*\[\]()~`>#+\-=|{}.!\\])/g;
|
|
236
|
+
export function escapeMarkdownV2(text) {
|
|
237
|
+
return text.replace(MD_ESCAPE_CHARS, "\\$1");
|
|
238
|
+
}
|
|
239
|
+
export function truncateAtWord(text, maxLen) {
|
|
240
|
+
if (text.length <= maxLen)
|
|
241
|
+
return text;
|
|
242
|
+
const truncated = text.slice(0, maxLen);
|
|
243
|
+
const lastSpace = truncated.lastIndexOf(" ");
|
|
244
|
+
return (lastSpace > maxLen * 0.7 ? truncated.slice(0, lastSpace) : truncated) + "...";
|
|
245
|
+
}
|
|
246
|
+
function stripMarkdown(text) {
|
|
247
|
+
return text
|
|
248
|
+
.replace(/\\([_*\[\]()~`>#+\-=|{}.!\\])/g, "$1")
|
|
249
|
+
.replace(/[*_`~]/g, "");
|
|
250
|
+
}
|
|
251
|
+
//# sourceMappingURL=telegram-api.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"telegram-api.js","sourceRoot":"","sources":["../src/telegram-api.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
function normalizeTopicMapping(projectName, value) {
|
|
2
|
+
if (typeof value === "string") {
|
|
3
|
+
return { projectName, topicId: value };
|
|
4
|
+
}
|
|
5
|
+
return {
|
|
6
|
+
projectId: value.projectId,
|
|
7
|
+
projectName: value.projectName || projectName,
|
|
8
|
+
topicId: value.topicId,
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
export async function resolveMappedProjectIdForTopic(ctx, chatId, companyId, messageThreadId) {
|
|
12
|
+
if (!messageThreadId)
|
|
13
|
+
return undefined;
|
|
14
|
+
const topicMap = (await ctx.state.get({
|
|
15
|
+
scopeKind: "instance",
|
|
16
|
+
stateKey: `topic-map-${chatId}`,
|
|
17
|
+
}));
|
|
18
|
+
if (!topicMap)
|
|
19
|
+
return undefined;
|
|
20
|
+
const topicId = String(messageThreadId);
|
|
21
|
+
const match = Object.entries(topicMap)
|
|
22
|
+
.map(([projectName, value]) => normalizeTopicMapping(projectName, value))
|
|
23
|
+
.find((mapping) => mapping.topicId === topicId);
|
|
24
|
+
if (!match)
|
|
25
|
+
return undefined;
|
|
26
|
+
if (match.projectId)
|
|
27
|
+
return match.projectId;
|
|
28
|
+
try {
|
|
29
|
+
const projects = await ctx.projects.list({ companyId, limit: 100 });
|
|
30
|
+
const exactMatch = projects.find((project) => project.name === match.projectName);
|
|
31
|
+
if (exactMatch)
|
|
32
|
+
return exactMatch.id;
|
|
33
|
+
return projects.find((project) => project.name?.toLowerCase() === match.projectName.toLowerCase())?.id;
|
|
34
|
+
}
|
|
35
|
+
catch (err) {
|
|
36
|
+
ctx.logger.warn("Failed to look up project for legacy topic mapping", {
|
|
37
|
+
chatId,
|
|
38
|
+
companyId,
|
|
39
|
+
projectName: match.projectName,
|
|
40
|
+
error: String(err),
|
|
41
|
+
});
|
|
42
|
+
return undefined;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=topic-projects.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"topic-projects.js","sourceRoot":"","sources":["../src/topic-projects.ts"],"names":[],"mappings":"AAWA,SAAS,qBAAqB,CAAC,WAAmB,EAAE,KAAwB;IAC1E,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;IACzC,CAAC;IACD,OAAO;QACL,SAAS,EAAE,KAAK,CAAC,SAAS;QAC1B,WAAW,EAAE,KAAK,CAAC,WAAW,IAAI,WAAW;QAC7C,OAAO,EAAE,KAAK,CAAC,OAAO;KACvB,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,8BAA8B,CAClD,GAAkB,EAClB,MAAc,EACd,SAAiB,EACjB,eAAwB;IAExB,IAAI,CAAC,eAAe;QAAE,OAAO,SAAS,CAAC;IAEvC,MAAM,QAAQ,GAAG,CAAC,MAAM,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC;QACpC,SAAS,EAAE,UAAU;QACrB,QAAQ,EAAE,aAAa,MAAM,EAAE;KAChC,CAAC,CAAoB,CAAC;IACvB,IAAI,CAAC,QAAQ;QAAE,OAAO,SAAS,CAAC;IAEhC,MAAM,OAAO,GAAG,MAAM,CAAC,eAAe,CAAC,CAAC;IACxC,MAAM,KAAK,GAAG,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC;SACnC,GAAG,CAAC,CAAC,CAAC,WAAW,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,qBAAqB,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC;SACxE,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,OAAO,KAAK,OAAO,CAAC,CAAC;IAElD,IAAI,CAAC,KAAK;QAAE,OAAO,SAAS,CAAC;IAC7B,IAAI,KAAK,CAAC,SAAS;QAAE,OAAO,KAAK,CAAC,SAAS,CAAC;IAE5C,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC;QACpE,MAAM,UAAU,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,KAAK,KAAK,CAAC,WAAW,CAAC,CAAC;QAClF,IAAI,UAAU;YAAE,OAAO,UAAU,CAAC,EAAE,CAAC;QACrC,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,WAAW,EAAE,KAAK,KAAK,CAAC,WAAW,CAAC,WAAW,EAAE,CAAC,EAAE,EAAE,CAAC;IACzG,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,oDAAoD,EAAE;YACpE,MAAM;YACN,SAAS;YACT,WAAW,EAAE,KAAK,CAAC,WAAW;YAC9B,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC;SACnB,CAAC,CAAC;QACH,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC"}
|