wappa 0.1.0__py3-none-any.whl

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.

Potentially problematic release.


This version of wappa might be problematic. Click here for more details.

Files changed (211) hide show
  1. wappa/__init__.py +85 -0
  2. wappa/api/__init__.py +1 -0
  3. wappa/api/controllers/__init__.py +10 -0
  4. wappa/api/controllers/webhook_controller.py +441 -0
  5. wappa/api/dependencies/__init__.py +15 -0
  6. wappa/api/dependencies/whatsapp_dependencies.py +220 -0
  7. wappa/api/dependencies/whatsapp_media_dependencies.py +26 -0
  8. wappa/api/middleware/__init__.py +7 -0
  9. wappa/api/middleware/error_handler.py +158 -0
  10. wappa/api/middleware/owner.py +99 -0
  11. wappa/api/middleware/request_logging.py +184 -0
  12. wappa/api/routes/__init__.py +6 -0
  13. wappa/api/routes/health.py +102 -0
  14. wappa/api/routes/webhooks.py +211 -0
  15. wappa/api/routes/whatsapp/__init__.py +15 -0
  16. wappa/api/routes/whatsapp/whatsapp_interactive.py +429 -0
  17. wappa/api/routes/whatsapp/whatsapp_media.py +440 -0
  18. wappa/api/routes/whatsapp/whatsapp_messages.py +195 -0
  19. wappa/api/routes/whatsapp/whatsapp_specialized.py +516 -0
  20. wappa/api/routes/whatsapp/whatsapp_templates.py +431 -0
  21. wappa/api/routes/whatsapp_combined.py +35 -0
  22. wappa/cli/__init__.py +9 -0
  23. wappa/cli/main.py +199 -0
  24. wappa/core/__init__.py +6 -0
  25. wappa/core/config/__init__.py +5 -0
  26. wappa/core/config/settings.py +161 -0
  27. wappa/core/events/__init__.py +41 -0
  28. wappa/core/events/default_handlers.py +642 -0
  29. wappa/core/events/event_dispatcher.py +244 -0
  30. wappa/core/events/event_handler.py +247 -0
  31. wappa/core/events/webhook_factory.py +219 -0
  32. wappa/core/factory/__init__.py +15 -0
  33. wappa/core/factory/plugin.py +68 -0
  34. wappa/core/factory/wappa_builder.py +326 -0
  35. wappa/core/logging/__init__.py +5 -0
  36. wappa/core/logging/context.py +100 -0
  37. wappa/core/logging/logger.py +343 -0
  38. wappa/core/plugins/__init__.py +34 -0
  39. wappa/core/plugins/auth_plugin.py +169 -0
  40. wappa/core/plugins/cors_plugin.py +128 -0
  41. wappa/core/plugins/custom_middleware_plugin.py +182 -0
  42. wappa/core/plugins/database_plugin.py +235 -0
  43. wappa/core/plugins/rate_limit_plugin.py +183 -0
  44. wappa/core/plugins/redis_plugin.py +224 -0
  45. wappa/core/plugins/wappa_core_plugin.py +261 -0
  46. wappa/core/plugins/webhook_plugin.py +253 -0
  47. wappa/core/types.py +108 -0
  48. wappa/core/wappa_app.py +546 -0
  49. wappa/database/__init__.py +18 -0
  50. wappa/database/adapter.py +107 -0
  51. wappa/database/adapters/__init__.py +17 -0
  52. wappa/database/adapters/mysql_adapter.py +187 -0
  53. wappa/database/adapters/postgresql_adapter.py +169 -0
  54. wappa/database/adapters/sqlite_adapter.py +174 -0
  55. wappa/domain/__init__.py +28 -0
  56. wappa/domain/builders/__init__.py +5 -0
  57. wappa/domain/builders/message_builder.py +189 -0
  58. wappa/domain/entities/__init__.py +5 -0
  59. wappa/domain/enums/messenger_platform.py +123 -0
  60. wappa/domain/factories/__init__.py +6 -0
  61. wappa/domain/factories/media_factory.py +450 -0
  62. wappa/domain/factories/message_factory.py +497 -0
  63. wappa/domain/factories/messenger_factory.py +244 -0
  64. wappa/domain/interfaces/__init__.py +32 -0
  65. wappa/domain/interfaces/base_repository.py +94 -0
  66. wappa/domain/interfaces/cache_factory.py +85 -0
  67. wappa/domain/interfaces/cache_interface.py +199 -0
  68. wappa/domain/interfaces/expiry_repository.py +68 -0
  69. wappa/domain/interfaces/media_interface.py +311 -0
  70. wappa/domain/interfaces/messaging_interface.py +523 -0
  71. wappa/domain/interfaces/pubsub_repository.py +151 -0
  72. wappa/domain/interfaces/repository_factory.py +108 -0
  73. wappa/domain/interfaces/shared_state_repository.py +122 -0
  74. wappa/domain/interfaces/state_repository.py +123 -0
  75. wappa/domain/interfaces/tables_repository.py +215 -0
  76. wappa/domain/interfaces/user_repository.py +114 -0
  77. wappa/domain/interfaces/webhooks/__init__.py +1 -0
  78. wappa/domain/models/media_result.py +110 -0
  79. wappa/domain/models/platforms/__init__.py +15 -0
  80. wappa/domain/models/platforms/platform_config.py +104 -0
  81. wappa/domain/services/__init__.py +11 -0
  82. wappa/domain/services/tenant_credentials_service.py +56 -0
  83. wappa/messaging/__init__.py +7 -0
  84. wappa/messaging/whatsapp/__init__.py +1 -0
  85. wappa/messaging/whatsapp/client/__init__.py +5 -0
  86. wappa/messaging/whatsapp/client/whatsapp_client.py +417 -0
  87. wappa/messaging/whatsapp/handlers/__init__.py +13 -0
  88. wappa/messaging/whatsapp/handlers/whatsapp_interactive_handler.py +653 -0
  89. wappa/messaging/whatsapp/handlers/whatsapp_media_handler.py +579 -0
  90. wappa/messaging/whatsapp/handlers/whatsapp_specialized_handler.py +434 -0
  91. wappa/messaging/whatsapp/handlers/whatsapp_template_handler.py +416 -0
  92. wappa/messaging/whatsapp/messenger/__init__.py +5 -0
  93. wappa/messaging/whatsapp/messenger/whatsapp_messenger.py +904 -0
  94. wappa/messaging/whatsapp/models/__init__.py +61 -0
  95. wappa/messaging/whatsapp/models/basic_models.py +65 -0
  96. wappa/messaging/whatsapp/models/interactive_models.py +287 -0
  97. wappa/messaging/whatsapp/models/media_models.py +215 -0
  98. wappa/messaging/whatsapp/models/specialized_models.py +304 -0
  99. wappa/messaging/whatsapp/models/template_models.py +261 -0
  100. wappa/persistence/cache_factory.py +93 -0
  101. wappa/persistence/json/__init__.py +14 -0
  102. wappa/persistence/json/cache_adapters.py +271 -0
  103. wappa/persistence/json/handlers/__init__.py +1 -0
  104. wappa/persistence/json/handlers/state_handler.py +250 -0
  105. wappa/persistence/json/handlers/table_handler.py +263 -0
  106. wappa/persistence/json/handlers/user_handler.py +213 -0
  107. wappa/persistence/json/handlers/utils/__init__.py +1 -0
  108. wappa/persistence/json/handlers/utils/file_manager.py +153 -0
  109. wappa/persistence/json/handlers/utils/key_factory.py +11 -0
  110. wappa/persistence/json/handlers/utils/serialization.py +121 -0
  111. wappa/persistence/json/json_cache_factory.py +76 -0
  112. wappa/persistence/json/storage_manager.py +285 -0
  113. wappa/persistence/memory/__init__.py +14 -0
  114. wappa/persistence/memory/cache_adapters.py +271 -0
  115. wappa/persistence/memory/handlers/__init__.py +1 -0
  116. wappa/persistence/memory/handlers/state_handler.py +250 -0
  117. wappa/persistence/memory/handlers/table_handler.py +280 -0
  118. wappa/persistence/memory/handlers/user_handler.py +213 -0
  119. wappa/persistence/memory/handlers/utils/__init__.py +1 -0
  120. wappa/persistence/memory/handlers/utils/key_factory.py +11 -0
  121. wappa/persistence/memory/handlers/utils/memory_store.py +317 -0
  122. wappa/persistence/memory/handlers/utils/ttl_manager.py +235 -0
  123. wappa/persistence/memory/memory_cache_factory.py +76 -0
  124. wappa/persistence/memory/storage_manager.py +235 -0
  125. wappa/persistence/redis/README.md +699 -0
  126. wappa/persistence/redis/__init__.py +11 -0
  127. wappa/persistence/redis/cache_adapters.py +285 -0
  128. wappa/persistence/redis/ops.py +880 -0
  129. wappa/persistence/redis/redis_cache_factory.py +71 -0
  130. wappa/persistence/redis/redis_client.py +231 -0
  131. wappa/persistence/redis/redis_handler/__init__.py +26 -0
  132. wappa/persistence/redis/redis_handler/state_handler.py +176 -0
  133. wappa/persistence/redis/redis_handler/table.py +158 -0
  134. wappa/persistence/redis/redis_handler/user.py +138 -0
  135. wappa/persistence/redis/redis_handler/utils/__init__.py +12 -0
  136. wappa/persistence/redis/redis_handler/utils/key_factory.py +32 -0
  137. wappa/persistence/redis/redis_handler/utils/serde.py +146 -0
  138. wappa/persistence/redis/redis_handler/utils/tenant_cache.py +268 -0
  139. wappa/persistence/redis/redis_manager.py +189 -0
  140. wappa/processors/__init__.py +6 -0
  141. wappa/processors/base_processor.py +262 -0
  142. wappa/processors/factory.py +550 -0
  143. wappa/processors/whatsapp_processor.py +810 -0
  144. wappa/schemas/__init__.py +6 -0
  145. wappa/schemas/core/__init__.py +71 -0
  146. wappa/schemas/core/base_message.py +499 -0
  147. wappa/schemas/core/base_status.py +322 -0
  148. wappa/schemas/core/base_webhook.py +312 -0
  149. wappa/schemas/core/types.py +253 -0
  150. wappa/schemas/core/webhook_interfaces/__init__.py +48 -0
  151. wappa/schemas/core/webhook_interfaces/base_components.py +293 -0
  152. wappa/schemas/core/webhook_interfaces/universal_webhooks.py +348 -0
  153. wappa/schemas/factory.py +754 -0
  154. wappa/schemas/webhooks/__init__.py +3 -0
  155. wappa/schemas/whatsapp/__init__.py +6 -0
  156. wappa/schemas/whatsapp/base_models.py +285 -0
  157. wappa/schemas/whatsapp/message_types/__init__.py +93 -0
  158. wappa/schemas/whatsapp/message_types/audio.py +350 -0
  159. wappa/schemas/whatsapp/message_types/button.py +267 -0
  160. wappa/schemas/whatsapp/message_types/contact.py +464 -0
  161. wappa/schemas/whatsapp/message_types/document.py +421 -0
  162. wappa/schemas/whatsapp/message_types/errors.py +195 -0
  163. wappa/schemas/whatsapp/message_types/image.py +424 -0
  164. wappa/schemas/whatsapp/message_types/interactive.py +430 -0
  165. wappa/schemas/whatsapp/message_types/location.py +416 -0
  166. wappa/schemas/whatsapp/message_types/order.py +372 -0
  167. wappa/schemas/whatsapp/message_types/reaction.py +271 -0
  168. wappa/schemas/whatsapp/message_types/sticker.py +328 -0
  169. wappa/schemas/whatsapp/message_types/system.py +317 -0
  170. wappa/schemas/whatsapp/message_types/text.py +411 -0
  171. wappa/schemas/whatsapp/message_types/unsupported.py +273 -0
  172. wappa/schemas/whatsapp/message_types/video.py +344 -0
  173. wappa/schemas/whatsapp/status_models.py +479 -0
  174. wappa/schemas/whatsapp/validators.py +454 -0
  175. wappa/schemas/whatsapp/webhook_container.py +438 -0
  176. wappa/webhooks/__init__.py +17 -0
  177. wappa/webhooks/core/__init__.py +71 -0
  178. wappa/webhooks/core/base_message.py +499 -0
  179. wappa/webhooks/core/base_status.py +322 -0
  180. wappa/webhooks/core/base_webhook.py +312 -0
  181. wappa/webhooks/core/types.py +253 -0
  182. wappa/webhooks/core/webhook_interfaces/__init__.py +48 -0
  183. wappa/webhooks/core/webhook_interfaces/base_components.py +293 -0
  184. wappa/webhooks/core/webhook_interfaces/universal_webhooks.py +441 -0
  185. wappa/webhooks/factory.py +754 -0
  186. wappa/webhooks/whatsapp/__init__.py +6 -0
  187. wappa/webhooks/whatsapp/base_models.py +285 -0
  188. wappa/webhooks/whatsapp/message_types/__init__.py +93 -0
  189. wappa/webhooks/whatsapp/message_types/audio.py +350 -0
  190. wappa/webhooks/whatsapp/message_types/button.py +267 -0
  191. wappa/webhooks/whatsapp/message_types/contact.py +464 -0
  192. wappa/webhooks/whatsapp/message_types/document.py +421 -0
  193. wappa/webhooks/whatsapp/message_types/errors.py +195 -0
  194. wappa/webhooks/whatsapp/message_types/image.py +424 -0
  195. wappa/webhooks/whatsapp/message_types/interactive.py +430 -0
  196. wappa/webhooks/whatsapp/message_types/location.py +416 -0
  197. wappa/webhooks/whatsapp/message_types/order.py +372 -0
  198. wappa/webhooks/whatsapp/message_types/reaction.py +271 -0
  199. wappa/webhooks/whatsapp/message_types/sticker.py +328 -0
  200. wappa/webhooks/whatsapp/message_types/system.py +317 -0
  201. wappa/webhooks/whatsapp/message_types/text.py +411 -0
  202. wappa/webhooks/whatsapp/message_types/unsupported.py +273 -0
  203. wappa/webhooks/whatsapp/message_types/video.py +344 -0
  204. wappa/webhooks/whatsapp/status_models.py +479 -0
  205. wappa/webhooks/whatsapp/validators.py +454 -0
  206. wappa/webhooks/whatsapp/webhook_container.py +438 -0
  207. wappa-0.1.0.dist-info/METADATA +269 -0
  208. wappa-0.1.0.dist-info/RECORD +211 -0
  209. wappa-0.1.0.dist-info/WHEEL +4 -0
  210. wappa-0.1.0.dist-info/entry_points.txt +2 -0
  211. wappa-0.1.0.dist-info/licenses/LICENSE +201 -0
