tempest-fastapi-sdk 0.43.0__tar.gz → 0.45.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 (383) hide show
  1. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/CHANGELOG.md +52 -0
  2. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/PKG-INFO +2 -2
  3. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/README.md +1 -1
  4. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/docs/recipes/index.en.md +2 -0
  5. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/docs/recipes/index.md +2 -0
  6. tempest_fastapi_sdk-0.45.0/docs/recipes/multi-tenant.en.md +120 -0
  7. tempest_fastapi_sdk-0.45.0/docs/recipes/multi-tenant.md +120 -0
  8. tempest_fastapi_sdk-0.45.0/docs/recipes/outbox.en.md +121 -0
  9. tempest_fastapi_sdk-0.45.0/docs/recipes/outbox.md +120 -0
  10. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/docs/reference.md +4 -0
  11. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/mkdocs.yml +4 -0
  12. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/pyproject.toml +1 -1
  13. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/__init__.py +9 -1
  14. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/db/__init__.py +10 -0
  15. tempest_fastapi_sdk-0.45.0/tempest_fastapi_sdk/db/outbox.py +352 -0
  16. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/db/repository.py +47 -0
  17. tempest_fastapi_sdk-0.45.0/tempest_fastapi_sdk/db/tenant.py +348 -0
  18. tempest_fastapi_sdk-0.45.0/tests/db/test_outbox.py +179 -0
  19. tempest_fastapi_sdk-0.45.0/tests/db/test_tenant.py +170 -0
  20. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/uv.lock +45 -45
  21. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/.github/workflows/ci.yml +0 -0
  22. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/.github/workflows/docs.yml +0 -0
  23. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/.github/workflows/release-pypi.yml +0 -0
  24. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/.gitignore +0 -0
  25. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/.python-version +0 -0
  26. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/CLAUDE.md +0 -0
  27. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/Makefile +0 -0
  28. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/docs/architecture.en.md +0 -0
  29. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/docs/architecture.md +0 -0
  30. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/docs/changelog.en.md +0 -0
  31. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/docs/changelog.md +0 -0
  32. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/docs/contributing.en.md +0 -0
  33. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/docs/contributing.md +0 -0
  34. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/docs/index.en.md +0 -0
  35. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/docs/index.md +0 -0
  36. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/docs/installation.en.md +0 -0
  37. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/docs/installation.md +0 -0
  38. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/docs/learning/index.en.md +0 -0
  39. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/docs/learning/index.md +0 -0
  40. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/docs/learning/marketplace/api.en.md +0 -0
  41. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/docs/learning/marketplace/api.md +0 -0
  42. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/docs/learning/marketplace/business-rules.en.md +0 -0
  43. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/docs/learning/marketplace/business-rules.md +0 -0
  44. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/docs/learning/marketplace/domain.en.md +0 -0
  45. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/docs/learning/marketplace/domain.md +0 -0
  46. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/docs/learning/marketplace/flows.en.md +0 -0
  47. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/docs/learning/marketplace/flows.md +0 -0
  48. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/docs/learning/marketplace/index.en.md +0 -0
  49. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/docs/learning/marketplace/index.md +0 -0
  50. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/docs/migration.en.md +0 -0
  51. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/docs/migration.md +0 -0
  52. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/docs/recipes/admin.en.md +0 -0
  53. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/docs/recipes/admin.md +0 -0
  54. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/docs/recipes/auth-flow.en.md +0 -0
  55. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/docs/recipes/auth-flow.md +0 -0
  56. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/docs/recipes/br-helpers.en.md +0 -0
  57. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/docs/recipes/br-helpers.md +0 -0
  58. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/docs/recipes/cache.en.md +0 -0
  59. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/docs/recipes/cache.md +0 -0
  60. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/docs/recipes/cli.en.md +0 -0
  61. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/docs/recipes/cli.md +0 -0
  62. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/docs/recipes/database.en.md +0 -0
  63. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/docs/recipes/database.md +0 -0
  64. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/docs/recipes/downloads.en.md +0 -0
  65. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/docs/recipes/downloads.md +0 -0
  66. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/docs/recipes/email.en.md +0 -0
  67. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/docs/recipes/email.md +0 -0
  68. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/docs/recipes/http-client.en.md +0 -0
  69. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/docs/recipes/http-client.md +0 -0
  70. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/docs/recipes/http.en.md +0 -0
  71. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/docs/recipes/http.md +0 -0
  72. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/docs/recipes/idempotency.en.md +0 -0
  73. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/docs/recipes/idempotency.md +0 -0
  74. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/docs/recipes/logging.en.md +0 -0
  75. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/docs/recipes/logging.md +0 -0
  76. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/docs/recipes/metrics.en.md +0 -0
  77. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/docs/recipes/metrics.md +0 -0
  78. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/docs/recipes/mfa.en.md +0 -0
  79. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/docs/recipes/mfa.md +0 -0
  80. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/docs/recipes/observability.en.md +0 -0
  81. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/docs/recipes/observability.md +0 -0
  82. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/docs/recipes/queue-tasks.en.md +0 -0
  83. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/docs/recipes/queue-tasks.md +0 -0
  84. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/docs/recipes/realtime.en.md +0 -0
  85. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/docs/recipes/realtime.md +0 -0
  86. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/docs/recipes/security.en.md +0 -0
  87. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/docs/recipes/security.md +0 -0
  88. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/docs/recipes/sessions.en.md +0 -0
  89. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/docs/recipes/sessions.md +0 -0
  90. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/docs/recipes/storage.en.md +0 -0
  91. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/docs/recipes/storage.md +0 -0
  92. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/docs/recipes/testing.en.md +0 -0
  93. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/docs/recipes/testing.md +0 -0
  94. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/docs/recipes/uploads.en.md +0 -0
  95. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/docs/recipes/uploads.md +0 -0
  96. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/docs/recipes/utilities.en.md +0 -0
  97. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/docs/recipes/utilities.md +0 -0
  98. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/docs/recipes/webpush.en.md +0 -0
  99. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/docs/recipes/webpush.md +0 -0
  100. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/docs/recipes/websocket.en.md +0 -0
  101. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/docs/recipes/websocket.md +0 -0
  102. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/docs/reference.en.md +0 -0
  103. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/docs/roadmap.en.md +0 -0
  104. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/docs/roadmap.md +0 -0
  105. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/docs/tutorial.en.md +0 -0
  106. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/docs/tutorial.md +0 -0
  107. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/scripts/extract_recipe.py +0 -0
  108. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/admin/__init__.py +0 -0
  109. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/admin/auth.py +0 -0
  110. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/admin/config.py +0 -0
  111. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/admin/forms.py +0 -0
  112. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/admin/router.py +0 -0
  113. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/admin/session.py +0 -0
  114. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/admin/site.py +0 -0
  115. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/admin/static/admin.css +0 -0
  116. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/admin/templates/base.html +0 -0
  117. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/admin/templates/dashboard.html +0 -0
  118. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/admin/templates/detail.html +0 -0
  119. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/admin/templates/form.html +0 -0
  120. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/admin/templates/list.html +0 -0
  121. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/admin/templates/login.html +0 -0
  122. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/admin/templates/logs.html +0 -0
  123. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/admin/templates/mfa.html +0 -0
  124. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/api/__init__.py +0 -0
  125. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/api/cookies.py +0 -0
  126. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/api/dependencies/__init__.py +0 -0
  127. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/api/dependencies/auth.py +0 -0
  128. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/api/handlers.py +0 -0
  129. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/api/middlewares/__init__.py +0 -0
  130. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/api/middlewares/body_size.py +0 -0
  131. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/api/middlewares/cors.py +0 -0
  132. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/api/middlewares/csrf.py +0 -0
  133. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/api/middlewares/idempotency.py +0 -0
  134. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/api/middlewares/rate_limit.py +0 -0
  135. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/api/middlewares/request_id.py +0 -0
  136. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/api/oauth.py +0 -0
  137. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/api/routers/__init__.py +0 -0
  138. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/api/routers/health.py +0 -0
  139. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/api/routers/logs.py +0 -0
  140. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/api/routers/metrics.py +0 -0
  141. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/api/routers/tool_spec.py +0 -0
  142. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/api/server.py +0 -0
  143. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/api/static.py +0 -0
  144. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/api/tracing.py +0 -0
  145. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/api/webhooks.py +0 -0
  146. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/auth/__init__.py +0 -0
  147. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/auth/page_renderer.py +0 -0
  148. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/auth/router.py +0 -0
  149. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/auth/schemas.py +0 -0
  150. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/auth/service.py +0 -0
  151. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/auth/templates/activation.html +0 -0
  152. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/auth/templates/activation_error.html +0 -0
  153. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/auth/templates/activation_success.html +0 -0
  154. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/auth/templates/password_reset.html +0 -0
  155. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/auth/templates/password_reset_error.html +0 -0
  156. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/auth/templates/password_reset_form.html +0 -0
  157. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/auth/templates/password_reset_success.html +0 -0
  158. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/cache/__init__.py +0 -0
  159. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/cache/decorator.py +0 -0
  160. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/cache/redis_manager.py +0 -0
  161. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/cli/__init__.py +0 -0
  162. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/cli/_templates/README.md.tmpl +0 -0
  163. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/cli/_templates/env.example.tmpl +0 -0
  164. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/cli/_templates/gitignore.tmpl +0 -0
  165. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/cli/_templates/main.py.tmpl +0 -0
  166. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/cli/_templates/pyproject.toml.tmpl +0 -0
  167. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/cli/_templates/src/__init__.py.tmpl +0 -0
  168. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/cli/_templates/src/api/__init__.py.tmpl +0 -0
  169. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/cli/_templates/src/api/app.py.tmpl +0 -0
  170. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/cli/_templates/src/api/dependencies/__init__.py.tmpl +0 -0
  171. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/cli/_templates/src/api/dependencies/auth.py.tmpl +0 -0
  172. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/cli/_templates/src/api/dependencies/resources.py.tmpl +0 -0
  173. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/cli/_templates/src/api/routers/__init__.py.tmpl +0 -0
  174. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/cli/_templates/src/controllers/__init__.py.tmpl +0 -0
  175. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/cli/_templates/src/core/__init__.py.tmpl +0 -0
  176. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/cli/_templates/src/core/exceptions.py.tmpl +0 -0
  177. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/cli/_templates/src/core/settings.py.tmpl +0 -0
  178. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/cli/_templates/src/db/__init__.py.tmpl +0 -0
  179. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/cli/_templates/src/db/models/__init__.py.tmpl +0 -0
  180. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/cli/_templates/src/db/models/user.py.tmpl +0 -0
  181. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/cli/_templates/src/db/repositories/__init__.py.tmpl +0 -0
  182. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/cli/_templates/src/schemas/__init__.py.tmpl +0 -0
  183. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/cli/_templates/src/server.py.tmpl +0 -0
  184. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/cli/_templates/src/services/__init__.py.tmpl +0 -0
  185. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/cli/_templates/src/utils/__init__.py.tmpl +0 -0
  186. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/cli/_templates/tests/__init__.py.tmpl +0 -0
  187. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/cli/_templates/tests/test_smoke.py.tmpl +0 -0
  188. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/cli/db.py +0 -0
  189. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/cli/docker_compose.py +0 -0
  190. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/cli/generate.py +0 -0
  191. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/cli/lint.py +0 -0
  192. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/cli/main.py +0 -0
  193. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/cli/new.py +0 -0
  194. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/cli/src_layers.py +0 -0
  195. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/cli/user.py +0 -0
  196. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/controllers/__init__.py +0 -0
  197. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/controllers/base.py +0 -0
  198. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/core/__init__.py +0 -0
  199. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/core/context.py +0 -0
  200. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/core/enums.py +0 -0
  201. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/core/logging.py +0 -0
  202. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/db/_alembic_templates/__init__.py +0 -0
  203. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/db/_alembic_templates/env.py.template +0 -0
  204. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/db/alembic_hooks.py +0 -0
  205. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/db/connection.py +0 -0
  206. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/db/migrations.py +0 -0
  207. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/db/mixins.py +0 -0
  208. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/db/model.py +0 -0
  209. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/db/slow_query.py +0 -0
  210. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/db/user_model.py +0 -0
  211. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/db/user_recovery_code_model.py +0 -0
  212. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/db/user_token_model.py +0 -0
  213. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/exceptions/__init__.py +0 -0
  214. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/exceptions/base.py +0 -0
  215. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/exceptions/conflict.py +0 -0
  216. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/exceptions/forbidden.py +0 -0
  217. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/exceptions/jwt.py +0 -0
  218. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/exceptions/not_found.py +0 -0
  219. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/exceptions/too_many_requests.py +0 -0
  220. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/exceptions/unauthorized.py +0 -0
  221. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/exceptions/upload.py +0 -0
  222. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/exceptions/validation.py +0 -0
  223. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/py.typed +0 -0
  224. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/queue/__init__.py +0 -0
  225. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/queue/manager.py +0 -0
  226. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/schemas/__init__.py +0 -0
  227. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/schemas/base.py +0 -0
  228. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/schemas/link_headers.py +0 -0
  229. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/schemas/logs.py +0 -0
  230. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/schemas/pagination.py +0 -0
  231. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/schemas/response.py +0 -0
  232. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/services/__init__.py +0 -0
  233. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/services/base.py +0 -0
  234. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/sessions/__init__.py +0 -0
  235. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/sessions/dependencies.py +0 -0
  236. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/sessions/middleware.py +0 -0
  237. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/sessions/router.py +0 -0
  238. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/sessions/schemas.py +0 -0
  239. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/sessions/service.py +0 -0
  240. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/sessions/store.py +0 -0
  241. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/settings/__init__.py +0 -0
  242. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/settings/base.py +0 -0
  243. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/settings/mixins.py +0 -0
  244. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/sse/__init__.py +0 -0
  245. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/sse/event_stream.py +0 -0
  246. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/storage/__init__.py +0 -0
  247. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/storage/minio_client.py +0 -0
  248. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/tasks/__init__.py +0 -0
  249. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/tasks/manager.py +0 -0
  250. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/tasks/scheduler.py +0 -0
  251. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/testing/__init__.py +0 -0
  252. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/testing/database.py +0 -0
  253. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/utils/__init__.py +0 -0
  254. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/utils/client_ip.py +0 -0
  255. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/utils/datetime.py +0 -0
  256. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/utils/dict.py +0 -0
  257. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/utils/download.py +0 -0
  258. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/utils/email.py +0 -0
  259. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/utils/http_client.py +0 -0
  260. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/utils/jwt.py +0 -0
  261. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/utils/log.py +0 -0
  262. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/utils/metrics.py +0 -0
  263. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/utils/opaque_token.py +0 -0
  264. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/utils/password.py +0 -0
  265. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/utils/regex.py +0 -0
  266. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/utils/storage_backends.py +0 -0
  267. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/utils/throttle.py +0 -0
  268. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/utils/totp.py +0 -0
  269. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/utils/upload.py +0 -0
  270. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/webpush/__init__.py +0 -0
  271. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/webpush/dispatcher.py +0 -0
  272. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/webpush/schemas.py +0 -0
  273. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/websockets/__init__.py +0 -0
  274. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/websockets/hub.py +0 -0
  275. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/websockets/router.py +0 -0
  276. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/websockets/schemas.py +0 -0
  277. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/__init__.py +0 -0
  278. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/admin/__init__.py +0 -0
  279. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/admin/test_auth.py +0 -0
  280. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/admin/test_forms.py +0 -0
  281. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/admin/test_logs_nav.py +0 -0
  282. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/admin/test_mfa.py +0 -0
  283. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/admin/test_router.py +0 -0
  284. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/admin/test_site.py +0 -0
  285. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/admin/test_user_model.py +0 -0
  286. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/api/__init__.py +0 -0
  287. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/api/test_body_size.py +0 -0
  288. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/api/test_cookies.py +0 -0
  289. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/api/test_cors.py +0 -0
  290. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/api/test_csrf.py +0 -0
  291. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/api/test_dependencies_auth.py +0 -0
  292. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/api/test_handlers.py +0 -0
  293. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/api/test_health_router.py +0 -0
  294. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/api/test_idempotency.py +0 -0
  295. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/api/test_jwt_dependency.py +0 -0
  296. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/api/test_logs_router.py +0 -0
  297. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/api/test_oauth.py +0 -0
  298. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/api/test_prometheus.py +0 -0
  299. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/api/test_rate_limit.py +0 -0
  300. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/api/test_request_id_middleware.py +0 -0
  301. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/api/test_role_dependency.py +0 -0
  302. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/api/test_server.py +0 -0
  303. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/api/test_static.py +0 -0
  304. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/api/test_tool_spec.py +0 -0
  305. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/api/test_tracing.py +0 -0
  306. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/api/test_webhooks.py +0 -0
  307. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/api/test_webhooks_rsa.py +0 -0
  308. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/auth/__init__.py +0 -0
  309. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/auth/test_mfa.py +0 -0
  310. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/auth/test_service.py +0 -0
  311. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/cache/__init__.py +0 -0
  312. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/cache/test_decorator.py +0 -0
  313. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/cache/test_redis_manager.py +0 -0
  314. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/cli/__init__.py +0 -0
  315. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/cli/test_db.py +0 -0
  316. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/cli/test_docker_compose.py +0 -0
  317. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/cli/test_generate.py +0 -0
  318. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/cli/test_main.py +0 -0
  319. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/cli/test_user.py +0 -0
  320. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/conftest.py +0 -0
  321. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/controllers/__init__.py +0 -0
  322. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/controllers/test_base.py +0 -0
  323. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/core/__init__.py +0 -0
  324. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/core/test_context.py +0 -0
  325. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/core/test_enums.py +0 -0
  326. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/core/test_logging.py +0 -0
  327. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/db/__init__.py +0 -0
  328. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/db/test_alembic_hooks.py +0 -0
  329. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/db/test_bulk_ops.py +0 -0
  330. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/db/test_connection.py +0 -0
  331. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/db/test_migrations.py +0 -0
  332. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/db/test_mixins.py +0 -0
  333. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/db/test_model.py +0 -0
  334. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/db/test_repository.py +0 -0
  335. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/db/test_slow_query.py +0 -0
  336. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/exceptions/__init__.py +0 -0
  337. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/exceptions/test_exceptions.py +0 -0
  338. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/queue/__init__.py +0 -0
  339. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/queue/test_manager.py +0 -0
  340. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/schemas/__init__.py +0 -0
  341. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/schemas/test_base.py +0 -0
  342. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/schemas/test_cursor_pagination.py +0 -0
  343. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/schemas/test_link_headers.py +0 -0
  344. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/schemas/test_pagination.py +0 -0
  345. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/schemas/test_response.py +0 -0
  346. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/services/__init__.py +0 -0
  347. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/services/test_base.py +0 -0
  348. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/sessions/__init__.py +0 -0
  349. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/sessions/test_sessions.py +0 -0
  350. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/settings/__init__.py +0 -0
  351. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/settings/test_base.py +0 -0
  352. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/settings/test_mixins.py +0 -0
  353. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/sse/__init__.py +0 -0
  354. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/sse/test_event_stream.py +0 -0
  355. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/storage/__init__.py +0 -0
  356. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/storage/test_minio_client.py +0 -0
  357. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/tasks/__init__.py +0 -0
  358. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/tasks/test_manager.py +0 -0
  359. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/tasks/test_scheduler.py +0 -0
  360. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/testing/__init__.py +0 -0
  361. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/testing/test_database.py +0 -0
  362. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/utils/__init__.py +0 -0
  363. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/utils/test_client_ip.py +0 -0
  364. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/utils/test_datetime.py +0 -0
  365. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/utils/test_dict.py +0 -0
  366. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/utils/test_download.py +0 -0
  367. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/utils/test_email.py +0 -0
  368. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/utils/test_http_client.py +0 -0
  369. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/utils/test_jwt.py +0 -0
  370. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/utils/test_lazy_extras.py +0 -0
  371. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/utils/test_log.py +0 -0
  372. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/utils/test_metrics.py +0 -0
  373. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/utils/test_opaque_token.py +0 -0
  374. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/utils/test_password.py +0 -0
  375. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/utils/test_regex.py +0 -0
  376. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/utils/test_storage_backends.py +0 -0
  377. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/utils/test_throttle.py +0 -0
  378. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/utils/test_upload.py +0 -0
  379. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/webpush/__init__.py +0 -0
  380. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/webpush/test_dispatcher.py +0 -0
  381. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/webpush/test_schemas.py +0 -0
  382. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/websockets/__init__.py +0 -0
  383. {tempest_fastapi_sdk-0.43.0 → tempest_fastapi_sdk-0.45.0}/tests/websockets/test_hub_and_router.py +0 -0
