tempest-fastapi-sdk 0.82.1__tar.gz → 0.87.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 (475) hide show
  1. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/CHANGELOG.md +96 -0
  2. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/CLAUDE.md +66 -24
  3. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/PKG-INFO +7 -2
  4. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/README.md +3 -1
  5. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/admin.en.md +110 -3
  6. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/admin.md +108 -3
  7. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/auth-flow.en.md +117 -0
  8. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/auth-flow.md +116 -0
  9. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/index.en.md +1 -0
  10. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/index.md +1 -0
  11. tempest_fastapi_sdk-0.87.0/docs/recipes/vision.en.md +128 -0
  12. tempest_fastapi_sdk-0.87.0/docs/recipes/vision.md +127 -0
  13. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/reference.md +18 -0
  14. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/mkdocs.yml +1 -0
  15. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/pyproject.toml +18 -1
  16. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/__init__.py +17 -1
  17. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/admin/__init__.py +8 -0
  18. tempest_fastapi_sdk-0.87.0/tempest_fastapi_sdk/admin/actions.py +160 -0
  19. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/admin/config.py +58 -0
  20. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/admin/forms.py +16 -2
  21. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/admin/router.py +287 -41
  22. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/admin/static/admin.css +18 -0
  23. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/admin/templates/form.html +4 -1
  24. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/admin/templates/list.html +16 -4
  25. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/api/dependencies/auth.py +28 -7
  26. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/auth/__init__.py +14 -0
  27. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/auth/router.py +234 -50
  28. tempest_fastapi_sdk-0.87.0/tempest_fastapi_sdk/auth/token_delivery.py +158 -0
  29. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/settings/mixins.py +76 -1
  30. tempest_fastapi_sdk-0.87.0/tempest_fastapi_sdk/vision/__init__.py +85 -0
  31. tempest_fastapi_sdk-0.87.0/tempest_fastapi_sdk/vision/mapping.py +123 -0
  32. tempest_fastapi_sdk-0.87.0/tempest_fastapi_sdk/vision/schemas.py +111 -0
  33. tempest_fastapi_sdk-0.87.0/tests/admin/test_actions.py +183 -0
  34. tempest_fastapi_sdk-0.87.0/tests/admin/test_rich_filters.py +176 -0
  35. tempest_fastapi_sdk-0.87.0/tests/admin/test_upload_field.py +161 -0
  36. tempest_fastapi_sdk-0.87.0/tests/auth/test_cookie_delivery.py +303 -0
  37. tempest_fastapi_sdk-0.87.0/tests/vision/test_vision.py +95 -0
  38. tempest_fastapi_sdk-0.87.0/tests/websockets/__init__.py +0 -0
  39. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/uv.lock +297 -3
  40. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/.github/workflows/ci.yml +0 -0
  41. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/.github/workflows/docs.yml +0 -0
  42. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/.github/workflows/release-pypi.yml +0 -0
  43. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/.gitignore +0 -0
  44. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/.python-version +0 -0
  45. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/Makefile +0 -0
  46. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/architecture.en.md +0 -0
  47. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/architecture.md +0 -0
  48. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/changelog.en.md +0 -0
  49. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/changelog.md +0 -0
  50. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/contributing.en.md +0 -0
  51. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/contributing.md +0 -0
  52. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/index.en.md +0 -0
  53. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/index.md +0 -0
  54. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/installation.en.md +0 -0
  55. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/installation.md +0 -0
  56. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/learning/index.en.md +0 -0
  57. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/learning/index.md +0 -0
  58. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/learning/marketplace/api.en.md +0 -0
  59. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/learning/marketplace/api.md +0 -0
  60. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/learning/marketplace/business-rules.en.md +0 -0
  61. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/learning/marketplace/business-rules.md +0 -0
  62. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/learning/marketplace/domain.en.md +0 -0
  63. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/learning/marketplace/domain.md +0 -0
  64. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/learning/marketplace/flows.en.md +0 -0
  65. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/learning/marketplace/flows.md +0 -0
  66. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/learning/marketplace/index.en.md +0 -0
  67. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/learning/marketplace/index.md +0 -0
  68. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/migration.en.md +0 -0
  69. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/migration.md +0 -0
  70. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/audit-trail.en.md +0 -0
  71. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/audit-trail.md +0 -0
  72. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/br-helpers.en.md +0 -0
  73. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/br-helpers.md +0 -0
  74. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/cache.en.md +0 -0
  75. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/cache.md +0 -0
  76. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/cli.en.md +0 -0
  77. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/cli.md +0 -0
  78. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/database.en.md +0 -0
  79. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/database.md +0 -0
  80. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/deploy-safety.en.md +0 -0
  81. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/deploy-safety.md +0 -0
  82. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/downloads.en.md +0 -0
  83. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/downloads.md +0 -0
  84. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/email.en.md +0 -0
  85. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/email.md +0 -0
  86. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/feature-flags.en.md +0 -0
  87. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/feature-flags.md +0 -0
  88. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/fields.en.md +0 -0
  89. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/fields.md +0 -0
  90. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/http-client.en.md +0 -0
  91. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/http-client.md +0 -0
  92. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/http.en.md +0 -0
  93. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/http.md +0 -0
  94. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/idempotency.en.md +0 -0
  95. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/idempotency.md +0 -0
  96. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/logging.en.md +0 -0
  97. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/logging.md +0 -0
  98. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/metrics.en.md +0 -0
  99. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/metrics.md +0 -0
  100. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/mfa.en.md +0 -0
  101. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/mfa.md +0 -0
  102. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/multi-tenant.en.md +0 -0
  103. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/multi-tenant.md +0 -0
  104. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/observability.en.md +0 -0
  105. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/observability.md +0 -0
  106. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/offline-sync.en.md +0 -0
  107. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/offline-sync.md +0 -0
  108. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/outbox.en.md +0 -0
  109. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/outbox.md +0 -0
  110. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/queue-tasks.en.md +0 -0
  111. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/queue-tasks.md +0 -0
  112. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/realtime.en.md +0 -0
  113. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/realtime.md +0 -0
  114. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/refresh-tokens.en.md +0 -0
  115. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/refresh-tokens.md +0 -0
  116. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/security.en.md +0 -0
  117. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/security.md +0 -0
  118. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/sessions.en.md +0 -0
  119. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/sessions.md +0 -0
  120. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/sse.en.md +0 -0
  121. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/sse.md +0 -0
  122. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/storage.en.md +0 -0
  123. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/storage.md +0 -0
  124. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/stored-files.en.md +0 -0
  125. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/stored-files.md +0 -0
  126. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/testing.en.md +0 -0
  127. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/testing.md +0 -0
  128. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/typing.en.md +0 -0
  129. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/typing.md +0 -0
  130. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/uploads.en.md +0 -0
  131. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/uploads.md +0 -0
  132. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/utilities.en.md +0 -0
  133. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/utilities.md +0 -0
  134. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/webpush.en.md +0 -0
  135. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/webpush.md +0 -0
  136. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/websocket.en.md +0 -0
  137. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/websocket.md +0 -0
  138. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/reference.en.md +0 -0
  139. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/roadmap.en.md +0 -0
  140. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/roadmap.md +0 -0
  141. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/tutorial.en.md +0 -0
  142. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/tutorial.md +0 -0
  143. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/mkdocs_hooks/llmstxt.py +0 -0
  144. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/scripts/extract_recipe.py +0 -0
  145. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/admin/auth.py +0 -0
  146. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/admin/discovery.py +0 -0
  147. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/admin/session.py +0 -0
  148. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/admin/site.py +0 -0
  149. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/admin/templates/base.html +0 -0
  150. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/admin/templates/dashboard.html +0 -0
  151. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/admin/templates/detail.html +0 -0
  152. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/admin/templates/login.html +0 -0
  153. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/admin/templates/logs.html +0 -0
  154. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/admin/templates/mfa.html +0 -0
  155. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/admin/theme.py +0 -0
  156. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/api/__init__.py +0 -0
  157. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/api/cookies.py +0 -0
  158. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/api/dependencies/__init__.py +0 -0
  159. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/api/handlers.py +0 -0
  160. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/api/middlewares/__init__.py +0 -0
  161. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/api/middlewares/body_size.py +0 -0
  162. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/api/middlewares/cors.py +0 -0
  163. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/api/middlewares/csrf.py +0 -0
  164. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/api/middlewares/graceful.py +0 -0
  165. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/api/middlewares/idempotency.py +0 -0
  166. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/api/middlewares/rate_limit.py +0 -0
  167. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/api/middlewares/request_id.py +0 -0
  168. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/api/oauth.py +0 -0
  169. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/api/routers/__init__.py +0 -0
  170. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/api/routers/health.py +0 -0
  171. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/api/routers/logs.py +0 -0
  172. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/api/routers/metrics.py +0 -0
  173. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/api/routers/tool_spec.py +0 -0
  174. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/api/server.py +0 -0
  175. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/api/static.py +0 -0
  176. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/api/tracing.py +0 -0
  177. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/api/webhooks.py +0 -0
  178. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/auth/guards.py +0 -0
  179. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/auth/locale.py +0 -0
  180. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/auth/page_renderer.py +0 -0
  181. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/auth/schemas.py +0 -0
  182. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/auth/service.py +0 -0
  183. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/auth/templates/en-US/activation.html +0 -0
  184. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/auth/templates/en-US/activation_error.html +0 -0
  185. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/auth/templates/en-US/activation_success.html +0 -0
  186. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/auth/templates/en-US/password_reset.html +0 -0
  187. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/auth/templates/en-US/password_reset_error.html +0 -0
  188. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/auth/templates/en-US/password_reset_form.html +0 -0
  189. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/auth/templates/en-US/password_reset_success.html +0 -0
  190. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/auth/templates/pt-BR/activation.html +0 -0
  191. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/auth/templates/pt-BR/activation_error.html +0 -0
  192. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/auth/templates/pt-BR/activation_success.html +0 -0
  193. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/auth/templates/pt-BR/password_reset.html +0 -0
  194. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/auth/templates/pt-BR/password_reset_error.html +0 -0
  195. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/auth/templates/pt-BR/password_reset_form.html +0 -0
  196. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/auth/templates/pt-BR/password_reset_success.html +0 -0
  197. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cache/__init__.py +0 -0
  198. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cache/decorator.py +0 -0
  199. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cache/invalidation.py +0 -0
  200. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cache/redis_manager.py +0 -0
  201. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/__init__.py +0 -0
  202. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/_templates/Dockerfile.tmpl +0 -0
  203. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/_templates/README.md.tmpl +0 -0
  204. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/_templates/dockerignore.tmpl +0 -0
  205. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/_templates/env.example.tmpl +0 -0
  206. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/_templates/gitignore.tmpl +0 -0
  207. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/_templates/main.py.tmpl +0 -0
  208. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/_templates/pyproject.toml.tmpl +0 -0
  209. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/_templates/src/__init__.py.tmpl +0 -0
  210. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/_templates/src/api/__init__.py.tmpl +0 -0
  211. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/_templates/src/api/app.py.tmpl +0 -0
  212. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/_templates/src/api/dependencies/__init__.py.tmpl +0 -0
  213. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/_templates/src/api/dependencies/auth.py.tmpl +0 -0
  214. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/_templates/src/api/dependencies/resources.py.tmpl +0 -0
  215. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/_templates/src/api/routers/__init__.py.tmpl +0 -0
  216. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/_templates/src/controllers/__init__.py.tmpl +0 -0
  217. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/_templates/src/core/__init__.py.tmpl +0 -0
  218. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/_templates/src/core/exceptions.py.tmpl +0 -0
  219. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/_templates/src/core/settings.py.tmpl +0 -0
  220. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/_templates/src/db/__init__.py.tmpl +0 -0
  221. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/_templates/src/db/models/__init__.py.tmpl +0 -0
  222. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/_templates/src/db/models/user.py.tmpl +0 -0
  223. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/_templates/src/db/repositories/__init__.py.tmpl +0 -0
  224. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/_templates/src/schemas/__init__.py.tmpl +0 -0
  225. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/_templates/src/server.py.tmpl +0 -0
  226. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/_templates/src/services/__init__.py.tmpl +0 -0
  227. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/_templates/src/utils/__init__.py.tmpl +0 -0
  228. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/_templates/tests/__init__.py.tmpl +0 -0
  229. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/_templates/tests/test_smoke.py.tmpl +0 -0
  230. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/config.py +0 -0
  231. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/db.py +0 -0
  232. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/docker_compose.py +0 -0
  233. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/generate.py +0 -0
  234. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/lint.py +0 -0
  235. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/main.py +0 -0
  236. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/new.py +0 -0
  237. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/secrets.py +0 -0
  238. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/src_layers.py +0 -0
  239. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/user.py +0 -0
  240. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/controllers/__init__.py +0 -0
  241. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/controllers/base.py +0 -0
  242. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/core/__init__.py +0 -0
  243. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/core/context.py +0 -0
  244. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/core/enums.py +0 -0
  245. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/core/logging.py +0 -0
  246. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/core/typed.py +0 -0
  247. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/db/__init__.py +0 -0
  248. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/db/_alembic_templates/__init__.py +0 -0
  249. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/db/_alembic_templates/env.py.template +0 -0
  250. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/db/alembic_hooks.py +0 -0
  251. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/db/audit.py +0 -0
  252. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/db/backup.py +0 -0
  253. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/db/connection.py +0 -0
  254. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/db/migrations.py +0 -0
  255. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/db/mixins.py +0 -0
  256. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/db/model.py +0 -0
  257. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/db/outbox.py +0 -0
  258. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/db/repository.py +0 -0
  259. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/db/slow_query.py +0 -0
  260. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/db/tenant.py +0 -0
  261. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/db/user_model.py +0 -0
  262. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/db/user_recovery_code_model.py +0 -0
  263. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/db/user_refresh_token_model.py +0 -0
  264. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/db/user_token_model.py +0 -0
  265. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/db/webpush_subscription_model.py +0 -0
  266. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/exceptions/__init__.py +0 -0
  267. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/exceptions/base.py +0 -0
  268. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/exceptions/conflict.py +0 -0
  269. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/exceptions/forbidden.py +0 -0
  270. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/exceptions/i18n.py +0 -0
  271. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/exceptions/jwt.py +0 -0
  272. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/exceptions/not_found.py +0 -0
  273. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/exceptions/too_many_requests.py +0 -0
  274. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/exceptions/unauthorized.py +0 -0
  275. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/exceptions/upload.py +0 -0
  276. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/exceptions/validation.py +0 -0
  277. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/flags/__init__.py +0 -0
  278. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/flags/backends.py +0 -0
  279. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/flags/dependencies.py +0 -0
  280. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/flags/service.py +0 -0
  281. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/py.typed +0 -0
  282. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/queue/__init__.py +0 -0
  283. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/queue/manager.py +0 -0
  284. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/schemas/__init__.py +0 -0
  285. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/schemas/base.py +0 -0
  286. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/schemas/link_headers.py +0 -0
  287. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/schemas/logs.py +0 -0
  288. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/schemas/pagination.py +0 -0
  289. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/schemas/response.py +0 -0
  290. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/services/__init__.py +0 -0
  291. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/services/base.py +0 -0
  292. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/services/file_mixin.py +0 -0
  293. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/sessions/__init__.py +0 -0
  294. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/sessions/dependencies.py +0 -0
  295. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/sessions/middleware.py +0 -0
  296. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/sessions/router.py +0 -0
  297. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/sessions/schemas.py +0 -0
  298. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/sessions/service.py +0 -0
  299. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/sessions/store.py +0 -0
  300. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/settings/__init__.py +0 -0
  301. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/settings/base.py +0 -0
  302. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/sse/__init__.py +0 -0
  303. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/sse/broker.py +0 -0
  304. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/sse/event_stream.py +0 -0
  305. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/storage/__init__.py +0 -0
  306. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/storage/minio_client.py +0 -0
  307. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/tasks/__init__.py +0 -0
  308. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/tasks/manager.py +0 -0
  309. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/tasks/scheduler.py +0 -0
  310. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/testing/__init__.py +0 -0
  311. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/testing/database.py +0 -0
  312. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/utils/__init__.py +0 -0
  313. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/utils/client_ip.py +0 -0
  314. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/utils/data/br_locations.json +0 -0
  315. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/utils/datetime.py +0 -0
  316. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/utils/dict.py +0 -0
  317. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/utils/download.py +0 -0
  318. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/utils/email.py +0 -0
  319. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/utils/fields.py +0 -0
  320. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/utils/http_client.py +0 -0
  321. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/utils/jwt.py +0 -0
  322. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/utils/locations.py +0 -0
  323. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/utils/log.py +0 -0
  324. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/utils/metrics.py +0 -0
  325. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/utils/opaque_token.py +0 -0
  326. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/utils/password.py +0 -0
  327. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/utils/regex.py +0 -0
  328. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/utils/storage_backends.py +0 -0
  329. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/utils/throttle.py +0 -0
  330. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/utils/totp.py +0 -0
  331. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/utils/upload.py +0 -0
  332. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/webpush/__init__.py +0 -0
  333. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/webpush/dispatcher.py +0 -0
  334. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/webpush/router.py +0 -0
  335. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/webpush/schemas.py +0 -0
  336. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/webpush/service.py +0 -0
  337. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/websockets/__init__.py +0 -0
  338. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/websockets/hub.py +0 -0
  339. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/websockets/router.py +0 -0
  340. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/websockets/schemas.py +0 -0
  341. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/__init__.py +0 -0
  342. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/admin/__init__.py +0 -0
  343. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/admin/test_auth.py +0 -0
  344. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/admin/test_discovery.py +0 -0
  345. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/admin/test_forms.py +0 -0
  346. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/admin/test_logs_nav.py +0 -0
  347. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/admin/test_mfa.py +0 -0
  348. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/admin/test_router.py +0 -0
  349. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/admin/test_site.py +0 -0
  350. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/admin/test_theme.py +0 -0
  351. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/admin/test_user_model.py +0 -0
  352. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/api/__init__.py +0 -0
  353. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/api/test_body_size.py +0 -0
  354. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/api/test_cookies.py +0 -0
  355. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/api/test_cors.py +0 -0
  356. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/api/test_csrf.py +0 -0
  357. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/api/test_dependencies_auth.py +0 -0
  358. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/api/test_graceful.py +0 -0
  359. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/api/test_handlers.py +0 -0
  360. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/api/test_health_router.py +0 -0
  361. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/api/test_idempotency.py +0 -0
  362. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/api/test_jwt_dependency.py +0 -0
  363. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/api/test_logs_router.py +0 -0
  364. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/api/test_oauth.py +0 -0
  365. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/api/test_prometheus.py +0 -0
  366. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/api/test_rate_limit.py +0 -0
  367. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/api/test_rate_limit_extras.py +0 -0
  368. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/api/test_request_id_middleware.py +0 -0
  369. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/api/test_role_dependency.py +0 -0
  370. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/api/test_server.py +0 -0
  371. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/api/test_static.py +0 -0
  372. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/api/test_tool_spec.py +0 -0
  373. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/api/test_tracing.py +0 -0
  374. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/api/test_webhooks.py +0 -0
  375. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/api/test_webhooks_rsa.py +0 -0
  376. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/auth/__init__.py +0 -0
  377. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/auth/test_guards.py +0 -0
  378. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/auth/test_locale.py +0 -0
  379. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/auth/test_mfa.py +0 -0
  380. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/auth/test_refresh.py +0 -0
  381. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/auth/test_refresh_db.py +0 -0
  382. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/auth/test_service.py +0 -0
  383. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/cache/__init__.py +0 -0
  384. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/cache/test_decorator.py +0 -0
  385. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/cache/test_invalidation.py +0 -0
  386. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/cache/test_redis_manager.py +0 -0
  387. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/cli/__init__.py +0 -0
  388. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/cli/test_config.py +0 -0
  389. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/cli/test_db.py +0 -0
  390. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/cli/test_db_seed.py +0 -0
  391. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/cli/test_docker_compose.py +0 -0
  392. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/cli/test_generate.py +0 -0
  393. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/cli/test_lint_strictness.py +0 -0
  394. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/cli/test_main.py +0 -0
  395. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/cli/test_secrets.py +0 -0
  396. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/cli/test_user.py +0 -0
  397. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/conftest.py +0 -0
  398. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/controllers/__init__.py +0 -0
  399. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/controllers/test_base.py +0 -0
  400. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/core/__init__.py +0 -0
  401. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/core/test_context.py +0 -0
  402. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/core/test_enums.py +0 -0
  403. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/core/test_logging.py +0 -0
  404. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/core/test_typed.py +0 -0
  405. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/db/__init__.py +0 -0
  406. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/db/test_alembic_hooks.py +0 -0
  407. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/db/test_audit.py +0 -0
  408. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/db/test_backup.py +0 -0
  409. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/db/test_bulk_ops.py +0 -0
  410. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/db/test_connection.py +0 -0
  411. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/db/test_migrations.py +0 -0
  412. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/db/test_mixins.py +0 -0
  413. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/db/test_model.py +0 -0
  414. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/db/test_outbox.py +0 -0
  415. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/db/test_repository.py +0 -0
  416. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/db/test_safe_upgrade.py +0 -0
  417. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/db/test_slow_query.py +0 -0
  418. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/db/test_tenant.py +0 -0
  419. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/exceptions/__init__.py +0 -0
  420. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/exceptions/test_exceptions.py +0 -0
  421. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/exceptions/test_i18n.py +0 -0
  422. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/flags/__init__.py +0 -0
  423. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/flags/test_flags.py +0 -0
  424. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/queue/__init__.py +0 -0
  425. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/queue/test_manager.py +0 -0
  426. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/schemas/__init__.py +0 -0
  427. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/schemas/test_base.py +0 -0
  428. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/schemas/test_cursor_pagination.py +0 -0
  429. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/schemas/test_link_headers.py +0 -0
  430. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/schemas/test_pagination.py +0 -0
  431. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/schemas/test_response.py +0 -0
  432. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/services/__init__.py +0 -0
  433. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/services/test_base.py +0 -0
  434. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/services/test_file_mixin.py +0 -0
  435. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/sessions/__init__.py +0 -0
  436. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/sessions/test_sessions.py +0 -0
  437. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/settings/__init__.py +0 -0
  438. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/settings/test_base.py +0 -0
  439. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/settings/test_mixins.py +0 -0
  440. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/sse/__init__.py +0 -0
  441. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/sse/test_broker.py +0 -0
  442. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/sse/test_event_stream.py +0 -0
  443. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/storage/__init__.py +0 -0
  444. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/storage/test_minio_client.py +0 -0
  445. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/tasks/__init__.py +0 -0
  446. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/tasks/test_manager.py +0 -0
  447. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/tasks/test_scheduler.py +0 -0
  448. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/testing/__init__.py +0 -0
  449. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/testing/test_database.py +0 -0
  450. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/utils/__init__.py +0 -0
  451. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/utils/test_client_ip.py +0 -0
  452. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/utils/test_datetime.py +0 -0
  453. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/utils/test_dict.py +0 -0
  454. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/utils/test_download.py +0 -0
  455. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/utils/test_email.py +0 -0
  456. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/utils/test_fields.py +0 -0
  457. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/utils/test_http_client.py +0 -0
  458. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/utils/test_jwt.py +0 -0
  459. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/utils/test_lazy_extras.py +0 -0
  460. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/utils/test_locations.py +0 -0
  461. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/utils/test_log.py +0 -0
  462. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/utils/test_metrics.py +0 -0
  463. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/utils/test_opaque_token.py +0 -0
  464. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/utils/test_password.py +0 -0
  465. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/utils/test_regex.py +0 -0
  466. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/utils/test_storage_backends.py +0 -0
  467. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/utils/test_throttle.py +0 -0
  468. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/utils/test_upload.py +0 -0
  469. {tempest_fastapi_sdk-0.82.1/tests/webpush → tempest_fastapi_sdk-0.87.0/tests/vision}/__init__.py +0 -0
  470. {tempest_fastapi_sdk-0.82.1/tests/websockets → tempest_fastapi_sdk-0.87.0/tests/webpush}/__init__.py +0 -0
  471. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/webpush/test_dispatcher.py +0 -0
  472. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/webpush/test_router.py +0 -0
  473. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/webpush/test_schemas.py +0 -0
  474. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/webpush/test_service.py +0 -0
  475. {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/websockets/test_hub_and_router.py +0 -0
@@ -5,6 +5,102 @@ All notable changes to **tempest-fastapi-sdk** are listed below.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.87.0] — 2026-07-02
9
+
10
+ ### Added
11
+
12
+ - **Configurable token delivery for the auth router.** `make_auth_router`
13
+ now supports three ways of handing back the JWT pair, selected by
14
+ `AUTH_TOKEN_DELIVERY` (or the `token_delivery=` argument):
15
+ - `"bearer"` (default) — tokens in the JSON body only. Unchanged,
16
+ fully backward-compatible behaviour.
17
+ - `"cookie"` — `access_token` / `refresh_token` set as `HttpOnly`
18
+ cookies on `/auth/login`, `/auth/refresh`, `/auth/logout`; the body
19
+ omits the token values (safer against XSS). `POST /auth/refresh`
20
+ reads the refresh token from the cookie and rotates the pair;
21
+ `POST /auth/logout` clears the cookies (and revokes the refresh
22
+ family when a `refresh_token_model` is wired).
23
+ - `"both"` — the bearer endpoints stay at `/auth/*` and a parallel
24
+ cookie set is mounted at `/auth/cookie/*`, so one backend can serve
25
+ web (cookie) and mobile/API (bearer) clients.
26
+ - New `AUTH_COOKIE_SECURE`, `AUTH_COOKIE_SAMESITE`, `AUTH_COOKIE_DOMAIN`,
27
+ `AUTH_ACCESS_COOKIE_NAME` and `AUTH_REFRESH_COOKIE_NAME` settings tune
28
+ the cookie security attributes.
29
+ - New public exports: `TokenDelivery`, `AuthCookieConfig`,
30
+ `apply_auth_cookies`, `clear_auth_cookies`.
31
+ - `make_bearer_token_dependency` / `make_jwt_user_dependency` gained a
32
+ `cookie_name=` argument: when set, the access token is read from that
33
+ cookie if the `Authorization` header is absent (header still wins), so
34
+ the same guarded routes work in cookie mode.
35
+
36
+ ### Notes
37
+
38
+ - Activation, signup auto-login and the MFA-verify step still return the
39
+ JWT pair in the body regardless of `AUTH_TOKEN_DELIVERY` — cookie
40
+ delivery covers the login / refresh / logout session lifecycle.
41
+
42
+ ## [0.86.0] — 2026-06-28
43
+
44
+ ### Added
45
+
46
+ - **Admin rich list filters.** `list_filter` fields now auto-pick a
47
+ widget by column type instead of rendering a useful dropdown only for
48
+ booleans: **enum** columns become a member dropdown, **foreign keys**
49
+ (whose target has a registered `AdminModel`) become a related-row
50
+ dropdown, **date/datetime** columns become an inclusive date-range
51
+ (two date inputs → `<field>__gte` / `<field>__lte`), and any other
52
+ column becomes a text input (equality). Booleans keep the Yes/No
53
+ dropdown. All filters preserve search / sort / pagination in the URL.
54
+
55
+ ## [0.85.0] — 2026-06-28
56
+
57
+ ### Added
58
+
59
+ - **Admin file / image upload fields.** `AdminModel` gained
60
+ `upload_fields=[...]` + `upload_storage=...`: listed String columns
61
+ render as file inputs in the create/edit form (which auto-switches to
62
+ `multipart/form-data`), the posted file is streamed to the storage
63
+ backend (`LocalUploadStorage` / `MinIOUploadStorage`), and the returned
64
+ storage key is written to the column. On edit, omitting the file keeps
65
+ the current value; on create, a missing file for a non-nullable column
66
+ is a required-field error. Registering `upload_fields` without
67
+ `upload_storage` raises `ValueError`.
68
+
69
+ ## [0.84.0] — 2026-06-28
70
+
71
+ ### Added
72
+
73
+ - **Admin custom actions (`@admin_action`).** Beyond the three hardcoded
74
+ bulk operations (activate / deactivate / delete), the admin now takes
75
+ user-defined actions: decorate an async function with `@admin_action`
76
+ and register it via `AdminModel(actions=[...])`. Each renders in the
77
+ list view's bulk dropdown (namespaced `custom:<name>` so it can't
78
+ collide with the built-ins), runs on the checked rows, and flashes a
79
+ banner from its `AdminActionResult`. The handler receives an
80
+ `AdminActionContext` (selected ids, a request-scoped repository, the DB
81
+ session, the request, the admin session, and the acting principal) and
82
+ stays directly callable/testable — the decorator only attaches
83
+ metadata. Exported from `tempest_fastapi_sdk` and
84
+ `tempest_fastapi_sdk.admin` (`admin_action`, `AdminAction`,
85
+ `AdminActionContext`, `AdminActionResult`).
86
+
87
+ ## [0.83.0] — 2026-06-28
88
+
89
+ ### Added
90
+
91
+ - **Computer-vision integration via the `[vision]` extra
92
+ (`ort-vision-sdk`).** New `tempest_fastapi_sdk.vision` submodule wraps
93
+ the ONNX Runtime inference library with the FastAPI layer it lacks:
94
+ Pydantic response schemas (`DetectionSchema`, `ClassificationSchema`,
95
+ `SegmentationSchema`, `BoundingBoxSchema`, `ClassProbabilitySchema`)
96
+ and mappers (`to_detection_schemas`, `to_classification_schema`,
97
+ `to_segmentation_schemas`) that convert a model result into them. The
98
+ `Detector` / `Classifier` / `Segmenter` task classes are re-exported
99
+ **lazily** — accessing one without the extra raises a clear
100
+ `ImportError` pointing at `[vision]`; the schemas and mappers carry no
101
+ such dependency. Like `cache` / `queue` / `tasks`, vision is
102
+ submodule-only (`from tempest_fastapi_sdk.vision import Detector`).
103
+
8
104
  ## [0.82.1] — 2026-06-28
