4 Commits

Author SHA1 Message Date
lukaszraczylo 9cfe193e2e docs(reference): regenerate after typed-allowed-updates merge
PR #1 changed AllowedUpdates type and shifted longpoll.go line numbers but left docs/reference/ stale, breaking the codegen-clean CI gate.
2026-05-09 21:19:09 +01:00
lukaszraczylo 79c0617867 Merge pull request #1 from lukaszraczylo/feat/typed-allowed-updates
feat(api): type AllowedUpdates as []UpdateType for compile-time typo …
2026-05-09 20:53:45 +01:00
lukaszraczylo 60eb0a89b5 refactor(api): typed enums for emoji-list fields (DiceEmoji, ReactionEmoji)
Two API fields carry restricted emoji-value sets that the scraper's
curly-quote regex strips during IR extraction (multi-byte boundary
issue): ReactionTypeEmoji.Emoji and sendDice.Emoji. They previously
typed as plain string with no compile-time guarantee on values.

Add hand-curated typed-string enums in api/enums.go (the manual file,
not enums.gen.go):

  - DiceEmoji: 6 constants (Dice, Dart, Basketball, Football, Bowling,
    SlotMachine) covering Telegram's full set for sendDice.
  - ReactionEmoji: 73 constants covering the canonical reaction set
    from https://core.telegram.org/bots/api#reactiontypeemoji. Names
    follow Unicode CLDR short names where one exists, otherwise stable
    common-English labels (e.g. ThumbsUp, Heart, Clown, ManTechnologist).

Wire the field-type override via cmd/genapi/emitter.go:

  - fieldTypeOverrides map keyed "<TypeOrParamsName>.<FieldName>".
  - goField/multipartFieldEntry consult the override after the enum-plan
    lookup; falls through to the default goType when nothing matches.
  - methods.tmpl gains goFieldP/multipartFieldEntryP helpers that pass
    the params type name as override-parent (the params struct doesn't
    share a Go type with the field, so the existing parent="" enum-key
    convention is preserved).

Regenerated api/types.gen.go and api/methods.gen.go now type the two
fields as ReactionEmoji and DiceEmoji respectively. No other Emoji
field is affected (override is scoped per parent type). regen-from-
fixture is byte-deterministic across runs.

Add api/emoji_enums_test.go covering const wire values, reflection
checks on field types, and a marshal/unmarshal round-trip for
ReactionTypeEmoji.
2026-05-09 20:47:16 +01:00
lukaszraczylo 62c76e7e4e feat(api): type AllowedUpdates as []UpdateType for compile-time typo safety
Both SetWebhookParams.AllowedUpdates and GetUpdatesParams.AllowedUpdates
(plus the WebhookInfo.AllowedUpdates field on the response side) were
typed []string, forcing callers to cast every typed constant:

  AllowedUpdates: []string{
      string(api.UpdateMessage),
      string(api.UpdateMyChatMember),
      ...
  }

Switch to []UpdateType so the same call site is typo-safe end-to-end:

  AllowedUpdates: []UpdateType{
      api.UpdateMessage,
      api.UpdateMyChatMember,
      ...
  }

Wire format is unchanged — UpdateType is type UpdateType string, marshals
identically as JSON strings. The MultipartFields()/runtime.go encoding
paths likewise continue to work via json.Marshal on the typed slice.

Implementation note: api/methods.gen.go and api/types.gen.go are
generated by cmd/genapi from internal/spec/api.json, where the field is
described as Array of String. The Telegram docs do not enumerate the
allowed_updates values inline, so the scraper cannot synthesise the
enum and UpdateType lives hand-curated in api/enums.go (see existing
doc comment there). The retype is therefore done as a small pinned
override inside cmd/genapi/emitter.go's goField — keyed on the wire
field name allowed_updates with elem type string — so the change
survives a future regeneration of the .gen.go files. transport/longpoll
drops the now-unnecessary []string conversion.