@@ -5,6 +5,58 @@ 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.45.0] — 2026-06-11
9
+
10
+ ### Added
11
+
12
+ - **`TenantScopedRepository[ModelType]`** — a `BaseRepository` locked
13
+ to a single tenant for shared-schema multi-tenancy. Bind a
14
+ `tenant_id` (and optional `tenant_field`, default `"tenant_id"`) at
15
+ construction; it injects `WHERE tenant_id = ?` into **every** read
16
+ (`get`/`get_or_none`/`get_by_id`/`exists`/`first`/`list`/`count`/
17
+ `paginate`/`cursor_paginate`/`delete_many`) and stamps the tenant id
18
+ onto **every** write (`add`/`add_all`). `delete` / `delete_batch` add
19
+ the tenant predicate to the `DELETE` so a guessed id from another
20
+ tenant matches nothing — cross-tenant access (even probing existence
21
+ by id) is impossible through the repository. The constructor raises
22
+ `AttributeError` at boot if the model lacks the tenant column.
23
+ `tenant_column` property exposes the mapped column for custom queries.
24
+
25
+ ### Docs
26
+
27
+ - New bilingual recipe **Multi-tenant**, added to the nav (under
28
+ Database), the recipes index, and the API reference.
29
+
30
+ ## [0.44.0] — 2026-06-11
31
+
32
+ ### Added
33
+
34
+ - **Transactional outbox.** New `BaseOutboxModel` (abstract — the
35
+ project subclasses it and picks `__tablename__`) carrying `topic`,
36
+ `payload` (JSON), `status`, `attempts` / `max_attempts`,
37
+ `available_at`, `sent_at` and `last_error`. `OutboxModel.new_event(
38
+ topic, payload)` builds a pending row.
39
+ - **`BaseRepository.save_with_outbox(model, event)`** inserts the
40
+ business row and the outbox event in the **same transaction**, so an
41
+ event can never reference a rolled-back row (and a committed row
42
+ always has its event durably queued) — the fix for the dual-write
43
+ problem.
44
+ - **`OutboxRelay`** drains pending rows and publishes them through a
45
+ caller-supplied async `publish` callable (no hard broker dependency
46
+ — works with `AsyncBrokerManager`, a webhook, a test spy). Marks each
47
+ row `sent`; on failure increments `attempts`, records `last_error`,
48
+ reschedules with exponential backoff, and marks `failed` once the
49
+ attempt budget is spent. Locks the batch with `FOR UPDATE SKIP
50
+ LOCKED` on PostgreSQL/MySQL (multi-worker safe), falling back to a
51
+ plain select on SQLite. `drain_once()` for one batch (tests/cron),
52
+ `run(poll_interval=...)` for the loop.
53
+ - **`OutboxStatus`** enum (`pending` / `sent` / `failed`).
54
+
55
+ ### Docs
56
+
57
+ - New bilingual recipe **Outbox transacional / Transactional outbox**,
58
+ added to the nav, the recipes index, and the API reference.
59
+
8
60
  ## [0.43.0] — 2026-06-11