9
105
 
10
106
  ### Fixed
@@ -88,8 +88,32 @@ The SDK currently covers (Sep 2025+, post-v0.31.x):
88
88
  - **Pagination** — offset + cursor.
89
89
  - **Settings mixins** — every `*Settings` carries
90
90
  `title`/`description`/`examples` on every field.
91
- - **SSE** — `EventStream`, `sse_response`.
92
- - **Throttle** — `AttemptThrottle` (memory + Redis).
91
+ - **SSE** — `EventStream`, `ServerSentEvent`, `sse_response`, and
92
+ `SSEBroker` (per-channel fan-out; in-memory single-process, or
93
+ multi-worker via an injected Redis pub/sub bridge — same call site).
94
+ - **Throttle** — `AttemptThrottle` (any `ThrottleBackend`, e.g.
95
+ `redis.asyncio.Redis`; no in-memory backend bundled).
96
+ - **Base CRUD layers** — `BaseService[Repo, Resp, UpdateT]` and
97
+ `BaseController[Service, Resp, UpdateT]` with
98
+ `get_by_id`/`get_or_none`/`list`/`paginate`/`count`/`exists`/`update`/
99
+ `delete`; `update` is partial-aware (PUT/PATCH) and `UpdateT` is an
100
+ optional 3rd generic (defaults to `BaseSchema`, PEP 696).
101
+ - **Base enums** — `BaseStrEnum` / `BaseIntEnum` with
102
+ `values`/`keys`/`choices`/`to_dict`/`from_value`/`has_value`/`has_key`.
103
+ - **Validated field types** — `tempest_fastapi_sdk.utils` Annotated
104
+ Pydantic types: `PositiveIntField`/`NonNegativeIntField`/`CentsField`/
105
+ `PortField`/`PositiveFloatField`/`NonNegativeFloatField`/`PercentField`/
106
+ `RatioField`/`LatitudeField`/`LongitudeField`/`PriceField`/
107
+ `NonEmptyStrField`/`SlugField`/`HexColorField`.
108
+ - **Runtime typing** — `strict_types` / `typed` / `require_annotations`
109
+ decorators (over `pydantic.validate_call`); ruff `ANN` enabled in the
110
+ SDK and `tempest new` templates (ANN401 off — `Any` is valid); a
111
+ `[tool.tempest] typing_strictness` knob (`lenient`/`standard`/`strict`,
112
+ `--strictness` override) layered onto `tempest lint`/`fix`/`type`/`check`.
113
+ - **Vision** (`[vision]` extra) — `tempest_fastapi_sdk.vision` wrapping
114
+ `ort-vision-sdk`: lazy `Detector`/`Classifier`/`Segmenter` + prediction
115
+ schemas + `to_detection_schemas`/`to_classification_schema`/
116
+ `to_segmentation_schemas` mappers.
93
117
  - **Upload** — `UploadUtils` with pluggable backends