@@ -0,0 +1,68 @@
1
+ """
2
+ Expiry repository interface.
3
+
4
+ Defines contract for TTL-based workflow management in Redis.
5
+ """
6
+
7
+ from abc import abstractmethod
8
+ from datetime import timedelta
9
+
10
+ from .base_repository import IBaseRepository
11
+
12
+
13
+ class IExpiryRepository(IBaseRepository):
14
+ """
15
+ Interface for TTL-based workflow management.
16
+
17
+ Handles expiry triggers and time-based automation with context binding.
18
+ Uses the 'expiry' Redis pool (database 8).
19
+
20
+ This interface mirrors the RedisTrigger implementation:
21
+ - create_expiry_trigger(action, identifier, ttl) -> set(action, identifier, ttl_seconds)
22
+ - delete_expiry_trigger(action, identifier) -> delete(action, identifier)
23
+ - delete_all_expiry_triggers_by_id(identifier) -> delete_all_by_identifier(identifier)
24
+ """
25
+
26
+ @abstractmethod
27
+ async def create_expiry_trigger(
28
+ self, action: str, identifier: str, ttl: timedelta
29
+ ) -> str:
30
+ """
31
+ Create expiry trigger for automated workflow.
32
+
33
+ Args:
34
+ action: Action name to trigger when expired (e.g., "reservation_reminder")
35
+ identifier: Unique identifier for this trigger (e.g., transaction_ref)
36
+ ttl: Time until trigger fires
37
+
38
+ Returns:
39
+ Trigger key identifier
40
+ """
41
+ pass
42
+
43
+ @abstractmethod
44
+ async def delete_expiry_trigger(self, action: str, identifier: str) -> bool:
45
+ """
46
+ Delete specific expiry trigger.
47
+
48
+ Args:
49
+ action: Action name of the trigger
50
+ identifier: Unique identifier of the trigger
51
+
52
+ Returns:
53
+ True if trigger was deleted
54
+ """
55
+ pass
56
+
57
+ @abstractmethod
58
+ async def delete_all_expiry_triggers_by_id(self, identifier: str) -> bool:
59
+ """
60
+ Delete all expiry triggers for a specific identifier.
61
+
62
+ Args:
63
+ identifier: Unique identifier to delete all triggers for
64
+
65
+ Returns:
66
+ True if triggers were deleted
67
+ """
68
+ pass
@@ -0,0 +1,311 @@
1
+ """
2
+ Media handling interface for platform-agnostic media operations.
3
+
4
+ This interface defines the contract for media handling operations that can be
5
+ implemented across different messaging platforms (WhatsApp, Telegram, Teams, etc.).
6
+
7
+ Based on existing WhatsAppServiceMedia implementation from handle_media.py
8
+ and WhatsApp Cloud API 2025 specifications for the 4 core endpoints:
9
+ - POST /PHONE_NUMBER_ID/media (upload)
10
+ - GET /MEDIA_ID (get info/URL)
11
+ - DELETE /MEDIA_ID (delete)
12
+ - GET /MEDIA_URL (download)
13
+ """
14
+
15
+ from abc import ABC, abstractmethod
16
+ from collections.abc import AsyncIterator
17
+ from pathlib import Path
18
+ from typing import BinaryIO
19
+
20
+ from wappa.domain.models.media_result import (
21
+ MediaDeleteResult,
22
+ MediaDownloadResult,
23
+ MediaInfoResult,
24
+ MediaUploadResult,
25
+ )
26
+ from wappa.schemas.core.types import PlatformType
27
+
28
+
29
+ class IMediaHandler(ABC):
30
+ """
31
+ Platform-agnostic media handling interface.
32
+
33
+ Provides consistent media operations across different messaging platforms
34
+ while abstracting platform-specific implementations.
35
+
36
+ Based on existing WhatsAppServiceMedia methods:
37
+ - upload_media() -> upload_media()
38
+ - get_media_url() -> get_media_info()
39
+ - download_media() -> download_media()
40
+ - delete_media() -> delete_media()
41
+ """
42
+
43
+ @property
44
+ @abstractmethod
45
+ def platform(self) -> PlatformType:
46
+ """Get the platform this handler manages."""
47
+ pass
48
+
49
+ @property
50
+ @abstractmethod
51
+ def tenant_id(self) -> str:
52
+ """Get the tenant ID this handler serves.
53
+
54
+ Note: In WhatsApp context, this is the phone_number_id.
55
+ Different platforms may use different tenant identifiers.
56
+ """
57
+ pass
58
+
59
+ @property
60
+ @abstractmethod
61
+ def supported_media_types(self) -> set[str]:
62
+ """Get supported MIME types for this platform.
63
+
64
+ Returns:
65
+ Set of supported MIME type strings
66
+ """
67
+ pass
68
+
69
+ @property
70
+ @abstractmethod
71
+ def max_file_size(self) -> dict[str, int]:
72
+ """Get maximum file sizes in bytes by media category.
73
+
74
+ Returns:
75
+ Dictionary mapping media categories to max sizes in bytes
76
+ Example: {"image": 5242880, "video": 16777216, "audio": 16777216, "document": 104857600}
77
+ """
78
+ pass
79
+
80
+ # Upload Operations (POST /PHONE_NUMBER_ID/media)
81
+ @abstractmethod
82
+ async def upload_media(
83
+ self,
84
+ file_path: str | Path,
85
+ media_type: str | None = None,
86
+ filename: str | None = None,
87
+ ) -> MediaUploadResult:
88
+ """
89
+ Upload media file to platform.
90
+
91
+ Based on existing WhatsAppServiceMedia.upload_media() method.
92
+ Implements POST /PHONE_NUMBER_ID/media endpoint.
93
+
94
+ Args:
95
+ file_path: Path to the file to upload
96
+ media_type: MIME type (auto-detected if None)
97
+ filename: Original filename (extracted from path if None)
98
+
99
+ Returns:
100
+ MediaUploadResult with upload status and media ID
101
+
102
+ Raises:
103
+ FileNotFoundError: If file doesn't exist
104
+ ValueError: If MIME type unsupported or file too large
105
+ Platform-specific exceptions for API failures
106
+ """
107
+ pass
108
+
109
+ @abstractmethod
110
+ async def upload_media_from_bytes(
111
+ self, file_data: bytes, media_type: str, filename: str
112
+ ) -> MediaUploadResult:
113
+ """
114
+ Upload media from bytes data.
115
+
116
+ Extension of existing upload functionality for in-memory files.
117
+ Implements POST /PHONE_NUMBER_ID/media endpoint.
118
+
119
+ Args:
120
+ file_data: Binary file data
121
+ media_type: MIME type of the data
122
+ filename: Filename for the upload
123
+
124
+ Returns:
125
+ MediaUploadResult with upload status and media ID
126
+
127
+ Raises:
128
+ ValueError: If MIME type unsupported or file too large
129
+ Platform-specific exceptions for API failures
130
+ """
131
+ pass
132
+
133
+ @abstractmethod
134
+ async def upload_media_from_stream(
135
+ self,
136
+ file_stream: BinaryIO,
137
+ media_type: str,
138
+ filename: str,
139
+ file_size: int | None = None,
140
+ ) -> MediaUploadResult:
141
+ """
142
+ Upload media from file stream.
143
+
144
+ Extension of existing upload functionality for streaming uploads.
145
+ Implements POST /PHONE_NUMBER_ID/media endpoint.
146
+
147
+ Args:
148
+ file_stream: Binary file stream
149
+ media_type: MIME type of the data
150
+ filename: Filename for the upload
151
+ file_size: Size of the file (for progress tracking)
152
+
153
+ Returns:
154
+ MediaUploadResult with upload status and media ID
155
+
156
+ Raises:
157
+ ValueError: If MIME type unsupported or file too large
158
+ Platform-specific exceptions for API failures
159
+ """
160
+ pass
161
+
162
+ # Retrieval Operations (GET /MEDIA_ID)
163
+ @abstractmethod
164
+ async def get_media_info(self, media_id: str) -> MediaInfoResult:
165
+ """
166
+ Get media information by ID.
167
+
168
+ Based on existing WhatsAppServiceMedia.get_media_url() method.
169
+ Implements GET /MEDIA_ID endpoint.
170
+
171
+ WhatsApp API Response:
172
+ {
173
+ "messaging_product": "whatsapp",
174
+ "url": "<URL>",
175
+ "mime_type": "<MIME_TYPE>",
176
+ "sha256": "<HASH>",
177
+ "file_size": "<FILE_SIZE>",
178
+ "id": "<MEDIA_ID>"
179
+ }
180
+
181
+ Args:
182
+ media_id: Platform-specific media identifier
183
+
184
+ Returns:
185
+ MediaInfoResult with media info or error details
186
+
187
+ Note:
188
+ URLs expire after 5 minutes in WhatsApp Cloud API.
189
+ Call this method again if URL expires.
190
+ """
191
+ pass
192
+
193
+ # Download Operations (GET /MEDIA_URL)
194
+ @abstractmethod
195
+ async def download_media(
196
+ self,
197
+ media_id: str,
198
+ destination_path: str | Path | None = None,
199
+ sender_id: str | None = None,
200
+ ) -> MediaDownloadResult:
201
+ """
202
+ Download media by ID.
203
+
204
+ Based on existing WhatsAppServiceMedia.download_media() method.
205
+ Implements workflow: GET /MEDIA_ID -> GET /MEDIA_URL
206
+
207
+ Args:
208
+ media_id: Platform-specific media identifier
209
+ destination_path: Optional path to save file
210
+ sender_id: Optional sender ID for filename generation
211
+
212
+ Returns:
213
+ MediaDownloadResult with file data and metadata
214
+
215
+ Note:
216
+ If destination_path provided, saves file to disk.
217
+ If not provided, returns file data in memory.
218
+ Handles URL expiration by re-fetching URL if needed.
219
+ """
220
+ pass
221
+
222
+ @abstractmethod
223
+ async def stream_media(
224
+ self, media_id: str, chunk_size: int = 8192
225
+ ) -> AsyncIterator[bytes]:
226
+ """
227
+ Stream media by ID for large files.
228
+
229
+ Extension of download functionality for memory-efficient streaming.
230
+ Implements workflow: GET /MEDIA_ID -> GET /MEDIA_URL with streaming.
231
+
232
+ Args:
233
+ media_id: Platform-specific media identifier
234
+ chunk_size: Size of chunks to yield
235
+
236
+ Yields:
237
+ Bytes chunks of the media file
238
+
239
+ Raises:
240
+ Platform-specific exceptions for API failures or URL expiration
241
+ """
242
+ pass
243
+
244
+ # Delete Operations (DELETE /MEDIA_ID)
245
+ @abstractmethod
246
+ async def delete_media(self, media_id: str) -> MediaDeleteResult:
247
+ """
248
+ Delete media by ID.
249
+
250
+ Based on existing WhatsAppServiceMedia.delete_media() method.
251
+ Implements DELETE /MEDIA_ID endpoint.
252
+
253
+ WhatsApp API Response:
254
+ {
255
+ "success": true
256
+ }
257
+
258
+ Args:
259
+ media_id: Platform-specific media identifier to delete
260
+
261
+ Returns:
262
+ MediaDeleteResult with deletion status
263
+
264
+ Note:
265
+ Media files persist for 30 days unless deleted earlier.
266
+ Deletion is permanent and cannot be undone.
267
+ """
268
+ pass
269
+
270
+ # Validation Operations
271
+ @abstractmethod
272
+ def validate_media_type(self, mime_type: str) -> bool:
273
+ """
274
+ Validate if MIME type is supported by platform.
275
+
276
+ Args:
277
+ mime_type: MIME type to validate
278
+
279
+ Returns:
280
+ True if supported, False otherwise
281
+ """
282
+ pass
283
+
284
+ @abstractmethod
285
+ def validate_file_size(self, file_size: int, mime_type: str) -> bool:
286
+ """
287
+ Validate if file size is within platform limits.
288
+
289
+ Args:
290
+ file_size: File size in bytes
291
+ mime_type: MIME type of the file
292
+
293
+ Returns:
294
+ True if within limits, False otherwise
295
+ """
296
+ pass
297
+
298
+ @abstractmethod
299
+ def get_media_limits(self) -> dict[str, any]:
300
+ """
301
+ Get platform-specific media limits and constraints.
302
+
303
+ Returns:
304
+ Dictionary containing platform-specific limits
305
+ Example: {
306
+ "max_sizes": {"image": 5242880, "video": 16777216},
307
+ "supported_types": ["image/jpeg", "video/mp4"],
308
+ "url_expiry_minutes": 5
309
+ }
310
+ """
311
+ pass