9
61
 
10
62
  ### Added
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tempest-fastapi-sdk
3
- Version: 0.43.0
3
+ Version: 0.45.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
@@ -238,7 +238,7 @@ Since `0.7.1` every optional dependency is imported lazily at first instantiatio
238
238
  | Module | Exports |
239
239
  | --- | --- |
240
240
  | `tempest_fastapi_sdk.schemas` | `BaseSchema`, `BaseResponseSchema`, `BasePaginationFilterSchema`, `BasePaginationSchema[T]`, `CursorPaginationFilterSchema`, `CursorPaginationSchema`, `LogEntrySchema`, `encode_cursor`, `decode_cursor`, `build_pagination_link_header` |
241
- | `tempest_fastapi_sdk.db` | `BaseModel`, `BaseUserModel`, `BaseUserTokenModel`, `BaseUserRecoveryCodeModel`, `make_user_recovery_code_model`, `UserTokenPurpose`, `BaseRepository[ModelType]`, `AsyncDatabaseManager`, `AlembicHelper`, `NAMING_CONVENTION`, `AuditMixin`, `SoftDeleteMixin`, `MFAMixin`, `BASE_COLUMN_ORDER`, `reorder_base_columns_first`, `compose_hooks`, `SlowQueryLogger` |
241
+ | `tempest_fastapi_sdk.db` | `BaseModel`, `BaseUserModel`, `BaseUserTokenModel`, `BaseUserRecoveryCodeModel`, `make_user_recovery_code_model`, `UserTokenPurpose`, `BaseRepository[ModelType]`, `TenantScopedRepository[ModelType]`, `AsyncDatabaseManager`, `AlembicHelper`, `NAMING_CONVENTION`, `AuditMixin`, `SoftDeleteMixin`, `MFAMixin`, `BASE_COLUMN_ORDER`, `reorder_base_columns_first`, `compose_hooks`, `SlowQueryLogger`, `BaseOutboxModel`, `OutboxRelay`, `OutboxStatus`, `BaseRepository.save_with_outbox` |
242
242
  | `tempest_fastapi_sdk.exceptions` | `AppException`, `NotFoundException`, `ConflictException`, `ValidationException`, `UnauthorizedException`, `ForbiddenException`, `InvalidTokenException`, `ExpiredTokenException`, `FileTooLargeException`, `InvalidFileTypeException`, `TooManyRequestsException` |