94
118
  (`LocalUploadStorage`, `MinIOUploadStorage`), download helpers,
95
119
  presigned URLs.
@@ -99,17 +123,26 @@ The SDK currently covers (Sep 2025+, post-v0.31.x):
99
123
  - **Email** — SMTP via `EmailUtils` + Jinja2 template rendering
100
124
  with bundled defaults (`activation.html`, `password_reset.html`)
101
125
  shadowable by the project's `template_dir`.
102
- - **WebPush** + webhook signatures.
126
+ - **WebPush** `WebPushDispatcher` (`send`/`send_many`, 404/410
127
+ pruning), subscription storage (`BaseWebPushSubscriptionModel` +
128
+ `make_web_push_subscription_model`) + `WebPushSubscriptionService`
129
+ (`subscribe`/`unsubscribe`/`list_for_user`/`notify_user` with
130
+ auto-prune of gone endpoints) + `make_web_push_router` (opt-in
131
+ `/subscribe` + `/unsubscribe`, aligned with `tempest-react-sdk`);
132
+ webhook signatures.
103
133
  - **Cache** — Redis manager + `@cached`.
104
134
  - **Queue / tasks** — FastStream + TaskIQ wrappers.
105
- - **BR validators** — CPF/CNPJ/CEP/phone.
135
+ - **BR validators** — CPF/CNPJ/CEP/phone, with `*Field` Pydantic types
136
+ (`CPFField`/`CNPJField`/`CPFOrCNPJField`/`PhoneBRField`/`CEPField`;
137
+ pre-0.76 unsuffixed names kept as deprecated aliases).
106
138
  - **BR localities** — `UF` (StrEnum, 27 siglas) + `Region`
