tempest-fastapi-sdk 0.44.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.
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/CHANGELOG.md +22 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/PKG-INFO +2 -2
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/README.md +1 -1
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/docs/recipes/index.en.md +1 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/docs/recipes/index.md +1 -0
- tempest_fastapi_sdk-0.45.0/docs/recipes/multi-tenant.en.md +120 -0
- tempest_fastapi_sdk-0.45.0/docs/recipes/multi-tenant.md +120 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/docs/reference.md +1 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/mkdocs.yml +2 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/pyproject.toml +1 -1
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/__init__.py +3 -1
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/db/__init__.py +4 -0
- tempest_fastapi_sdk-0.45.0/tempest_fastapi_sdk/db/tenant.py +348 -0
- tempest_fastapi_sdk-0.45.0/tests/db/test_tenant.py +170 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/uv.lock +1 -1
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/.github/workflows/ci.yml +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/.github/workflows/docs.yml +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/.github/workflows/release-pypi.yml +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/.gitignore +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/.python-version +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/CLAUDE.md +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/Makefile +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/docs/architecture.en.md +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/docs/architecture.md +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/docs/changelog.en.md +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/docs/changelog.md +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/docs/contributing.en.md +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/docs/contributing.md +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/docs/index.en.md +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/docs/index.md +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/docs/installation.en.md +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/docs/installation.md +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/docs/learning/index.en.md +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/docs/learning/index.md +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/docs/learning/marketplace/api.en.md +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/docs/learning/marketplace/api.md +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/docs/learning/marketplace/business-rules.en.md +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/docs/learning/marketplace/business-rules.md +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/docs/learning/marketplace/domain.en.md +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/docs/learning/marketplace/domain.md +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/docs/learning/marketplace/flows.en.md +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/docs/learning/marketplace/flows.md +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/docs/learning/marketplace/index.en.md +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/docs/learning/marketplace/index.md +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/docs/migration.en.md +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/docs/migration.md +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/docs/recipes/admin.en.md +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/docs/recipes/admin.md +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/docs/recipes/auth-flow.en.md +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/docs/recipes/auth-flow.md +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/docs/recipes/br-helpers.en.md +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/docs/recipes/br-helpers.md +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/docs/recipes/cache.en.md +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/docs/recipes/cache.md +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/docs/recipes/cli.en.md +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/docs/recipes/cli.md +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/docs/recipes/database.en.md +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/docs/recipes/database.md +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/docs/recipes/downloads.en.md +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/docs/recipes/downloads.md +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/docs/recipes/email.en.md +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/docs/recipes/email.md +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/docs/recipes/http-client.en.md +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/docs/recipes/http-client.md +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/docs/recipes/http.en.md +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/docs/recipes/http.md +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/docs/recipes/idempotency.en.md +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/docs/recipes/idempotency.md +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/docs/recipes/logging.en.md +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/docs/recipes/logging.md +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/docs/recipes/metrics.en.md +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/docs/recipes/metrics.md +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/docs/recipes/mfa.en.md +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/docs/recipes/mfa.md +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/docs/recipes/observability.en.md +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/docs/recipes/observability.md +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/docs/recipes/outbox.en.md +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/docs/recipes/outbox.md +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/docs/recipes/queue-tasks.en.md +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/docs/recipes/queue-tasks.md +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/docs/recipes/realtime.en.md +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/docs/recipes/realtime.md +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/docs/recipes/security.en.md +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/docs/recipes/security.md +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/docs/recipes/sessions.en.md +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/docs/recipes/sessions.md +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/docs/recipes/storage.en.md +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/docs/recipes/storage.md +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/docs/recipes/testing.en.md +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/docs/recipes/testing.md +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/docs/recipes/uploads.en.md +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/docs/recipes/uploads.md +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/docs/recipes/utilities.en.md +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/docs/recipes/utilities.md +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/docs/recipes/webpush.en.md +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/docs/recipes/webpush.md +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/docs/recipes/websocket.en.md +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/docs/recipes/websocket.md +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/docs/reference.en.md +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/docs/roadmap.en.md +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/docs/roadmap.md +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/docs/tutorial.en.md +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/docs/tutorial.md +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/scripts/extract_recipe.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/admin/__init__.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/admin/auth.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/admin/config.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/admin/forms.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/admin/router.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/admin/session.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/admin/site.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/admin/static/admin.css +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/admin/templates/base.html +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/admin/templates/dashboard.html +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/admin/templates/detail.html +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/admin/templates/form.html +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/admin/templates/list.html +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/admin/templates/login.html +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/admin/templates/logs.html +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/admin/templates/mfa.html +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/api/__init__.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/api/cookies.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/api/dependencies/__init__.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/api/dependencies/auth.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/api/handlers.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/api/middlewares/__init__.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/api/middlewares/body_size.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/api/middlewares/cors.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/api/middlewares/csrf.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/api/middlewares/idempotency.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/api/middlewares/rate_limit.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/api/middlewares/request_id.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/api/oauth.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/api/routers/__init__.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/api/routers/health.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/api/routers/logs.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/api/routers/metrics.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/api/routers/tool_spec.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/api/server.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/api/static.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/api/tracing.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/api/webhooks.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/auth/__init__.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/auth/page_renderer.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/auth/router.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/auth/schemas.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/auth/service.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/auth/templates/activation.html +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/auth/templates/activation_error.html +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/auth/templates/activation_success.html +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/auth/templates/password_reset.html +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/auth/templates/password_reset_error.html +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/auth/templates/password_reset_form.html +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/auth/templates/password_reset_success.html +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/cache/__init__.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/cache/decorator.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/cache/redis_manager.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/cli/__init__.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/cli/_templates/README.md.tmpl +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/cli/_templates/env.example.tmpl +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/cli/_templates/gitignore.tmpl +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/cli/_templates/main.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/cli/_templates/pyproject.toml.tmpl +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/cli/_templates/src/__init__.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/cli/_templates/src/api/__init__.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/cli/_templates/src/api/app.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/cli/_templates/src/api/dependencies/__init__.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/cli/_templates/src/api/dependencies/auth.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/cli/_templates/src/api/dependencies/resources.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/cli/_templates/src/api/routers/__init__.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/cli/_templates/src/controllers/__init__.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/cli/_templates/src/core/__init__.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/cli/_templates/src/core/exceptions.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/cli/_templates/src/core/settings.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/cli/_templates/src/db/__init__.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/cli/_templates/src/db/models/__init__.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/cli/_templates/src/db/models/user.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/cli/_templates/src/db/repositories/__init__.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/cli/_templates/src/schemas/__init__.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/cli/_templates/src/server.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/cli/_templates/src/services/__init__.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/cli/_templates/src/utils/__init__.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/cli/_templates/tests/__init__.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/cli/_templates/tests/test_smoke.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/cli/db.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/cli/docker_compose.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/cli/generate.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/cli/lint.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/cli/main.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/cli/new.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/cli/src_layers.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/cli/user.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/controllers/__init__.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/controllers/base.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/core/__init__.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/core/context.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/core/enums.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/core/logging.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/db/_alembic_templates/__init__.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/db/_alembic_templates/env.py.template +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/db/alembic_hooks.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/db/connection.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/db/migrations.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/db/mixins.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/db/model.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/db/outbox.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/db/repository.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/db/slow_query.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/db/user_model.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/db/user_recovery_code_model.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/db/user_token_model.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/exceptions/__init__.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/exceptions/base.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/exceptions/conflict.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/exceptions/forbidden.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/exceptions/jwt.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/exceptions/not_found.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/exceptions/too_many_requests.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/exceptions/unauthorized.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/exceptions/upload.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/exceptions/validation.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/py.typed +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/queue/__init__.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/queue/manager.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/schemas/__init__.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/schemas/base.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/schemas/link_headers.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/schemas/logs.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/schemas/pagination.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/schemas/response.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/services/__init__.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/services/base.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/sessions/__init__.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/sessions/dependencies.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/sessions/middleware.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/sessions/router.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/sessions/schemas.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/sessions/service.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/sessions/store.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/settings/__init__.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/settings/base.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/settings/mixins.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/sse/__init__.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/sse/event_stream.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/storage/__init__.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/storage/minio_client.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/tasks/__init__.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/tasks/manager.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/tasks/scheduler.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/testing/__init__.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/testing/database.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/utils/__init__.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/utils/client_ip.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/utils/datetime.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/utils/dict.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/utils/download.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/utils/email.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/utils/http_client.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/utils/jwt.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/utils/log.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/utils/metrics.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/utils/opaque_token.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/utils/password.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/utils/regex.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/utils/storage_backends.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/utils/throttle.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/utils/totp.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/utils/upload.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/webpush/__init__.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/webpush/dispatcher.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/webpush/schemas.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/websockets/__init__.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/websockets/hub.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/websockets/router.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/websockets/schemas.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/__init__.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/admin/__init__.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/admin/test_auth.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/admin/test_forms.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/admin/test_logs_nav.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/admin/test_mfa.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/admin/test_router.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/admin/test_site.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/admin/test_user_model.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/api/__init__.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/api/test_body_size.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/api/test_cookies.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/api/test_cors.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/api/test_csrf.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/api/test_dependencies_auth.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/api/test_handlers.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/api/test_health_router.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/api/test_idempotency.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/api/test_jwt_dependency.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/api/test_logs_router.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/api/test_oauth.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/api/test_prometheus.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/api/test_rate_limit.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/api/test_request_id_middleware.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/api/test_role_dependency.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/api/test_server.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/api/test_static.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/api/test_tool_spec.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/api/test_tracing.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/api/test_webhooks.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/api/test_webhooks_rsa.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/auth/__init__.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/auth/test_mfa.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/auth/test_service.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/cache/__init__.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/cache/test_decorator.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/cache/test_redis_manager.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/cli/__init__.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/cli/test_db.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/cli/test_docker_compose.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/cli/test_generate.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/cli/test_main.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/cli/test_user.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/conftest.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/controllers/__init__.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/controllers/test_base.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/core/__init__.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/core/test_context.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/core/test_enums.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/core/test_logging.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/db/__init__.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/db/test_alembic_hooks.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/db/test_bulk_ops.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/db/test_connection.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/db/test_migrations.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/db/test_mixins.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/db/test_model.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/db/test_outbox.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/db/test_repository.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/db/test_slow_query.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/exceptions/__init__.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/exceptions/test_exceptions.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/queue/__init__.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/queue/test_manager.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/schemas/__init__.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/schemas/test_base.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/schemas/test_cursor_pagination.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/schemas/test_link_headers.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/schemas/test_pagination.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/schemas/test_response.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/services/__init__.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/services/test_base.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/sessions/__init__.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/sessions/test_sessions.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/settings/__init__.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/settings/test_base.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/settings/test_mixins.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/sse/__init__.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/sse/test_event_stream.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/storage/__init__.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/storage/test_minio_client.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/tasks/__init__.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/tasks/test_manager.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/tasks/test_scheduler.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/testing/__init__.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/testing/test_database.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/utils/__init__.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/utils/test_client_ip.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/utils/test_datetime.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/utils/test_dict.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/utils/test_download.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/utils/test_email.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/utils/test_http_client.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/utils/test_jwt.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/utils/test_lazy_extras.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/utils/test_log.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/utils/test_metrics.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/utils/test_opaque_token.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/utils/test_password.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/utils/test_regex.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/utils/test_storage_backends.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/utils/test_throttle.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/utils/test_upload.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/webpush/__init__.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/webpush/test_dispatcher.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/webpush/test_schemas.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/websockets/__init__.py +0 -0
- {tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tests/websockets/test_hub_and_router.py +0 -0
|
@@ -5,6 +5,28 @@ 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
|
+
|
|
8
30
|
## [0.44.0] — 2026-06-11
|
|
9
31
|
|
|
10
32
|
### Added
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: tempest-fastapi-sdk
|
|
3
|
-
Version: 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`, `BaseOutboxModel`, `OutboxRelay`, `OutboxStatus`, `BaseRepository.save_with_outbox` |
|
|
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`, `BaseOutboxModel`, `OutboxRelay`, `OutboxStatus`, `BaseRepository.save_with_outbox` |
|
|
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,6 +10,7 @@ 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 |
|
|
@@ -10,6 +10,7 @@ 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` |
|
|
@@ -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.
|
|
@@ -31,6 +31,7 @@ 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
|
|
@@ -86,6 +86,7 @@ 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
|
|
@@ -200,6 +201,7 @@ nav:
|
|
|
200
201
|
- Receitas:
|
|
201
202
|
- recipes/index.md
|
|
202
203
|
- Banco de dados: recipes/database.md
|
|
204
|
+
- Multi-tenant: recipes/multi-tenant.md
|
|
203
205
|
- Camada HTTP: recipes/http.md
|
|
204
206
|
- "HTTP client (saída)": recipes/http-client.md
|
|
205
207
|
- Cache: recipes/cache.md
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "tempest-fastapi-sdk"
|
|
3
|
-
version = "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"
|
|
@@ -109,6 +109,7 @@ from tempest_fastapi_sdk.db import (
|
|
|
109
109
|
OutboxStatus,
|
|
110
110
|
SlowQueryLogger,
|
|
111
111
|
SoftDeleteMixin,
|
|
112
|
+
TenantScopedRepository,
|
|
112
113
|
UserTokenPurpose,
|
|
113
114
|
compose_hooks,
|
|
114
115
|
make_user_recovery_code_model,
|
|
@@ -247,7 +248,7 @@ from tempest_fastapi_sdk.websockets import (
|
|
|
247
248
|
make_websocket_router,
|
|
248
249
|
)
|
|
249
250
|
|
|
250
|
-
__version__: str = "0.
|
|
251
|
+
__version__: str = "0.45.0"
|
|
251
252
|
|
|
252
253
|
__all__: list[str] = [
|
|
253
254
|
"BASE_COLUMN_ORDER",
|
|
@@ -387,6 +388,7 @@ __all__: list[str] = [
|
|
|
387
388
|
"SystemMetrics",
|
|
388
389
|
"TOTPHelper",
|
|
389
390
|
"TaskIQSettings",
|
|
391
|
+
"TenantScopedRepository",
|
|
390
392
|
"ThrottleBackend",
|
|
391
393
|
"ThrottleStatus",
|
|
392
394
|
"TokenSettings",
|
{tempest_fastapi_sdk-0.44.0 → tempest_fastapi_sdk-0.45.0}/tempest_fastapi_sdk/db/__init__.py
RENAMED
|
@@ -26,6 +26,9 @@ from tempest_fastapi_sdk.db.outbox import OutboxRelay as OutboxRelay
|
|
|
26
26
|
from tempest_fastapi_sdk.db.outbox import OutboxStatus as OutboxStatus
|
|
27
27
|
from tempest_fastapi_sdk.db.repository import BaseRepository as BaseRepository
|
|
28
28
|
from tempest_fastapi_sdk.db.slow_query import SlowQueryLogger as SlowQueryLogger
|
|
29
|
+
from tempest_fastapi_sdk.db.tenant import (
|
|
30
|
+
TenantScopedRepository as TenantScopedRepository,
|
|
31
|
+
)
|
|
29
32
|
from tempest_fastapi_sdk.db.user_model import BaseUserModel as BaseUserModel
|
|
30
33
|
from tempest_fastapi_sdk.db.user_recovery_code_model import (
|
|
31
34
|
BaseUserRecoveryCodeModel as BaseUserRecoveryCodeModel,
|
|
@@ -58,6 +61,7 @@ __all__: list[str] = [
|
|
|
58
61
|
"OutboxStatus",
|
|
59
62
|
"SlowQueryLogger",
|
|
60
63
|
"SoftDeleteMixin",
|
|
64
|
+
"TenantScopedRepository",
|
|
61
65
|
"UserTokenPurpose",
|
|
62
66
|
"compose_hooks",
|
|
63
67
|
"make_user_recovery_code_model",
|