243
243
  | `tempest_fastapi_sdk.settings` | `BaseAppSettings`, `ServerSettings`, `LogSettings`, `DatabaseSettings`, `RedisSettings`, `RabbitMQSettings`, `JWTSettings`, `CORSSettings`, `EmailSettings`, `UploadSettings`, `TokenSettings`, `WebPushSettings`, `TaskIQSettings`, `MinIOSettings`, `AuthSettings` |
244
244
  | `tempest_fastapi_sdk.api` | `register_exception_handlers`, `app_exception_handler`, `apply_cors`, `make_health_router`, `make_logs_router`, `make_prometheus_router`, `make_prometheus_registry`, `PrometheusMiddleware`, `LogSource`, `make_tool_spec_router`, `make_token_dependency`, `make_bearer_token_dependency`, `make_jwt_user_dependency`, `make_role_dependency`, `make_permission_dependency`, `require_x_token`, `run_server`, `RequestIDMiddleware`, `RateLimitMiddleware`, `IdempotencyMiddleware`, `MemoryIdempotencyStore`, `RedisIdempotencyStore`, `BodySizeLimitMiddleware`, `CSRFMiddleware`, `make_csrf_token_dependency`, `WebhookSignatureVerifier`, `RSAWebhookSignatureVerifier`, OAuth2 (`GoogleOAuthClient`, `GitHubOAuthClient`, `OIDCProvider`), `HardenedStaticFiles`, `DEFAULT_STATIC_SECURITY_HEADERS`, `set_cookie`, `clear_cookie`, `SameSite`, `HealthCheck`, `setup_tracing` *(extra: `[otel]`)* |
@@ -136,7 +136,7 @@ Since `0.7.1` every optional dependency is imported lazily at first instantiatio
136
136
  | Module | Exports |
137
137
  | --- | --- |
138
138
  | `tempest_fastapi_sdk.schemas` | `BaseSchema`, `BaseResponseSchema`, `BasePaginationFilterSchema`, `BasePaginationSchema[T]`, `CursorPaginationFilterSchema`, `CursorPaginationSchema`, `LogEntrySchema`, `encode_cursor`, `decode_cursor`, `build_pagination_link_header` |
139
- | `tempest_fastapi_sdk.db` | `BaseModel`, `BaseUserModel`, `BaseUserTokenModel`, `BaseUserRecoveryCodeModel`, `make_user_recovery_code_model`, `UserTokenPurpose`, `BaseRepository[ModelType]`, `AsyncDatabaseManager`, `AlembicHelper`, `NAMING_CONVENTION`, `AuditMixin`, `SoftDeleteMixin`, `MFAMixin`, `BASE_COLUMN_ORDER`, `reorder_base_columns_first`, `compose_hooks`, `SlowQueryLogger` |
139
+ | `tempest_fastapi_sdk.db` | `BaseModel`, `BaseUserModel`, `BaseUserTokenModel`, `BaseUserRecoveryCodeModel`, `make_user_recovery_code_model`, `UserTokenPurpose`, `BaseRepository[ModelType]`, `TenantScopedRepository[ModelType]`, `AsyncDatabaseManager`, `AlembicHelper`, `NAMING_CONVENTION`, `AuditMixin`, `SoftDeleteMixin`, `MFAMixin`, `BASE_COLUMN_ORDER`, `reorder_base_columns_first`, `compose_hooks`, `SlowQueryLogger`, `BaseOutboxModel`, `OutboxRelay`, `OutboxStatus`, `BaseRepository.save_with_outbox` |
140
140
  | `tempest_fastapi_sdk.exceptions` | `AppException`, `NotFoundException`, `ConflictException`, `ValidationException`, `UnauthorizedException`, `ForbiddenException`, `InvalidTokenException`, `ExpiredTokenException`, `FileTooLargeException`, `InvalidFileTypeException`, `TooManyRequestsException` |