107
139
  (5 macro-regiões IBGE), `StateBR`/`CityBR` schemas, offline
108
140
  dataset of 27 states + 5606 municipalities (IBGE-derived,
109
141
  DF as 36 administrative regions), `list_states`/`get_state`/
110
142
  `cities_by_uf`/`states_by_region`, `is_valid_uf`/`normalize_uf`,
111
143
  `is_valid_city`/`normalize_city` (accent/case-insensitive),
112
- `UFField`/`CityNameField`.
144
+ `UFField`/`CityNameField`, plus `ChoiceBR` + `uf_choices`/
145
+ `region_choices`/`city_choices` (frontend `<select>` choices).
113
146
  - **Rate limit** — `RateLimitMiddleware` (sliding window) with
114
147
  pluggable store (`MemoryRateLimitStore` / `RedisRateLimitStore`,
115
148
  atomic Lua) and per-principal key extractors (`key_by_ip`,
@@ -131,7 +164,11 @@ The SDK currently covers (Sep 2025+, post-v0.31.x):
131
164
  - **Admin panel** — Jinja + HTMX (`AdminSite`, `AdminModel`,
132
165
  `make_admin_router`), typed theming via `AdminTheme` (colors /
133
166
  logo / favicon / font / radius / footer / dark mode /
134
- `custom_css_url`, injected as `:root` overrides).
167
+ `custom_css_url`, injected as `:root` overrides), custom bulk actions
168
+ (`@admin_action` + `AdminModel(actions=[...])`, `AdminActionContext` /
169
+ `AdminActionResult`), file/image upload fields (`AdminModel(
170
+ upload_fields=[...], upload_storage=...)`), rich list filters
171
+ (bool/enum/FK select, date-range, text — auto by column type).
135
172
  - **CLI** — `tempest new` (scaffolds layered service +
136
173
  docker-compose + multi-stage uv `Dockerfile`/`.dockerignore`),
137
174
  `tempest generate --docker` (regen compose) / `--dockerfile`
@@ -169,41 +206,46 @@ then move it up to the covers list.
169
206
  foundation the user asked for first; the functional Tier 1 items below
170
207
  inherit the look for free. Now in the covers list.
171
208
 
