@hasna/connectors 1.4.1 → 1.4.2
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/bin/index.js +1272 -314
- package/bin/mcp.js +524 -211
- package/bin/serve.js +1208 -256
- package/connectors/adobe/package.json +1 -1
- package/connectors/aitableai/package.json +1 -1
- package/connectors/alchemy/package.json +1 -1
- package/connectors/alerty/package.json +1 -1
- package/connectors/alienvault/package.json +1 -1
- package/connectors/alphamoon/package.json +1 -1
- package/connectors/alttextai/package.json +1 -1
- package/connectors/amadeus/package.json +1 -1
- package/connectors/amadeus/src/api/client.ts +6 -6
- package/connectors/amadeus/src/cli/index.ts +6 -6
- package/connectors/amadeus/src/utils/output.ts +5 -5
- package/connectors/amazon/package.json +1 -1
- package/connectors/amilia/package.json +1 -1
- package/connectors/amqpsender/package.json +1 -1
- package/connectors/announcekit/package.json +1 -1
- package/connectors/anthropic/.env.example +1 -1
- package/connectors/anyscale/package.json +1 -1
- package/connectors/apiary/package.json +1 -1
- package/connectors/apiflash/package.json +1 -1
- package/connectors/apitemplateio/package.json +1 -1
- package/connectors/apptivegrid/package.json +1 -1
- package/connectors/assemblyai/package.json +1 -1
- package/connectors/autom/package.json +1 -1
- package/connectors/automizy/package.json +1 -1
- package/connectors/autopilot/package.json +1 -1
- package/connectors/awscognito/package.json +1 -1
- package/connectors/bamboohr/package.json +1 -1
- package/connectors/bannerbear/package.json +1 -1
- package/connectors/baseten/package.json +1 -1
- package/connectors/box/package.json +1 -1
- package/connectors/brevo/package.json +1 -1
- package/connectors/calendly/package.json +1 -1
- package/connectors/cerebras/package.json +1 -1
- package/connectors/chargebee/package.json +1 -1
- package/connectors/clearbit/package.json +1 -1
- package/connectors/cloudflare-workers/package.json +1 -1
- package/connectors/coda/package.json +1 -1
- package/connectors/coingecko/package.json +1 -1
- package/connectors/convertkit/package.json +1 -1
- package/connectors/customerio/package.json +1 -1
- package/connectors/databricks/package.json +1 -1
- package/connectors/datadog/package.json +1 -1
- package/connectors/datasoap/README.md +2 -2
- package/connectors/datasoap/package.json +1 -1
- package/connectors/datumbox/README.md +2 -2
- package/connectors/datumbox/package.json +1 -1
- package/connectors/dayschedule/README.md +2 -2
- package/connectors/dayschedule/package.json +1 -1
- package/connectors/deepgram/package.json +1 -1
- package/connectors/deepinfra/README.md +2 -2
- package/connectors/deepinfra/package.json +1 -1
- package/connectors/deepl/README.md +2 -2
- package/connectors/deepl/package.json +1 -1
- package/connectors/deepseek/package.json +1 -1
- package/connectors/demio/README.md +2 -2
- package/connectors/demio/package.json +1 -1
- package/connectors/descript/README.md +2 -2
- package/connectors/descript/package.json +1 -1
- package/connectors/detrack/README.md +2 -2
- package/connectors/detrack/package.json +1 -1
- package/connectors/devcycle/README.md +2 -2
- package/connectors/devcycle/package.json +1 -1
- package/connectors/dhl/README.md +2 -2
- package/connectors/dhl/package.json +1 -1
- package/connectors/docusign/package.json +1 -1
- package/connectors/dropbox/package.json +1 -1
- package/connectors/fal/package.json +1 -1
- package/connectors/fathom/package.json +1 -1
- package/connectors/fireworks/package.json +1 -1
- package/connectors/gitlab/package.json +1 -1
- package/connectors/googlechat/README.md +1 -2
- package/connectors/googledrive/src/api/client.ts +5 -5
- package/connectors/googledrive/src/api/files.ts +11 -11
- package/connectors/googledrive/src/api/folders.ts +2 -2
- package/connectors/googledrive/src/cli/index.ts +4 -4
- package/connectors/googledrive/src/utils/output.ts +3 -3
- package/connectors/googleforms/README.md +1 -2
- package/connectors/googleperspective/README.md +1 -2
- package/connectors/grafana/package.json +1 -1
- package/connectors/growbots/README.md +2 -2
- package/connectors/growbots/package.json +1 -1
- package/connectors/gumroad/package.json +1 -1
- package/connectors/gupshup/README.md +2 -2
- package/connectors/gupshup/package.json +1 -1
- package/connectors/guru/README.md +2 -2
- package/connectors/guru/package.json +1 -1
- package/connectors/hackernews/README.md +2 -2
- package/connectors/hackernews/package.json +1 -1
- package/connectors/halopsa/README.md +2 -2
- package/connectors/halopsa/package.json +1 -1
- package/connectors/handwrytten/README.md +2 -2
- package/connectors/handwrytten/package.json +1 -1
- package/connectors/hansei/README.md +2 -2
- package/connectors/hansei/package.json +1 -1
- package/connectors/harrypotterapi/README.md +2 -2
- package/connectors/harrypotterapi/package.json +1 -1
- package/connectors/harvest/README.md +2 -2
- package/connectors/harvest/package.json +1 -1
- package/connectors/headlesstesting/README.md +2 -2
- package/connectors/headlesstesting/package.json +1 -1
- package/connectors/homeassistant/package.json +1 -1
- package/connectors/klaviyo/package.json +1 -1
- package/connectors/lemonsqueezy/package.json +1 -1
- package/connectors/lighthouse/src/api/index.ts +1 -1
- package/connectors/linkedin/package.json +1 -1
- package/connectors/linkish/README.md +2 -2
- package/connectors/linkish/package.json +1 -1
- package/connectors/liveagent/README.md +2 -2
- package/connectors/liveagent/package.json +1 -1
- package/connectors/localazy/README.md +2 -2
- package/connectors/localazy/package.json +1 -1
- package/connectors/loginradius/README.md +2 -2
- package/connectors/loginradius/package.json +1 -1
- package/connectors/lokalise/README.md +2 -2
- package/connectors/lokalise/package.json +1 -1
- package/connectors/lonescale/README.md +2 -2
- package/connectors/lonescale/package.json +1 -1
- package/connectors/lucidchart/README.md +2 -2
- package/connectors/lucidchart/package.json +1 -1
- package/connectors/luma/package.json +1 -1
- package/connectors/magento2/README.md +2 -2
- package/connectors/magento2/package.json +1 -1
- package/connectors/mailcheck/README.md +2 -2
- package/connectors/mailcheck/package.json +1 -1
- package/connectors/mailchimp/package.json +1 -1
- package/connectors/mailerlite/README.md +2 -2
- package/connectors/mailerlite/package.json +1 -1
- package/connectors/mailersend/README.md +2 -2
- package/connectors/mailersend/package.json +1 -1
- package/connectors/mailify/README.md +2 -2
- package/connectors/mailify/package.json +1 -1
- package/connectors/mailjet/README.md +2 -2
- package/connectors/mailjet/package.json +1 -1
- package/connectors/mailmodo/README.md +2 -2
- package/connectors/mailmodo/package.json +1 -1
- package/connectors/malcore/README.md +2 -2
- package/connectors/malcore/package.json +1 -1
- package/connectors/mandrill/README.md +2 -2
- package/connectors/mandrill/package.json +1 -1
- package/connectors/marcomrobot/README.md +2 -2
- package/connectors/marcomrobot/package.json +1 -1
- package/connectors/marketingmasterio/README.md +2 -2
- package/connectors/marketingmasterio/package.json +1 -1
- package/connectors/marketplacer/README.md +2 -2
- package/connectors/marketplacer/package.json +1 -1
- package/connectors/marketstack/README.md +2 -2
- package/connectors/marketstack/package.json +1 -1
- package/connectors/matrix/README.md +1 -1
- package/connectors/matrix/package.json +1 -1
- package/connectors/mattermost/README.md +1 -1
- package/connectors/mattermost/package.json +1 -1
- package/connectors/mautic/README.md +1 -1
- package/connectors/mautic/package.json +1 -1
- package/connectors/mav/README.md +1 -1
- package/connectors/mav/package.json +1 -1
- package/connectors/maverick/README.md +1 -1
- package/connectors/maverick/package.json +1 -1
- package/connectors/mem/README.md +1 -1
- package/connectors/mem/package.json +1 -1
- package/connectors/messagebird/package.json +1 -1
- package/connectors/metabase/README.md +1 -1
- package/connectors/metabase/package.json +1 -1
- package/connectors/miro/package.json +1 -1
- package/connectors/mocean/package.json +1 -1
- package/connectors/modal/package.json +1 -1
- package/connectors/monday/package.json +1 -1
- package/connectors/monicacrm/package.json +1 -1
- package/connectors/moonclerk/package.json +1 -1
- package/connectors/moonmail/package.json +1 -1
- package/connectors/morph/package.json +1 -1
- package/connectors/mqtt/package.json +1 -1
- package/connectors/msg91/package.json +1 -1
- package/connectors/mubert/package.json +1 -1
- package/connectors/murf/package.json +1 -1
- package/connectors/mux/package.json +1 -1
- package/connectors/netlify/package.json +1 -1
- package/connectors/okta/package.json +1 -1
- package/connectors/paddle/package.json +1 -1
- package/connectors/perplexity/package.json +1 -1
- package/connectors/pinterest/package.json +1 -1
- package/connectors/pipedrive/package.json +1 -1
- package/connectors/plaid/package.json +1 -1
- package/connectors/quickchart/README.md +2 -2
- package/connectors/quintadb/README.md +2 -2
- package/connectors/rabbitmq/README.md +2 -2
- package/connectors/radar/README.md +2 -2
- package/connectors/raindrop/README.md +2 -2
- package/connectors/rapid7insightvm/README.md +2 -2
- package/connectors/raventools/README.md +2 -2
- package/connectors/rawgvideogamesdatabase/README.md +2 -2
- package/connectors/rdstationcrm/README.md +2 -2
- package/connectors/readai/README.md +2 -2
- package/connectors/roboflow/package.json +1 -1
- package/connectors/runway/package.json +1 -1
- package/connectors/sendgrid/package.json +1 -1
- package/connectors/shuffler/package.json +1 -1
- package/connectors/sierrainteractive/package.json +1 -1
- package/connectors/sifter/package.json +1 -1
- package/connectors/signaturit/package.json +1 -1
- package/connectors/signl4/package.json +1 -1
- package/connectors/simpleem/package.json +1 -1
- package/connectors/simplehash/package.json +1 -1
- package/connectors/simplekpi/package.json +1 -1
- package/connectors/simplelocalize/package.json +1 -1
- package/connectors/simplero/package.json +1 -1
- package/connectors/smartrecruiters/package.json +1 -1
- package/connectors/smtp2go/package.json +1 -1
- package/connectors/snowflake/package.json +1 -1
- package/connectors/sparkpost/package.json +1 -1
- package/connectors/split-io/package.json +1 -1
- package/connectors/split-io/src/api/client.test.ts +20 -0
- package/connectors/split-io/src/cli/index.ts +9 -9
- package/connectors/sprinklr/package.json +1 -1
- package/connectors/sprout-social/package.json +1 -1
- package/connectors/square/package.json +1 -1
- package/connectors/sse-trigger/package.json +1 -1
- package/connectors/stability-api-platform/AGENTS.md +1 -1
- package/connectors/standout/package.json +1 -1
- package/connectors/statuspage/package.json +1 -1
- package/connectors/stoplight/package.json +1 -1
- package/connectors/stoplight-api-platform/package.json +1 -1
- package/connectors/strand-ai/CLAUDE.md +1 -1
- package/connectors/stripe-financial-connections/package.json +1 -1
- package/connectors/stripe-terminal/package.json +1 -1
- package/connectors/stytch/package.json +1 -1
- package/connectors/sumo-logic/package.json +1 -1
- package/connectors/supabase/package.json +1 -1
- package/connectors/supabase-api-platform/package.json +1 -1
- package/connectors/sysdig/package.json +1 -1
- package/connectors/tableau/package.json +1 -1
- package/connectors/takecareos/README.md +2 -2
- package/connectors/takecareos/package.json +1 -1
- package/connectors/telegram/src/api/bot.ts +20 -0
- package/connectors/telegram/src/api/client.ts +32 -0
- package/connectors/telegram/src/api/files.test.ts +103 -0
- package/connectors/telegram/src/api/index.ts +1 -0
- package/connectors/telegram/src/api/messages.test.ts +8 -2
- package/connectors/telegram/src/cli/files.test.ts +40 -0
- package/connectors/telegram/src/cli/files.ts +38 -0
- package/connectors/telegram/src/cli/index.ts +27 -30
- package/connectors/telegram/src/cli/updates.test.ts +176 -0
- package/connectors/telegram/src/cli/updates.ts +95 -0
- package/connectors/telegram/src/index.ts +1 -0
- package/connectors/telegram/src/types/index.ts +13 -0
- package/connectors/terraform-cloud/package.json +1 -1
- package/connectors/textit/package.json +1 -1
- package/connectors/thousandeyes/package.json +1 -1
- package/connectors/ticket-tailor/package.json +1 -1
- package/connectors/ticketsource/package.json +1 -1
- package/connectors/tiktokads/README.md +1 -1
- package/connectors/time-saved/package.json +1 -1
- package/connectors/tipalti/package.json +1 -1
- package/connectors/tomtom/AGENTS.md +1 -1
- package/connectors/totp/package.json +1 -1
- package/connectors/traverse/package.json +1 -1
- package/connectors/travo-ai/package.json +1 -1
- package/connectors/trigger-dev/package.json +1 -1
- package/connectors/trigger-dev-api-platform/package.json +1 -1
- package/connectors/turbot-pipes/package.json +1 -1
- package/connectors/turso/package.json +1 -1
- package/connectors/turso-api-platform/package.json +1 -1
- package/connectors/tyk-api-platform/package.json +1 -1
- package/connectors/umami/package.json +1 -1
- package/connectors/unifold/package.json +1 -1
- package/connectors/unione/package.json +1 -1
- package/connectors/uniprot/README.md +1 -1
- package/connectors/uniswap-api/package.json +1 -1
- package/connectors/ups/package.json +1 -1
- package/connectors/usereframe/package.json +1 -1
- package/connectors/vanta/package.json +1 -1
- package/connectors/vela/package.json +1 -1
- package/connectors/velum-labs/package.json +1 -1
- package/connectors/vercel/package.json +1 -1
- package/connectors/vercel-blob/package.json +1 -1
- package/connectors/vercel-blob-platform/package.json +1 -1
- package/connectors/vercel-edge-config/package.json +1 -1
- package/connectors/vercel-edge-config-platform/package.json +1 -1
- package/connectors/vertex-ai/package.json +1 -1
- package/connectors/vidyard/package.json +1 -1
- package/connectors/vonage/package.json +1 -1
- package/connectors/voygr/package.json +1 -1
- package/connectors/wait/package.json +1 -1
- package/connectors/walmart-marketplace/package.json +1 -1
- package/connectors/wato/package.json +1 -1
- package/connectors/wave-accounting/package.json +1 -1
- package/connectors/wayco/package.json +1 -1
- package/connectors/webpagetest/package.json +1 -1
- package/connectors/weezevent/package.json +1 -1
- package/connectors/wikipedia/src/api/client.ts +1 -1
- package/connectors/wildcard/package.json +1 -1
- package/connectors/windmill/package.json +1 -1
- package/connectors/wise/package.json +1 -1
- package/connectors/withai/package.json +1 -1
- package/connectors/wiz/CLAUDE.md +1 -1
- package/connectors/wiz/package.json +1 -1
- package/connectors/wordfence/package.json +1 -1
- package/connectors/wordfence-api-platform/package.json +1 -1
- package/connectors/workos/package.json +1 -1
- package/connectors/write-binary-file/package.json +1 -1
- package/connectors/xai/.env.example +1 -1
- package/connectors/xai-api-platform/src/api/client.test.ts +1 -1
- package/connectors/xai-api-platform/src/cli/index.ts +1 -1
- package/connectors/xai-api-platform/src/utils/config.ts +1 -1
- package/connectors/xai-grok/.env.example +1 -1
- package/connectors/xai-grok/src/api/client.test.ts +3 -3
- package/connectors/xai-grok/src/cli/index.ts +1 -1
- package/connectors/xai-grok/src/utils/config.ts +1 -1
- package/connectors/ynab/package.json +1 -1
- package/connectors/you-com/README.md +2 -2
- package/connectors/you-com/package.json +1 -1
- package/connectors/yousign/package.json +1 -1
- package/connectors/zendesk/.env.example +4 -4
- package/connectors/zendesk/CLAUDE.md +1 -3
- package/connectors/zendesk/Makefile +18 -5
- package/connectors/zendesk/README.md +3 -8
- package/connectors/zendesk/SCAFFOLD.md +6 -5
- package/connectors/zerosettle/package.json +1 -1
- package/connectors/zoho-bigin/CLAUDE.md +1 -1
- package/connectors/zoho-campaigns/package.json +1 -1
- package/connectors/zoho-sign/package.json +1 -1
- package/connectors/zoho-subscriptions/CLAUDE.md +1 -1
- package/connectors/zohoprojects/CLAUDE.md +1 -1
- package/connectors/zolvo/package.json +1 -1
- package/connectors/zoom-api/package.json +1 -1
- package/connectors/zymbly/README.md +2 -2
- package/connectors/zymbly/package.json +1 -1
- package/dashboard/dist/assets/index-8uoGZF7B.js +280 -0
- package/dashboard/dist/index.html +1 -1
- package/dist/db/locks.d.ts +1 -1
- package/dist/index.js +17 -15
- package/dist/lib/connector-resolver.d.ts +1 -1
- package/dist/lib/llm.d.ts +1 -1
- package/dist/lib/open-browser.d.ts +18 -0
- package/dist/lib/open-browser.test.d.ts +1 -0
- package/package.json +6 -4
- package/dashboard/dist/assets/index-DlEljRrW.js +0 -285
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @hasna/connect-takecareos
|
|
2
2
|
|
|
3
|
-
TakeCareOS connector for the [
|
|
3
|
+
TakeCareOS connector for the [connectors](https://github.com/hasna/apps) registry.
|
|
4
4
|
|
|
5
5
|
TakeCareOS is a home-care agency operating system. This connector wraps its public
|
|
6
6
|
REST API to manage clients (care recipients), caregivers, shifts, incident reports,
|
|
@@ -18,7 +18,7 @@ The connector authenticates with a Bearer API key. Provide it via environment
|
|
|
18
18
|
variable, a CLI flag, or a stored profile:
|
|
19
19
|
|
|
20
20
|
```bash
|
|
21
|
-
export TAKECAREOS_API_KEY
|
|
21
|
+
export TAKECAREOS_API_KEY=<your-api-key>
|
|
22
22
|
# optional, for a dedicated/regional host
|
|
23
23
|
export TAKECAREOS_BASE_URL=https://api.takecareos.com/v1
|
|
24
24
|
```
|
|
@@ -59,6 +59,11 @@ export interface GetFileOptions {
|
|
|
59
59
|
fileId: string;
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
+
export interface DownloadFileResult {
|
|
63
|
+
file: TelegramFile;
|
|
64
|
+
data: Uint8Array;
|
|
65
|
+
}
|
|
66
|
+
|
|
62
67
|
export interface BotName {
|
|
63
68
|
name: string;
|
|
64
69
|
}
|
|
@@ -220,4 +225,19 @@ export class BotApi {
|
|
|
220
225
|
},
|
|
221
226
|
});
|
|
222
227
|
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Resolve and download a Telegram file
|
|
231
|
+
*/
|
|
232
|
+
async downloadFile(options: GetFileOptions): Promise<DownloadFileResult> {
|
|
233
|
+
const file = await this.getFile(options);
|
|
234
|
+
if (!file.file_path) {
|
|
235
|
+
throw new Error('Telegram did not return a downloadable file path');
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
return {
|
|
239
|
+
file,
|
|
240
|
+
data: await this.client.downloadFile(file.file_path),
|
|
241
|
+
};
|
|
242
|
+
}
|
|
223
243
|
}
|
|
@@ -118,6 +118,38 @@ export class TelegramClient {
|
|
|
118
118
|
return this.request<T>(method, { body: formData });
|
|
119
119
|
}
|
|
120
120
|
|
|
121
|
+
/**
|
|
122
|
+
* Download a file returned by the Telegram Bot API
|
|
123
|
+
*/
|
|
124
|
+
async downloadFile(filePath: string): Promise<Uint8Array> {
|
|
125
|
+
const normalizedPath = filePath.replace(/^\/+/, '');
|
|
126
|
+
if (!normalizedPath) {
|
|
127
|
+
throw new Error('Telegram file path is required');
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const encodedPath = normalizedPath
|
|
131
|
+
.split('/')
|
|
132
|
+
.map(segment => encodeURIComponent(segment))
|
|
133
|
+
.join('/');
|
|
134
|
+
const url = `${TELEGRAM_API_BASE}/file/bot${this.botToken}/${encodedPath}`;
|
|
135
|
+
|
|
136
|
+
let response: Response;
|
|
137
|
+
try {
|
|
138
|
+
response = await fetch(url);
|
|
139
|
+
} catch {
|
|
140
|
+
throw new Error('Failed to download Telegram file');
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
if (!response.ok) {
|
|
144
|
+
throw new TelegramApiError(
|
|
145
|
+
`Telegram file download failed with HTTP ${response.status}`,
|
|
146
|
+
response.status
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
return new Uint8Array(await response.arrayBuffer());
|
|
151
|
+
}
|
|
152
|
+
|
|
121
153
|
/**
|
|
122
154
|
* Get a preview of the bot token (for display/debugging)
|
|
123
155
|
*/
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { afterEach, describe, expect, mock, test } from 'bun:test';
|
|
2
|
+
import { Telegram } from './index';
|
|
3
|
+
|
|
4
|
+
const originalFetch = globalThis.fetch;
|
|
5
|
+
|
|
6
|
+
afterEach(() => {
|
|
7
|
+
globalThis.fetch = originalFetch;
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
describe('Telegram files API', () => {
|
|
11
|
+
test('resolves a file ID and downloads its bytes from the authenticated file URL', async () => {
|
|
12
|
+
const botToken = '123456:test-token';
|
|
13
|
+
const fetchMock = mock(async (
|
|
14
|
+
input: string | URL | Request,
|
|
15
|
+
_init?: RequestInit
|
|
16
|
+
) => {
|
|
17
|
+
const url = String(input);
|
|
18
|
+
if (url.endsWith('/getFile')) {
|
|
19
|
+
return Response.json({
|
|
20
|
+
ok: true,
|
|
21
|
+
result: {
|
|
22
|
+
file_id: 'incoming-file-id',
|
|
23
|
+
file_unique_id: 'unique-file-id',
|
|
24
|
+
file_size: 4,
|
|
25
|
+
file_path: 'documents/report 1.pdf',
|
|
26
|
+
},
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return new Response(new Uint8Array([1, 2, 3, 4]));
|
|
31
|
+
});
|
|
32
|
+
globalThis.fetch = fetchMock as unknown as typeof fetch;
|
|
33
|
+
|
|
34
|
+
const telegram = new Telegram({ botToken });
|
|
35
|
+
const downloaded = await telegram.bot.downloadFile({
|
|
36
|
+
fileId: 'incoming-file-id',
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
expect(fetchMock).toHaveBeenCalledTimes(2);
|
|
40
|
+
expect(String(fetchMock.mock.calls[0]?.[0])).toBe(
|
|
41
|
+
`https://api.telegram.org/bot${botToken}/getFile`
|
|
42
|
+
);
|
|
43
|
+
expect(JSON.parse(String(fetchMock.mock.calls[0]?.[1]?.body))).toEqual({
|
|
44
|
+
file_id: 'incoming-file-id',
|
|
45
|
+
});
|
|
46
|
+
expect(String(fetchMock.mock.calls[1]?.[0])).toBe(
|
|
47
|
+
`https://api.telegram.org/file/bot${botToken}/documents/report%201.pdf`
|
|
48
|
+
);
|
|
49
|
+
expect(downloaded.file.file_path).toBe('documents/report 1.pdf');
|
|
50
|
+
expect(downloaded.data).toEqual(new Uint8Array([1, 2, 3, 4]));
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
test('fails explicitly when Telegram does not return a file path', async () => {
|
|
54
|
+
const fetchMock = mock(async () =>
|
|
55
|
+
Response.json({
|
|
56
|
+
ok: true,
|
|
57
|
+
result: {
|
|
58
|
+
file_id: 'incoming-file-id',
|
|
59
|
+
file_unique_id: 'unique-file-id',
|
|
60
|
+
},
|
|
61
|
+
})
|
|
62
|
+
);
|
|
63
|
+
globalThis.fetch = fetchMock as unknown as typeof fetch;
|
|
64
|
+
|
|
65
|
+
const telegram = new Telegram({ botToken: '123456:test-token' });
|
|
66
|
+
|
|
67
|
+
expect(
|
|
68
|
+
telegram.bot.downloadFile({ fileId: 'incoming-file-id' })
|
|
69
|
+
).rejects.toThrow('Telegram did not return a downloadable file path');
|
|
70
|
+
expect(fetchMock).toHaveBeenCalledTimes(1);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
test('does not expose the bot token in download errors', async () => {
|
|
74
|
+
const botToken = '123456:must-not-leak';
|
|
75
|
+
const fetchMock = mock(async (
|
|
76
|
+
input: string | URL | Request,
|
|
77
|
+
_init?: RequestInit
|
|
78
|
+
) => {
|
|
79
|
+
if (String(input).endsWith('/getFile')) {
|
|
80
|
+
return Response.json({
|
|
81
|
+
ok: true,
|
|
82
|
+
result: {
|
|
83
|
+
file_id: 'incoming-file-id',
|
|
84
|
+
file_unique_id: 'unique-file-id',
|
|
85
|
+
file_path: 'photos/file.jpg',
|
|
86
|
+
},
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
return new Response('not found', { status: 404 });
|
|
90
|
+
});
|
|
91
|
+
globalThis.fetch = fetchMock as unknown as typeof fetch;
|
|
92
|
+
|
|
93
|
+
const telegram = new Telegram({ botToken });
|
|
94
|
+
|
|
95
|
+
try {
|
|
96
|
+
await telegram.bot.downloadFile({ fileId: 'incoming-file-id' });
|
|
97
|
+
throw new Error('Expected download to fail');
|
|
98
|
+
} catch (err) {
|
|
99
|
+
expect(String(err)).toContain('Telegram file download failed');
|
|
100
|
+
expect(String(err)).not.toContain(botToken);
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
});
|
|
@@ -9,7 +9,10 @@ afterEach(() => {
|
|
|
9
9
|
|
|
10
10
|
describe("Telegram messages API", () => {
|
|
11
11
|
test("sends raw exclamation marks unless MarkdownV2 parse mode is requested", async () => {
|
|
12
|
-
const fetchMock = mock(async (
|
|
12
|
+
const fetchMock = mock(async (
|
|
13
|
+
_input: string | URL | Request,
|
|
14
|
+
_init?: RequestInit
|
|
15
|
+
) =>
|
|
13
16
|
Response.json({
|
|
14
17
|
ok: true,
|
|
15
18
|
result: {
|
|
@@ -37,7 +40,10 @@ describe("Telegram messages API", () => {
|
|
|
37
40
|
});
|
|
38
41
|
|
|
39
42
|
test("preserves raw text when HTML parse mode is explicit", async () => {
|
|
40
|
-
const fetchMock = mock(async (
|
|
43
|
+
const fetchMock = mock(async (
|
|
44
|
+
_input: string | URL | Request,
|
|
45
|
+
_init?: RequestInit
|
|
46
|
+
) =>
|
|
41
47
|
Response.json({
|
|
42
48
|
ok: true,
|
|
43
49
|
result: {
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { afterEach, describe, expect, test } from 'bun:test';
|
|
2
|
+
import { mkdtempSync, readFileSync, rmSync } from 'fs';
|
|
3
|
+
import { tmpdir } from 'os';
|
|
4
|
+
import { join } from 'path';
|
|
5
|
+
import { resolveDownloadPath, writeDownloadedFile } from './files';
|
|
6
|
+
|
|
7
|
+
let temporaryDirectory: string | undefined;
|
|
8
|
+
|
|
9
|
+
afterEach(() => {
|
|
10
|
+
if (temporaryDirectory) {
|
|
11
|
+
rmSync(temporaryDirectory, { recursive: true, force: true });
|
|
12
|
+
temporaryDirectory = undefined;
|
|
13
|
+
}
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
describe('Telegram CLI file downloads', () => {
|
|
17
|
+
test('uses Telegram file name when the output is a directory', () => {
|
|
18
|
+
temporaryDirectory = mkdtempSync(join(tmpdir(), 'connect-telegram-'));
|
|
19
|
+
|
|
20
|
+
expect(resolveDownloadPath('photos/file_42.jpg', temporaryDirectory)).toBe(
|
|
21
|
+
join(temporaryDirectory, 'file_42.jpg')
|
|
22
|
+
);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
test('creates parent directories without overwriting an existing file', () => {
|
|
26
|
+
temporaryDirectory = mkdtempSync(join(tmpdir(), 'connect-telegram-'));
|
|
27
|
+
const destination = join(temporaryDirectory, 'nested', 'file.bin');
|
|
28
|
+
|
|
29
|
+
writeDownloadedFile(destination, new Uint8Array([1, 2, 3]));
|
|
30
|
+
expect(new Uint8Array(readFileSync(destination))).toEqual(
|
|
31
|
+
new Uint8Array([1, 2, 3])
|
|
32
|
+
);
|
|
33
|
+
expect(() =>
|
|
34
|
+
writeDownloadedFile(destination, new Uint8Array([4, 5, 6]))
|
|
35
|
+
).toThrow('Refusing to overwrite existing file');
|
|
36
|
+
expect(new Uint8Array(readFileSync(destination))).toEqual(
|
|
37
|
+
new Uint8Array([1, 2, 3])
|
|
38
|
+
);
|
|
39
|
+
});
|
|
40
|
+
});
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, statSync, writeFileSync } from 'fs';
|
|
2
|
+
import { basename, dirname, join, resolve, sep } from 'path';
|
|
3
|
+
|
|
4
|
+
export function resolveDownloadPath(
|
|
5
|
+
telegramFilePath: string,
|
|
6
|
+
outputPath?: string
|
|
7
|
+
): string {
|
|
8
|
+
const defaultName = basename(telegramFilePath);
|
|
9
|
+
if (!defaultName || defaultName === '.' || defaultName === sep) {
|
|
10
|
+
throw new Error('Telegram did not return a usable file name');
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
if (!outputPath) {
|
|
14
|
+
return resolve(defaultName);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const requestedPath = resolve(outputPath);
|
|
18
|
+
if (
|
|
19
|
+
(existsSync(requestedPath) && statSync(requestedPath).isDirectory()) ||
|
|
20
|
+
(!existsSync(requestedPath) && outputPath.endsWith(sep))
|
|
21
|
+
) {
|
|
22
|
+
return join(requestedPath, defaultName);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return requestedPath;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function writeDownloadedFile(
|
|
29
|
+
destinationPath: string,
|
|
30
|
+
data: Uint8Array
|
|
31
|
+
): void {
|
|
32
|
+
if (existsSync(destinationPath)) {
|
|
33
|
+
throw new Error(`Refusing to overwrite existing file: ${destinationPath}`);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
mkdirSync(dirname(destinationPath), { recursive: true });
|
|
37
|
+
writeFileSync(destinationPath, data, { flag: 'wx' });
|
|
38
|
+
}
|
|
@@ -4,6 +4,8 @@ import chalk from 'chalk';
|
|
|
4
4
|
import { readFileSync, existsSync } from 'fs';
|
|
5
5
|
import { basename } from 'path';
|
|
6
6
|
import { Telegram } from '../api';
|
|
7
|
+
import { resolveDownloadPath, writeDownloadedFile } from './files';
|
|
8
|
+
import { formatUpdate } from './updates';
|
|
7
9
|
import {
|
|
8
10
|
getBotToken,
|
|
9
11
|
setBotToken,
|
|
@@ -455,36 +457,7 @@ program
|
|
|
455
457
|
return;
|
|
456
458
|
}
|
|
457
459
|
|
|
458
|
-
|
|
459
|
-
const formatted = updates.map(u => {
|
|
460
|
-
const result: Record<string, unknown> = {
|
|
461
|
-
update_id: u.update_id,
|
|
462
|
-
};
|
|
463
|
-
|
|
464
|
-
if (u.message) {
|
|
465
|
-
result.type = 'message';
|
|
466
|
-
result.from = u.message.from?.username || u.message.from?.first_name || 'unknown';
|
|
467
|
-
result.chat_id = u.message.chat.id;
|
|
468
|
-
result.text = u.message.text || '[media]';
|
|
469
|
-
result.date = new Date(u.message.date * 1000).toISOString();
|
|
470
|
-
} else if (u.callback_query) {
|
|
471
|
-
result.type = 'callback_query';
|
|
472
|
-
result.from = u.callback_query.from.username || u.callback_query.from.first_name;
|
|
473
|
-
result.data = u.callback_query.data;
|
|
474
|
-
} else if (u.inline_query) {
|
|
475
|
-
result.type = 'inline_query';
|
|
476
|
-
result.from = u.inline_query.from.username || u.inline_query.from.first_name;
|
|
477
|
-
result.query = u.inline_query.query;
|
|
478
|
-
} else if (u.edited_message) {
|
|
479
|
-
result.type = 'edited_message';
|
|
480
|
-
result.chat_id = u.edited_message.chat.id;
|
|
481
|
-
} else if (u.channel_post) {
|
|
482
|
-
result.type = 'channel_post';
|
|
483
|
-
result.chat_id = u.channel_post.chat.id;
|
|
484
|
-
}
|
|
485
|
-
|
|
486
|
-
return result;
|
|
487
|
-
});
|
|
460
|
+
const formatted = updates.map(formatUpdate);
|
|
488
461
|
|
|
489
462
|
print(formatted, getFormat(program));
|
|
490
463
|
info(`Showing ${updates.length} update(s). Last update_id: ${updates[updates.length - 1].update_id}`);
|
|
@@ -494,6 +467,30 @@ program
|
|
|
494
467
|
}
|
|
495
468
|
});
|
|
496
469
|
|
|
470
|
+
program
|
|
471
|
+
.command('get-file <fileId>')
|
|
472
|
+
.description('Download a Telegram file by file ID')
|
|
473
|
+
.option('-o, --output <path>', 'Output file or directory (defaults to the Telegram file name)')
|
|
474
|
+
.action(async (fileId: string, opts: { output?: string }) => {
|
|
475
|
+
try {
|
|
476
|
+
const client = getClient();
|
|
477
|
+
const downloaded = await client.bot.downloadFile({ fileId });
|
|
478
|
+
const destination = resolveDownloadPath(downloaded.file.file_path!, opts.output);
|
|
479
|
+
writeDownloadedFile(destination, downloaded.data);
|
|
480
|
+
|
|
481
|
+
print({
|
|
482
|
+
file_id: downloaded.file.file_id,
|
|
483
|
+
file_unique_id: downloaded.file.file_unique_id,
|
|
484
|
+
file_path: downloaded.file.file_path,
|
|
485
|
+
output: destination,
|
|
486
|
+
bytes: downloaded.data.byteLength,
|
|
487
|
+
}, getFormat(program));
|
|
488
|
+
} catch (err) {
|
|
489
|
+
error(String(err));
|
|
490
|
+
process.exit(1);
|
|
491
|
+
}
|
|
492
|
+
});
|
|
493
|
+
|
|
497
494
|
// ============================================
|
|
498
495
|
// Chat Commands
|
|
499
496
|
// ============================================
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import { describe, expect, test } from 'bun:test';
|
|
2
|
+
import type { TelegramMessage, TelegramUpdate } from '../types';
|
|
3
|
+
import { formatUpdate } from './updates';
|
|
4
|
+
|
|
5
|
+
function updateWith(message: Partial<TelegramMessage>): TelegramUpdate {
|
|
6
|
+
return {
|
|
7
|
+
update_id: 428687256,
|
|
8
|
+
message: {
|
|
9
|
+
message_id: 42,
|
|
10
|
+
date: 1,
|
|
11
|
+
chat: { id: 123, type: 'private' },
|
|
12
|
+
from: {
|
|
13
|
+
id: 456,
|
|
14
|
+
is_bot: false,
|
|
15
|
+
first_name: 'Andrei',
|
|
16
|
+
username: 'andrei',
|
|
17
|
+
},
|
|
18
|
+
...message,
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
describe('Telegram update formatting', () => {
|
|
24
|
+
test('exposes the largest incoming photo file ID and caption', () => {
|
|
25
|
+
const formatted = formatUpdate(updateWith({
|
|
26
|
+
caption: 'Please inspect this screenshot',
|
|
27
|
+
photo: [
|
|
28
|
+
{
|
|
29
|
+
file_id: 'small-photo-id',
|
|
30
|
+
file_unique_id: 'small-unique-id',
|
|
31
|
+
width: 90,
|
|
32
|
+
height: 90,
|
|
33
|
+
file_size: 100,
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
file_id: 'large-photo-id',
|
|
37
|
+
file_unique_id: 'large-unique-id',
|
|
38
|
+
width: 1280,
|
|
39
|
+
height: 720,
|
|
40
|
+
file_size: 5000,
|
|
41
|
+
},
|
|
42
|
+
],
|
|
43
|
+
}));
|
|
44
|
+
|
|
45
|
+
expect(formatted).toMatchObject({
|
|
46
|
+
update_id: 428687256,
|
|
47
|
+
type: 'message',
|
|
48
|
+
message_id: 42,
|
|
49
|
+
caption: 'Please inspect this screenshot',
|
|
50
|
+
media: {
|
|
51
|
+
type: 'photo',
|
|
52
|
+
file_id: 'large-photo-id',
|
|
53
|
+
file_unique_id: 'large-unique-id',
|
|
54
|
+
width: 1280,
|
|
55
|
+
height: 720,
|
|
56
|
+
file_size: 5000,
|
|
57
|
+
},
|
|
58
|
+
});
|
|
59
|
+
expect(formatted).not.toHaveProperty('text', '[media]');
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
test('exposes actionable metadata for every typed downloadable media kind', () => {
|
|
63
|
+
const cases: Array<{
|
|
64
|
+
mediaType: string;
|
|
65
|
+
message: Partial<TelegramMessage>;
|
|
66
|
+
fileId: string;
|
|
67
|
+
expected: Record<string, unknown>;
|
|
68
|
+
}> = [
|
|
69
|
+
{
|
|
70
|
+
mediaType: 'animation',
|
|
71
|
+
fileId: 'animation-id',
|
|
72
|
+
message: {
|
|
73
|
+
animation: {
|
|
74
|
+
file_id: 'animation-id',
|
|
75
|
+
file_unique_id: 'animation-unique-id',
|
|
76
|
+
width: 640,
|
|
77
|
+
height: 360,
|
|
78
|
+
duration: 4,
|
|
79
|
+
file_name: 'instruction.gif',
|
|
80
|
+
mime_type: 'image/gif',
|
|
81
|
+
file_size: 2500,
|
|
82
|
+
},
|
|
83
|
+
},
|
|
84
|
+
expected: {
|
|
85
|
+
width: 640,
|
|
86
|
+
height: 360,
|
|
87
|
+
duration: 4,
|
|
88
|
+
file_name: 'instruction.gif',
|
|
89
|
+
mime_type: 'image/gif',
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
mediaType: 'document',
|
|
94
|
+
fileId: 'document-id',
|
|
95
|
+
message: {
|
|
96
|
+
document: {
|
|
97
|
+
file_id: 'document-id',
|
|
98
|
+
file_unique_id: 'document-unique-id',
|
|
99
|
+
file_name: 'instructions.pdf',
|
|
100
|
+
mime_type: 'application/pdf',
|
|
101
|
+
file_size: 1000,
|
|
102
|
+
},
|
|
103
|
+
},
|
|
104
|
+
expected: {
|
|
105
|
+
file_name: 'instructions.pdf',
|
|
106
|
+
mime_type: 'application/pdf',
|
|
107
|
+
},
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
mediaType: 'audio',
|
|
111
|
+
fileId: 'audio-id',
|
|
112
|
+
message: {
|
|
113
|
+
audio: {
|
|
114
|
+
file_id: 'audio-id',
|
|
115
|
+
file_unique_id: 'audio-unique-id',
|
|
116
|
+
duration: 12,
|
|
117
|
+
file_name: 'note.mp3',
|
|
118
|
+
mime_type: 'audio/mpeg',
|
|
119
|
+
},
|
|
120
|
+
},
|
|
121
|
+
expected: { duration: 12, file_name: 'note.mp3', mime_type: 'audio/mpeg' },
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
mediaType: 'video',
|
|
125
|
+
fileId: 'video-id',
|
|
126
|
+
message: {
|
|
127
|
+
video: {
|
|
128
|
+
file_id: 'video-id',
|
|
129
|
+
file_unique_id: 'video-unique-id',
|
|
130
|
+
width: 1920,
|
|
131
|
+
height: 1080,
|
|
132
|
+
duration: 8,
|
|
133
|
+
file_name: 'screen.mp4',
|
|
134
|
+
mime_type: 'video/mp4',
|
|
135
|
+
},
|
|
136
|
+
},
|
|
137
|
+
expected: { width: 1920, height: 1080, duration: 8, file_name: 'screen.mp4' },
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
mediaType: 'voice',
|
|
141
|
+
fileId: 'voice-id',
|
|
142
|
+
message: {
|
|
143
|
+
voice: {
|
|
144
|
+
file_id: 'voice-id',
|
|
145
|
+
file_unique_id: 'voice-unique-id',
|
|
146
|
+
duration: 5,
|
|
147
|
+
mime_type: 'audio/ogg',
|
|
148
|
+
},
|
|
149
|
+
},
|
|
150
|
+
expected: { duration: 5, mime_type: 'audio/ogg' },
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
mediaType: 'video_note',
|
|
154
|
+
fileId: 'video-note-id',
|
|
155
|
+
message: {
|
|
156
|
+
video_note: {
|
|
157
|
+
file_id: 'video-note-id',
|
|
158
|
+
file_unique_id: 'video-note-unique-id',
|
|
159
|
+
length: 384,
|
|
160
|
+
duration: 6,
|
|
161
|
+
},
|
|
162
|
+
},
|
|
163
|
+
expected: { length: 384, duration: 6 },
|
|
164
|
+
},
|
|
165
|
+
];
|
|
166
|
+
|
|
167
|
+
for (const testCase of cases) {
|
|
168
|
+
const formatted = formatUpdate(updateWith(testCase.message));
|
|
169
|
+
expect(formatted.media).toMatchObject({
|
|
170
|
+
type: testCase.mediaType,
|
|
171
|
+
file_id: testCase.fileId,
|
|
172
|
+
...testCase.expected,
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
});
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
TelegramAnimation,
|
|
3
|
+
TelegramAudio,
|
|
4
|
+
TelegramDocument,
|
|
5
|
+
TelegramMessage,
|
|
6
|
+
TelegramPhotoSize,
|
|
7
|
+
TelegramUpdate,
|
|
8
|
+
TelegramVideo,
|
|
9
|
+
TelegramVideoNote,
|
|
10
|
+
TelegramVoice,
|
|
11
|
+
} from '../types';
|
|
12
|
+
|
|
13
|
+
type TelegramMedia =
|
|
14
|
+
| ({ type: 'photo' } & TelegramPhotoSize)
|
|
15
|
+
| ({ type: 'animation' } & TelegramAnimation)
|
|
16
|
+
| ({ type: 'document' } & TelegramDocument)
|
|
17
|
+
| ({ type: 'audio' } & TelegramAudio)
|
|
18
|
+
| ({ type: 'video' } & TelegramVideo)
|
|
19
|
+
| ({ type: 'voice' } & TelegramVoice)
|
|
20
|
+
| ({ type: 'video_note' } & TelegramVideoNote);
|
|
21
|
+
|
|
22
|
+
export function getMessageMedia(message: TelegramMessage): TelegramMedia | undefined {
|
|
23
|
+
const photo = message.photo?.at(-1);
|
|
24
|
+
if (photo) {
|
|
25
|
+
return { type: 'photo', ...photo };
|
|
26
|
+
}
|
|
27
|
+
if (message.animation) {
|
|
28
|
+
return { type: 'animation', ...message.animation };
|
|
29
|
+
}
|
|
30
|
+
if (message.document) {
|
|
31
|
+
return { type: 'document', ...message.document };
|
|
32
|
+
}
|
|
33
|
+
if (message.audio) {
|
|
34
|
+
return { type: 'audio', ...message.audio };
|
|
35
|
+
}
|
|
36
|
+
if (message.video) {
|
|
37
|
+
return { type: 'video', ...message.video };
|
|
38
|
+
}
|
|
39
|
+
if (message.voice) {
|
|
40
|
+
return { type: 'voice', ...message.voice };
|
|
41
|
+
}
|
|
42
|
+
if (message.video_note) {
|
|
43
|
+
return { type: 'video_note', ...message.video_note };
|
|
44
|
+
}
|
|
45
|
+
return undefined;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function formatMessage(
|
|
49
|
+
result: Record<string, unknown>,
|
|
50
|
+
type: string,
|
|
51
|
+
message: TelegramMessage
|
|
52
|
+
): void {
|
|
53
|
+
result.type = type;
|
|
54
|
+
result.message_id = message.message_id;
|
|
55
|
+
result.from = message.from?.username || message.from?.first_name || 'unknown';
|
|
56
|
+
result.chat_id = message.chat.id;
|
|
57
|
+
if (message.text !== undefined) {
|
|
58
|
+
result.text = message.text;
|
|
59
|
+
}
|
|
60
|
+
if (message.caption !== undefined) {
|
|
61
|
+
result.caption = message.caption;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const media = getMessageMedia(message);
|
|
65
|
+
if (media) {
|
|
66
|
+
result.media = media;
|
|
67
|
+
}
|
|
68
|
+
result.date = new Date(message.date * 1000).toISOString();
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export function formatUpdate(update: TelegramUpdate): Record<string, unknown> {
|
|
72
|
+
const result: Record<string, unknown> = {
|
|
73
|
+
update_id: update.update_id,
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
if (update.message) {
|
|
77
|
+
formatMessage(result, 'message', update.message);
|
|
78
|
+
} else if (update.callback_query) {
|
|
79
|
+
result.type = 'callback_query';
|
|
80
|
+
result.from = update.callback_query.from.username || update.callback_query.from.first_name;
|
|
81
|
+
result.data = update.callback_query.data;
|
|
82
|
+
} else if (update.inline_query) {
|
|
83
|
+
result.type = 'inline_query';
|
|
84
|
+
result.from = update.inline_query.from.username || update.inline_query.from.first_name;
|
|
85
|
+
result.query = update.inline_query.query;
|
|
86
|
+
} else if (update.edited_message) {
|
|
87
|
+
formatMessage(result, 'edited_message', update.edited_message);
|
|
88
|
+
} else if (update.channel_post) {
|
|
89
|
+
formatMessage(result, 'channel_post', update.channel_post);
|
|
90
|
+
} else if (update.edited_channel_post) {
|
|
91
|
+
formatMessage(result, 'edited_channel_post', update.edited_channel_post);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return result;
|
|
95
|
+
}
|