141
141
  | `tempest_fastapi_sdk.settings` | `BaseAppSettings`, `ServerSettings`, `LogSettings`, `DatabaseSettings`, `RedisSettings`, `RabbitMQSettings`, `JWTSettings`, `CORSSettings`, `EmailSettings`, `UploadSettings`, `TokenSettings`, `WebPushSettings`, `TaskIQSettings`, `MinIOSettings`, `AuthSettings` |
142
142
  | `tempest_fastapi_sdk.api` | `register_exception_handlers`, `app_exception_handler`, `apply_cors`, `make_health_router`, `make_logs_router`, `make_prometheus_router`, `make_prometheus_registry`, `PrometheusMiddleware`, `LogSource`, `make_tool_spec_router`, `make_token_dependency`, `make_bearer_token_dependency`, `make_jwt_user_dependency`, `make_role_dependency`, `make_permission_dependency`, `require_x_token`, `run_server`, `RequestIDMiddleware`, `RateLimitMiddleware`, `IdempotencyMiddleware`, `MemoryIdempotencyStore`, `RedisIdempotencyStore`, `BodySizeLimitMiddleware`, `CSRFMiddleware`, `make_csrf_token_dependency`, `WebhookSignatureVerifier`, `RSAWebhookSignatureVerifier`, OAuth2 (`GoogleOAuthClient`, `GitHubOAuthClient`, `OIDCProvider`), `HardenedStaticFiles`, `DEFAULT_STATIC_SECURITY_HEADERS`, `set_cookie`, `clear_cookie`, `SameSite`, `HealthCheck`, `setup_tracing` *(extra: `[otel]`)* |
@@ -10,11 +10,13 @@ Bite-sized "I want to wire X" walkthroughs. Each page starts with **what problem
10
10
  | Theme | Covers |
11
11
  | --- | --- |
12
12
  | **[Database »](database.md)** | `BaseRepository`, `BaseModel`, `AuditMixin` / `SoftDeleteMixin`, cursor pagination, Alembic helper |
13
+ | **[Multi-tenant »](multi-tenant.md)** | `TenantScopedRepository` — `tenant_id` isolation on every query |
13
14
  | **[HTTP layer »](http.md)** | `apply_cors`, `RequestIDMiddleware`, `RateLimitMiddleware`, `make_health_router`, JWT / role / permission dependencies, webhook signature verifier, pagination Link headers, tool-spec router |
14
15
  | **[HTTP client (outbound) »](http-client.md)** | `HTTPClient` — typed httpx with retry/backoff, circuit-breaker, X-Request-ID; `RetryPolicy`, `CircuitOpenError` |
15
16
  | **[Cache »](cache.md)** | `AsyncRedisManager`, `@cached` decorator |
16
17
  | **[Real-time »](realtime.md)** | Server-Sent Events (`EventStream`, `sse_response`) |
17
18
  | **[Queue & Tasks »](queue-tasks.md)** | FastStream (`AsyncBrokerManager`), TaskIQ (`AsyncTaskBrokerManager`), `AsyncTaskScheduler`, transactional outbox |
19
+ | **[Transactional outbox »](outbox.md)** | `BaseOutboxModel`, `OutboxRelay`, `save_with_outbox` — reliable events |
18
20
  | **[Transactional email »](email.md)** | `EmailUtils` — SMTP, text/HTML body, attachments, Jinja2 templates |
19
21
  | **[Web Push »](webpush.md)** | `WebPushDispatcher`, VAPID schemas, broadcast with pruning |
20
22
  | **[Logging »](logging.md)** | `LogUtils`, structured JSON logging, request-ID propagation |
@@ -10,11 +10,13 @@ Passo a passo curtos no estilo "quero conectar X". Cada página começa com **qu
10
10
  | Tema | Cobre |
11
11
  | --- | --- |
12
12
  | **[Banco de dados »](database.md)** | `BaseRepository`, `BaseModel`, `AuditMixin` / `SoftDeleteMixin`, paginação por cursor, helper de Alembic |
13
+ | **[Multi-tenant »](multi-tenant.md)** | `TenantScopedRepository` — isolamento por `tenant_id` em toda query |
13
14
  | **[Camada HTTP »](http.md)** | `apply_cors`, `RequestIDMiddleware`, `RateLimitMiddleware`, `make_health_router`, dependências de JWT / role / permissão, verificador de assinatura de webhook, headers Link de paginação, router de tool-spec |
14
15
  | **[HTTP client (saída) »](http-client.md)** | `HTTPClient` — httpx tipado com retry/backoff, circuit-breaker, X-Request-ID; `RetryPolicy`, `CircuitOpenError` |
15
16
  | **[Cache »](cache.md)** | `AsyncRedisManager`, decorator `@cached` |
16
17
  | **[Tempo real »](realtime.md)** | Server-Sent Events (`EventStream`, `sse_response`) |
17
18
  | **[Fila e Tarefas »](queue-tasks.md)** | FastStream (`AsyncBrokerManager`), TaskIQ (`AsyncTaskBrokerManager`), `AsyncTaskScheduler`, outbox transacional |
19
+ | **[Outbox transacional »](outbox.md)** | `BaseOutboxModel`, `OutboxRelay`, `save_with_outbox` — eventos confiáveis |
18
20
  | **[Email transacional »](email.md)** | `EmailUtils` — SMTP, corpo texto/HTML, anexos, templates Jinja2 |
19
21
  | **[Web Push »](webpush.md)** | `WebPushDispatcher`, schemas VAPID, broadcast com poda |
20
22
  | **[Logging »](logging.md)** | `LogUtils`, logging JSON estruturado, propagação de request-ID |