209
+ **Shipped — custom actions (v0.84.0).** `@admin_action` decorator +
210
+ `AdminModel(actions=[...])` + `AdminActionContext`/`AdminActionResult`;
211
+ custom entries render in the bulk dropdown (namespaced `custom:<name>`),
212
+ run on the checked rows, and flash a banner on the list view. Now in the
213
+ covers list.
214
+
215
+ **Shipped — file / image upload field (v0.85.0).** `AdminModel(
216
+ upload_fields=[...], upload_storage=...)` renders String columns as file
217
+ inputs, streams the upload to `LocalUploadStorage` / `MinIOUploadStorage`,
218
+ and stores the returned key. Now in the covers list.
219
+
220
+ **Shipped — rich filters (v0.86.0).** `list_filter` fields auto-pick a
221
+ widget by column type: bool / enum / FK → select, date/datetime →
222
+ inclusive date-range (two inputs → `__gte`/`__lte`), other → text.
223
+ Now in the covers list.
224
+
172
225
  **Tier 1 — high value, reuses an existing engine (low effort):**
173
226
 
174
- 1. **Custom actions (NEXT)** — `@admin_action` decorator on `AdminModel`
175
- for user-defined row / bulk operations (Django `actions`, Nova
176
- actions). Today only 3 are hardcoded (activate / deactivate /
177
- delete). This is the foundation the rest build on.
178
- 2. **File / image upload field** — a new form widget wired to the
179
- existing `UploadUtils` (`LocalUploadStorage` / `MinIOUploadStorage`).
180
- Engine is already shipped; admin just needs the widget + storage
181
- binding.
182
- 3. **Rich filters** — enum / choice / FK / date-range filters in the
183
- list view (today only boolean fields auto-render a filter dropdown).
184
- Quick UX win.
185
- 4. **Audit history viewer** — a per-row change timeline wired to the
227
+ 1. **Audit history viewer (NEXT)** — a per-row change timeline wired to the
186
228
  existing `BaseAuditLogModel` + `diff_snapshots`. Today the detail
187
229
  view only shows `created_by` / `updated_by` stamps, not full history.
188
230
  Engine is already shipped.
189
231
 
190
232
  **Tier 2 — high value, medium effort:**
191
233
 
192
- 5. **Autocomplete FK fields** — HTMX search endpoint backing FK inputs,
234
+ 2. **Autocomplete FK fields** — HTMX search endpoint backing FK inputs,
193
235
  removing the 1000-row `<select>` cap and the plain-UUID fallback
194
236
  (Django `autocomplete_fields`, Nova search).
195
- 6. **Inlines / nested relations** — edit child rows inside the parent's
237
+ 3. **Inlines / nested relations** — edit child rows inside the parent's
196
238
  detail / edit view (Django `StackedInline` / `TabularInline`).
197
- 7. **Dashboard business metrics / charts** — value / trend / partition
239
+ 4. **Dashboard business metrics / charts** — value / trend / partition
198
240
  cards (Nova metrics), wired to the existing metrics module. Distinct
199
241
  from today's system CPU/RAM/disk panel.
200
242
 
201
243
  **Tier 3 — nice-to-have:**
202
244
 
203
- 8. **RBAC granular** — per-model / per-action admin permissions beyond
245
+ 5. **RBAC granular** — per-model / per-action admin permissions beyond
204
246
  today's `is_admin` + `can_create` / `can_edit` / `can_delete`.
205
- 9. **CSV import** — bulk upload counterpart to the existing export.
206
- 10. **Lenses** — saved alternate views / queries per model (Nova).
247
+ 6. **CSV import** — bulk upload counterpart to the existing export.
248
+ 7. **Lenses** — saved alternate views / queries per model (Nova).
207
249
 
208
250
  Origin: competitor gap analysis (Django Admin, Laravel Nova, SQLAdmin,
209
251
  Starlette-Admin) run 2026-06-26. Do **not** treat the tiers as locked —
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tempest-fastapi-sdk
3
- Version: 0.82.1
3
+ Version: 0.87.0
4
4
  Summary: Shared FastAPI building blocks: base schemas, ORM model, async repository, exceptions, pagination and settings — the conventions used across Tempest projects.
5
5
  Project-URL: Homepage, https://github.com/mauriciobenjamin700/tempest-fastapi-sdk
6
6
  Project-URL: Repository, https://github.com/mauriciobenjamin700/tempest-fastapi-sdk
@@ -49,6 +49,7 @@ Requires-Dist: opentelemetry-instrumentation-fastapi>=0.48b0; extra == 'all'
49
49
  Requires-Dist: opentelemetry-instrumentation-httpx>=0.48b0; extra == 'all'
50
50
  Requires-Dist: opentelemetry-instrumentation-sqlalchemy>=0.48b0; extra == 'all'
51
51
  Requires-Dist: opentelemetry-sdk>=1.27.0; extra == 'all'
52
+ Requires-Dist: ort-vision-sdk>=0.4.0; extra == 'all'
52
53
  Requires-Dist: prometheus-client>=0.20.0; extra == 'all'
53
54
  Requires-Dist: psutil>=6.0.0; extra == 'all'
54
55
  Requires-Dist: pyjwt>=2.12.1; extra == 'all'
@@ -96,6 +97,8 @@ Requires-Dist: taskiq>=0.11.0; extra == 'tasks'
96
97
  Provides-Extra: upload
97
98
  Requires-Dist: aiofiles>=24.1.0; extra == 'upload'
98
99
  Requires-Dist: python-multipart>=0.0.12; extra == 'upload'
100
+ Provides-Extra: vision
101
+ Requires-Dist: ort-vision-sdk>=0.4.0; extra == 'vision'
99
102
  Provides-Extra: webpush
100
103
  Requires-Dist: cryptography>=42.0.0; extra == 'webpush'
101
104
  Requires-Dist: pywebpush>=2.0.0; extra == 'webpush'
@@ -219,6 +222,7 @@ Feature-rich helpers pull in third-party dependencies that you only need when yo
219
222
  | `[http]` | `httpx` | `HTTPClient`, `RetryPolicy`, `CircuitOpenError`, OAuth2 / OIDC providers |
220
223
  | `[prometheus]` | `prometheus-client` | `PrometheusMiddleware`, `make_prometheus_router`, `make_prometheus_registry` |
221
224
  | `[mfa]` | `pyotp` | `TOTPHelper` + MFA/2FA endpoints on the bundled auth flow |
225
+ | `[vision]` | `ort-vision-sdk` | `Detector` / `Classifier` / `Segmenter` (ONNX) + prediction schemas |
222
226
  | `[otel]` | `opentelemetry-sdk` + OTLP/gRPC exporter + FastAPI/SQLAlchemy/httpx instrumentors | `setup_tracing` — distributed tracing |
223
227
  | `[sqlite]` | `aiosqlite` | SQLite async driver for `sqlite+aiosqlite://` URLs (dev default) |
224
228
  | `[postgres]` | `asyncpg` | PostgreSQL async driver for `postgresql+asyncpg://` URLs (production) |
@@ -259,10 +263,11 @@ Since `0.7.1` every optional dependency is imported lazily at first instantiatio
259
263
  | `tempest_fastapi_sdk.utils.http_client` *(extra: `[http]`)* | `HTTPClient`, `RetryPolicy`, `CircuitOpenError`, `REQUEST_ID_HEADER` — typed httpx wrapper |
260
264
  | `tempest_fastapi_sdk.utils.storage_backends` *(extra: `[upload]`)* | `UploadStorage` protocol, `LocalUploadStorage`, `MinIOUploadStorage`, `UploadResult`, `ContentValidator` |
261
265
  | `tempest_fastapi_sdk.tasks` *(extra: `[tasks]`)* | `AsyncTaskBrokerManager` (TaskIQ lifecycle wrapper), `AsyncTaskScheduler` (periodic / cron tasks) |
266
+ | `tempest_fastapi_sdk.vision` *(extra: `[vision]`)* | `Detector`, `Classifier`, `Segmenter` (ONNX, lazy), `DetectionSchema`/`ClassificationSchema`/`SegmentationSchema`/`BoundingBoxSchema`/`ClassProbabilitySchema`, `to_detection_schemas`/`to_classification_schema`/`to_segmentation_schemas` |
262
267
  | `tempest_fastapi_sdk.utils` | `to_utc`, `utcnow`, `modify_dict`, `LogUtils`, `AttemptThrottle`/`ThrottleBackend`/`ThrottleStatus`, `generate_opaque_token`/`hash_opaque_token`/`verify_opaque_token`, `get_client_ip`/`get_client_ip_from_scope`, `PasswordUtils` *(extra: `[auth]`)*, `JWTUtils` *(extra: `[auth]`)*, `TOTPHelper` *(extra: `[mfa]`)*, `EmailUtils` *(extra: `[email]`)*, `UploadUtils`/`sniff_mime` *(extra: `[upload]`)*, `DownloadUtils`/`build_content_disposition` *(no extra)*, `MetricsUtils`/`CPUMetrics`/`MemoryMetrics`/`DiskMetrics`/`GPUMetrics`/`SystemMetrics` *(extra: `[metrics]`)*, validated field types (`PositiveIntField`, `NonNegativeIntField`, `CentsField`, `PortField`, `PositiveFloatField`, `NonNegativeFloatField`, `PercentField`, `RatioField`, `LatitudeField`, `LongitudeField`, `PriceField`, `NonEmptyStrField`, `SlugField`, `HexColorField`), BR regex helpers (`CPFField`, `CNPJField`, `CPFOrCNPJField`, `PhoneBRField`, `CEPField` — old names without the suffix kept as deprecated aliases — `is_valid_*`, `normalize_*`, `only_digits`, `*_PATTERN`), BR states/cities (`UF`, `Region`, `StateBR`, `CityBR`, `ChoiceBR`, `UFField`, `CityNameField`, `list_states`, `get_state`, `cities_by_uf`, `states_by_region`, `uf_choices`/`region_choices`/`city_choices`, `is_valid_uf`/`normalize_uf`, `is_valid_city`/`normalize_city`) |
