aiogram-webhook 1.0.0__tar.gz → 2.0.0__tar.gz

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.
Files changed (53) hide show
  1. {aiogram_webhook-1.0.0 → aiogram_webhook-2.0.0}/PKG-INFO +55 -33
  2. {aiogram_webhook-1.0.0 → aiogram_webhook-2.0.0}/README.md +37 -16
  3. {aiogram_webhook-1.0.0 → aiogram_webhook-2.0.0}/pyproject.toml +10 -64
  4. aiogram_webhook-2.0.0/src/aiogram_webhook/__init__.py +21 -0
  5. aiogram_webhook-1.0.0/aiogram_webhook/adapters/aiohttp.py → aiogram_webhook-2.0.0/src/aiogram_webhook/adapters/aiohttp/adapter.py +25 -20
  6. aiogram_webhook-2.0.0/src/aiogram_webhook/adapters/aiohttp/mapping.py +15 -0
  7. aiogram_webhook-2.0.0/src/aiogram_webhook/adapters/base_adapter.py +86 -0
  8. aiogram_webhook-2.0.0/src/aiogram_webhook/adapters/base_mapping.py +38 -0
  9. aiogram_webhook-2.0.0/src/aiogram_webhook/adapters/fastapi/adapter.py +49 -0
  10. aiogram_webhook-2.0.0/src/aiogram_webhook/adapters/fastapi/mapping.py +15 -0
  11. aiogram_webhook-2.0.0/src/aiogram_webhook/config/__init__.py +0 -0
  12. aiogram_webhook-2.0.0/src/aiogram_webhook/config/bot.py +12 -0
  13. aiogram_webhook-2.0.0/src/aiogram_webhook/config/webhook.py +19 -0
  14. {aiogram_webhook-1.0.0 → aiogram_webhook-2.0.0/src}/aiogram_webhook/engines/base.py +43 -28
  15. aiogram_webhook-2.0.0/src/aiogram_webhook/engines/simple.py +101 -0
  16. aiogram_webhook-2.0.0/src/aiogram_webhook/engines/token.py +126 -0
  17. {aiogram_webhook-1.0.0 → aiogram_webhook-2.0.0/src}/aiogram_webhook/routing/base.py +3 -3
  18. {aiogram_webhook-1.0.0 → aiogram_webhook-2.0.0/src}/aiogram_webhook/routing/path.py +2 -2
  19. {aiogram_webhook-1.0.0 → aiogram_webhook-2.0.0/src}/aiogram_webhook/routing/query.py +1 -1
  20. {aiogram_webhook-1.0.0 → aiogram_webhook-2.0.0/src}/aiogram_webhook/security/__init__.py +2 -2
  21. aiogram_webhook-2.0.0/src/aiogram_webhook/security/checks/__init__.py +0 -0
  22. aiogram_webhook-2.0.0/src/aiogram_webhook/security/checks/check.py +17 -0
  23. aiogram_webhook-2.0.0/src/aiogram_webhook/security/checks/ip.py +83 -0
  24. {aiogram_webhook-1.0.0 → aiogram_webhook-2.0.0/src}/aiogram_webhook/security/secret_token.py +17 -5
  25. {aiogram_webhook-1.0.0 → aiogram_webhook-2.0.0/src}/aiogram_webhook/security/security.py +14 -8
  26. aiogram_webhook-1.0.0/.github/dependabot.yml +0 -11
  27. aiogram_webhook-1.0.0/.github/workflows/release.yml +0 -54
  28. aiogram_webhook-1.0.0/.github/workflows/tests.yml +0 -39
  29. aiogram_webhook-1.0.0/.gitignore +0 -207
  30. aiogram_webhook-1.0.0/CHANGELOG.md +0 -145
  31. aiogram_webhook-1.0.0/CONTRIBUTING.md +0 -78
  32. aiogram_webhook-1.0.0/LICENSE +0 -21
  33. aiogram_webhook-1.0.0/aiogram_webhook/__init__.py +0 -20
  34. aiogram_webhook-1.0.0/aiogram_webhook/adapters/base.py +0 -75
  35. aiogram_webhook-1.0.0/aiogram_webhook/adapters/fastapi.py +0 -43
  36. aiogram_webhook-1.0.0/aiogram_webhook/engines/simple.py +0 -91
  37. aiogram_webhook-1.0.0/aiogram_webhook/engines/token.py +0 -118
  38. aiogram_webhook-1.0.0/aiogram_webhook/security/checks/check.py +0 -14
  39. aiogram_webhook-1.0.0/aiogram_webhook/security/checks/ip.py +0 -89
  40. aiogram_webhook-1.0.0/tests/conftest.py +0 -14
  41. aiogram_webhook-1.0.0/tests/fixtures/__init__.py +0 -4
  42. aiogram_webhook-1.0.0/tests/fixtures/fixtures_bound_request.py +0 -39
  43. aiogram_webhook-1.0.0/tests/fixtures/fixtures_checks.py +0 -22
  44. aiogram_webhook-1.0.0/tests/test_ip_check.py +0 -202
  45. aiogram_webhook-1.0.0/tests/test_routing.py +0 -157
  46. aiogram_webhook-1.0.0/tests/test_secret_token.py +0 -49
  47. aiogram_webhook-1.0.0/tests/test_security.py +0 -77
  48. {aiogram_webhook-1.0.0 → aiogram_webhook-2.0.0/src}/aiogram_webhook/adapters/__init__.py +0 -0
  49. {aiogram_webhook-1.0.0/aiogram_webhook/security/checks → aiogram_webhook-2.0.0/src/aiogram_webhook/adapters/aiohttp}/__init__.py +0 -0
  50. {aiogram_webhook-1.0.0/tests → aiogram_webhook-2.0.0/src/aiogram_webhook/adapters/fastapi}/__init__.py +0 -0
  51. {aiogram_webhook-1.0.0 → aiogram_webhook-2.0.0/src}/aiogram_webhook/engines/__init__.py +0 -0
  52. {aiogram_webhook-1.0.0 → aiogram_webhook-2.0.0/src}/aiogram_webhook/routing/__init__.py +0 -0
  53. {aiogram_webhook-1.0.0 → aiogram_webhook-2.0.0/src}/aiogram_webhook/routing/static.py +0 -0