@@ -0,0 +1,120 @@
1
+ # Multi-tenant (TenantScopedRepository)
2
+
3
+ In a **shared-schema** multi-tenant database, every tenant's rows live in
4
+ the same table, told apart by a `tenant_id` column. The danger is obvious:
5
+ forget **one** `WHERE tenant_id = ?` and tenant A reads (or deletes)
6
+ tenant B's data. `TenantScopedRepository` takes that risk off the table —
7
+ you bind the `tenant_id` at construction and it injects the filter into
8
+ **every** read and stamps it onto **every** write. Call sites can't get it
9
+ wrong.
10
+
11
+ !!! info "Where this fits"
12
+ It's a `BaseRepository` that behaves identically — same API
13
+ ([Database](database.md)). The difference is invisible to the caller:
14
+ tenant scoping is automatic.
15
+
16
+ ## 1. The model needs a tenant column
17
+
18
+ ```python
19
+ from uuid import UUID
20
+
21
+ from sqlalchemy import String, Uuid
22
+ from sqlalchemy.orm import Mapped, mapped_column
23
+
24
+ from tempest_fastapi_sdk import BaseModel
25
+
26
+
27
+ class OrderModel(BaseModel):
28
+ """Order — isolated per tenant."""
29
+
30
+ __tablename__ = "order"
31
+
32
+ tenant_id: Mapped[UUID] = mapped_column(Uuid(), nullable=False, index=True)
33
+ total: Mapped[int] = mapped_column(nullable=False)
34
+ ```
35
+
36
+ ## 2. Build the repository bound to the tenant
37
+
38
+ The `tenant_id` usually comes from the request's JWT / session / header:
39
+
40
+ ```python
41
+ from uuid import UUID
42
+
43
+ from sqlalchemy.ext.asyncio import AsyncSession
44
+
45
+ from tempest_fastapi_sdk import TenantScopedRepository
46
+
47
+ from src.db.models import OrderModel
48
+
49
+
50
+ def get_order_repo(
51
+ session: AsyncSession, tenant_id: UUID
52
+ ) -> TenantScopedRepository[OrderModel]:
53
+ """Order repository locked to the request's tenant."""
54
+ return TenantScopedRepository(session, model=OrderModel, tenant_id=tenant_id)
55
+ ```
56
+
57
+ If the model has no `tenant_id` column, the constructor raises
58
+ `AttributeError` immediately — you catch the mistake at boot, not in
59
+ production. Different column name? Pass `tenant_field="org_id"`.
60
+
61
+ ## 3. Use it like any repository
62
+
63
+ Every read comes filtered; every write comes stamped:
64
+
65
+ ```python
66
+ from uuid import UUID
67
+
68
+ from tempest_fastapi_sdk import TenantScopedRepository
69
+
70
+ from src.db.models import OrderModel
71
+
72
+
73
+ async def list_orders(repo: TenantScopedRepository[OrderModel]) -> list[OrderModel]:
74
+ """Only THIS tenant's orders — no manual WHERE."""
75
+ return await repo.list() # WHERE tenant_id = <bound tenant>
76
+
77
+
78
+ async def create_order(
79
+ repo: TenantScopedRepository[OrderModel], total: int
80
+ ) -> OrderModel:
81
+ """tenant_id is stamped automatically on insert."""
82
+ return await repo.add(OrderModel(total=total))
83
+ ```
84
+
85
+ ### Cross-tenant access is impossible, even by id
86
+
87
+ `get_by_id`, `delete` and `delete_batch` are scoped too. An id from another
88
+ tenant simply **doesn't match** — indistinguishable from a row that never
89
+ existed:
90
+
91
+ ```python
92
+ from uuid import UUID
93
+
94
+ from tempest_fastapi_sdk import TenantScopedRepository
95
+
96
+ from src.db.models import OrderModel
97
+
98
+
99
+ async def fetch(repo: TenantScopedRepository[OrderModel], order_id: UUID) -> OrderModel:
100
+ """Raises NotFound if the order belongs to ANOTHER tenant — no existence leak."""
101
+ return await repo.get_by_id(order_id)
102
+ ```
103
+
104
+ `delete_many({})` deletes only **this** tenant's rows, never the whole
105
+ table — the tenant predicate is always added.
106
+
107
+ !!! warning "Raw queries are your responsibility"
108
+ A subclass that builds its own `select(...)` without going through
109
+ `_apply_filters` — or a pre-built `query=` passed to `paginate` — is
110
+ **not** auto-scoped. In those cases, add
111
+ `.where(self.tenant_column == self.tenant_id)` yourself.
112
+
113
+ ## Recap
114
+
115
+ - The model declares `tenant_id` (or another column, via `tenant_field=`).
116
+ - `TenantScopedRepository(session, model=..., tenant_id=...)` injects the
117
+ filter into every read and stamps every write.
118
+ - `get_by_id` / `delete` / `delete_batch` / `delete_many` are scoped —
119
+ cross-tenant access is impossible through the repository methods.
120
+ - The constructor validates the tenant column exists at boot.
@@ -0,0 +1,120 @@
1
+ # Multi-tenant (TenantScopedRepository)
2
+
3
+ Num banco multi-tenant de **schema compartilhado**, as linhas de todos os
4
+ tenants moram na mesma tabela, separadas por uma coluna `tenant_id`. O
5
+ perigo é claro: esquecer **um** `WHERE tenant_id = ?` e o tenant A lê (ou
6
+ apaga) os dados do tenant B. `TenantScopedRepository` tira esse risco da
7
+ mesa — você amarra o `tenant_id` na construção e ele injeta o filtro em
8
+ **toda** leitura e carimba em **toda** escrita. Os call sites não têm como
9
+ errar.
10
+
11
+ !!! info "Onde isso encaixa"
12
+ É um `BaseRepository` que se comporta igualzinho — mesma API
13
+ ([Banco de dados](database.md)). A diferença é invisível pro chamador:
14
+ o escopo de tenant é automático.
15
+
16
+ ## 1. O modelo precisa da coluna de tenant
17
+
18
+ ```python
19
+ from uuid import UUID
20
+
21
+ from sqlalchemy import String, Uuid
22
+ from sqlalchemy.orm import Mapped, mapped_column
23
+
24
+ from tempest_fastapi_sdk import BaseModel
25
+
26
+
27
+ class OrderModel(BaseModel):
28
+ """Pedido — isolado por tenant."""
29
+
30
+ __tablename__ = "order"
31
+
32
+ tenant_id: Mapped[UUID] = mapped_column(Uuid(), nullable=False, index=True)
33
+ total: Mapped[int] = mapped_column(nullable=False)
34
+ ```
35
+
36
+ ## 2. Construa o repositório amarrado ao tenant
37
+
38
+ O `tenant_id` normalmente vem do JWT / sessão / header do request:
39
+
40
+ ```python
41
+ from uuid import UUID
42
+
43
+ from sqlalchemy.ext.asyncio import AsyncSession
44
+
45
+ from tempest_fastapi_sdk import TenantScopedRepository
46
+
47
+ from src.db.models import OrderModel
48
+
49
+
50
+ def get_order_repo(
51
+ session: AsyncSession, tenant_id: UUID
52
+ ) -> TenantScopedRepository[OrderModel]:
53
+ """Repositório de pedidos travado no tenant do request."""
54
+ return TenantScopedRepository(session, model=OrderModel, tenant_id=tenant_id)
55
+ ```
56
+
57
+ Se o modelo não tiver a coluna `tenant_id`, o construtor levanta
58
+ `AttributeError` na hora — você descobre o erro no boot, não em produção.
59
+ Coluna com outro nome? Passe `tenant_field="org_id"`.
60
+
61
+ ## 3. Use como qualquer repositório
62
+
63
+ Toda leitura já vem filtrada; toda escrita já vem carimbada:
64
+
65
+ ```python
66
+ from uuid import UUID
67
+
68
+ from tempest_fastapi_sdk import TenantScopedRepository
69
+
70
+ from src.db.models import OrderModel
71
+
72
+
73
+ async def list_orders(repo: TenantScopedRepository[OrderModel]) -> list[OrderModel]:
74
+ """Só os pedidos DESTE tenant — sem WHERE manual."""
75
+ return await repo.list() # WHERE tenant_id = <tenant amarrado>
76
+
77
+
78
+ async def create_order(
79
+ repo: TenantScopedRepository[OrderModel], total: int
80
+ ) -> OrderModel:
81
+ """tenant_id é carimbado automaticamente no insert."""
82
+ return await repo.add(OrderModel(total=total))
83
+ ```
84
+
85
+ ### Acesso cruzado é impossível, mesmo por id
86
+
87
+ `get_by_id`, `delete` e `delete_batch` também são escopados. Um id de outro
88
+ tenant simplesmente **não casa** — é indistinguível de uma linha que nunca
89
+ existiu:
90
+
91
+ ```python
92
+ from uuid import UUID
93
+
94
+ from tempest_fastapi_sdk import TenantScopedRepository
95
+
96
+ from src.db.models import OrderModel
97
+
98
+
99
+ async def fetch(repo: TenantScopedRepository[OrderModel], order_id: UUID) -> OrderModel:
100
+ """Levanta NotFound se o pedido for de OUTRO tenant — sem vazar existência."""
101
+ return await repo.get_by_id(order_id)
102
+ ```
103
+
104
+ `delete_many({})` apaga só as linhas **deste** tenant, nunca a tabela
105
+ inteira — o predicado de tenant é sempre adicionado.
106
+
107
+ !!! warning "Queries cruas são responsabilidade sua"
108
+ Uma subclasse que monta o próprio `select(...)` sem passar por
109
+ `_apply_filters` — ou um `query=` pré-montado passado pro `paginate` —
110
+ **não** é escopado automaticamente. Nesses casos, adicione
111
+ `.where(self.tenant_column == self.tenant_id)` você mesmo.
112
+
113
+ ## Recap
114
+
115
+ - O modelo declara `tenant_id` (ou outra coluna, via `tenant_field=`).
116
+ - `TenantScopedRepository(session, model=..., tenant_id=...)` injeta o
117
+ filtro em toda leitura e carimba toda escrita.
118
+ - `get_by_id` / `delete` / `delete_batch` / `delete_many` são escopados —
119
+ acesso cruzado entre tenants é impossível pelos métodos do repositório.
120
+ - Construtor valida a existência da coluna de tenant no boot.
@@ -0,0 +1,121 @@
1
+ # Transactional outbox (reliable events)
2
+
3
+ When a handler **writes a row** and **publishes an event**, doing the two
4
+ as independent operations is fragile: if the process dies *after* the
5
+ commit but *before* the publish, the event is lost; if it dies after the
6
+ publish but before the commit, a phantom event references a row that never
7
+ existed. This is the **dual-write problem**.
8
+
9
+ The **outbox** pattern fixes it: write the business row **and** an
10
+ `outbox` row in the **same transaction**. Either both commit or neither
11
+ does. A separate *relay* reads the pending rows and publishes them to the
12
+ broker, marking each one sent. The broker can be down for minutes — the
13
+ events wait, durably, in the table.
14
+
15
+ !!! info "Where this fits"
16
+ It complements the [`AsyncBrokerManager`](queue-tasks.md): the broker
17
+ *publishes*, the outbox *guarantees* the event exists to be published.
18
+ The relay takes any publish callable — so it works with FastStream, a
19
+ webhook, whatever.
20
+
21
+ ## 1. The outbox table
22
+
23
+ `BaseOutboxModel` is abstract — the project creates the concrete table
24
+ (just like `BaseUserModel`):
25
+
26
+ ```python
27
+ from tempest_fastapi_sdk import BaseOutboxModel
28
+
29
+
30
+ class OutboxModel(BaseOutboxModel):
31
+ """The service's pending-events table."""
32
+
33
+ __tablename__ = "outbox"
34
+ ```
35
+
36
+ It ships `topic`, `payload` (JSON), `status`, `attempts`, `max_attempts`,
37
+ `available_at`, `sent_at` and `last_error` — on top of `BaseModel`'s four
38
+ canonical columns (`id` / `is_active` / `created_at` / `updated_at`).
39
+ Generate the migration with the [`AlembicHelper`](database.md) like any
40
+ other table.
41
+
42
+ ## 2. Write atomically
43
+
44
+ In the service/repository, use `save_with_outbox` instead of `add`: it
45
+ inserts the business model **and** the event in one transaction.
46
+
47
+ ```python
48
+ from tempest_fastapi_sdk import BaseRepository
49
+
50
+ from src.db.models import OrderModel, OutboxModel
51
+
52
+
53
+ async def place_order(repo: BaseRepository[OrderModel], data: dict[str, object]) -> OrderModel:
54
+ """Create the order and queue the event in the same transaction."""
55
+ order = OrderModel(**data)
56
+ event = OutboxModel.new_event("orders.created", {"order": data})
57
+ return await repo.save_with_outbox(order, event)
58
+ ```
59
+
60
+ If the `commit` fails (e.g. a unique constraint), **both** rows are rolled
61
+ back — no orphan event is ever left behind.
62
+
63
+ ## 3. Drain and publish (the relay)
64
+
65
+ `OutboxRelay` reads pending rows and calls your publish callable. It does
66
+ not import any specific broker — you pass the function:
67
+
68
+ ```python
69
+ import asyncio
70
+
71
+ from tempest_fastapi_sdk import AsyncDatabaseManager, BaseOutboxModel, OutboxRelay
72
+
73
+ from src.db.models import OutboxModel
74
+
75
+
76
+ async def run_relay(db: AsyncDatabaseManager, broker: object) -> None:
77
+ """Publish pending events continuously."""
78
+
79
+ async def publish(event: BaseOutboxModel) -> None:
80
+ """Forward one event to the broker."""
81
+ await broker.publish(event.payload, event.topic) # type: ignore[attr-defined]
82
+
83
+ relay: OutboxRelay = OutboxRelay(db, model=OutboxModel, publish=publish)
84
+ await relay.run(poll_interval=1.0) # loops until the task is cancelled
85
+ ```
86
+
87
+ Run the relay as a separate process/worker (or a task in the lifespan).
88
+ Each published event becomes `status="sent"` with `sent_at` set.
89
+
90
+ ### Failures and retry
91
+
92
+ If `publish` raises, the relay does **not** mark the event sent: it
93
+ increments `attempts`, records the error in `last_error`, and reschedules
94
+ the event with exponential backoff (`available_at` in the future). Once
95
+ `attempts` reaches `max_attempts`, the row becomes `status="failed"` and
96
+ stays in the table for manual inspection (never auto-retried again).
97
+
98
+ !!! tip "Multiple workers"
99
+ On PostgreSQL/MySQL the relay locks the batch with `FOR UPDATE SKIP
100
+ LOCKED`, so you can run **several** relay workers without publishing
101
+ the same event twice. On SQLite (no row locks) it falls back to a
102
+ plain `SELECT` — use a single worker.
103
+
104
+ ### Drain once (tests / cron)
105
+
106
+ For loop-free scenarios (a test, a cron job), call `drain_once()`, which
107
+ returns how many events were published:
108
+
109
+ ```python
110
+ published: int = await relay.drain_once()
111
+ ```
112
+
113
+ ## Recap
114
+
115
+ - `BaseOutboxModel` → concrete `OutboxModel(__tablename__="outbox")`.
116
+ - `repo.save_with_outbox(model, event)` writes business + event
117
+ **atomically**.
118
+ - `OutboxRelay(db, model=..., publish=...).run()` publishes pending rows,
119
+ with retry/backoff and `sent` / `failed` marking.
120
+ - `OutboxModel.new_event(topic, payload)` builds the event; `drain_once()`
121
+ drains one batch for tests/cron.
@@ -0,0 +1,120 @@
1
+ # Outbox transacional (eventos confiáveis)
2
+
3
+ Quando um handler **grava uma linha** e **publica um evento**, fazer as
4
+ duas coisas como operações independentes é frágil: se o processo morre
5
+ *depois* do commit mas *antes* do publish, o evento some; se morre depois
6
+ do publish mas antes do commit, sobra um evento fantasma apontando pra uma
7
+ linha que nunca existiu. Isso é o **dual-write problem**.
8
+
9
+ O padrão **outbox** resolve: grave a linha de negócio **e** uma linha
10
+ `outbox` na **mesma transação**. Ou as duas comitam, ou nenhuma. Um
11
+ *relay* separado lê as linhas pendentes e publica no broker, marcando cada
12
+ uma como enviada. O broker pode ficar minutos fora do ar — os eventos
13
+ esperam, duráveis, na tabela.
14
+
15
+ !!! info "Onde isso encaixa"
16
+ Complementa o [`AsyncBrokerManager`](queue-tasks.md): o broker
17
+ *publica*, o outbox *garante* que o evento existe pra ser publicado. O
18
+ relay usa qualquer callable de publish — então funciona com FastStream,
19
+ webhook, o que for.
20
+
21
+ ## 1. A tabela outbox
22
+
23
+ `BaseOutboxModel` é abstrata — o projeto cria a tabela concreta (igual a
24
+ `BaseUserModel`):
25
+
26
+ ```python
27
+ from tempest_fastapi_sdk import BaseOutboxModel
28
+
29
+
30
+ class OutboxModel(BaseOutboxModel):
31
+ """Tabela de eventos pendentes do serviço."""
32
+
33
+ __tablename__ = "outbox"
34
+ ```
35
+
36
+ Ela já traz `topic`, `payload` (JSON), `status`, `attempts`,
37
+ `max_attempts`, `available_at`, `sent_at` e `last_error` — além das quatro
38
+ colunas canônicas do `BaseModel` (`id` / `is_active` / `created_at` /
39
+ `updated_at`). Gere a migration com o [`AlembicHelper`](database.md) como
40
+ qualquer outra tabela.
41
+
42
+ ## 2. Gravar de forma atômica
43
+
44
+ No service/repository, use `save_with_outbox` em vez de `add`: ele insere o
45
+ modelo de negócio **e** o evento numa transação só.
46
+
47
+ ```python
48
+ from tempest_fastapi_sdk import BaseRepository
49
+
50
+ from src.db.models import OrderModel, OutboxModel
51
+
52
+
53
+ async def place_order(repo: BaseRepository[OrderModel], data: dict[str, object]) -> OrderModel:
54
+ """Cria o pedido e enfileira o evento na mesma transação."""
55
+ order = OrderModel(**data)
56
+ event = OutboxModel.new_event("orders.created", {"order": data})
57
+ return await repo.save_with_outbox(order, event)
58
+ ```
59
+
60
+ Se o `commit` falhar (ex.: constraint única), **as duas** linhas são
61
+ revertidas — nunca sobra evento órfão.
62
+
63
+ ## 3. Drenar e publicar (o relay)
64
+
65
+ `OutboxRelay` lê as linhas pendentes e chama o seu callable de publish. Ele
66
+ não importa nenhum broker específico — você passa a função:
67
+
68
+ ```python
69
+ import asyncio
70
+
71
+ from tempest_fastapi_sdk import AsyncDatabaseManager, BaseOutboxModel, OutboxRelay
72
+
73
+ from src.db.models import OutboxModel
74
+
75
+
76
+ async def run_relay(db: AsyncDatabaseManager, broker: object) -> None:
77
+ """Publica eventos pendentes continuamente."""
78
+
79
+ async def publish(event: BaseOutboxModel) -> None:
80
+ """Encaminha um evento pro broker."""
81
+ await broker.publish(event.payload, event.topic) # type: ignore[attr-defined]
82
+
83
+ relay: OutboxRelay = OutboxRelay(db, model=OutboxModel, publish=publish)
84
+ await relay.run(poll_interval=1.0) # loop até a task ser cancelada
85
+ ```
86
+
87
+ Rode o relay como um processo/worker separado (ou uma task no lifespan).
88
+ Cada evento publicado vira `status="sent"` com `sent_at` preenchido.
89
+
90
+ ### Falhas e retry
91
+
92
+ Se o `publish` levanta exceção, o relay **não** marca como enviado: ele
93
+ incrementa `attempts`, guarda o erro em `last_error` e reagenda o evento
94
+ com backoff exponencial (`available_at` no futuro). Quando `attempts`
95
+ chega em `max_attempts`, a linha vira `status="failed"` e fica na tabela
96
+ pra inspeção manual (nunca mais é retentada automaticamente).
97
+
98
+ !!! tip "Múltiplos workers"
99
+ Em PostgreSQL/MySQL o relay trava o lote com `FOR UPDATE SKIP LOCKED`,
100
+ então você pode rodar **vários** workers de relay sem publicar o mesmo
101
+ evento duas vezes. Em SQLite (sem lock de linha) ele cai pra um
102
+ `SELECT` simples — use um worker só.
103
+
104
+ ### Drenar uma vez (testes / cron)
105
+
106
+ Pra cenários sem loop (um teste, um cron job), chame `drain_once()`, que
107
+ devolve quantos eventos foram publicados:
108
+
109
+ ```python
110
+ published: int = await relay.drain_once()
111
+ ```
112
+
113
+ ## Recap
114
+
115
+ - `BaseOutboxModel` → tabela concreta `OutboxModel(__tablename__="outbox")`.
116
+ - `repo.save_with_outbox(model, event)` grava negócio + evento **atômico**.
117
+ - `OutboxRelay(db, model=..., publish=...).run()` publica os pendentes,
118
+ com retry/backoff e marcação `sent` / `failed`.
119
+ - `OutboxModel.new_event(topic, payload)` monta o evento; `drain_once()`
120
+ drena um lote pra testes/cron.
@@ -31,12 +31,16 @@ Gerada automaticamente a partir das docstrings do SDK via [`mkdocstrings`](https
31
31
  ::: tempest_fastapi_sdk.db.user_recovery_code_model.BaseUserRecoveryCodeModel
32
32
  ::: tempest_fastapi_sdk.db.user_recovery_code_model.make_user_recovery_code_model
33
33
  ::: tempest_fastapi_sdk.db.repository.BaseRepository
34
+ ::: tempest_fastapi_sdk.db.tenant.TenantScopedRepository
34
35
  ::: tempest_fastapi_sdk.db.mixins.SoftDeleteMixin
35
36
  ::: tempest_fastapi_sdk.db.mixins.AuditMixin
36
37
  ::: tempest_fastapi_sdk.db.mixins.MFAMixin
37
38
  ::: tempest_fastapi_sdk.db.connection.AsyncDatabaseManager
38
39
  ::: tempest_fastapi_sdk.db.migrations.AlembicHelper
39
40
  ::: tempest_fastapi_sdk.db.slow_query.SlowQueryLogger
41
+ ::: tempest_fastapi_sdk.db.outbox.BaseOutboxModel
42
+ ::: tempest_fastapi_sdk.db.outbox.OutboxRelay
43
+ ::: tempest_fastapi_sdk.db.outbox.OutboxStatus
40
44
 
41
45
  ---
42
46
 
@@ -86,12 +86,14 @@ plugins:
86
86
  Tutorial: Tutorial
87
87
  Receitas: Recipes
88
88
  Banco de dados: Database
89
+ Multi-tenant: Multi-tenant
89
90
  Camada HTTP: HTTP layer
90
91
  "HTTP client (saída)": "HTTP client (outbound)"
91
92
  Cache: Cache
92
93
  Tempo real: Real-time
93
94
  WebSocket router: WebSocket router
94
95
  Fila e Tarefas: Queue & Tasks
96
+ Outbox transacional: Transactional outbox
95
97
  Email transacional: Transactional email
96
98
  Web Push: Web Push
97
99
  Logging: Logging
@@ -199,12 +201,14 @@ nav:
199
201
  - Receitas:
200
202
  - recipes/index.md
201
203
  - Banco de dados: recipes/database.md
204
+ - Multi-tenant: recipes/multi-tenant.md
202
205
  - Camada HTTP: recipes/http.md
203
206
  - "HTTP client (saída)": recipes/http-client.md
204
207
  - Cache: recipes/cache.md
205
208
  - Tempo real: recipes/realtime.md
206
209
  - WebSocket router: recipes/websocket.md
207
210
  - Fila e Tarefas: recipes/queue-tasks.md
211
+ - Outbox transacional: recipes/outbox.md
208
212
  - Email transacional: recipes/email.md
209
213
  - Web Push: recipes/webpush.md
210
214
  - Logging: recipes/logging.md
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "tempest-fastapi-sdk"
3
- version = "0.43.0"
3
+ version = "0.45.0"
4
4
  description = "Shared FastAPI building blocks: base schemas, ORM model, async repository, exceptions, pagination and settings — the conventions used across Tempest projects."
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.11"