263
268
  | `tempest_fastapi_sdk.cli` | `tempest` console script — `new <name>` (scaffold layered service), `lint` / `format` / `fmt-check` / `type` / `test` / `check` (run preferred quality gates), `version` / `--version` |
264
269
 
265
- Core primitives are re-exported from `tempest_fastapi_sdk` at the top level — `from tempest_fastapi_sdk import BaseModel, BaseRepository, AppException` always works. The extras-gated managers in `tempest_fastapi_sdk.cache`, `tempest_fastapi_sdk.queue` and `tempest_fastapi_sdk.tasks` must be imported from their own submodule (`from tempest_fastapi_sdk.queue import AsyncBrokerManager`).
270
+ Core primitives are re-exported from `tempest_fastapi_sdk` at the top level — `from tempest_fastapi_sdk import BaseModel, BaseRepository, AppException` always works. The extras-gated managers in `tempest_fastapi_sdk.cache`, `tempest_fastapi_sdk.queue`, `tempest_fastapi_sdk.tasks` and `tempest_fastapi_sdk.vision` must be imported from their own submodule (`from tempest_fastapi_sdk.queue import AsyncBrokerManager`).
266
271
 
267
272
  ---
268
273
 
@@ -116,6 +116,7 @@ Feature-rich helpers pull in third-party dependencies that you only need when yo
116
116
  | `[http]` | `httpx` | `HTTPClient`, `RetryPolicy`, `CircuitOpenError`, OAuth2 / OIDC providers |
117
117
  | `[prometheus]` | `prometheus-client` | `PrometheusMiddleware`, `make_prometheus_router`, `make_prometheus_registry` |
118
118
  | `[mfa]` | `pyotp` | `TOTPHelper` + MFA/2FA endpoints on the bundled auth flow |
119
+ | `[vision]` | `ort-vision-sdk` | `Detector` / `Classifier` / `Segmenter` (ONNX) + prediction schemas |
119
120
  | `[otel]` | `opentelemetry-sdk` + OTLP/gRPC exporter + FastAPI/SQLAlchemy/httpx instrumentors | `setup_tracing` — distributed tracing |
120
121
  | `[sqlite]` | `aiosqlite` | SQLite async driver for `sqlite+aiosqlite://` URLs (dev default) |
121
122
  | `[postgres]` | `asyncpg` | PostgreSQL async driver for `postgresql+asyncpg://` URLs (production) |
@@ -156,10 +157,11 @@ Since `0.7.1` every optional dependency is imported lazily at first instantiatio
156
157
  | `tempest_fastapi_sdk.utils.http_client` *(extra: `[http]`)* | `HTTPClient`, `RetryPolicy`, `CircuitOpenError`, `REQUEST_ID_HEADER` — typed httpx wrapper |
157
158
  | `tempest_fastapi_sdk.utils.storage_backends` *(extra: `[upload]`)* | `UploadStorage` protocol, `LocalUploadStorage`, `MinIOUploadStorage`, `UploadResult`, `ContentValidator` |
158
159
  | `tempest_fastapi_sdk.tasks` *(extra: `[tasks]`)* | `AsyncTaskBrokerManager` (TaskIQ lifecycle wrapper), `AsyncTaskScheduler` (periodic / cron tasks) |
160
+ | `tempest_fastapi_sdk.vision` *(extra: `[vision]`)* | `Detector`, `Classifier`, `Segmenter` (ONNX, lazy), `DetectionSchema`/`ClassificationSchema`/`SegmentationSchema`/`BoundingBoxSchema`/`ClassProbabilitySchema`, `to_detection_schemas`/`to_classification_schema`/`to_segmentation_schemas` |
159
161
  | `tempest_fastapi_sdk.utils` | `to_utc`, `utcnow`, `modify_dict`, `LogUtils`, `AttemptThrottle`/`ThrottleBackend`/`ThrottleStatus`, `generate_opaque_token`/`hash_opaque_token`/`verify_opaque_token`, `get_client_ip`/`get_client_ip_from_scope`, `PasswordUtils` *(extra: `[auth]`)*, `JWTUtils` *(extra: `[auth]`)*, `TOTPHelper` *(extra: `[mfa]`)*, `EmailUtils` *(extra: `[email]`)*, `UploadUtils`/`sniff_mime` *(extra: `[upload]`)*, `DownloadUtils`/`build_content_disposition` *(no extra)*, `MetricsUtils`/`CPUMetrics`/`MemoryMetrics`/`DiskMetrics`/`GPUMetrics`/`SystemMetrics` *(extra: `[metrics]`)*, validated field types (`PositiveIntField`, `NonNegativeIntField`, `CentsField`, `PortField`, `PositiveFloatField`, `NonNegativeFloatField`, `PercentField`, `RatioField`, `LatitudeField`, `LongitudeField`, `PriceField`, `NonEmptyStrField`, `SlugField`, `HexColorField`), BR regex helpers (`CPFField`, `CNPJField`, `CPFOrCNPJField`, `PhoneBRField`, `CEPField` — old names without the suffix kept as deprecated aliases — `is_valid_*`, `normalize_*`, `only_digits`, `*_PATTERN`), BR states/cities (`UF`, `Region`, `StateBR`, `CityBR`, `ChoiceBR`, `UFField`, `CityNameField`, `list_states`, `get_state`, `cities_by_uf`, `states_by_region`, `uf_choices`/`region_choices`/`city_choices`, `is_valid_uf`/`normalize_uf`, `is_valid_city`/`normalize_city`) |
160
162
  | `tempest_fastapi_sdk.cli` | `tempest` console script — `new <name>` (scaffold layered service), `lint` / `format` / `fmt-check` / `type` / `test` / `check` (run preferred quality gates), `version` / `--version` |
161
163
 
162
- Core primitives are re-exported from `tempest_fastapi_sdk` at the top level — `from tempest_fastapi_sdk import BaseModel, BaseRepository, AppException` always works. The extras-gated managers in `tempest_fastapi_sdk.cache`, `tempest_fastapi_sdk.queue` and `tempest_fastapi_sdk.tasks` must be imported from their own submodule (`from tempest_fastapi_sdk.queue import AsyncBrokerManager`).
164
+ Core primitives are re-exported from `tempest_fastapi_sdk` at the top level — `from tempest_fastapi_sdk import BaseModel, BaseRepository, AppException` always works. The extras-gated managers in `tempest_fastapi_sdk.cache`, `tempest_fastapi_sdk.queue`, `tempest_fastapi_sdk.tasks` and `tempest_fastapi_sdk.vision` must be imported from their own submodule (`from tempest_fastapi_sdk.queue import AsyncBrokerManager`).
163
165
 
164
166
  ---
165
167
 
@@ -1,7 +1,7 @@
1
1
  # Admin site
2
2
 
3
3
 
4
- Django-style management UI mounted under `/admin`. Operators sign in with a user row from the database (no separate admin password store) and browse every registered model from the browser, so the database port can stay closed on private networks. The panel is feature-complete (Django-admin parity): a list view with search / per-field filters / sortable columns, full CRUD (create / edit / delete), bulk actions, CSV/JSON export, FK-select widgets, a dashboard with live row counts + system metrics, optional TOTP MFA at login, and an audit trail stamping `created_by` / `updated_by`. Still on the roadmap: file upload and inline/related editing.
4
+ Django-style management UI mounted under `/admin`. Operators sign in with a user row from the database (no separate admin password store) and browse every registered model from the browser, so the database port can stay closed on private networks. The panel is feature-complete (Django-admin parity): a list view with search / rich per-field filters (enum / FK / date-range) / sortable columns, full CRUD (create / edit / delete), bulk actions, CSV/JSON export, FK-select widgets, a dashboard with live row counts + system metrics, optional TOTP MFA at login, file/image upload fields, and an audit trail stamping `created_by` / `updated_by`. Still on the roadmap: inline/related editing.
5
5
 
6
6
  Requires the `[admin]` extra:
7
7
 