@@ -1,35 +1,36 @@
1
- Metadata-Version: 2.4
1
+ Metadata-Version: 2.3
2
2
  Name: aiogram-webhook
3
- Version: 1.0.0
3
+ Version: 2.0.0
4
4
  Summary: A python library for integrating webhook support with multiple web frameworks in aiogram. Organizes bot operation via webhooks for both single and multi-bot setups.
5
- Project-URL: Homepage, https://github.com/m-xim/aiogram-webhook
6
- Project-URL: Repository, https://github.com/m-xim/aiogram-webhook
7
- Project-URL: Issues, https://github.com/m-xim/aiogram-webhook/issues
8
- Project-URL: Documentation, https://github.com/m-xim/aiogram-webhook#readme
5
+ Keywords: aiogram,telegram,webhook,fastapi,aiohttp,multibot
6
+ Author: m-xim
9
7
  Author-email: m-xim <i@m-xim.ru>
10
8
  License: MIT
11
- License-File: LICENSE
12
- Keywords: aiogram,aiohttp,fastapi,multibot,telegram,webhook
13
- Classifier: Operating System :: OS Independent
14
9
  Classifier: Programming Language :: Python :: 3
15
10
  Classifier: Programming Language :: Python :: 3.10
16
11
  Classifier: Programming Language :: Python :: 3.11
17
12
  Classifier: Programming Language :: Python :: 3.12
18
13
  Classifier: Programming Language :: Python :: 3.13
14
+ Classifier: Programming Language :: Python :: 3.14
19
15
  Classifier: Topic :: Software Development :: Libraries
20
- Requires-Python: >=3.10
16
+ Classifier: Operating System :: OS Independent
21
17
  Requires-Dist: aiogram>=3.14.0
22
18
  Requires-Dist: yarl>=1.17.0
19
+ Requires-Dist: aiohttp>=3.9.0 ; extra == 'aiohttp'
20
+ Requires-Dist: ruff ; extra == 'dev'
21
+ Requires-Dist: ty ; extra == 'dev'
22
+ Requires-Dist: pytest ; extra == 'dev'
23
+ Requires-Dist: pytest-asyncio ; extra == 'dev'
24
+ Requires-Dist: httpx ; extra == 'dev'
25
+ Requires-Dist: fastapi>=0.128.0 ; extra == 'fastapi'
26
+ Requires-Python: >=3.10
27
+ Project-URL: Homepage, https://github.com/m-xim/aiogram-webhook
28
+ Project-URL: Repository, https://github.com/m-xim/aiogram-webhook
29
+ Project-URL: Issues, https://github.com/m-xim/aiogram-webhook/issues
30
+ Project-URL: Documentation, https://github.com/m-xim/aiogram-webhook#readme
23
31
  Provides-Extra: aiohttp
24
- Requires-Dist: aiohttp>=3.9.0; extra == 'aiohttp'
25
32
  Provides-Extra: dev
26
- Requires-Dist: httpx; extra == 'dev'
27
- Requires-Dist: pytest; extra == 'dev'
28
- Requires-Dist: pytest-asyncio; extra == 'dev'
29
- Requires-Dist: ruff; extra == 'dev'
30
- Requires-Dist: ty; extra == 'dev'
31
33
  Provides-Extra: fastapi
32
- Requires-Dist: fastapi>=0.128.0; extra == 'fastapi'
33
34
  Description-Content-Type: text/markdown
34
35
 
35
36
  # aiogram-webhook
@@ -74,38 +75,43 @@ from fastapi import FastAPI
74
75
  from aiogram import Bot, Dispatcher, Router
75
76
  from aiogram.filters import CommandStart
76
77
  from aiogram.types import Message
77
- from aiogram_webhook import SimpleEngine, FastApiWebAdapter
78
+ from aiogram_webhook import SimpleEngine, FastApiWebAdapter, WebhookConfig
78
79
  from aiogram_webhook.routing import StaticRouting
79
80
 
80
81
  router = Router()
81
82
 
83
+
82
84
  @router.message(CommandStart())
83
85
  async def start(message: Message):
84
86
  await message.answer("OK")
85
87
 
88
+
86
89
  dispatcher = Dispatcher()
87
90
  dispatcher.include_router(router)
88
91
  bot = Bot("BOT_TOKEN")
89
92
 
90
- engine = SimpleEngine( # or other engine
93
+
94
+ engine = SimpleEngine(
91
95
  dispatcher,
92
96
  bot,
93
97
  web_adapter=FastApiWebAdapter(),
94
98
  routing=StaticRouting(url="https://example.com/webhook"),
99
+ webhook_config=WebhookConfig(allowed_updates=["message", "callback_query"], drop_pending_updates=True),
95
100
  # security=Security(...)
96
101
  )
97
102
 
103
+
98
104
  @asynccontextmanager
99
105
  async def lifespan(app: FastAPI):
100
106
  engine.register(app)
101
- await engine.set_webhook(
102
- drop_pending_updates=True,
103
- allowed_updates=("message", "callback_query"),
104
- )
107
+ await engine.set_webhook() # Uses webhook_config defaults
108
+ # Or override specific params:
109
+ # await engine.set_webhook(max_connections=100)
105
110
  await engine.on_startup(app)
106
111
  yield
107
112
  await engine.on_shutdown(app)
108
113
 
114
+
109
115
  app = FastAPI(lifespan=lifespan)
110
116
  ```
111
117
 
@@ -114,29 +120,33 @@ app = FastAPI(lifespan=lifespan)
114
120
  from aiogram import Bot, Dispatcher, Router
115
121
  from aiogram.filters import CommandStart
116
122
  from aiogram.types import Message
117
- from aiogram_webhook import SimpleEngine, AiohttpWebAdapter
123
+ from aiogram_webhook import SimpleEngine, AiohttpWebAdapter, WebhookConfig
118
124
  from aiogram_webhook.routing import StaticRouting
119
125
  from aiohttp import web
120
126
 
121
127
  router = Router()
122
128
 
129
+
123
130
  @router.message(CommandStart())
124
131
  async def start(message: Message):
125
132
  await message.answer("OK")
126
133
 
127
- async def on_startup(bot: Bot, webhook_engine:SimpleEngine) -> None:
134
+
135
+ async def on_startup(bot: Bot, webhook_engine: SimpleEngine) -> None:
128
136
  await webhook_engine.set_webhook()
129
137
 
138
+
130
139
  dispatcher = Dispatcher()
131
140
  dispatcher.include_router(router)
132
141
  dispatcher.startup.register(on_startup)
133
142
  bot = Bot("BOT_TOKEN")
134
143
 
135
- engine = SimpleEngine( # or other engine
144
+ engine = SimpleEngine(
136
145
  dispatcher,
137
146
  bot,
138
147
  web_adapter=AiohttpWebAdapter(),
139
148
  routing=StaticRouting(url="https://example.com/webhook"),
149
+ webhook_config=WebhookConfig(allowed_updates=["message", "callback_query"]),
140
150
  # security=Security(...)
141
151
  )
142
152
  app = web.Application()
@@ -155,21 +165,23 @@ Used for serving a single Telegram bot. Suitable for most standard scenarios whe
155
165
 
156
166
  - Connects aiogram `Dispatcher` and `Bot` to the selected web framework (FastAPI, aiohttp, etc.)
157
167
  - Handles webhook requests for a single bot
158
- - Requires explicit dispatcher, bot, web_adapter, and routing (security is optional)
168
+ - Requires explicit dispatcher, bot, web_adapter, and routing (security and webhook_config are optional)
159
169
 
160
170
  **Example:**
161
171
  ```python
162
172
  from aiogram import Bot, Dispatcher
163
- from aiogram_webhook import SimpleEngine, FastApiWebAdapter
173
+ from aiogram_webhook import SimpleEngine, FastApiWebAdapter, WebhookConfig
164
174
  from aiogram_webhook.routing import StaticRouting
165
175
 
166
176
  bot = Bot("BOT_TOKEN")
167
177
  dispatcher = Dispatcher()
178
+
168
179
  engine = SimpleEngine(
169
180
  dispatcher,
170
181
  bot,
171
182
  web_adapter=FastApiWebAdapter(),
172
183
  routing=StaticRouting(url="https://example.com/webhook"),
184
+ webhook_config=WebhookConfig(allowed_updates=["message", "callback_query"], drop_pending_updates=True),
173
185
  # security=Security(...)
174
186
  )
175
187
  ```
@@ -180,7 +192,7 @@ Allows you to serve multiple Telegram bots in a single application. Useful if yo
180
192
 
181
193
  - Allows serving multiple bots via a single endpoint
182
194
  - Uses the bot token for request routing
183
- - Requires dispatcher, web_adapter, routing, bot_settings (a dict with bot settings), security (optional)
195
+ - Requires dispatcher, web_adapter, routing, bot_settings (optional), webhook_config (optional), and security (optional)
184
196
 
185
197
  **Example:**
186
198
 
@@ -189,11 +201,12 @@ from aiogram import Dispatcher, Router
189
201
  from aiogram.client.default import DefaultBotProperties
190
202
  from aiogram.types import Message
191
203
  from aiogram.filters import Command, CommandObject
192
- from aiogram_webhook import TokenEngine, FastApiWebAdapter
204
+ from aiogram_webhook import TokenEngine, FastApiWebAdapter, WebhookConfig, BotConfig
193
205
  from aiogram_webhook.routing import PathRouting
194
206
 
195
207
  router = Router()
196
208
 
209
+
197
210
  @router.message(Command("addbot"))
198
211
  async def add_bot_handler(message: Message, command: CommandObject, webhook_engine: TokenEngine):
199
212
  token = command.args
@@ -203,14 +216,17 @@ async def add_bot_handler(message: Message, command: CommandObject, webhook_engi
203
216
  new_bot = await webhook_engine.set_webhook(token)
204
217
  await message.answer(f"Bot #{new_bot.id} started!")
205
218
 
219
+
206
220
  dispatcher = Dispatcher()
207
221
  dispatcher.include_router(router)
208
222
 
223
+
209
224
  engine = TokenEngine(
210
225
  dispatcher,
211
226
  web_adapter=FastApiWebAdapter(),
212
227
  routing=PathRouting(url="https://example.com/webhook/{bot_token}"),
213
- bot_settings={"default": DefaultBotProperties(parse_mode="HTML")},
228
+ bot_config=BotConfig(default=DefaultBotProperties(parse_mode="HTML")),
229
+ webhook_config=WebhookConfig(allowed_updates=["message", "callback_query"]),
214
230
  # security=Security(...)
215
231
  )
216
232
  ```
@@ -302,6 +318,12 @@ See [routing examples](/src/aiogram_webhook/routing) for implementation details.
302
318
 
303
319
  ---
304
320
 
321
+ ## ⚙️ Webhook Configuration
322
+
323
+ `WebhookConfig` allows you to set default parameters for the Telegram [`setWebhook`](https://core.telegram.org/bots/api#setwebhook) API call. All parameters are optional and can be overridden when calling `engine.set_webhook()`.
324
+
325
+ ---
326
+
305
327
  ## 🛡️ Security
306
328
 
307
329
  aiogram-webhook provides a flexible and extensible security system for processing webhook requests. You can use built-in mechanisms, combine them, or implement your own checks.
@@ -310,8 +332,8 @@ aiogram-webhook provides a flexible and extensible security system for processin
310
332
  from aiogram_webhook.security import Security, StaticSecretToken, IPCheck
311
333
 
312
334
  security = Security(
313
- IPCheck(), # and other checks...
314
- secret_token=StaticSecretToken("YOUR_SECRET_TOKEN")
335
+ IPCheck(), # and other checks...
336
+ secret_token=StaticSecretToken("YOUR_SECRET_TOKEN"),
315
337
  )
316
338
  ```
317
339
 
@@ -40,38 +40,43 @@ from fastapi import FastAPI
40
40
  from aiogram import Bot, Dispatcher, Router
41
41
  from aiogram.filters import CommandStart
42
42
  from aiogram.types import Message
43
- from aiogram_webhook import SimpleEngine, FastApiWebAdapter
43
+ from aiogram_webhook import SimpleEngine, FastApiWebAdapter, WebhookConfig
44
44
  from aiogram_webhook.routing import StaticRouting
45
45
 
46
46
  router = Router()
47
47
 
48
+
48
49
  @router.message(CommandStart())
49
50
  async def start(message: Message):
50
51
  await message.answer("OK")
51
52
 
53
+
52
54
  dispatcher = Dispatcher()
53
55
  dispatcher.include_router(router)
54
56
  bot = Bot("BOT_TOKEN")
55
57
 
56
- engine = SimpleEngine( # or other engine
58
+
59
+ engine = SimpleEngine(
57
60
  dispatcher,
58
61
  bot,
59
62
  web_adapter=FastApiWebAdapter(),
60
63
  routing=StaticRouting(url="https://example.com/webhook"),
64
+ webhook_config=WebhookConfig(allowed_updates=["message", "callback_query"], drop_pending_updates=True),
61
65
  # security=Security(...)
62
66
  )
63
67
 
68
+
64
69
  @asynccontextmanager
65
70
  async def lifespan(app: FastAPI):
66
71
  engine.register(app)
67
- await engine.set_webhook(
68
- drop_pending_updates=True,
69
- allowed_updates=("message", "callback_query"),
70
- )
72
+ await engine.set_webhook() # Uses webhook_config defaults
73
+ # Or override specific params:
74
+ # await engine.set_webhook(max_connections=100)
71
75
  await engine.on_startup(app)
72
76
  yield
73
77
  await engine.on_shutdown(app)
74
78
 
79
+
75
80
  app = FastAPI(lifespan=lifespan)
76
81
  ```
77
82
 
@@ -80,29 +85,33 @@ app = FastAPI(lifespan=lifespan)
80
85
  from aiogram import Bot, Dispatcher, Router
81
86
  from aiogram.filters import CommandStart
82
87
  from aiogram.types import Message
83
- from aiogram_webhook import SimpleEngine, AiohttpWebAdapter
88
+ from aiogram_webhook import SimpleEngine, AiohttpWebAdapter, WebhookConfig
84
89
  from aiogram_webhook.routing import StaticRouting
85
90
  from aiohttp import web
86
91
 
87
92
  router = Router()
88
93
 
94
+
89
95
  @router.message(CommandStart())
90
96
  async def start(message: Message):
91
97
  await message.answer("OK")
92
98
 
93
- async def on_startup(bot: Bot, webhook_engine:SimpleEngine) -> None:
99
+
100
+ async def on_startup(bot: Bot, webhook_engine: SimpleEngine) -> None:
94
101
  await webhook_engine.set_webhook()
95
102
 
103
+
96
104
  dispatcher = Dispatcher()
97
105
  dispatcher.include_router(router)
98
106
  dispatcher.startup.register(on_startup)
99
107
  bot = Bot("BOT_TOKEN")
100
108
 
101
- engine = SimpleEngine( # or other engine
109
+ engine = SimpleEngine(
102
110
  dispatcher,
103
111
  bot,
104
112
  web_adapter=AiohttpWebAdapter(),
105
113
  routing=StaticRouting(url="https://example.com/webhook"),
114
+ webhook_config=WebhookConfig(allowed_updates=["message", "callback_query"]),
106
115
  # security=Security(...)
107
116
  )
108
117
  app = web.Application()
@@ -121,21 +130,23 @@ Used for serving a single Telegram bot. Suitable for most standard scenarios whe
121
130
 
122
131
  - Connects aiogram `Dispatcher` and `Bot` to the selected web framework (FastAPI, aiohttp, etc.)
123
132
  - Handles webhook requests for a single bot
124
- - Requires explicit dispatcher, bot, web_adapter, and routing (security is optional)
133
+ - Requires explicit dispatcher, bot, web_adapter, and routing (security and webhook_config are optional)
125
134
 
126
135
  **Example:**
127
136
  ```python
128
137
  from aiogram import Bot, Dispatcher
129
- from aiogram_webhook import SimpleEngine, FastApiWebAdapter
138
+ from aiogram_webhook import SimpleEngine, FastApiWebAdapter, WebhookConfig
130
139
  from aiogram_webhook.routing import StaticRouting
131
140
 
132
141
  bot = Bot("BOT_TOKEN")
133
142
  dispatcher = Dispatcher()
143
+
134
144
  engine = SimpleEngine(
135
145
  dispatcher,
136
146
  bot,
137
147
  web_adapter=FastApiWebAdapter(),
138
148
  routing=StaticRouting(url="https://example.com/webhook"),
149
+ webhook_config=WebhookConfig(allowed_updates=["message", "callback_query"], drop_pending_updates=True),
139
150
  # security=Security(...)
140
151
  )
141
152
  ```
@@ -146,7 +157,7 @@ Allows you to serve multiple Telegram bots in a single application. Useful if yo
146
157
 
147
158
  - Allows serving multiple bots via a single endpoint
148
159
  - Uses the bot token for request routing
149
- - Requires dispatcher, web_adapter, routing, bot_settings (a dict with bot settings), security (optional)
160
+ - Requires dispatcher, web_adapter, routing, bot_settings (optional), webhook_config (optional), and security (optional)
150
161
 
151
162
  **Example:**
152
163
 
@@ -155,11 +166,12 @@ from aiogram import Dispatcher, Router
155
166
  from aiogram.client.default import DefaultBotProperties
156
167
  from aiogram.types import Message
157
168
  from aiogram.filters import Command, CommandObject
158
- from aiogram_webhook import TokenEngine, FastApiWebAdapter
169
+ from aiogram_webhook import TokenEngine, FastApiWebAdapter, WebhookConfig, BotConfig
159
170
  from aiogram_webhook.routing import PathRouting
160
171
 
161
172
  router = Router()
162
173
 
174
+
163
175
  @router.message(Command("addbot"))
164
176
  async def add_bot_handler(message: Message, command: CommandObject, webhook_engine: TokenEngine):
165
177
  token = command.args
@@ -169,14 +181,17 @@ async def add_bot_handler(message: Message, command: CommandObject, webhook_engi
169
181
  new_bot = await webhook_engine.set_webhook(token)
170
182
  await message.answer(f"Bot #{new_bot.id} started!")
171
183
 
184
+
172
185
  dispatcher = Dispatcher()
173
186
  dispatcher.include_router(router)
174
187
 
188
+
175
189
  engine = TokenEngine(
176
190
  dispatcher,
177
191
  web_adapter=FastApiWebAdapter(),
178
192
  routing=PathRouting(url="https://example.com/webhook/{bot_token}"),
179
- bot_settings={"default": DefaultBotProperties(parse_mode="HTML")},
193
+ bot_config=BotConfig(default=DefaultBotProperties(parse_mode="HTML")),
194
+ webhook_config=WebhookConfig(allowed_updates=["message", "callback_query"]),
180
195
  # security=Security(...)
181
196
  )
182
197
  ```
@@ -268,6 +283,12 @@ See [routing examples](/src/aiogram_webhook/routing) for implementation details.
268
283
 
269
284
  ---
270
285
 
286
+ ## ⚙️ Webhook Configuration
287
+
288
+ `WebhookConfig` allows you to set default parameters for the Telegram [`setWebhook`](https://core.telegram.org/bots/api#setwebhook) API call. All parameters are optional and can be overridden when calling `engine.set_webhook()`.
289
+
290
+ ---
291
+
271
292
  ## 🛡️ Security
272
293
 
273
294
  aiogram-webhook provides a flexible and extensible security system for processing webhook requests. You can use built-in mechanisms, combine them, or implement your own checks.
@@ -276,8 +297,8 @@ aiogram-webhook provides a flexible and extensible security system for processin
276
297
  from aiogram_webhook.security import Security, StaticSecretToken, IPCheck
277
298
 
278
299
  security = Security(
279
- IPCheck(), # and other checks...
280
- secret_token=StaticSecretToken("YOUR_SECRET_TOKEN")
300
+ IPCheck(), # and other checks...
301
+ secret_token=StaticSecretToken("YOUR_SECRET_TOKEN"),
281
302
  )
282
303
  ```
283
304
 
@@ -1,14 +1,11 @@
1
1
  [project]
2
2
  name = "aiogram-webhook"
3
- version = "1.0.0"
3
+ version = "2.0.0"
4
4
  description = "A python library for integrating webhook support with multiple web frameworks in aiogram. Organizes bot operation via webhooks for both single and multi-bot setups."
5
5
  readme = "README.md"
6
6
  license = { text = "MIT" }
7
- authors = [
8
- { name = "m-xim", email = "i@m-xim.ru" },
9
- ]
7
+ authors = [{ name = "m-xim", email = "i@m-xim.ru" }]
10
8
  requires-python = ">=3.10"
11
- packages = [{ include = "aiogram_webhook" }]
12
9
  dependencies = [
13
10
  "aiogram>=3.14.0",
14
11
  "yarl>=1.17.0",
@@ -28,6 +25,7 @@ classifiers = [
28
25
  "Programming Language :: Python :: 3.11",
29
26
  "Programming Language :: Python :: 3.12",
30
27
  "Programming Language :: Python :: 3.13",
28
+ "Programming Language :: Python :: 3.14",
31
29
  "Topic :: Software Development :: Libraries",
32
30
  "Operating System :: OS Independent",
33
31
  ]
@@ -54,11 +52,12 @@ dev = [
54
52
  ]
55
53
 
56
54
  [build-system]
57
- requires = ["hatchling"]
58
- build-backend = "hatchling.build"
55
+ requires = ["uv_build"]
56
+ build-backend = "uv_build"
57
+
58
+ [tool.uv]
59
+ package = true
59
60
 
60
- [tool.hatch.build]
61
- sources = ["src"]
62
61
 
63
62
  [tool.semantic_release]
64
63
  version_source = "pyproject"
@@ -70,59 +69,6 @@ version_toml = [
70
69
  [tool.semantic_release.branches.main]
71
70
  match = "main"
72
71
 
73
- [tool.semantic_release.branches.dev]
74
- match = "dev"
72
+ [tool.semantic_release.branches.develop]
73
+ match = "develop"
75
74
  prerelease = true
76
-
77
- [tool.ruff]
78
- line-length = 120
79
- exclude = [".venv", "__pycache__"]
80
-
81
- [tool.ruff.format]
82
- skip-magic-trailing-comma = false
83
-
84
- [tool.ruff.lint]
85
- select = ["ALL"]
86
- ignore = [
87
- "D",
88
- "ANN",
89
- "PLR09",
90
- "COM812",
91
-
92
- "ERA001",
93
- "T201",
94
- "RUF059",
95
- "BLE001",
96
- "RUF001",
97
- "RUF003",
98
-
99
- "TRY003",
100
- "EM101",
101
-
102
- "RUF002",
103
- "EM102",
104
-
105
- "FBT001",
106
- "FBT002",
107
- "TD002",
108
- "FIX002",
109
-
110
- "TD003",
111
- "PLR2004",
112
- "N806",
113
- "E501",
114
- "N815"
115
- ]
116
-
117
- [tool.ruff.lint.flake8-tidy-imports]
118
- ban-relative-imports = "all"
119
-
120
- [tool.ruff.lint.per-file-ignores]
121
- "tests/**/*" = [
122
- "PLR2004",
123
- "S101",
124
- "TID252",
125
- "S106",
126
- "S105",
127
- "ARG002"
128
- ]
@@ -0,0 +1,21 @@
1
+ from aiogram_webhook.config.bot import BotConfig
2
+ from aiogram_webhook.config.webhook import WebhookConfig
3
+ from aiogram_webhook.engines.simple import SimpleEngine
4
+ from aiogram_webhook.engines.token import TokenEngine
5
+
6
+ __all__ = ["BotConfig", "SimpleEngine", "TokenEngine", "WebhookConfig"]
7
+
8
+
9
+ try:
10
+ from aiogram_webhook.adapters.aiohttp.adapter import AiohttpWebAdapter # noqa: F401
11
+
12
+ __all__.insert(0, "AiohttpWebAdapter")
13
+ except ImportError:
14
+ pass
15
+
16
+ try:
17
+ from aiogram_webhook.adapters.fastapi.adapter import FastApiWebAdapter # noqa: F401
18
+
19
+ __all__.insert(1, "FastApiWebAdapter")
20
+ except ImportError:
21
+ pass
@@ -1,44 +1,46 @@
1
- from ipaddress import IPv4Address, IPv6Address
2
1
  from typing import TYPE_CHECKING, Any, cast
3
2
 
4
3
  from aiohttp.web import Application, Request
5
4
  from aiohttp.web_response import Response, json_response
6
5
 
7
- from aiogram_webhook.adapters.base import BoundRequest, WebAdapter
6
+ from aiogram_webhook.adapters.aiohttp.mapping import AiohttpHeadersMapping, AiohttpQueryMapping
7
+ from aiogram_webhook.adapters.base_adapter import BoundRequest, WebAdapter
8
8
 
9
9
  if TYPE_CHECKING:
10
10
  from asyncio import Transport
11
11
 
12
12
 
13
- class AiohttpBoundRequest(BoundRequest):
14
- adapter: "AiohttpWebAdapter"
15
- request: Request
13
+ class AiohttpBoundRequest(BoundRequest[Request]):
14
+ def __init__(self, request: Request):
15
+ super().__init__(request)
16
+ self._headers = AiohttpHeadersMapping(self.request.headers)
17
+ self._query_params = AiohttpQueryMapping(self.request.query)
16
18
 
17
- async def json(self) -> dict[str, Any]:
19
+ async def json(self):
18
20
  return await self.request.json()
19
21
 
20
- def header(self, name: str) -> Any | None:
21
- return self.request.headers.get(name)
22
-
23
- def query_param(self, name: str) -> Any | None:
24
- return self.request.query.get(name)
25
-
26
- def path_param(self, name: str) -> Any | None:
27
- return self.request.match_info.get(name)
28
-
29
- def ip(self) -> IPv4Address | IPv6Address | str | None:
22
+ @property
23
+ def client_ip(self):
30
24
  if peer_name := cast("Transport", self.request.transport).get_extra_info("peername"):
31
25
  return peer_name[0]
32
-
33
26
  return None
34
27
 
35
- def json_response(self, status: int, payload: dict[str, Any]) -> Response:
36
- return json_response(status=status, data=payload)
28
+ @property
29
+ def headers(self) -> AiohttpHeadersMapping:
30
+ return self._headers
31
+
32
+ @property
33
+ def query_params(self) -> AiohttpQueryMapping:
34
+ return self._query_params
35
+
36
+ @property
37
+ def path_params(self):
38
+ return self.request.match_info
37
39
 
38
40
 
39
41
  class AiohttpWebAdapter(WebAdapter):
40
42
  def bind(self, request: Request) -> AiohttpBoundRequest:
41
- return AiohttpBoundRequest(adapter=self, request=request)
43
+ return AiohttpBoundRequest(request=request)
42
44
 
43
45
  def register(self, app: Application, path, handler, on_startup=None, on_shutdown=None) -> None:
44
46
  async def endpoint(request: Request):
@@ -49,3 +51,6 @@ class AiohttpWebAdapter(WebAdapter):
49
51
  app.on_startup.append(on_startup)
50
52
  if on_shutdown is not None:
51
53
  app.on_shutdown.append(on_shutdown)
54
+
55
+ def create_json_response(self, status: int, payload: dict[str, Any]) -> Response:
56
+ return json_response(status=status, data=payload)
@@ -0,0 +1,15 @@
1
+ from typing import Any
2
+
3
+ from multidict import CIMultiDictProxy, MultiMapping
4
+
5
+ from aiogram_webhook.adapters.base_mapping import MappingABC
6
+
7
+
8
+ class AiohttpHeadersMapping(MappingABC[CIMultiDictProxy[str]]):
9
+ def getlist(self, name: str) -> list[Any]:
10
+ return self._mapping.getall(name, [])
11
+
12
+
13
+ class AiohttpQueryMapping(MappingABC[MultiMapping[str]]):
14
+ def getlist(self, name: str) -> list[Any]:
15
+ return self._mapping.getall(name, [])