Backward incompatibility: callers passing untyped []string variables
will need to convert; callers using untyped string literals inside the
slice ARE fine because Go's untyped-literal rule auto-converts.
2026-05-09 20:20:30 +01:00
9 changed files with 399 additions and 22 deletions
+96
View File
@@ -0,0 +1,96 @@
package api
import (
"reflect"
"testing"
"github.com/goccy/go-json"
"github.com/stretchr/testify/require"
)
// TestDiceEmoji_Constants pins the canonical six dice-emoji values so a
// regen, refactor, or accidental rename can't silently break the wire
// contract.
func TestDiceEmoji_Constants(t *testing.T) {
cases := []struct {
name string
got DiceEmoji
want string
}{
{"Dice", DiceEmojiDice, "🎲"},
{"Dart", DiceEmojiDart, "🎯"},
{"Basketball", DiceEmojiBasketball, "🏀"},
{"Football", DiceEmojiFootball, "⚽"},
{"Bowling", DiceEmojiBowling, "🎳"},
{"SlotMachine", DiceEmojiSlotMachine, "🎰"},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
require.Equal(t, c.want, string(c.got))
})
}
}
// TestSendDiceParams_EmojiFieldType asserts the codegen override wired
// SendDiceParams.Emoji to the typed enum (not plain string). Reflection
// catches a regression even if the file compiles via implicit string
// conversion of an untyped literal.
func TestSendDiceParams_EmojiFieldType(t *testing.T) {
rt := reflect.TypeOf(SendDiceParams{})
f, ok := rt.FieldByName("Emoji")
require.True(t, ok, "SendDiceParams.Emoji not present")
require.Equal(t, "DiceEmoji", f.Type.Name())
}
// TestSendDiceParams_MarshalJSON exercises the marshalled wire form to
// prove the typed enum still serialises as a JSON string holding the
// raw emoji bytes — i.e. the type override doesn't accidentally
// double-encode.
func TestSendDiceParams_MarshalJSON(t *testing.T) {
p := &SendDiceParams{
ChatID: ChatIDFromInt(1),
Emoji: DiceEmojiBasketball,
}
data, err := json.Marshal(p)
require.NoError(t, err)
require.Contains(t, string(data), `"emoji":"🏀"`)
}
// TestReactionEmoji_Constants spot-checks a representative slice of the
// 73-value enum. A full enumeration would be redundant — the test is
// here to lock the wire form, not to retest the const-block.
func TestReactionEmoji_Constants(t *testing.T) {
require.Equal(t, "👍", string(ReactionEmojiThumbsUp))
require.Equal(t, "👎", string(ReactionEmojiThumbsDown))
require.Equal(t, "❤", string(ReactionEmojiHeart))
require.Equal(t, "🔥", string(ReactionEmojiFire))
require.Equal(t, "💯", string(ReactionEmojiHundredPoints))
require.Equal(t, "🤡", string(ReactionEmojiClown))
}
// TestReactionTypeEmoji_FieldType asserts the codegen override wired
// ReactionTypeEmoji.Emoji to the typed enum.
func TestReactionTypeEmoji_FieldType(t *testing.T) {
rt := reflect.TypeOf(ReactionTypeEmoji{})
f, ok := rt.FieldByName("Emoji")
require.True(t, ok, "ReactionTypeEmoji.Emoji not present")
require.Equal(t, "ReactionEmoji", f.Type.Name())
}
// TestReactionTypeEmoji_RoundTrip proves a typed-enum value survives
// JSON marshal → unmarshal cycle without losing fidelity. The
// discriminator MarshalJSON on ReactionTypeEmoji forces type="emoji",
// so we set it explicitly here for symmetry with the unmarshal path.
func TestReactionTypeEmoji_RoundTrip(t *testing.T) {
in := &ReactionTypeEmoji{
Type: ReactionTypeKindEmoji,
Emoji: ReactionEmojiThumbsUp,
}
data, err := json.Marshal(in)
require.NoError(t, err)
require.Contains(t, string(data), `"emoji":"👍"`)
var out ReactionTypeEmoji
require.NoError(t, json.Unmarshal(data, &out))
require.Equal(t, ReactionEmojiThumbsUp, out.Emoji)
}
+104
View File
@@ -32,3 +32,107 @@ const (
UpdateChatBoost UpdateType = "chat_boost"
UpdateRemovedChatBoost UpdateType = "removed_chat_boost"
)
// DiceEmoji is the set of emoji values accepted by sendDice. Telegram's
// canonical list is "🎲", "🎯", "🏀", "⚽", "🎳", "🎰". The codegen
// scraper drops these values during regex extraction (multi-byte
// boundary issues with curly-quoted emoji), so this enum is hand-
// curated and wired into SendDiceParams.Emoji via the per-field type
// override in cmd/genapi/emitter.go.
type DiceEmoji string
const (
DiceEmojiDice DiceEmoji = "🎲"
DiceEmojiDart DiceEmoji = "🎯"
DiceEmojiBasketball DiceEmoji = "🏀"
DiceEmojiFootball DiceEmoji = "⚽"
DiceEmojiBowling DiceEmoji = "🎳"
DiceEmojiSlotMachine DiceEmoji = "🎰"
)
// ReactionEmoji is the set of emoji Telegram allows in a
// ReactionTypeEmoji.Emoji value. Hand-curated from
// https://core.telegram.org/bots/api#reactiontypeemoji because the
// scraper's curly-quote regex strips the emoji literals (byte-boundary
// issue on multi-byte sequences). Names mirror the Unicode CLDR short
// name where one exists; otherwise a stable common-English label.
// Telegram occasionally extends this set — passers of unrecognised
// strings still type-check (ReactionEmoji is a string alias) so this
// list need not block runtime use of newer values.
type ReactionEmoji string
const (
ReactionEmojiHeart ReactionEmoji = "❤"
ReactionEmojiThumbsUp ReactionEmoji = "👍"
ReactionEmojiThumbsDown ReactionEmoji = "👎"
ReactionEmojiFire ReactionEmoji = "🔥"
ReactionEmojiSmilingFaceWithHearts ReactionEmoji = "🥰"
ReactionEmojiClappingHands ReactionEmoji = "👏"
ReactionEmojiBeamingFace ReactionEmoji = "😁"
ReactionEmojiThinkingFace ReactionEmoji = "🤔"
ReactionEmojiExplodingHead ReactionEmoji = "🤯"
ReactionEmojiScreamingFace ReactionEmoji = "😱"
ReactionEmojiCursingFace ReactionEmoji = "🤬"
ReactionEmojiCryingFace ReactionEmoji = "😢"
ReactionEmojiPartyPopper ReactionEmoji = "🎉"
ReactionEmojiStarStruck ReactionEmoji = "🤩"
ReactionEmojiVomiting ReactionEmoji = "🤮"
ReactionEmojiPileOfPoo ReactionEmoji = "💩"
ReactionEmojiFoldedHands ReactionEmoji = "🙏"
ReactionEmojiOKHand ReactionEmoji = "👌"
ReactionEmojiDove ReactionEmoji = "🕊"
ReactionEmojiClown ReactionEmoji = "🤡"
ReactionEmojiYawning ReactionEmoji = "🥱"
ReactionEmojiWoozyFace ReactionEmoji = "🥴"
ReactionEmojiHeartEyes ReactionEmoji = "😍"
ReactionEmojiWhale ReactionEmoji = "🐳"
ReactionEmojiHeartOnFire ReactionEmoji = "❤‍🔥"
ReactionEmojiNewMoonFace ReactionEmoji = "🌚"
ReactionEmojiHotDog ReactionEmoji = "🌭"
ReactionEmojiHundredPoints ReactionEmoji = "💯"
ReactionEmojiRollingOnFloor ReactionEmoji = "🤣"
ReactionEmojiLightning ReactionEmoji = "⚡"
ReactionEmojiBanana ReactionEmoji = "🍌"
ReactionEmojiTrophy ReactionEmoji = "🏆"
ReactionEmojiBrokenHeart ReactionEmoji = "💔"
ReactionEmojiRaisedEyebrow ReactionEmoji = "🤨"
ReactionEmojiNeutralFace ReactionEmoji = "😐"
ReactionEmojiStrawberry ReactionEmoji = "🍓"
ReactionEmojiChampagne ReactionEmoji = "🍾"
ReactionEmojiKissMark ReactionEmoji = "💋"
ReactionEmojiMiddleFinger ReactionEmoji = "🖕"
ReactionEmojiDevil ReactionEmoji = "😈"
ReactionEmojiSleeping ReactionEmoji = "😴"
ReactionEmojiLoudlyCrying ReactionEmoji = "😭"
ReactionEmojiNerd ReactionEmoji = "🤓"
ReactionEmojiGhost ReactionEmoji = "👻"
ReactionEmojiManTechnologist ReactionEmoji = "👨‍💻"
ReactionEmojiEyes ReactionEmoji = "👀"
ReactionEmojiJackOLantern ReactionEmoji = "🎃"
ReactionEmojiSeeNoEvil ReactionEmoji = "🙈"
ReactionEmojiHalo ReactionEmoji = "😇"
ReactionEmojiFearful ReactionEmoji = "😨"
ReactionEmojiHandshake ReactionEmoji = "🤝"
ReactionEmojiWriting ReactionEmoji = "✍"
ReactionEmojiHugging ReactionEmoji = "🤗"
ReactionEmojiSaluting ReactionEmoji = "🫡"
ReactionEmojiSantaClaus ReactionEmoji = "🎅"
ReactionEmojiChristmasTree ReactionEmoji = "🎄"
ReactionEmojiSnowman ReactionEmoji = "☃"
ReactionEmojiNailPolish ReactionEmoji = "💅"
ReactionEmojiZanyFace ReactionEmoji = "🤪"
ReactionEmojiMoai ReactionEmoji = "🗿"
ReactionEmojiCool ReactionEmoji = "🆒"
ReactionEmojiHeartWithArrow ReactionEmoji = "💘"
ReactionEmojiHearNoEvil ReactionEmoji = "🙉"
ReactionEmojiUnicorn ReactionEmoji = "🦄"
ReactionEmojiKissingFace ReactionEmoji = "😘"
ReactionEmojiPill ReactionEmoji = "💊"
ReactionEmojiSpeakNoEvil ReactionEmoji = "🙊"
ReactionEmojiSmilingFaceWithSunglasses ReactionEmoji = "😎"
ReactionEmojiAlienMonster ReactionEmoji = "👾"
ReactionEmojiManShrugging ReactionEmoji = "🤷‍♂"
ReactionEmojiPersonShrugging ReactionEmoji = "🤷"
ReactionEmojiWomanShrugging ReactionEmoji = "🤷‍♀"
ReactionEmojiPoutingFace ReactionEmoji = "😡"
)
+3 -3
View File
@@ -27,7 +27,7 @@ type GetUpdatesParams struct {
// Timeout in seconds for long polling. Defaults to 0, i.e. usual short polling. Should be positive, short polling should be used for testing purposes only.
Timeout *int64 `json:"timeout,omitempty"`
// A JSON-serialized list of the update types you want your bot to receive. For example, specify ["message", "edited_channel_post", "callback_query"] to only receive updates of these types. See Update for a complete list of available update types. Specify an empty list to receive all update types except chat_member, message_reaction, and message_reaction_count (default). If not specified, the previous setting will be used.Please note that this parameter doesn't affect updates created before the call to getUpdates, so unwanted updates may be received for a short period of time.
AllowedUpdates []string `json:"allowed_updates,omitempty"`
AllowedUpdates []UpdateType `json:"allowed_updates,omitempty"`
}
// GetUpdates calls the getUpdates Telegram Bot API method.
@@ -54,7 +54,7 @@ type SetWebhookParams struct {
// The maximum allowed number of simultaneous HTTPS connections to the webhook for update delivery, 1-100. Defaults to 40. Use lower values to limit the load on your bot's server, and higher values to increase your bot's throughput.
MaxConnections *int64 `json:"max_connections,omitempty"`
// A JSON-serialized list of the update types you want your bot to receive. For example, specify ["message", "edited_channel_post", "callback_query"] to only receive updates of these types. See Update for a complete list of available update types. Specify an empty list to receive all update types except chat_member, message_reaction, and message_reaction_count (default). If not specified, the previous setting will be used.Please note that this parameter doesn't affect updates created before the call to the setWebhook, so unwanted updates may be received for a short period of time.
AllowedUpdates []string `json:"allowed_updates,omitempty"`
AllowedUpdates []UpdateType `json:"allowed_updates,omitempty"`
// Pass True to drop all pending updates
DropPendingUpdates *bool `json:"drop_pending_updates,omitempty"`
// A secret token to be sent in a header “X-Telegram-Bot-Api-Secret-Token” in every webhook request, 1-256 characters. Only characters A-Z, a-z, 0-9, _ and - are allowed. The header is useful to ensure that the request comes from a webhook set by you.
@@ -1953,7 +1953,7 @@ type SendDiceParams struct {
// Identifier of the direct messages topic to which the message will be sent; required if the message is sent to a direct messages chat
DirectMessagesTopicID *int64 `json:"direct_messages_topic_id,omitempty"`
// Emoji on which the dice throw animation is based. Currently, must be one of “”, “”, “”, “”, “”, or “”. Dice can have values 1-6 for “”, “” and “”, values 1-5 for “” and “”, and values 1-64 for “”. Defaults to “”
Emoji string `json:"emoji,omitempty"`
Emoji DiceEmoji `json:"emoji,omitempty"`
// Sends the message silently. Users will receive a notification with no sound.
DisableNotification *bool `json:"disable_notification,omitempty"`
// Protects the contents of the sent message from forwarding
+2 -2
View File
@@ -91,7 +91,7 @@ type WebhookInfo struct {
// Optional. The maximum allowed number of simultaneous HTTPS connections to the webhook for update delivery
MaxConnections *int64 `json:"max_connections,omitempty"`
// Optional. A list of update types the bot is subscribed to. Defaults to all update types except chat_member
AllowedUpdates []string `json:"allowed_updates,omitempty"`
AllowedUpdates []UpdateType `json:"allowed_updates,omitempty"`
}
// This object represents a Telegram user or bot.
@@ -3472,7 +3472,7 @@ type ReactionTypeEmoji struct {
// Type of the reaction, always “emoji”
Type ReactionTypeKind `json:"type"`
// Reaction emoji. Currently, it can be one of "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", ""
Emoji string `json:"emoji"`
Emoji ReactionEmoji `json:"emoji"`
}
// MarshalJSON encodes ReactionTypeEmoji with the discriminator field
+71 -3
View File
@@ -46,6 +46,30 @@ var runtimeTypes = map[string]bool{
"MessageOrBool": true,
}
// fieldTypeOverrides maps "<TypeOrParamsName>.<FieldName>" → Go type expression.
// Used for fields whose values are restricted but whose enum the scraper
// can't detect (Telegram's curly-quoted emoji literals are routinely
// stripped by the scraper's regex due to byte-boundary issues with
// multi-byte sequences). The hand-curated typed-string enum lives in
// api/enums.go (manual file); this override just retypes the field so
// callers get IDE completion and compile-time checks. Generated fields
// stay typed even after `make regen`.
var fieldTypeOverrides = map[string]string{
"ReactionTypeEmoji.Emoji": "ReactionEmoji",
"SendDiceParams.Emoji": "DiceEmoji",
}
// fieldTypeOverride returns the override type for a (parent, fieldName)
// pair, or "" if none. parent is the Go type name owning the field —
// either a struct type (e.g. "ReactionTypeEmoji") or a method-params
// type (e.g. "SendDiceParams").
func fieldTypeOverride(parent, fieldName string) string {
if parent == "" {
return ""
}
return fieldTypeOverrides[parent+"."+fieldName]
}
// discriminatorSpec describes how to decode a sealed-interface union by
// peeking at a single JSON field.
type discriminatorSpec struct {
@@ -395,6 +419,9 @@ func funcs(plan *enumPlan) template.FuncMap {
"goField": func(parent string, f spec.Field) string {
return goField(plan, parent, f)
},
"goFieldP": func(methodName string, f spec.Field) string {
return goFieldX(plan, "", title(methodName)+"Params", f)
},
"docComment": docComment,
"isOptional": func(f spec.Field) bool { return !f.Required },
"not": func(b bool) bool { return !b },
@@ -404,6 +431,9 @@ func funcs(plan *enumPlan) template.FuncMap {
"multipartFieldEntry": func(parent string, f spec.Field) string {
return multipartFieldEntry(plan, parent, f)
},
"multipartFieldEntryP": func(methodName string, f spec.Field) string {
return multipartFieldEntryX(plan, "", title(methodName)+"Params", f)
},
"multipartFileEntry": multipartFileEntry,
"returnGoType": returnGoType,
// enum helpers
@@ -503,7 +533,17 @@ func multipartFileEntry(f spec.Field) string {
// when non-zero/non-empty. Typed-string enum fields are cast to string
// before assignment because the multipart map is map[string]string.
func multipartFieldEntry(plan *enumPlan, parent string, f spec.Field) string {
enumName := plan.FieldEnum(parent, f.Name)
return multipartFieldEntryX(plan, parent, parent, f)
}
// multipartFieldEntryX mirrors goFieldX: enumParent keys the enum plan,
// overrideParent keys fieldTypeOverrides. They differ only for method
// params.
func multipartFieldEntryX(plan *enumPlan, enumParent, overrideParent string, f spec.Field) string {
enumName := plan.FieldEnum(enumParent, f.Name)
if enumName == "" {
enumName = fieldTypeOverride(overrideParent, f.Name)
}
switch f.Type.Kind {
case spec.KindPrimitive:
switch f.Type.Name {
@@ -775,12 +815,40 @@ func matchesVariants(got []string, want ...string) bool {
// has a planned enum name for (parent, field), the field's Go type is
// the enum identifier. Typed-string enums use the zero string ""
// behaviour for omitempty, so we do not pointer-wrap optional enum
// fields. Parent is "" for method parameters.
// fields. Parent is "" for method parameters; pass the params type
// name (e.g. "SendDiceParams") via overrideParent when calling from
// the methods template so fieldTypeOverrides can resolve.
func goField(plan *enumPlan, parent string, f spec.Field) string {
return goFieldX(plan, parent, parent, f)
}
// goFieldX is the underlying field-emitter. enumParent is used for the
// enum-plan lookup (which keys method params under ""); overrideParent
// is used for fieldTypeOverrides (which keys method params under the
// params type name). For struct types both are the same; for method
// params they differ.
func goFieldX(plan *enumPlan, enumParent, overrideParent string, f spec.Field) string {
tag := fmt.Sprintf("`json:%q`", f.JSONName+omitempty(f))
if name := plan.FieldEnum(parent, f.Name); name != "" {
if name := plan.FieldEnum(enumParent, f.Name); name != "" {
return fmt.Sprintf("%s %s %s", f.Name, name, tag)
}
if name := fieldTypeOverride(overrideParent, f.Name); name != "" {
return fmt.Sprintf("%s %s %s", f.Name, name, tag)
}
// Pinned companion-enum retype: allowed_updates is an Array of String
// in the upstream spec, but the Go API exposes a hand-curated
// UpdateType (api/enums.go) since the values are not enumerated
// inline by Telegram. Retype []string → []UpdateType wherever the
// wire field is allowed_updates so callers can pass typed constants
// (api.UpdateMessage, ...) without string casts. Wire format is
// unchanged: UpdateType is a typed string, marshals identically.
if f.JSONName == "allowed_updates" &&
f.Type.Kind == spec.KindArray &&
f.Type.ElemType != nil &&
f.Type.ElemType.Kind == spec.KindPrimitive &&
f.Type.ElemType.Name == "string" {
return fmt.Sprintf("%s []UpdateType %s", f.Name, tag)
}
return fmt.Sprintf("%s %s %s", f.Name, goType(f.Type, !f.Required), tag)
}
+3 -3
View File
@@ -15,12 +15,12 @@ import (
var _ = strconv.Itoa // keep import for multipart helpers
var _ = json.Marshal // keep import for complex multipart fields
{{range .Methods}}
{{range .Methods}}{{$methodName := .Name}}
// {{title .Name}}Params is the parameter set for {{title .Name}}.
//
{{docComment .Doc -}}
type {{title .Name}}Params struct {
{{range .Params}}{{docComment .Doc}} {{goField "" .}}
{{range .Params}}{{docComment .Doc}} {{goFieldP $methodName .}}
{{end}}}
{{if .HasFiles}}
// HasFile reports whether a multipart upload is required.
@@ -31,7 +31,7 @@ func (p *{{title .Name}}Params) HasFile() bool {
// MultipartFields returns the non-file fields used in the multipart body.
func (p *{{title .Name}}Params) MultipartFields() map[string]string {
out := map[string]string{}
{{range .Params}}{{if not (isFileField .)}}{{multipartFieldEntry "" .}}{{end}}{{end}} return out
{{range .Params}}{{if not (isFileField .)}}{{multipartFieldEntryP $methodName .}}{{end}}{{end}} return out
}
// MultipartFiles returns the file parts.
+118 -5
View File
@@ -289,6 +289,7 @@ Package api contains the Telegram Bot API object types and method wrappers, gene
- [type DeleteStoryParams](<#DeleteStoryParams>)
- [type DeleteWebhookParams](<#DeleteWebhookParams>)
- [type Dice](<#Dice>)
- [type DiceEmoji](<#DiceEmoji>)
- [type DirectMessagePriceChanged](<#DirectMessagePriceChanged>)
- [type DirectMessagesTopic](<#DirectMessagesTopic>)
- [type Document](<#Document>)
@@ -651,6 +652,7 @@ Package api contains the Telegram Bot API object types and method wrappers, gene
- [type ProximityAlertTriggered](<#ProximityAlertTriggered>)
- [type ReactionCount](<#ReactionCount>)
- [func \(m \*ReactionCount\) UnmarshalJSON\(data \[\]byte\) error](<#ReactionCount.UnmarshalJSON>)
- [type ReactionEmoji](<#ReactionEmoji>)
- [type ReactionType](<#ReactionType>)
- [func UnmarshalReactionType\(data \[\]byte\) \(ReactionType, error\)](<#UnmarshalReactionType>)
- [type ReactionTypeCustomEmoji](<#ReactionTypeCustomEmoji>)
@@ -4884,6 +4886,28 @@ type Dice struct {
}
```
<a name="DiceEmoji"></a>
## type [DiceEmoji](<https://github.com/lukaszraczylo/go-telegram/blob/main/api/enums.go#L42>)
DiceEmoji is the set of emoji values accepted by sendDice. Telegram's canonical list is "🎲", "🎯", "🏀", "⚽", "🎳", "🎰". The codegen scraper drops these values during regex extraction \(multi\-byte boundary issues with curly\-quoted emoji\), so this enum is hand\- curated and wired into SendDiceParams.Emoji via the per\-field type override in cmd/genapi/emitter.go.
```go
type DiceEmoji string
```
<a name="DiceEmojiDice"></a>
```go
const (
DiceEmojiDice DiceEmoji = "🎲"
DiceEmojiDart DiceEmoji = "🎯"
DiceEmojiBasketball DiceEmoji = "🏀"
DiceEmojiFootball DiceEmoji = "⚽"
DiceEmojiBowling DiceEmoji = "🎳"
DiceEmojiSlotMachine DiceEmoji = "🎰"
)
```
<a name="DirectMessagePriceChanged"></a>
## type [DirectMessagePriceChanged](<https://github.com/lukaszraczylo/go-telegram/blob/main/api/types.gen.go#L2179-L2184>)
@@ -6096,7 +6120,7 @@ type GetUpdatesParams struct {
// Timeout in seconds for long polling. Defaults to 0, i.e. usual short polling. Should be positive, short polling should be used for testing purposes only.
Timeout *int64 `json:"timeout,omitempty"`
// A JSON-serialized list of the update types you want your bot to receive. For example, specify ["message", "edited_channel_post", "callback_query"] to only receive updates of these types. See Update for a complete list of available update types. Specify an empty list to receive all update types except chat_member, message_reaction, and message_reaction_count (default). If not specified, the previous setting will be used.Please note that this parameter doesn't affect updates created before the call to getUpdates, so unwanted updates may be received for a short period of time.
AllowedUpdates []string `json:"allowed_updates,omitempty"`
AllowedUpdates []UpdateType `json:"allowed_updates,omitempty"`
}
```
@@ -11289,6 +11313,95 @@ func (m *ReactionCount) UnmarshalJSON(data []byte) error
UnmarshalJSON decodes ReactionCount by dispatching union\-typed fields \(Type\) through their concrete UnmarshalXxx helpers.
<a name="ReactionEmoji"></a>
## type [ReactionEmoji](<https://github.com/lukaszraczylo/go-telegram/blob/main/api/enums.go#L62>)
ReactionEmoji is the set of emoji Telegram allows in a ReactionTypeEmoji.Emoji value. Hand\-curated from https://core.telegram.org/bots/api#reactiontypeemoji because the scraper's curly\-quote regex strips the emoji literals \(byte\-boundary issue on multi\-byte sequences\). Names mirror the Unicode CLDR short name where one exists; otherwise a stable common\-English label. Telegram occasionally extends this set — passers of unrecognised strings still type\-check \(ReactionEmoji is a string alias\) so this list need not block runtime use of newer values.
```go
type ReactionEmoji string
```
<a name="ReactionEmojiHeart"></a>
```go
const (
ReactionEmojiHeart ReactionEmoji = "❤"
ReactionEmojiThumbsUp ReactionEmoji = "👍"
ReactionEmojiThumbsDown ReactionEmoji = "👎"
ReactionEmojiFire ReactionEmoji = "🔥"
ReactionEmojiSmilingFaceWithHearts ReactionEmoji = "🥰"
ReactionEmojiClappingHands ReactionEmoji = "👏"
ReactionEmojiBeamingFace ReactionEmoji = "😁"
ReactionEmojiThinkingFace ReactionEmoji = "🤔"
ReactionEmojiExplodingHead ReactionEmoji = "🤯"
ReactionEmojiScreamingFace ReactionEmoji = "😱"
ReactionEmojiCursingFace ReactionEmoji = "🤬"
ReactionEmojiCryingFace ReactionEmoji = "😢"
ReactionEmojiPartyPopper ReactionEmoji = "🎉"
ReactionEmojiStarStruck ReactionEmoji = "🤩"
ReactionEmojiVomiting ReactionEmoji = "🤮"
ReactionEmojiPileOfPoo ReactionEmoji = "💩"
ReactionEmojiFoldedHands ReactionEmoji = "🙏"
ReactionEmojiOKHand ReactionEmoji = "👌"
ReactionEmojiDove ReactionEmoji = "🕊"
ReactionEmojiClown ReactionEmoji = "🤡"
ReactionEmojiYawning ReactionEmoji = "🥱"
ReactionEmojiWoozyFace ReactionEmoji = "🥴"
ReactionEmojiHeartEyes ReactionEmoji = "😍"
ReactionEmojiWhale ReactionEmoji = "🐳"
ReactionEmojiHeartOnFire ReactionEmoji = "❤‍🔥"
ReactionEmojiNewMoonFace ReactionEmoji = "🌚"
ReactionEmojiHotDog ReactionEmoji = "🌭"
ReactionEmojiHundredPoints ReactionEmoji = "💯"
ReactionEmojiRollingOnFloor ReactionEmoji = "🤣"
ReactionEmojiLightning ReactionEmoji = "⚡"
ReactionEmojiBanana ReactionEmoji = "🍌"
ReactionEmojiTrophy ReactionEmoji = "🏆"
ReactionEmojiBrokenHeart ReactionEmoji = "💔"
ReactionEmojiRaisedEyebrow ReactionEmoji = "🤨"
ReactionEmojiNeutralFace ReactionEmoji = "😐"
ReactionEmojiStrawberry ReactionEmoji = "🍓"
ReactionEmojiChampagne ReactionEmoji = "🍾"
ReactionEmojiKissMark ReactionEmoji = "💋"
ReactionEmojiMiddleFinger ReactionEmoji = "🖕"
ReactionEmojiDevil ReactionEmoji = "😈"
ReactionEmojiSleeping ReactionEmoji = "😴"
ReactionEmojiLoudlyCrying ReactionEmoji = "😭"
ReactionEmojiNerd ReactionEmoji = "🤓"
ReactionEmojiGhost ReactionEmoji = "👻"
ReactionEmojiManTechnologist ReactionEmoji = "👨‍💻"
ReactionEmojiEyes ReactionEmoji = "👀"
ReactionEmojiJackOLantern ReactionEmoji = "🎃"
ReactionEmojiSeeNoEvil ReactionEmoji = "🙈"
ReactionEmojiHalo ReactionEmoji = "😇"
ReactionEmojiFearful ReactionEmoji = "😨"
ReactionEmojiHandshake ReactionEmoji = "🤝"
ReactionEmojiWriting ReactionEmoji = "✍"
ReactionEmojiHugging ReactionEmoji = "🤗"
ReactionEmojiSaluting ReactionEmoji = "🫡"
ReactionEmojiSantaClaus ReactionEmoji = "🎅"
ReactionEmojiChristmasTree ReactionEmoji = "🎄"
ReactionEmojiSnowman ReactionEmoji = "☃"
ReactionEmojiNailPolish ReactionEmoji = "💅"
ReactionEmojiZanyFace ReactionEmoji = "🤪"
ReactionEmojiMoai ReactionEmoji = "🗿"
ReactionEmojiCool ReactionEmoji = "🆒"
ReactionEmojiHeartWithArrow ReactionEmoji = "💘"
ReactionEmojiHearNoEvil ReactionEmoji = "🙉"
ReactionEmojiUnicorn ReactionEmoji = "🦄"
ReactionEmojiKissingFace ReactionEmoji = "😘"
ReactionEmojiPill ReactionEmoji = "💊"
ReactionEmojiSpeakNoEvil ReactionEmoji = "🙊"
ReactionEmojiSmilingFaceWithSunglasses ReactionEmoji = "😎"
ReactionEmojiAlienMonster ReactionEmoji = "👾"
ReactionEmojiManShrugging ReactionEmoji = "🤷‍♂"
ReactionEmojiPersonShrugging ReactionEmoji = "🤷"
ReactionEmojiWomanShrugging ReactionEmoji = "🤷‍♀"
ReactionEmojiPoutingFace ReactionEmoji = "😡"
)
```
<a name="ReactionType"></a>
## type [ReactionType](<https://github.com/lukaszraczylo/go-telegram/blob/main/api/types.gen.go#L3433>)
@@ -11348,7 +11461,7 @@ type ReactionTypeEmoji struct {
// Type of the reaction, always “emoji”
Type ReactionTypeKind `json:"type"`
// Reaction emoji. Currently, it can be one of "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", ""
Emoji string `json:"emoji"`
Emoji ReactionEmoji `json:"emoji"`
}
```
@@ -12150,7 +12263,7 @@ type SendDiceParams struct {
// Identifier of the direct messages topic to which the message will be sent; required if the message is sent to a direct messages chat
DirectMessagesTopicID *int64 `json:"direct_messages_topic_id,omitempty"`
// Emoji on which the dice throw animation is based. Currently, must be one of “”, “”, “”, “”, “”, or “”. Dice can have values 1-6 for “”, “” and “”, values 1-5 for “” and “”, and values 1-64 for “”. Defaults to “”
Emoji string `json:"emoji,omitempty"`
Emoji DiceEmoji `json:"emoji,omitempty"`
// Sends the message silently. Users will receive a notification with no sound.
DisableNotification *bool `json:"disable_notification,omitempty"`
// Protects the contents of the sent message from forwarding
@@ -13887,7 +14000,7 @@ type SetWebhookParams struct {
// The maximum allowed number of simultaneous HTTPS connections to the webhook for update delivery, 1-100. Defaults to 40. Use lower values to limit the load on your bot's server, and higher values to increase your bot's throughput.
MaxConnections *int64 `json:"max_connections,omitempty"`
// A JSON-serialized list of the update types you want your bot to receive. For example, specify ["message", "edited_channel_post", "callback_query"] to only receive updates of these types. See Update for a complete list of available update types. Specify an empty list to receive all update types except chat_member, message_reaction, and message_reaction_count (default). If not specified, the previous setting will be used.Please note that this parameter doesn't affect updates created before the call to the setWebhook, so unwanted updates may be received for a short period of time.
AllowedUpdates []string `json:"allowed_updates,omitempty"`
AllowedUpdates []UpdateType `json:"allowed_updates,omitempty"`
// Pass True to drop all pending updates
DropPendingUpdates *bool `json:"drop_pending_updates,omitempty"`
// A secret token to be sent in a header “X-Telegram-Bot-Api-Secret-Token” in every webhook request, 1-256 characters. Only characters A-Z, a-z, 0-9, _ and - are allowed. The header is useful to ensure that the request comes from a webhook set by you.
@@ -15953,7 +16066,7 @@ type WebhookInfo struct {
// Optional. The maximum allowed number of simultaneous HTTPS connections to the webhook for update delivery
MaxConnections *int64 `json:"max_connections,omitempty"`
// Optional. A list of update types the bot is subscribed to. Defaults to all update types except chat_member
AllowedUpdates []string `json:"allowed_updates,omitempty"`
AllowedUpdates []UpdateType `json:"allowed_updates,omitempty"`
}
```
+1 -1
View File
@@ -113,7 +113,7 @@ func (p *LongPoller) Run(ctx context.Context) error
Run implements Updater. It blocks until ctx is cancelled, Stop is called, or a fatal error occurs \(e.g. unauthorized\). See LongPoller for at\-least\-once delivery semantics on shutdown.
<a name="LongPoller.Stop"></a>
### func \(\*LongPoller\) [Stop](<https://github.com/lukaszraczylo/go-telegram/blob/main/transport/longpoll.go#L126>)
### func \(\*LongPoller\) [Stop](<https://github.com/lukaszraczylo/go-telegram/blob/main/transport/longpoll.go#L122>)
```go
func (p *LongPoller) Stop(ctx context.Context) error
+1 -5
View File
@@ -72,11 +72,7 @@ func (p *LongPoller) Run(ctx context.Context) error {
params.Timeout = &to
}
if len(p.AllowedTypes) > 0 {
allowed := make([]string, len(p.AllowedTypes))
for i, t := range p.AllowedTypes {
allowed[i] = string(t)
}
params.AllowedUpdates = allowed
params.AllowedUpdates = p.AllowedTypes
}
ups, err := api.GetUpdates(ctx, p.Bot, params)
if err != nil {