@@ -88,6 +88,14 @@ site.register(AdminModel(
88
88
 
89
89
  Every field reference also accepts a plain string (`list_display=["email", ...]`) for dynamic configuration, and `ordering` accepts a column (ascending), `desc(column)` / `asc(column)`, or a Django-style `"-created_at"` string. `register` returns the instance and raises `ValueError` on a duplicate slug. Slugs default to the model's `__tablename__` so URLs and database tables stay in sync.
90
90
 
91
+ !!! info "Filters auto-pick a widget per column type"
92
+ Each `list_filter` field renders the right widget by column type:
93
+ **boolean** → Yes/No dropdown; **enum** → dropdown of the members;
94
+ **FK** (whose target has a registered `AdminModel`) → dropdown of the
95
+ related rows (labelled via `search_fields`); **date/datetime** → two
96
+ date inputs (from/to, inclusive range); any other column → a text
97
+ input (equality). All preserve search/sort/pagination in the URL.
98
+
91
99
  !!! tip "Centered, customizable brand"
92
100
  The name shown in the center of the header comes from `brand`
93
101
  (optional). Without it, it falls back to `title` — so existing sites
@@ -178,7 +186,7 @@ app.include_router(
178
186
  - `GET /admin/logs` — **application logs** (when `show_logs=True`): reads the structured JSON files written by `configure_logging(log_dir=…)`, with source filter (`?source=`), free-text search (`?q=`) and pagination. Color-coded level badges. Renders an empty state when no log files exist yet.
179
187
  - `GET /admin/m/{slug}/` — list view with pagination + free-text search (`?q=`) + per-field filters (`?filter_<field>=value`) + clickable **column sorting** (`?sort=<column>&dir=asc|desc`).
180
188
  - `GET /admin/m/{slug}/export.csv` / `export.json` — **export** the current result set (honoring search/filters/sort) as CSV or JSON. Row cap via `make_admin_router(export_max_rows=…)` (default 5000).
181
- - `POST /admin/m/{slug}/bulk` — **bulk actions** (delete / activate / deactivate) on the selected rows.
189
+ - `POST /admin/m/{slug}/bulk` — **bulk actions** (delete / activate / deactivate + your **custom actions**) on the selected rows.
182
190
  - `GET/POST /admin/m/{slug}/new` — **create** a record (when `can_create`).
183
191
  - `GET /admin/m/{slug}/{identity}` — detail view with Edit/Delete controls.
184
192
  - `GET/POST /admin/m/{slug}/{identity}/edit` — **edit** a record (when `can_edit`).
@@ -196,7 +204,82 @@ app.include_router(
196
204
 
197
205
  **Audit trail**: create/edit through the admin stamps `created_by`/`updated_by` (from `AuditMixin`) with the acting admin's id; the detail view shows an **Audit** panel with timestamps and — when the model has the audit columns — the actor (UUID resolved to a display name via the auth backend). Models without `AuditMixin` show timestamps only.
198
206
 
199
- Not yet included (later roadmap phases): file upload, inline/related editing.
207
+ Not yet included (later roadmap phases): inline/related editing.
208
+
209
+ ## Custom actions (`@admin_action`)
210
+
211
+ Beyond the 3 built-ins (activate / deactivate / delete), you register
212
+ **your own actions** — an async function decorated with `@admin_action`
213
+ and passed to `AdminModel(actions=[...])`. Each becomes an option in the
214
+ bulk-action dropdown, operating on the checked rows.
215
+
216
+ ```python
217
+ from tempest_fastapi_sdk import (
218
+ AdminActionContext,
219
+ AdminActionResult,
220
+ AdminModel,
221
+ admin_action,
222
+ )
223
+
224
+
225
+ @admin_action(label="Send welcome")
226
+ async def send_welcome(ctx: AdminActionContext) -> AdminActionResult:
227
+ """Runs on the selected rows; the message is shown on the list view."""
228
+ users = await ctx.repository.list(filters={"id": ctx.ids})
229
+ for user in users:
230
+ await mailer.send_welcome(user.email)
231
+ return AdminActionResult(f"Sent {len(users)} emails.")
232
+
233
+
234
+ site.register(AdminModel(model=UserModel, actions=[send_welcome]))
235
+ ```
236
+
237
+ The handler receives an `AdminActionContext`:
238
+
239
+ | Field | What it is |
240
+ | --- | --- |
241
+ | `ids` | Identities of the checked rows. |
242
+ | `repository` | The model's `BaseRepository`, on the request session. |
243
+ | `db_session` | The DB session (for work beyond the repository). |
244
+ | `request` | The inbound request. |
245
+ | `session` | The authenticated admin session. |
246
+ | `principal` | The admin user row that triggered the action. |
247
+
248
+ Return an `AdminActionResult(message, category="success"|"error"|"warning")`
249
+ to flash a banner on the list view (or `None` for no banner). The
250
+ function stays **directly callable/testable** — the decorator only
251
+ attaches metadata. Use `name=` to pin the identifier (default: the
252
+ function name) and `dangerous=True` to mark a destructive action.
253
+
254
+ ## File / image upload field
255
+
256
+ A `String` column that stores a file's path/key can render as a **file
257
+ input** on the form. List the column in `upload_fields` and pass an
258
+ `upload_storage` (the SDK's existing backends — `LocalUploadStorage` /
259
+ `MinIOUploadStorage`). On submit the file is saved to storage and the
260
+ **returned key** is written to the column.
261
+
262
+ ```python
263
+ from tempest_fastapi_sdk import AdminModel
264
+ from tempest_fastapi_sdk.utils import LocalUploadStorage
265
+
266
+
267
+ site.register(AdminModel(
268
+ model=DocumentModel,
269
+ upload_fields=[DocumentModel.attachment], # String column holding the key
270
+ upload_storage=LocalUploadStorage("media/"), # or MinIOUploadStorage(...)
271
+ ))
272
+ ```
273
+
274
+ - The form becomes `multipart/form-data` automatically when `upload_fields` is set.
275
+ - **Create**: a file is required only when the column is `NOT NULL` with no default.
276
+ - **Edit**: no new file → keeps the current value (shows "Current: …"); a file → replaces it.
277
+ - The column stores the storage **key** (`<slug>/<field>/<uuid>.<ext>`); use `upload_storage` (or `UploadUtils`) to serve/download it later.
278
+
279
+ !!! warning "`upload_fields` requires `upload_storage`"
280
+ Registering `upload_fields` without `upload_storage` raises
281
+ `ValueError` at `AdminModel` construction — without storage there's
282
+ nowhere to write the file.
200
283
 
201
284
  !!! tip "Sidebar + burger navigation"
202
285
  Every authenticated page has a persistent **sidebar**: Dashboard, one
@@ -230,6 +313,30 @@ app.include_router(
230
313
  - Per-session CSRF token is generated at login and required by every form POST (login, logout, create, edit, delete, bulk actions).
231
314
  - `secret_key` must be at least 32 bytes — short keys raise `ValueError` at construction time.
232
315
 
316
+ !!! danger "Login looping? It's the cookie `Secure` flag over plain HTTP"
317
+ If `POST /admin/login` returns `303` (looks like success), but the following
318
+ `GET /admin/` redirects back to the login — forever — the session cookie is
319
+ **not coming back**. Almost-certain cause: `cookie_secure=True` while the
320
+ admin is served over **plain HTTP** (no TLS terminator in front). The browser
321
+ refuses to store a `Secure` cookie on a non-HTTPS connection, so no session
322
+ ever persists.
323
+
324
+ ```python
325
+ # ❌ Tied to DEBUG: in production DEBUG=false → cookie_secure=True,
326
+ # but with no HTTPS in front the login loops.
327
+ make_admin_router(..., cookie_secure=not settings.DEBUG)
328
+
329
+ # ✅ Dedicated toggle, independent of DEBUG:
330
+ make_admin_router(..., cookie_secure=settings.ADMIN_COOKIE_SECURE)
331
+ ```
332
+
333
+ **Right fix:** put HTTPS in front (nginx/Caddy terminating TLS) and keep
334
+ `cookie_secure=True` — the admin session cookie must not travel in the clear.
335
+ **Stopgap** only when the admin genuinely runs over HTTP (intranet, MVP):
336
+ `cookie_secure=False`, aware the session ships without `Secure`. Don't tie
337
+ this flag to `DEBUG` — turning debug on in production is worse than the
338
+ original problem.
339
+
233
340
  #### 5. Plug in a custom auth backend
234
341
 
235
342
  `AdminAuthBackend` is an ABC, so swap the default for LDAP / OAuth / external IAM by subclassing:
@@ -1,7 +1,7 @@
1
1
  # Painel admin
2
2
 
3
3
 
4
- UI de gerenciamento no estilo Django montada sob `/admin`. Operadores entram com uma linha de usuário do banco (sem store de senha de admin separado) e navegam por todo modelo registrado pelo navegador, então a porta do banco pode ficar fechada em redes privadas. O painel é completo (paridade com o Django admin): list view com busca / filtros por campo / colunas ordenáveis, CRUD completo (criar / editar / excluir), ações em massa, export CSV/JSON, widgets FK-select, dashboard com contagens de linhas + métricas de sistema, MFA TOTP opcional no login, e trilha de auditoria carimbando `created_by` / `updated_by`. Ainda no roadmap: upload de arquivo e edição inline/relacionada.
4
+ UI de gerenciamento no estilo Django montada sob `/admin`. Operadores entram com uma linha de usuário do banco (sem store de senha de admin separado) e navegam por todo modelo registrado pelo navegador, então a porta do banco pode ficar fechada em redes privadas. O painel é completo (paridade com o Django admin): list view com busca / filtros ricos por campo (enum / FK / range de data) / colunas ordenáveis, CRUD completo (criar / editar / excluir), ações em massa, export CSV/JSON, widgets FK-select, dashboard com contagens de linhas + métricas de sistema, MFA TOTP opcional no login, campos de upload de arquivo/imagem, e trilha de auditoria carimbando `created_by` / `updated_by`. Ainda no roadmap: edição inline/relacionada.
5
5
 
6
6
  Requer o extra `[admin]`:
7
7
 
@@ -88,6 +88,15 @@ site.register(AdminModel(
88
88
 
89
89
  Toda referência a campo também aceita uma string simples (`list_display=["email", ...]`) para configuração dinâmica, e `ordering` aceita uma coluna (ascendente), `desc(column)` / `asc(column)`, ou uma string no estilo Django `"-created_at"`. `register` retorna a instância e levanta `ValueError` em slug duplicado. Os slugs derivam por padrão do `__tablename__` do modelo, para que URLs e tabelas do banco fiquem em sincronia.
90
90
 
91
+ !!! info "Filtros automáticos por tipo de coluna"
92
+ Cada campo em `list_filter` vira o widget certo conforme o tipo da
93
+ coluna: **boolean** → dropdown Sim/Não; **enum** → dropdown com os
94
+ membros; **FK** (cujo destino tem `AdminModel` registrado) → dropdown
95
+ das linhas relacionadas (label pelo `search_fields`); **date/datetime**
96
+ → dois inputs de data (de/até, range inclusivo); qualquer outra coluna
97
+ → input de texto (igualdade). Tudo preserva busca/ordenação/paginação
98
+ na URL.
99
+
91
100
  !!! tip "Marca centralizada e customizável"
92
101
  O nome exibido no centro do header vem de `brand` (opcional). Sem ele, cai no `title` — então sites existentes não mudam. Use `brand` para mostrar um nome distinto (ex.: `"servus-backend-admin"`) centralizado no topo de toda página. A sidebar é fixa e **sobrepõe header e footer** no desktop (z-index maior) — comportamento automático do CSS embutido, sem config.
93
102
 
@@ -160,7 +169,7 @@ app.include_router(
160
169
  - `GET /admin/logs` — **logs da aplicação** (quando `show_logs=True`): lê os arquivos JSON estruturados escritos pelo `configure_logging(log_dir=…)`, com filtro por fonte (`?source=`), busca em texto (`?q=`) e paginação. Badges coloridos por nível. Quando ainda não há arquivos de log, mostra um estado vazio.
161
170
  - `GET /admin/m/{slug}/` — list view com paginação + busca em texto livre (`?q=`) + filtros por campo (`?filter_<field>=value`) + **ordenação por coluna** clicável (`?sort=<coluna>&dir=asc|desc`).
162
171
  - `GET /admin/m/{slug}/export.csv` / `export.json` — **exporta** o resultado atual (respeitando busca/filtros/ordenação) como CSV ou JSON. Limite de linhas via `make_admin_router(export_max_rows=…)` (default 5000).
163
- - `POST /admin/m/{slug}/bulk` — **ações em massa** (delete / activate / deactivate) nas linhas selecionadas.
172
+ - `POST /admin/m/{slug}/bulk` — **ações em massa** (delete / activate / deactivate + suas **ações customizadas**) nas linhas selecionadas.
164
173
  - `GET/POST /admin/m/{slug}/new` — **criar** registro (quando `can_create`).
165
174
  - `GET /admin/m/{slug}/{identity}` — detail view com botões Edit/Delete.
166
175
  - `GET/POST /admin/m/{slug}/{identity}/edit` — **editar** registro (quando `can_edit`).
@@ -178,7 +187,81 @@ app.include_router(
178
187
 
179
188
  **Audit trail**: create/edit pelo admin carimba `created_by`/`updated_by` (do `AuditMixin`) com o id do admin atuante; o detail mostra um painel **Audit** com timestamps e — quando o modelo tem as colunas de auditoria — o ator (UUID resolvido para nome via o auth backend). Modelos sem `AuditMixin` mostram só os timestamps.
180
189
 
181
- Ainda **não** incluídos (fases futuras do roadmap): upload de arquivo, inline/related editing.
190
+ Ainda **não** incluídos (fases futuras do roadmap): inline/related editing.
191
+
192
+ ## Ações customizadas (`@admin_action`)
193
+
194
+ Além das 3 fixas (activate / deactivate / delete), você registra **ações
195
+ próprias** — uma função async decorada com `@admin_action` e passada em
196
+ `AdminModel(actions=[...])`. Cada uma vira uma opção no dropdown de ações
197
+ em massa, operando nas linhas marcadas.
198
+
199
+ ```python
200
+ from tempest_fastapi_sdk import (
201
+ AdminActionContext,
202
+ AdminActionResult,
203
+ AdminModel,
204
+ admin_action,
205
+ )
206
+
207
+
208
+ @admin_action(label="Enviar boas-vindas")
209
+ async def send_welcome(ctx: AdminActionContext) -> AdminActionResult:
210
+ """Roda nas linhas selecionadas; a mensagem é exibida na list view."""
211
+ users = await ctx.repository.list(filters={"id": ctx.ids})
212
+ for user in users:
213
+ await mailer.send_welcome(user.email)
214
+ return AdminActionResult(f"{len(users)} e-mails enviados.")
215
+
216
+
217
+ site.register(AdminModel(model=UserModel, actions=[send_welcome]))
218
+ ```
219
+
220
+ O handler recebe um `AdminActionContext` com:
221
+
222
+ | Campo | O que é |
223
+ | --- | --- |
224
+ | `ids` | Identidades das linhas marcadas. |
225
+ | `repository` | `BaseRepository` do modelo, na sessão do request. |
226
+ | `db_session` | A sessão DB (pra trabalho além do repositório). |
227
+ | `request` | O request inbound. |
228
+ | `session` | A sessão do admin autenticado. |
229
+ | `principal` | A linha do usuário admin que disparou a ação. |
230
+
231
+ Retorne um `AdminActionResult(message, category="success"|"error"|"warning")`
232
+ pra exibir um banner na list view (ou `None` pra não mostrar nada). A
233
+ função fica **diretamente chamável/testável** — o decorator só anexa
234
+ metadados. Use `name=` pra fixar o identificador (default: nome da função)
235
+ e `dangerous=True` pra marcar ação destrutiva.
236
+
237
+ ## Campo de upload de arquivo / imagem
238
+
239
+ Uma coluna `String` que guarda o caminho/chave de um arquivo pode virar um
240
+ **input de upload** no formulário. Liste a coluna em `upload_fields` e
241
+ passe um `upload_storage` (os backends que o SDK já tem —
242
+ `LocalUploadStorage` / `MinIOUploadStorage`). No submit, o arquivo é
243
+ salvo no storage e a **chave retornada** é gravada na coluna.
244
+
245
+ ```python
246
+ from tempest_fastapi_sdk import AdminModel
247
+ from tempest_fastapi_sdk.utils import LocalUploadStorage
248
+
249
+
250
+ site.register(AdminModel(
251
+ model=DocumentModel,
252
+ upload_fields=[DocumentModel.attachment], # coluna String que guarda a chave
253
+ upload_storage=LocalUploadStorage("media/"), # ou MinIOUploadStorage(...)
254
+ ))
255
+ ```
256
+
257
+ - O form vira `multipart/form-data` automaticamente quando há `upload_fields`.
258
+ - **Create**: arquivo obrigatório só se a coluna for `NOT NULL` e sem default.
259
+ - **Edit**: sem arquivo novo → mantém o valor atual (mostra "Current: …"); com arquivo → substitui.
260
+ - A coluna guarda a **chave** do storage (`<slug>/<campo>/<uuid>.<ext>`); use o `upload_storage` (ou `UploadUtils`) pra servir/baixar depois.
261
+
262
+ !!! warning "`upload_fields` exige `upload_storage`"
263
+ Registrar `upload_fields` sem `upload_storage` levanta `ValueError` na
264
+ construção do `AdminModel` — sem storage não há onde gravar o arquivo.
182
265
 
183
266
  !!! tip "Navegação por sidebar + burger"
184
267
  Toda página autenticada tem uma **sidebar** persistente: Dashboard, um
@@ -212,6 +295,28 @@ app.include_router(
212
295
  - Um token CSRF por sessão é gerado no login e exigido por todo POST de formulário (login, logout, criar, editar, excluir, ações em massa).
213
296
  - `secret_key` deve ter ao menos 32 bytes — chaves curtas levantam `ValueError` no momento da construção.
214
297
 
298
+ !!! danger "Login em loop? É o `Secure` do cookie sobre HTTP puro"
299
+ Se o `POST /admin/login` responde `303` (parece sucesso), mas o `GET /admin/`
300
+ seguinte redireciona de volta pro login — repetindo pra sempre — o cookie de
301
+ sessão **não está voltando**. Causa quase certa: `cookie_secure=True` enquanto
302
+ o admin é servido por **HTTP puro** (sem TLS na frente). O browser recusa
303
+ gravar um cookie `Secure` em conexão não-HTTPS, então nenhuma sessão persiste.
304
+
305
+ ```python
306
+ # ❌ Atado a DEBUG: em produção DEBUG=false → cookie_secure=True,
307
+ # mas se não houver HTTPS na frente, o login entra em loop.
308
+ make_admin_router(..., cookie_secure=not settings.DEBUG)
309
+
310
+ # ✅ Controle dedicado, independente de DEBUG:
311
+ make_admin_router(..., cookie_secure=settings.ADMIN_COOKIE_SECURE)
312
+ ```
313
+
314
+ **Correção certa:** ponha HTTPS na frente (nginx/Caddy terminando TLS) e
315
+ deixe `cookie_secure=True` — o cookie da sessão admin não deve trafegar em
316
+ claro. **Paliativo** só quando o admin roda mesmo em HTTP (intranet, MVP):
317
+ `cookie_secure=False`, ciente de que a sessão vai sem `Secure`. Não amarre
318
+ esse flag ao `DEBUG` — ligar debug em produção é pior que o problema original.
319
+
215
320
  #### 5. Plugue um backend de auth customizado
216
321
 
217
322
  `AdminAuthBackend` é uma ABC, então troque o default por LDAP / OAuth / IAM externo subclasseando: