-
Notifications
You must be signed in to change notification settings - Fork 46
feat: Telegram provider (direct Bot API) #16
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
VanditKumar (KumarVandit)
wants to merge
83
commits into
photon-hq:main
from
KumarVandit:telegram-support
Closed
Changes from 6 commits
Commits
Show all changes
83 commits
Select commit
Hold shift + click to select a range
74fb8cb
feat: add comprehensive Telegram Bot API provider
KumarVandit 8c53775
fix: skip bot.start() polling when webhook mode is active
KumarVandit 74c4547
Remove webhook support, defer to future integration
KumarVandit 63d115b
Add webhook support for Telegram provider
KumarVandit 1ed749a
Add Inline Mode and HTML5 Games support
KumarVandit d6e8e57
Remove webhook server, refactor event handling with EventSink pattern
KumarVandit 9c6f2bf
Address CodeRabbit review findings
KumarVandit 0a5c4b4
Fix HttpError retry and chatMember userId mapping
KumarVandit 2557f09
Update README with Telegram provider and new platform actions
KumarVandit daba827
Address CodeRabbit README and type assertion feedback
KumarVandit 0fd8252
Capture game callbacks and document by-design decisions
KumarVandit 911ca45
feat(spectrum-ts): add contact content type with vCard support
underthestars-zhy 12a3280
refactor(examples): simplify basic example to use terminal provider
underthestars-zhy 5299fc8
Update README to document contact content type
underthestars-zhy 2858b28
Merge contact content type from ryan/contact-card
KumarVandit 70f618e
Wire contact content type through Telegram provider
KumarVandit 101b273
Add example bots: AI moderator (AI SDK) and inline knowledge agent (M…
KumarVandit 4932d4f
Add voice message content type with ffmpeg transcoding support
underthestars-zhy 5cd1392
Merge voice content type from ryan/feature-content-voice
KumarVandit 71c988c
Wire voice content type through Telegram provider
KumarVandit 69b474f
Merge latest main to resolve conflicts
KumarVandit ea15b2f
Remove example bots from this PR
KumarVandit 715fcea
Merge remote-tracking branch 'origin/main' into telegram-support
KumarVandit 2038041
Align Telegram provider with OutboundMessage + SendResult APIs
KumarVandit 4ab2df1
Expose platform client on PlatformInstance
KumarVandit e47f080
Strip Telegram provider to universal Spectrum APIs only
KumarVandit 81b1dd4
Rewrite Telegram provider against Bot API directly
KumarVandit b00ac6a
Address CodeRabbit review findings on Telegram provider
KumarVandit 4c0dd56
Merge remote-tracking branch 'origin/main' into telegram-support
KumarVandit 5600288
Add richlink content type support to Telegram provider
KumarVandit 9b81545
Use full LinkPreviewOptions API for Telegram richlinks
KumarVandit 898b6e4
Merge remote-tracking branch 'origin/main' into telegram-support
KumarVandit 2db84cd
Add reaction support to Telegram provider
KumarVandit dd8d9e7
Address CodeRabbit review: retry/client/events hardening + Bot API 9.…
KumarVandit 72e7f83
Address CodeRabbit re-review: transport unification + leak/channel-po…
KumarVandit 535de51
Fix CodeRabbit: decouple lazy media reads + defer signal cleanup
KumarVandit 6a1f08f
Address CodeRabbit nitpicks: input validation + error context + gener…
KumarVandit a585da1
Merge remote-tracking branch 'origin/main' into telegram-support
KumarVandit ffa8367
feat(provider/telegram): sync with PR #33/#35 + ship cache-free addit…
KumarVandit cd51deb
docs(provider/telegram): document richlink customization drop
KumarVandit 44ba062
fix(provider/telegram): nested-blob multipart corruption + retry_afte…
KumarVandit a4b90c4
refactor(provider/telegram): split events.ts into events/{inbound,rea…
KumarVandit e48b73d
feat(provider/telegram): in-process LRU cache for getMessage, reactio…
KumarVandit b21a618
Merge remote-tracking branch 'origin/main' into telegram-support
KumarVandit 023b57e
fix(provider/telegram): align with upstream PR #38 + #39 contracts
KumarVandit b75af6d
fix(provider/telegram): address CodeRabbit review findings on PR #16
KumarVandit 74f5288
fix(provider/telegram): address CodeRabbit follow-up review on PR #16
KumarVandit 4fe808d
fix(provider/telegram): address third CodeRabbit review on PR #16
KumarVandit 68e4933
fix(provider/telegram): address fourth CodeRabbit review on PR #16
KumarVandit dac6b91
chore(provider/telegram): address fifth CodeRabbit nitpick pass on PR…
KumarVandit 91a172f
fix(provider/telegram): address sixth CodeRabbit review on PR #16
KumarVandit 5df6691
fix(provider/telegram): address seventh CodeRabbit review on PR #16
KumarVandit 90455e2
fix(provider/telegram): address eighth CodeRabbit review on PR #16
KumarVandit 153d0e3
fix(provider/telegram): pre-validate group children + share identity …
KumarVandit 232a4f0
fix(provider/telegram): dedupe TelegramSpaceShape in identity.ts
KumarVandit c60d6d3
fix(provider/telegram): remove allow_adding_options + fix quiz JSDoc …
KumarVandit 6b701a5
revert(root): drop package.json gen drift check
KumarVandit 08d3a73
refactor(provider/telegram): scope bot-api-spec under telegram provider
KumarVandit 7cdea4e
Merge remote-tracking branch 'origin/main' into telegram-support
KumarVandit 1f7ff75
refactor(provider/telegram): align with collapsed messages+send surfa…
KumarVandit 4e2e7e9
fix(provider/telegram): clamp polling timeout to Telegram's 50s serve…
KumarVandit 511e946
fix(provider/telegram): truncate fractional polling timeouts in sanit…
KumarVandit 6ed91a2
fix(provider/telegram): cache coalesced album wrapper under its emit id
KumarVandit 51683a7
fix(provider/telegram): validate requestTimeoutMs in TelegramClient ctor
KumarVandit ac55058
chore(provider/telegram): clean up comments and dead schema fields
KumarVandit 03c4825
chore(provider/telegram): drop redundant validation and narrative com…
KumarVandit b77e8d1
refactor(provider/telegram): adopt quick-lru in place of handwritten …
KumarVandit d244dbf
fix(provider/telegram): tighten TelegramClient timeout handling
KumarVandit aca471e
feat(provider/telegram): add sendPoll allow_adding_options (Bot API 9.6)
KumarVandit 7a9843a
refactor(provider/telegram): reuse chatToSpace in space.resolve
KumarVandit 39200c1
fix(provider/telegram): sync cached poll options on poll updates
KumarVandit 8f8f631
fix(provider/telegram): harden sendGroupContent and sendContact paths
KumarVandit 1fa5616
fix(provider/telegram): reject nested Blob params in TelegramClient
KumarVandit 2f098ea
chore(provider/telegram): simplify extractEmoji ternary
KumarVandit 8938920
fix(provider/telegram): keep prose alongside link previews
KumarVandit 0c2733d
fix(provider/telegram): strict-parse Telegram message_id
KumarVandit 67b0b90
fix(provider/telegram): normalize baseUrl and propagate timeout aborts
KumarVandit 42efc61
fix(provider/telegram): replace stale album members in message cache
KumarVandit 9ffd439
feat(provider/telegram): surface readable title for private chats
KumarVandit 82ab8c2
fix(provider/telegram): reject zero/negative Telegram message_id
KumarVandit a1b998b
fix(provider/telegram): require non-empty token in TelegramClient
KumarVandit 761285a
fix(provider/telegram): drop undefined entries when merging retry policy
KumarVandit 8f69c12
refactor(provider/telegram): use native ErrorOptions.cause in network…
KumarVandit File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -35,3 +35,6 @@ report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json | |
|
|
||
| # Finder (MacOS) folder config | ||
| .DS_Store | ||
|
|
||
| # test results | ||
| test/ | ||
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,122 @@ | ||
| import { GrammyError, HttpError } from "grammy"; | ||
|
|
||
| export type LogLevel = "silent" | "error" | "warn" | "info" | "debug"; | ||
|
|
||
| const LOG_LEVELS: Record<LogLevel, number> = { | ||
| silent: 0, | ||
| error: 1, | ||
| warn: 2, | ||
| info: 3, | ||
| debug: 4, | ||
| }; | ||
|
|
||
| export interface TelegramLogger { | ||
| debug(message: string, ...args: unknown[]): void; | ||
| error(message: string, ...args: unknown[]): void; | ||
| info(message: string, ...args: unknown[]): void; | ||
| warn(message: string, ...args: unknown[]): void; | ||
| } | ||
|
|
||
| export const createLogger = (level: LogLevel = "error"): TelegramLogger => { | ||
| const threshold = LOG_LEVELS[level]; | ||
| const noop = () => {}; | ||
|
|
||
| return { | ||
| debug: | ||
| threshold >= LOG_LEVELS.debug | ||
| ? (msg, ...args) => console.debug(`[Telegram] ${msg}`, ...args) | ||
| : noop, | ||
| info: | ||
| threshold >= LOG_LEVELS.info | ||
| ? (msg, ...args) => console.info(`[Telegram] ${msg}`, ...args) | ||
| : noop, | ||
| warn: | ||
| threshold >= LOG_LEVELS.warn | ||
| ? (msg, ...args) => console.warn(`[Telegram] ${msg}`, ...args) | ||
| : noop, | ||
| error: | ||
| threshold >= LOG_LEVELS.error | ||
| ? (msg, ...args) => console.error(`[Telegram] ${msg}`, ...args) | ||
| : noop, | ||
| }; | ||
| }; | ||
|
|
||
| export class TelegramError extends Error { | ||
| readonly errorCode: number; | ||
| readonly description: string; | ||
| readonly retryAfter?: number; | ||
|
|
||
| constructor(errorCode: number, description: string, retryAfter?: number) { | ||
| super(`Telegram API error ${errorCode}: ${description}`); | ||
| this.name = "TelegramError"; | ||
| this.errorCode = errorCode; | ||
| this.description = description; | ||
| this.retryAfter = retryAfter; | ||
| } | ||
|
|
||
| static fromGrammyError(err: GrammyError): TelegramError { | ||
| const retryAfter = | ||
| err.error_code === 429 | ||
| ? (err.parameters?.retry_after ?? undefined) | ||
| : undefined; | ||
| return new TelegramError(err.error_code, err.description, retryAfter); | ||
| } | ||
|
|
||
| static fromUnknown(err: unknown): TelegramError | Error { | ||
| if (err instanceof TelegramError) { | ||
| return err; | ||
| } | ||
| if (err instanceof GrammyError) { | ||
| return TelegramError.fromGrammyError(err); | ||
| } | ||
| if (err instanceof HttpError) { | ||
| return new TelegramError(0, `Network error: ${err.message}`); | ||
| } | ||
| if (err instanceof Error) { | ||
| return err; | ||
| } | ||
| return new Error(String(err)); | ||
| } | ||
|
coderabbitai[bot] marked this conversation as resolved.
Outdated
|
||
| } | ||
|
|
||
| const sleep = (ms: number): Promise<void> => | ||
| new Promise((resolve) => setTimeout(resolve, ms)); | ||
|
|
||
| export const withRetry = async <T>( | ||
| fn: () => Promise<T>, | ||
| logger: TelegramLogger, | ||
| maxRetries = 3 | ||
| ): Promise<T> => { | ||
| let lastError: unknown; | ||
|
|
||
| for (let attempt = 0; attempt <= maxRetries; attempt++) { | ||
| try { | ||
| return await fn(); | ||
| } catch (err) { | ||
| lastError = err; | ||
| const wrapped = TelegramError.fromUnknown(err); | ||
|
|
||
| if (wrapped instanceof TelegramError && wrapped.retryAfter) { | ||
| const waitMs = wrapped.retryAfter * 1000; | ||
| logger.warn( | ||
| `Rate limited, retrying in ${wrapped.retryAfter}s (attempt ${attempt + 1}/${maxRetries + 1})` | ||
| ); | ||
| await sleep(waitMs); | ||
| continue; | ||
| } | ||
|
|
||
| if (wrapped instanceof TelegramError && wrapped.errorCode >= 500) { | ||
| const backoff = Math.min(1000 * 2 ** attempt, 30_000); | ||
| logger.warn( | ||
| `Server error ${wrapped.errorCode}, retrying in ${backoff}ms (attempt ${attempt + 1}/${maxRetries + 1})` | ||
| ); | ||
| await sleep(backoff); | ||
| continue; | ||
|
coderabbitai[bot] marked this conversation as resolved.
Outdated
|
||
| } | ||
|
|
||
| throw wrapped; | ||
| } | ||
| } | ||
|
|
||
| throw TelegramError.fromUnknown(lastError); | ||
| }; | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.