tempest-fastapi-sdk 0.78.0__tar.gz → 0.80.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.78.0 → tempest_fastapi_sdk-0.80.0}/CHANGELOG.md +33 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/PKG-INFO +7 -7
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/README.md +6 -6
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/docs/architecture.en.md +1 -1
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/docs/architecture.md +1 -1
- tempest_fastapi_sdk-0.80.0/docs/recipes/webpush.en.md +189 -0
- tempest_fastapi_sdk-0.80.0/docs/recipes/webpush.md +188 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/docs/reference.md +2 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/pyproject.toml +1 -1
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/__init__.py +7 -1
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/controllers/base.py +14 -4
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/db/__init__.py +8 -0
- tempest_fastapi_sdk-0.80.0/tempest_fastapi_sdk/db/webpush_subscription_model.py +126 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/services/base.py +16 -5
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/webpush/__init__.py +2 -0
- tempest_fastapi_sdk-0.80.0/tempest_fastapi_sdk/webpush/service.py +220 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/controllers/test_base.py +2 -2
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/services/test_base.py +1 -1
- tempest_fastapi_sdk-0.80.0/tests/webpush/test_service.py +135 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/uv.lock +1 -1
- tempest_fastapi_sdk-0.78.0/docs/recipes/webpush.en.md +0 -109
- tempest_fastapi_sdk-0.78.0/docs/recipes/webpush.md +0 -109
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/.github/workflows/ci.yml +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/.github/workflows/docs.yml +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/.github/workflows/release-pypi.yml +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/.gitignore +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/.python-version +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/CLAUDE.md +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/Makefile +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/docs/changelog.en.md +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/docs/changelog.md +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/docs/contributing.en.md +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/docs/contributing.md +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/docs/index.en.md +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/docs/index.md +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/docs/installation.en.md +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/docs/installation.md +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/docs/learning/index.en.md +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/docs/learning/index.md +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/docs/learning/marketplace/api.en.md +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/docs/learning/marketplace/api.md +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/docs/learning/marketplace/business-rules.en.md +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/docs/learning/marketplace/business-rules.md +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/docs/learning/marketplace/domain.en.md +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/docs/learning/marketplace/domain.md +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/docs/learning/marketplace/flows.en.md +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/docs/learning/marketplace/flows.md +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/docs/learning/marketplace/index.en.md +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/docs/learning/marketplace/index.md +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/docs/migration.en.md +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/docs/migration.md +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/docs/recipes/admin.en.md +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/docs/recipes/admin.md +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/docs/recipes/audit-trail.en.md +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/docs/recipes/audit-trail.md +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/docs/recipes/auth-flow.en.md +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/docs/recipes/auth-flow.md +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/docs/recipes/br-helpers.en.md +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/docs/recipes/br-helpers.md +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/docs/recipes/cache.en.md +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/docs/recipes/cache.md +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/docs/recipes/cli.en.md +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/docs/recipes/cli.md +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/docs/recipes/database.en.md +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/docs/recipes/database.md +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/docs/recipes/deploy-safety.en.md +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/docs/recipes/deploy-safety.md +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/docs/recipes/downloads.en.md +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/docs/recipes/downloads.md +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/docs/recipes/email.en.md +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/docs/recipes/email.md +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/docs/recipes/feature-flags.en.md +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/docs/recipes/feature-flags.md +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/docs/recipes/fields.en.md +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/docs/recipes/fields.md +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/docs/recipes/http-client.en.md +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/docs/recipes/http-client.md +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/docs/recipes/http.en.md +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/docs/recipes/http.md +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/docs/recipes/idempotency.en.md +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/docs/recipes/idempotency.md +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/docs/recipes/index.en.md +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/docs/recipes/index.md +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/docs/recipes/logging.en.md +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/docs/recipes/logging.md +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/docs/recipes/metrics.en.md +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/docs/recipes/metrics.md +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/docs/recipes/mfa.en.md +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/docs/recipes/mfa.md +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/docs/recipes/multi-tenant.en.md +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/docs/recipes/multi-tenant.md +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/docs/recipes/observability.en.md +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/docs/recipes/observability.md +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/docs/recipes/offline-sync.en.md +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/docs/recipes/offline-sync.md +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/docs/recipes/outbox.en.md +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/docs/recipes/outbox.md +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/docs/recipes/queue-tasks.en.md +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/docs/recipes/queue-tasks.md +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/docs/recipes/realtime.en.md +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/docs/recipes/realtime.md +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/docs/recipes/refresh-tokens.en.md +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/docs/recipes/refresh-tokens.md +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/docs/recipes/security.en.md +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/docs/recipes/security.md +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/docs/recipes/sessions.en.md +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/docs/recipes/sessions.md +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/docs/recipes/storage.en.md +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/docs/recipes/storage.md +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/docs/recipes/stored-files.en.md +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/docs/recipes/stored-files.md +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/docs/recipes/testing.en.md +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/docs/recipes/testing.md +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/docs/recipes/typing.en.md +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/docs/recipes/typing.md +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/docs/recipes/uploads.en.md +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/docs/recipes/uploads.md +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/docs/recipes/utilities.en.md +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/docs/recipes/utilities.md +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/docs/recipes/websocket.en.md +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/docs/recipes/websocket.md +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/docs/reference.en.md +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/docs/roadmap.en.md +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/docs/roadmap.md +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/docs/tutorial.en.md +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/docs/tutorial.md +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/mkdocs.yml +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/mkdocs_hooks/llmstxt.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/scripts/extract_recipe.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/admin/__init__.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/admin/auth.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/admin/config.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/admin/discovery.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/admin/forms.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/admin/router.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/admin/session.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/admin/site.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/admin/static/admin.css +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/admin/templates/base.html +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/admin/templates/dashboard.html +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/admin/templates/detail.html +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/admin/templates/form.html +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/admin/templates/list.html +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/admin/templates/login.html +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/admin/templates/logs.html +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/admin/templates/mfa.html +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/admin/theme.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/api/__init__.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/api/cookies.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/api/dependencies/__init__.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/api/dependencies/auth.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/api/handlers.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/api/middlewares/__init__.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/api/middlewares/body_size.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/api/middlewares/cors.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/api/middlewares/csrf.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/api/middlewares/graceful.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/api/middlewares/idempotency.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/api/middlewares/rate_limit.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/api/middlewares/request_id.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/api/oauth.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/api/routers/__init__.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/api/routers/health.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/api/routers/logs.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/api/routers/metrics.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/api/routers/tool_spec.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/api/server.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/api/static.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/api/tracing.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/api/webhooks.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/auth/__init__.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/auth/guards.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/auth/locale.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/auth/page_renderer.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/auth/router.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/auth/schemas.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/auth/service.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/auth/templates/en-US/activation.html +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/auth/templates/en-US/activation_error.html +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/auth/templates/en-US/activation_success.html +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/auth/templates/en-US/password_reset.html +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/auth/templates/en-US/password_reset_error.html +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/auth/templates/en-US/password_reset_form.html +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/auth/templates/en-US/password_reset_success.html +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/auth/templates/pt-BR/activation.html +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/auth/templates/pt-BR/activation_error.html +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/auth/templates/pt-BR/activation_success.html +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/auth/templates/pt-BR/password_reset.html +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/auth/templates/pt-BR/password_reset_error.html +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/auth/templates/pt-BR/password_reset_form.html +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/auth/templates/pt-BR/password_reset_success.html +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/cache/__init__.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/cache/decorator.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/cache/invalidation.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/cache/redis_manager.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/cli/__init__.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/cli/_templates/Dockerfile.tmpl +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/cli/_templates/README.md.tmpl +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/cli/_templates/dockerignore.tmpl +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/cli/_templates/env.example.tmpl +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/cli/_templates/gitignore.tmpl +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/cli/_templates/main.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/cli/_templates/pyproject.toml.tmpl +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/cli/_templates/src/__init__.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/cli/_templates/src/api/__init__.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/cli/_templates/src/api/app.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/cli/_templates/src/api/dependencies/__init__.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/cli/_templates/src/api/dependencies/auth.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/cli/_templates/src/api/dependencies/resources.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/cli/_templates/src/api/routers/__init__.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/cli/_templates/src/controllers/__init__.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/cli/_templates/src/core/__init__.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/cli/_templates/src/core/exceptions.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/cli/_templates/src/core/settings.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/cli/_templates/src/db/__init__.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/cli/_templates/src/db/models/__init__.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/cli/_templates/src/db/models/user.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/cli/_templates/src/db/repositories/__init__.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/cli/_templates/src/schemas/__init__.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/cli/_templates/src/server.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/cli/_templates/src/services/__init__.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/cli/_templates/src/utils/__init__.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/cli/_templates/tests/__init__.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/cli/_templates/tests/test_smoke.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/cli/config.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/cli/db.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/cli/docker_compose.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/cli/generate.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/cli/lint.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/cli/main.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/cli/new.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/cli/secrets.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/cli/src_layers.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/cli/user.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/controllers/__init__.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/core/__init__.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/core/context.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/core/enums.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/core/logging.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/core/typed.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/db/_alembic_templates/__init__.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/db/_alembic_templates/env.py.template +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/db/alembic_hooks.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/db/audit.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/db/backup.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/db/connection.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/db/migrations.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/db/mixins.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/db/model.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/db/outbox.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/db/repository.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/db/slow_query.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/db/tenant.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/db/user_model.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/db/user_recovery_code_model.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/db/user_refresh_token_model.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/db/user_token_model.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/exceptions/__init__.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/exceptions/base.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/exceptions/conflict.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/exceptions/forbidden.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/exceptions/i18n.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/exceptions/jwt.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/exceptions/not_found.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/exceptions/too_many_requests.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/exceptions/unauthorized.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/exceptions/upload.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/exceptions/validation.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/flags/__init__.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/flags/backends.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/flags/dependencies.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/flags/service.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/py.typed +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/queue/__init__.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/queue/manager.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/schemas/__init__.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/schemas/base.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/schemas/link_headers.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/schemas/logs.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/schemas/pagination.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/schemas/response.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/services/__init__.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/services/file_mixin.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/sessions/__init__.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/sessions/dependencies.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/sessions/middleware.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/sessions/router.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/sessions/schemas.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/sessions/service.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/sessions/store.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/settings/__init__.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/settings/base.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/settings/mixins.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/sse/__init__.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/sse/event_stream.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/storage/__init__.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/storage/minio_client.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/tasks/__init__.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/tasks/manager.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/tasks/scheduler.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/testing/__init__.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/testing/database.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/utils/__init__.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/utils/client_ip.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/utils/data/br_locations.json +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/utils/datetime.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/utils/dict.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/utils/download.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/utils/email.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/utils/fields.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/utils/http_client.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/utils/jwt.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/utils/locations.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/utils/log.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/utils/metrics.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/utils/opaque_token.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/utils/password.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/utils/regex.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/utils/storage_backends.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/utils/throttle.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/utils/totp.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/utils/upload.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/webpush/dispatcher.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/webpush/schemas.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/websockets/__init__.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/websockets/hub.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/websockets/router.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tempest_fastapi_sdk/websockets/schemas.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/__init__.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/admin/__init__.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/admin/test_auth.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/admin/test_discovery.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/admin/test_forms.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/admin/test_logs_nav.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/admin/test_mfa.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/admin/test_router.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/admin/test_site.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/admin/test_theme.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/admin/test_user_model.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/api/__init__.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/api/test_body_size.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/api/test_cookies.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/api/test_cors.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/api/test_csrf.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/api/test_dependencies_auth.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/api/test_graceful.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/api/test_handlers.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/api/test_health_router.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/api/test_idempotency.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/api/test_jwt_dependency.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/api/test_logs_router.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/api/test_oauth.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/api/test_prometheus.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/api/test_rate_limit.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/api/test_rate_limit_extras.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/api/test_request_id_middleware.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/api/test_role_dependency.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/api/test_server.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/api/test_static.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/api/test_tool_spec.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/api/test_tracing.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/api/test_webhooks.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/api/test_webhooks_rsa.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/auth/__init__.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/auth/test_guards.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/auth/test_locale.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/auth/test_mfa.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/auth/test_refresh.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/auth/test_refresh_db.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/auth/test_service.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/cache/__init__.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/cache/test_decorator.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/cache/test_invalidation.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/cache/test_redis_manager.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/cli/__init__.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/cli/test_config.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/cli/test_db.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/cli/test_db_seed.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/cli/test_docker_compose.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/cli/test_generate.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/cli/test_lint_strictness.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/cli/test_main.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/cli/test_secrets.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/cli/test_user.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/conftest.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/controllers/__init__.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/core/__init__.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/core/test_context.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/core/test_enums.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/core/test_logging.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/core/test_typed.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/db/__init__.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/db/test_alembic_hooks.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/db/test_audit.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/db/test_backup.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/db/test_bulk_ops.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/db/test_connection.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/db/test_migrations.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/db/test_mixins.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/db/test_model.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/db/test_outbox.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/db/test_repository.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/db/test_safe_upgrade.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/db/test_slow_query.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/db/test_tenant.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/exceptions/__init__.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/exceptions/test_exceptions.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/exceptions/test_i18n.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/flags/__init__.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/flags/test_flags.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/queue/__init__.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/queue/test_manager.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/schemas/__init__.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/schemas/test_base.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/schemas/test_cursor_pagination.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/schemas/test_link_headers.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/schemas/test_pagination.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/schemas/test_response.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/services/__init__.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/services/test_file_mixin.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/sessions/__init__.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/sessions/test_sessions.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/settings/__init__.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/settings/test_base.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/settings/test_mixins.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/sse/__init__.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/sse/test_event_stream.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/storage/__init__.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/storage/test_minio_client.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/tasks/__init__.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/tasks/test_manager.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/tasks/test_scheduler.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/testing/__init__.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/testing/test_database.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/utils/__init__.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/utils/test_client_ip.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/utils/test_datetime.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/utils/test_dict.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/utils/test_download.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/utils/test_email.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/utils/test_fields.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/utils/test_http_client.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/utils/test_jwt.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/utils/test_lazy_extras.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/utils/test_locations.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/utils/test_log.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/utils/test_metrics.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/utils/test_opaque_token.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/utils/test_password.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/utils/test_regex.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/utils/test_storage_backends.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/utils/test_throttle.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/utils/test_upload.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/webpush/__init__.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/webpush/test_dispatcher.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/webpush/test_schemas.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/websockets/__init__.py +0 -0
- {tempest_fastapi_sdk-0.78.0 → tempest_fastapi_sdk-0.80.0}/tests/websockets/test_hub_and_router.py +0 -0
|
@@ -5,6 +5,39 @@ 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.80.0] — 2026-06-28
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- **Web Push subscription storage + service.** The webpush module gained
|
|
13
|
+
the missing persistence layer so apps no longer hand-roll it:
|
|
14
|
+
`BaseWebPushSubscriptionModel` (abstract table, one row per user device,
|
|
15
|
+
unique `endpoint`) + `make_web_push_subscription_model(user_table=...)`
|
|
16
|
+
factory, mirroring the `BaseUserTokenModel` pattern; and
|
|
17
|
+
`WebPushSubscriptionService` (generic over the concrete model) with
|
|
18
|
+
`subscribe` (idempotent upsert keyed by endpoint), `unsubscribe`,
|
|
19
|
+
`list_for_user`, `prune`, and `notify_user` — which fans a payload out
|
|
20
|
+
to every device and **auto-prunes the ones the push service reports as
|
|
21
|
+
gone (404/410)**. The wire shape matches `PushSubscription.toJSON()`,
|
|
22
|
+
so it lines up 1:1 with `tempest-react-sdk`'s `WebPushClient`
|
|
23
|
+
`onSubscribe` / `onUnsubscribe` callbacks. Exported from
|
|
24
|
+
`tempest_fastapi_sdk`, `tempest_fastapi_sdk.webpush` and
|
|
25
|
+
`tempest_fastapi_sdk.db`.
|
|
26
|
+
|
|
27
|
+
## [0.79.0] — 2026-06-27
|
|
28
|
+
|
|
29
|
+
### Changed
|
|
30
|
+
|
|
31
|
+
- **`BaseService` / `BaseController` `update` payload is now generically
|
|
32
|
+
typed.** Both classes gained an optional third type parameter
|
|
33
|
+
`UpdateT` (bound to `BaseSchema`, default `BaseSchema`) so `update`
|
|
34
|
+
accepts the project's own update schema instead of the bare
|
|
35
|
+
`BaseSchema`: `BaseService[Repo, Resp, MyUpdateSchema]` /
|
|
36
|
+
`BaseController[Service, Resp, MyUpdateSchema]`. The default keeps every
|
|
37
|
+
existing two-argument subclass working unchanged. Implemented with a
|
|
38
|
+
PEP 695/696 `TypeVar` default via `typing_extensions` (already present
|
|
39
|
+
through Pydantic).
|
|
40
|
+
|
|
8
41
|
## [0.78.0] — 2026-06-27
|
|
9
42
|
|
|
10
43
|
### Added
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: tempest-fastapi-sdk
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.80.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
|
|
@@ -210,7 +210,7 @@ Feature-rich helpers pull in third-party dependencies that you only need when yo
|
|
|
210
210
|
| `[email]` | `aiosmtplib`, `jinja2` | `EmailUtils` + `render_template()` |
|
|
211
211
|
| `[upload]` | `aiofiles`, `python-multipart` | `UploadUtils`, `LocalUploadStorage`, `MinIOUploadStorage` (when combined with `[minio]`) |
|
|
212
212
|
| `[cache]` | `redis` | `AsyncRedisManager` |
|
|
213
|
-
| `[webpush]` | `pywebpush`, `cryptography` | `WebPushDispatcher` |
|
|
213
|
+
| `[webpush]` | `pywebpush`, `cryptography` | `WebPushDispatcher`, `WebPushSubscriptionService`, `BaseWebPushSubscriptionModel` |
|
|
214
214
|
| `[metrics]` | `psutil`, `nvidia-ml-py` | `MetricsUtils` |
|
|
215
215
|
| `[queue]` | `faststream[rabbit]` | `AsyncBrokerManager` (FastStream) |
|
|
216
216
|
| `[tasks]` | `taskiq`, `taskiq-aio-pika` | `AsyncTaskBrokerManager` (TaskIQ) |
|
|
@@ -241,7 +241,7 @@ Since `0.7.1` every optional dependency is imported lazily at first instantiatio
|
|
|
241
241
|
| Module | Exports |
|
|
242
242
|
| --- | --- |
|
|
243
243
|
| `tempest_fastapi_sdk.schemas` | `BaseSchema`, `BaseResponseSchema`, `BasePaginationFilterSchema`, `BasePaginationSchema[T]`, `CursorPaginationFilterSchema`, `CursorPaginationSchema`, `LogEntrySchema`, `encode_cursor`, `decode_cursor`, `build_pagination_link_header` |
|
|
244
|
-
| `tempest_fastapi_sdk.db` | `BaseModel`, `BaseUserModel`, `BaseUserTokenModel`, `BaseUserRecoveryCodeModel`, `make_user_recovery_code_model`, `UserTokenPurpose`, `BaseRepository[ModelType]`, `TenantScopedRepository[ModelType]`, `AsyncDatabaseManager`, `AlembicHelper` (+ `safe_upgrade`), `DestructiveMigrationError`, `NAMING_CONVENTION`, `AuditMixin`, `SoftDeleteMixin`, `MFAMixin`, `BASE_COLUMN_ORDER`, `reorder_base_columns_first`, `compose_hooks`, `SlowQueryLogger`, `BaseOutboxModel`, `OutboxRelay`, `OutboxStatus`, `BaseRepository.save_with_outbox`, audit trail (`BaseAuditLogModel`, `AuditAction`, `snapshot_model`, `diff_snapshots`, `BaseRepository.add_audited` / `update_audited` / `delete_audited`) |
|
|
244
|
+
| `tempest_fastapi_sdk.db` | `BaseModel`, `BaseUserModel`, `BaseUserTokenModel`, `BaseUserRecoveryCodeModel`, `make_user_recovery_code_model`, `UserTokenPurpose`, `BaseRepository[ModelType]`, `TenantScopedRepository[ModelType]`, `AsyncDatabaseManager`, `AlembicHelper` (+ `safe_upgrade`), `DestructiveMigrationError`, `NAMING_CONVENTION`, `AuditMixin`, `SoftDeleteMixin`, `MFAMixin`, `BASE_COLUMN_ORDER`, `reorder_base_columns_first`, `compose_hooks`, `SlowQueryLogger`, `BaseOutboxModel`, `OutboxRelay`, `OutboxStatus`, `BaseRepository.save_with_outbox`, audit trail (`BaseAuditLogModel`, `AuditAction`, `snapshot_model`, `diff_snapshots`, `BaseRepository.add_audited` / `update_audited` / `delete_audited`), `BaseWebPushSubscriptionModel` + `make_web_push_subscription_model` |
|
|
245
245
|
| `tempest_fastapi_sdk.exceptions` | `AppException`, `NotFoundException`, `ConflictException`, `ValidationException`, `UnauthorizedException`, `ForbiddenException`, `InvalidTokenException`, `ExpiredTokenException`, `FileTooLargeException`, `InvalidFileTypeException`, `TooManyRequestsException`, i18n (`MessageCatalog`, `default_message_catalog`, `parse_accept_language`, `DEFAULT_LOCALE`) |
|
|
246
246
|
| `tempest_fastapi_sdk.settings` | `BaseAppSettings`, `ServerSettings`, `LogSettings`, `DatabaseSettings`, `RedisSettings`, `RabbitMQSettings`, `JWTSettings`, `CORSSettings`, `EmailSettings`, `UploadSettings`, `TokenSettings`, `WebPushSettings`, `TaskIQSettings`, `MinIOSettings`, `AuthSettings` |
|
|
247
247
|
| `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` (+ `RateLimitStore`/`MemoryRateLimitStore`/`RedisRateLimitStore`/`RateLimitResult` and `key_by_ip`/`key_by_jwt_subject`/`key_by_jwt_claim`/`key_by_header`), `IdempotencyMiddleware`, `MemoryIdempotencyStore`, `RedisIdempotencyStore`, `BodySizeLimitMiddleware`, `CSRFMiddleware`, `make_csrf_token_dependency`, `GracefulShutdownMiddleware`, `WebhookSignatureVerifier`, `RSAWebhookSignatureVerifier`, OAuth2 (`GoogleOAuthClient`, `GitHubOAuthClient`, `OIDCProvider`), `HardenedStaticFiles`, `DEFAULT_STATIC_SECURITY_HEADERS`, `set_cookie`, `clear_cookie`, `SameSite`, `HealthCheck`, `setup_tracing` *(extra: `[otel]`)* |
|
|
@@ -253,7 +253,7 @@ Since `0.7.1` every optional dependency is imported lazily at first instantiatio
|
|
|
253
253
|
| `tempest_fastapi_sdk.sse` | `EventStream`, `ServerSentEvent`, `sse_response` |
|
|
254
254
|
| `tempest_fastapi_sdk.cache` *(extra: `[cache]`)* | `AsyncRedisManager`, `cached` (with `namespace` / `tags`), `CacheInvalidator`, `namespace_registry_key`, `tag_registry_key` |
|
|
255
255
|
| `tempest_fastapi_sdk.flags` | `FeatureFlags`, `FeatureFlagBackend`, `MemoryFeatureFlagBackend`, `EnvFeatureFlagBackend`, `RedisFeatureFlagBackend`, `CompositeFeatureFlagBackend`, `make_flag_dependency`, `coerce_flag` |
|
|
256
|
-
| `tempest_fastapi_sdk.webpush` *(extra: `[webpush]`)* | `WebPushDispatcher`, `WebPushError`, `WebPushGoneError`, `WebPushSubscriptionSchema`, `WebPushKeysSchema`, `WebPushPayloadSchema` |
|
|
256
|
+
| `tempest_fastapi_sdk.webpush` *(extra: `[webpush]`)* | `WebPushDispatcher`, `WebPushSubscriptionService`, `WebPushError`, `WebPushGoneError`, `WebPushSubscriptionSchema`, `WebPushKeysSchema`, `WebPushPayloadSchema` |
|
|
257
257
|
| `tempest_fastapi_sdk.queue` *(extra: `[queue]`)* | `AsyncBrokerManager` (FastStream lifecycle wrapper) |
|
|
258
258
|
| `tempest_fastapi_sdk.storage` *(extra: `[minio]`)* | `AsyncMinIOClient`, `ObjectStat` — async MinIO/S3 facade |
|
|
259
259
|
| `tempest_fastapi_sdk.utils.http_client` *(extra: `[http]`)* | `HTTPClient`, `RetryPolicy`, `CircuitOpenError`, `REQUEST_ID_HEADER` — typed httpx wrapper |
|
|
@@ -2126,7 +2126,7 @@ Each mixin owns its own env-var prefix — pick only the ones the service needs:
|
|
|
2126
2126
|
|
|
2127
2127
|
`BaseService[RepositoryT, ResponseT]` and `BaseController[ServiceT, ResponseT]` are generic skeletons matching the SDK layering (router → controller → service → repository). They expose pass-through CRUD methods so simple endpoints can subclass them without overriding anything; you override only methods that need orchestration.
|
|
2128
2128
|
|
|
2129
|
-
|
|
2129
|
+
`BaseService[RepositoryT, ResponseT]` accepts an optional third type argument — `BaseService[RepositoryT, ResponseT, UpdateT]` — that types the `update` payload (defaults to `BaseSchema`, so the two-argument form keeps working). What you inherit by subclassing it:
|
|
2130
2130
|
|
|
2131
2131
|
| Method | Returns | Notes |
|
|
2132
2132
|
| --- | --- | --- |
|
|
@@ -2136,7 +2136,7 @@ What you inherit by subclassing `BaseService[RepositoryT, ResponseT]`:
|
|
|
2136
2136
|
| `paginate(filters=None, order_by=None, page=1, page_size=20, ascending=True)` | `dict` with mapped `items` + `total`/`page`/`size`/`pages`. | Offset pagination via `repository.paginate`. |
|
|
2137
2137
|
| `count(filters=None)` | `int` | Pass-through to `repository.count`. |
|
|
2138
2138
|
| `exists(filters)` | `bool` | Pass-through to `repository.exists`. |
|
|
2139
|
-
| `update(id, data)` | `ResponseT` | Fetch by id, copy the fields present in `data` (
|
|
2139
|
+
| `update(id, data)` | `ResponseT` | Fetch by id, copy the fields present in `data` (typed `UpdateT`, the optional 3rd generic param — defaults to `BaseSchema`) onto the row, persist, map. `to_dict()` drops unset/`None`, so it serves PUT and PATCH alike. |
|
|
2140
2140
|
| `delete(id)` | `None` | Hard delete via `repository.delete`. |
|
|
2141
2141
|
|
|
2142
2142
|
`map_to_response` is `await`-ed when it returns a coroutine, so async mappers work transparently — no method override needed.
|
|
@@ -2149,7 +2149,7 @@ What you inherit by subclassing `BaseController[ServiceT, ResponseT]`:
|
|
|
2149
2149
|
| `list(filters, order_by, ascending)` | `service.list` | Same. |
|
|
2150
2150
|
| `paginate(filters, order_by, page, page_size, ascending)` | `service.paginate` | Same. |
|
|
2151
2151
|
| `count(filters)` | `service.count` | Same. |
|
|
2152
|
-
| `update(id, data)` | `service.update` |
|
|
2152
|
+
| `update(id, data)` | `service.update` | `data` typed by the optional 3rd generic param `UpdateT` (defaults to `BaseSchema`). |
|
|
2153
2153
|
| `delete(id)` | `service.delete` | Same. |
|
|
2154
2154
|
|
|
2155
2155
|
When a use case needs domain rules, override the inherited method in the service. When a use case needs to coordinate more than one service, override the inherited method (or add a new one) in the controller. The router never grows — it only depends on the controller.
|
|
@@ -107,7 +107,7 @@ Feature-rich helpers pull in third-party dependencies that you only need when yo
|
|
|
107
107
|
| `[email]` | `aiosmtplib`, `jinja2` | `EmailUtils` + `render_template()` |
|
|
108
108
|
| `[upload]` | `aiofiles`, `python-multipart` | `UploadUtils`, `LocalUploadStorage`, `MinIOUploadStorage` (when combined with `[minio]`) |
|
|
109
109
|
| `[cache]` | `redis` | `AsyncRedisManager` |
|
|
110
|
-
| `[webpush]` | `pywebpush`, `cryptography` | `WebPushDispatcher` |
|
|
110
|
+
| `[webpush]` | `pywebpush`, `cryptography` | `WebPushDispatcher`, `WebPushSubscriptionService`, `BaseWebPushSubscriptionModel` |
|
|
111
111
|
| `[metrics]` | `psutil`, `nvidia-ml-py` | `MetricsUtils` |
|
|
112
112
|
| `[queue]` | `faststream[rabbit]` | `AsyncBrokerManager` (FastStream) |
|
|
113
113
|
| `[tasks]` | `taskiq`, `taskiq-aio-pika` | `AsyncTaskBrokerManager` (TaskIQ) |
|
|
@@ -138,7 +138,7 @@ Since `0.7.1` every optional dependency is imported lazily at first instantiatio
|
|
|
138
138
|
| Module | Exports |
|
|
139
139
|
| --- | --- |
|
|
140
140
|
| `tempest_fastapi_sdk.schemas` | `BaseSchema`, `BaseResponseSchema`, `BasePaginationFilterSchema`, `BasePaginationSchema[T]`, `CursorPaginationFilterSchema`, `CursorPaginationSchema`, `LogEntrySchema`, `encode_cursor`, `decode_cursor`, `build_pagination_link_header` |
|
|
141
|
-
| `tempest_fastapi_sdk.db` | `BaseModel`, `BaseUserModel`, `BaseUserTokenModel`, `BaseUserRecoveryCodeModel`, `make_user_recovery_code_model`, `UserTokenPurpose`, `BaseRepository[ModelType]`, `TenantScopedRepository[ModelType]`, `AsyncDatabaseManager`, `AlembicHelper` (+ `safe_upgrade`), `DestructiveMigrationError`, `NAMING_CONVENTION`, `AuditMixin`, `SoftDeleteMixin`, `MFAMixin`, `BASE_COLUMN_ORDER`, `reorder_base_columns_first`, `compose_hooks`, `SlowQueryLogger`, `BaseOutboxModel`, `OutboxRelay`, `OutboxStatus`, `BaseRepository.save_with_outbox`, audit trail (`BaseAuditLogModel`, `AuditAction`, `snapshot_model`, `diff_snapshots`, `BaseRepository.add_audited` / `update_audited` / `delete_audited`) |
|
|
141
|
+
| `tempest_fastapi_sdk.db` | `BaseModel`, `BaseUserModel`, `BaseUserTokenModel`, `BaseUserRecoveryCodeModel`, `make_user_recovery_code_model`, `UserTokenPurpose`, `BaseRepository[ModelType]`, `TenantScopedRepository[ModelType]`, `AsyncDatabaseManager`, `AlembicHelper` (+ `safe_upgrade`), `DestructiveMigrationError`, `NAMING_CONVENTION`, `AuditMixin`, `SoftDeleteMixin`, `MFAMixin`, `BASE_COLUMN_ORDER`, `reorder_base_columns_first`, `compose_hooks`, `SlowQueryLogger`, `BaseOutboxModel`, `OutboxRelay`, `OutboxStatus`, `BaseRepository.save_with_outbox`, audit trail (`BaseAuditLogModel`, `AuditAction`, `snapshot_model`, `diff_snapshots`, `BaseRepository.add_audited` / `update_audited` / `delete_audited`), `BaseWebPushSubscriptionModel` + `make_web_push_subscription_model` |
|
|
142
142
|
| `tempest_fastapi_sdk.exceptions` | `AppException`, `NotFoundException`, `ConflictException`, `ValidationException`, `UnauthorizedException`, `ForbiddenException`, `InvalidTokenException`, `ExpiredTokenException`, `FileTooLargeException`, `InvalidFileTypeException`, `TooManyRequestsException`, i18n (`MessageCatalog`, `default_message_catalog`, `parse_accept_language`, `DEFAULT_LOCALE`) |
|
|
143
143
|
| `tempest_fastapi_sdk.settings` | `BaseAppSettings`, `ServerSettings`, `LogSettings`, `DatabaseSettings`, `RedisSettings`, `RabbitMQSettings`, `JWTSettings`, `CORSSettings`, `EmailSettings`, `UploadSettings`, `TokenSettings`, `WebPushSettings`, `TaskIQSettings`, `MinIOSettings`, `AuthSettings` |
|
|
144
144
|
| `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` (+ `RateLimitStore`/`MemoryRateLimitStore`/`RedisRateLimitStore`/`RateLimitResult` and `key_by_ip`/`key_by_jwt_subject`/`key_by_jwt_claim`/`key_by_header`), `IdempotencyMiddleware`, `MemoryIdempotencyStore`, `RedisIdempotencyStore`, `BodySizeLimitMiddleware`, `CSRFMiddleware`, `make_csrf_token_dependency`, `GracefulShutdownMiddleware`, `WebhookSignatureVerifier`, `RSAWebhookSignatureVerifier`, OAuth2 (`GoogleOAuthClient`, `GitHubOAuthClient`, `OIDCProvider`), `HardenedStaticFiles`, `DEFAULT_STATIC_SECURITY_HEADERS`, `set_cookie`, `clear_cookie`, `SameSite`, `HealthCheck`, `setup_tracing` *(extra: `[otel]`)* |
|
|
@@ -150,7 +150,7 @@ Since `0.7.1` every optional dependency is imported lazily at first instantiatio
|
|
|
150
150
|
| `tempest_fastapi_sdk.sse` | `EventStream`, `ServerSentEvent`, `sse_response` |
|
|
151
151
|
| `tempest_fastapi_sdk.cache` *(extra: `[cache]`)* | `AsyncRedisManager`, `cached` (with `namespace` / `tags`), `CacheInvalidator`, `namespace_registry_key`, `tag_registry_key` |
|
|
152
152
|
| `tempest_fastapi_sdk.flags` | `FeatureFlags`, `FeatureFlagBackend`, `MemoryFeatureFlagBackend`, `EnvFeatureFlagBackend`, `RedisFeatureFlagBackend`, `CompositeFeatureFlagBackend`, `make_flag_dependency`, `coerce_flag` |
|
|
153
|
-
| `tempest_fastapi_sdk.webpush` *(extra: `[webpush]`)* | `WebPushDispatcher`, `WebPushError`, `WebPushGoneError`, `WebPushSubscriptionSchema`, `WebPushKeysSchema`, `WebPushPayloadSchema` |
|
|
153
|
+
| `tempest_fastapi_sdk.webpush` *(extra: `[webpush]`)* | `WebPushDispatcher`, `WebPushSubscriptionService`, `WebPushError`, `WebPushGoneError`, `WebPushSubscriptionSchema`, `WebPushKeysSchema`, `WebPushPayloadSchema` |
|
|
154
154
|
| `tempest_fastapi_sdk.queue` *(extra: `[queue]`)* | `AsyncBrokerManager` (FastStream lifecycle wrapper) |
|
|
155
155
|
| `tempest_fastapi_sdk.storage` *(extra: `[minio]`)* | `AsyncMinIOClient`, `ObjectStat` — async MinIO/S3 facade |
|
|
156
156
|
| `tempest_fastapi_sdk.utils.http_client` *(extra: `[http]`)* | `HTTPClient`, `RetryPolicy`, `CircuitOpenError`, `REQUEST_ID_HEADER` — typed httpx wrapper |
|
|
@@ -2023,7 +2023,7 @@ Each mixin owns its own env-var prefix — pick only the ones the service needs:
|
|
|
2023
2023
|
|
|
2024
2024
|
`BaseService[RepositoryT, ResponseT]` and `BaseController[ServiceT, ResponseT]` are generic skeletons matching the SDK layering (router → controller → service → repository). They expose pass-through CRUD methods so simple endpoints can subclass them without overriding anything; you override only methods that need orchestration.
|
|
2025
2025
|
|
|
2026
|
-
|
|
2026
|
+
`BaseService[RepositoryT, ResponseT]` accepts an optional third type argument — `BaseService[RepositoryT, ResponseT, UpdateT]` — that types the `update` payload (defaults to `BaseSchema`, so the two-argument form keeps working). What you inherit by subclassing it:
|
|
2027
2027
|
|
|
2028
2028
|
| Method | Returns | Notes |
|
|
2029
2029
|
| --- | --- | --- |
|
|
@@ -2033,7 +2033,7 @@ What you inherit by subclassing `BaseService[RepositoryT, ResponseT]`:
|
|
|
2033
2033
|
| `paginate(filters=None, order_by=None, page=1, page_size=20, ascending=True)` | `dict` with mapped `items` + `total`/`page`/`size`/`pages`. | Offset pagination via `repository.paginate`. |
|
|
2034
2034
|
| `count(filters=None)` | `int` | Pass-through to `repository.count`. |
|
|
2035
2035
|
| `exists(filters)` | `bool` | Pass-through to `repository.exists`. |
|
|
2036
|
-
| `update(id, data)` | `ResponseT` | Fetch by id, copy the fields present in `data` (
|
|
2036
|
+
| `update(id, data)` | `ResponseT` | Fetch by id, copy the fields present in `data` (typed `UpdateT`, the optional 3rd generic param — defaults to `BaseSchema`) onto the row, persist, map. `to_dict()` drops unset/`None`, so it serves PUT and PATCH alike. |
|
|
2037
2037
|
| `delete(id)` | `None` | Hard delete via `repository.delete`. |
|
|
2038
2038
|
|
|
2039
2039
|
`map_to_response` is `await`-ed when it returns a coroutine, so async mappers work transparently — no method override needed.
|
|
@@ -2046,7 +2046,7 @@ What you inherit by subclassing `BaseController[ServiceT, ResponseT]`:
|
|
|
2046
2046
|
| `list(filters, order_by, ascending)` | `service.list` | Same. |
|
|
2047
2047
|
| `paginate(filters, order_by, page, page_size, ascending)` | `service.paginate` | Same. |
|
|
2048
2048
|
| `count(filters)` | `service.count` | Same. |
|
|
2049
|
-
| `update(id, data)` | `service.update` |
|
|
2049
|
+
| `update(id, data)` | `service.update` | `data` typed by the optional 3rd generic param `UpdateT` (defaults to `BaseSchema`). |
|
|
2050
2050
|
| `delete(id)` | `service.delete` | Same. |
|
|
2051
2051
|
|
|
2052
2052
|
When a use case needs domain rules, override the inherited method in the service. When a use case needs to coordinate more than one service, override the inherited method (or add a new one) in the controller. The router never grows — it only depends on the controller.
|
|
@@ -147,7 +147,7 @@ What you inherit by subclassing `BaseService[RepositoryT, ResponseT]`:
|
|
|
147
147
|
| `paginate(filters=None, order_by=None, page=1, page_size=20, ascending=True)` | `dict` with mapped `items` + `total`/`page`/`page_size`/`pages`. | Offset pagination via `repository.paginate`. |
|
|
148
148
|
| `count(filters=None)` | `int` | Pass-through to `repository.count`. |
|
|
149
149
|
| `exists(filters)` | `bool` | Pass-through to `repository.exists`. |
|
|
150
|
-
| `update(id, data)` | `ResponseT` | Fetch by id, copy the fields present in `data` (
|
|
150
|
+
| `update(id, data)` | `ResponseT` | Fetch by id, copy the fields present in `data` (typed by `UpdateT`, the optional 3rd generic param — defaults to `BaseSchema`) onto the row, persist, map. `to_dict()` drops unset/`None`, so it serves PUT and PATCH. |
|
|
151
151
|
| `delete(id)` | `None` | Hard delete via `repository.delete`. |
|
|
152
152
|
|
|
153
153
|
`map_to_response` is `await`-ed when it returns a coroutine, so async mappers work transparently — no method override needed.
|
|
@@ -147,7 +147,7 @@ O que você herda ao subclassear `BaseService[RepositoryT, ResponseT]`:
|
|
|
147
147
|
| `paginate(filters=None, order_by=None, page=1, page_size=20, ascending=True)` | `dict` com `items` mapeados + `total`/`page`/`page_size`/`pages`. | Paginação por offset via `repository.paginate`. |
|
|
148
148
|
| `count(filters=None)` | `int` | Pass-through para `repository.count`. |
|
|
149
149
|
| `exists(filters)` | `bool` | Pass-through para `repository.exists`. |
|
|
150
|
-
| `update(id, data)` | `ResponseT` | Busca por id, copia os campos presentes em `data` (
|
|
150
|
+
| `update(id, data)` | `ResponseT` | Busca por id, copia os campos presentes em `data` (tipado por `UpdateT`, o 3º parâmetro genérico opcional — default `BaseSchema`) na instância, persiste e mapeia. `to_dict()` descarta unset/`None`, então serve PUT e PATCH. |
|
|
151
151
|
| `delete(id)` | `None` | Hard delete via `repository.delete`. |
|
|
152
152
|
|
|
153
153
|
`map_to_response` é aguardado com `await` quando retorna uma coroutine, então mappers async funcionam de forma transparente — sem precisar sobrescrever o método.
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
# Web Push
|
|
2
|
+
|
|
3
|
+
VAPID-signed Web Push notifications to browsers via `WebPushDispatcher`.
|
|
4
|
+
It wraps the synchronous `pywebpush` library in `asyncio.to_thread` and
|
|
5
|
+
surfaces the two errors the application actually handles:
|
|
6
|
+
`WebPushGoneError` (HTTP 404/410 — delete the subscription) and
|
|
7
|
+
`WebPushError` (any other failure). Requires the `[webpush]` extra
|
|
8
|
+
(`pywebpush` + `cryptography`).
|
|
9
|
+
|
|
10
|
+
## VAPID configuration
|
|
11
|
+
|
|
12
|
+
`WebPushSettings` ships `VAPID_PUBLIC_KEY`, `VAPID_PRIVATE_KEY`, and
|
|
13
|
+
`VAPID_SUBJECT`. The **public** key goes to the frontend (in
|
|
14
|
+
`pushManager.subscribe`); the **private** key signs each push on the
|
|
15
|
+
backend. The `sub` must be a `mailto:` or `https:` URI.
|
|
16
|
+
|
|
17
|
+
```python
|
|
18
|
+
# src/services/notifications.py
|
|
19
|
+
from tempest_fastapi_sdk import WebPushDispatcher
|
|
20
|
+
|
|
21
|
+
from src.core.settings import settings
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
# settings.webpush_kwargs() -> vapid_private_key + vapid_subject + ttl_seconds
|
|
25
|
+
dispatcher = WebPushDispatcher(**settings.webpush_kwargs())
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Table + service (recommended)
|
|
29
|
+
|
|
30
|
+
To store the user's devices and deliver with automatic pruning, the SDK
|
|
31
|
+
ships the **base table** `BaseWebPushSubscriptionModel` (one row per
|
|
32
|
+
device, unique `endpoint`) and the **base service**
|
|
33
|
+
`WebPushSubscriptionService` (saves, removes and sends, pruning dead ones
|
|
34
|
+
itself). Like the auth pattern, the SDK provides the abstract row and the
|
|
35
|
+
project creates the concrete table with the FK to its `UserModel`:
|
|
36
|
+
|
|
37
|
+
```python
|
|
38
|
+
# src/db/models/web_push_subscription.py
|
|
39
|
+
from sqlalchemy import ForeignKey
|
|
40
|
+
from sqlalchemy.orm import Mapped, mapped_column
|
|
41
|
+
from uuid import UUID
|
|
42
|
+
|
|
43
|
+
from tempest_fastapi_sdk import BaseWebPushSubscriptionModel
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class WebPushSubscriptionModel(BaseWebPushSubscriptionModel):
|
|
47
|
+
"""A user device's Web Push subscription."""
|
|
48
|
+
|
|
49
|
+
__tablename__ = "web_push_subscriptions"
|
|
50
|
+
|
|
51
|
+
user_id: Mapped[UUID] = mapped_column(
|
|
52
|
+
ForeignKey("users.id", ondelete="CASCADE"),
|
|
53
|
+
nullable=False,
|
|
54
|
+
index=True,
|
|
55
|
+
)
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Build the service from a `BaseRepository` over the table + the VAPID
|
|
59
|
+
dispatcher:
|
|
60
|
+
|
|
61
|
+
```python
|
|
62
|
+
# src/api/dependencies/resources.py
|
|
63
|
+
from tempest_fastapi_sdk import BaseRepository, WebPushSubscriptionService
|
|
64
|
+
|
|
65
|
+
from src.core.settings import settings
|
|
66
|
+
from src.db.models import WebPushSubscriptionModel
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def get_push_service(session: AsyncSession) -> WebPushSubscriptionService:
|
|
70
|
+
repo = BaseRepository(session, model=WebPushSubscriptionModel)
|
|
71
|
+
dispatcher = WebPushDispatcher(**settings.webpush_kwargs())
|
|
72
|
+
return WebPushSubscriptionService(repo, dispatcher)
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
The service exposes:
|
|
76
|
+
|
|
77
|
+
| Method | What it does |
|
|
78
|
+
| --- | --- |
|
|
79
|
+
| `subscribe(user_id, subscription, *, user_agent=None)` | Persist the subscription, **idempotent by `endpoint`** — re-subscribe updates, never duplicates. |
|
|
80
|
+
| `unsubscribe(endpoint)` | Remove the subscription (no-op when absent). |
|
|
81
|
+
| `list_for_user(user_id)` | List the user's devices. |
|
|
82
|
+
| `notify_user(user_id, payload)` | Send to every device and **prune the dead ones** (404/410) before returning. Returns how many received it. |
|
|
83
|
+
|
|
84
|
+
## Aligned with tempest-react-sdk
|
|
85
|
+
|
|
86
|
+
`tempest-react-sdk`'s [`WebPushClient`](https://github.com/mauriciobenjamin700/tempest-react-sdk)
|
|
87
|
+
calls `onSubscribe(subscription)` / `onUnsubscribe(subscription)` with the
|
|
88
|
+
raw `PushSubscription.toJSON()`. That JSON *is* the
|
|
89
|
+
`WebPushSubscriptionSchema` (it aliases `expiration_time` ↔
|
|
90
|
+
`expirationTime`), so the frontend hits these endpoints directly:
|
|
91
|
+
|
|
92
|
+
```python
|
|
93
|
+
# src/api/routers/push.py
|
|
94
|
+
from fastapi import APIRouter, Depends, status
|
|
95
|
+
|
|
96
|
+
from tempest_fastapi_sdk import WebPushSubscriptionSchema, WebPushSubscriptionService
|
|
97
|
+
|
|
98
|
+
router = APIRouter(prefix="/api/push", tags=["push"])
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
@router.post("/subscribe", status_code=status.HTTP_201_CREATED)
|
|
102
|
+
async def subscribe(
|
|
103
|
+
subscription: WebPushSubscriptionSchema,
|
|
104
|
+
user: CurrentUser, # your auth dependency
|
|
105
|
+
service: WebPushSubscriptionService = Depends(get_push_service),
|
|
106
|
+
) -> dict[str, str]:
|
|
107
|
+
"""Receive the WebPushClient onSubscribe and persist the device."""
|
|
108
|
+
await service.subscribe(user.id, subscription)
|
|
109
|
+
return {"status": "subscribed"}
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
@router.post("/unsubscribe", status_code=status.HTTP_200_OK)
|
|
113
|
+
async def unsubscribe(
|
|
114
|
+
subscription: WebPushSubscriptionSchema,
|
|
115
|
+
service: WebPushSubscriptionService = Depends(get_push_service),
|
|
116
|
+
) -> dict[str, str]:
|
|
117
|
+
"""Receive the onUnsubscribe and remove the device."""
|
|
118
|
+
await service.unsubscribe(subscription.endpoint)
|
|
119
|
+
return {"status": "unsubscribed"}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Notify a user (all devices, automatic pruning built in):
|
|
123
|
+
|
|
124
|
+
```python
|
|
125
|
+
delivered: int = await service.notify_user(
|
|
126
|
+
user.id,
|
|
127
|
+
{"title": "Payment confirmed", "body": "Order approved."},
|
|
128
|
+
)
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## Send a notification (dispatcher directly)
|
|
132
|
+
|
|
133
|
+
The `payload` accepts `WebPushPayloadSchema`, `dict`, `str`, or `bytes`
|
|
134
|
+
(models and dicts are JSON-encoded). Handle `WebPushGoneError` to prune
|
|
135
|
+
the dead subscription from your store.
|
|
136
|
+
|
|
137
|
+
```python
|
|
138
|
+
from tempest_fastapi_sdk import (
|
|
139
|
+
WebPushGoneError,
|
|
140
|
+
WebPushPayloadSchema,
|
|
141
|
+
WebPushSubscriptionSchema,
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
async def notify_order_paid(
|
|
146
|
+
subscription: WebPushSubscriptionSchema,
|
|
147
|
+
order_id: str,
|
|
148
|
+
) -> None:
|
|
149
|
+
payload = WebPushPayloadSchema(
|
|
150
|
+
title="Payment confirmed",
|
|
151
|
+
body=f"Order {order_id} approved.",
|
|
152
|
+
icon="/static/icons/order.png",
|
|
153
|
+
data={"orderId": order_id, "url": f"/orders/{order_id}"},
|
|
154
|
+
)
|
|
155
|
+
try:
|
|
156
|
+
await dispatcher.send(subscription, payload)
|
|
157
|
+
except WebPushGoneError:
|
|
158
|
+
await subscriptions_repo.delete_by_endpoint(subscription.endpoint)
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
## Broadcast with automatic pruning
|
|
162
|
+
|
|
163
|
+
`send_many()` fans out the same payload concurrently (`asyncio.gather`)
|
|
164
|
+
and **returns the dead endpoints** (404/410) for you to remove — other
|
|
165
|
+
failures are logged, not raised.
|
|
166
|
+
|
|
167
|
+
```python
|
|
168
|
+
async def broadcast(
|
|
169
|
+
subs: list[WebPushSubscriptionSchema],
|
|
170
|
+
payload: WebPushPayloadSchema,
|
|
171
|
+
) -> None:
|
|
172
|
+
gone: list[str] = await dispatcher.send_many(subs, payload)
|
|
173
|
+
if gone:
|
|
174
|
+
await subscriptions_repo.delete_by_endpoints(gone)
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
!!! warning "Always prune dead subscriptions"
|
|
178
|
+
Subscriptions expire when the user changes device or revokes the
|
|
179
|
+
permission. Ignoring `WebPushGoneError` / the `send_many` return value
|
|
180
|
+
piles up zombie endpoints and wastes dispatch. Delete them as soon as
|
|
181
|
+
the push service answers 404/410.
|
|
182
|
+
|
|
183
|
+
## Recap
|
|
184
|
+
|
|
185
|
+
- Install `[webpush]` and configure `WebPushSettings` (VAPID keys).
|
|
186
|
+
- Public key → frontend; private key → signs the pushes on the backend.
|
|
187
|
+
- `BaseWebPushSubscriptionModel` table (one row per device, unique `endpoint`) + `WebPushSubscriptionService` (`subscribe`/`unsubscribe`/`notify_user`) — the recommended path, with automatic pruning.
|
|
188
|
+
- The `WebPushClient` JSON (tempest-react-sdk) *is* the `WebPushSubscriptionSchema` — `subscribe`/`unsubscribe` map directly.
|
|
189
|
+
- Low-level path: `send()` for one target, `send_many()` for broadcast (returns the dead ones); handle `WebPushGoneError` (404/410) by pruning the store.
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
# Web Push
|
|
2
|
+
|
|
3
|
+
Notificações Web Push (assinadas com VAPID) para navegadores via
|
|
4
|
+
`WebPushDispatcher`. Embrulha o `pywebpush` síncrono em
|
|
5
|
+
`asyncio.to_thread` e expõe os dois erros que a aplicação realmente
|
|
6
|
+
trata: `WebPushGoneError` (HTTP 404/410 — apague a inscrição) e
|
|
7
|
+
`WebPushError` (qualquer outra falha). Requer o extra `[webpush]`
|
|
8
|
+
(`pywebpush` + `cryptography`).
|
|
9
|
+
|
|
10
|
+
## Configuração VAPID
|
|
11
|
+
|
|
12
|
+
`WebPushSettings` traz `VAPID_PUBLIC_KEY`, `VAPID_PRIVATE_KEY` e
|
|
13
|
+
`VAPID_SUBJECT`. A chave **pública** vai para o frontend (no
|
|
14
|
+
`pushManager.subscribe`); a **privada** assina cada push no backend. O
|
|
15
|
+
`sub` deve ser um URI `mailto:` ou `https:`.
|
|
16
|
+
|
|
17
|
+
```python
|
|
18
|
+
# src/services/notifications.py
|
|
19
|
+
from tempest_fastapi_sdk import WebPushDispatcher
|
|
20
|
+
|
|
21
|
+
from src.core.settings import settings
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
# settings.webpush_kwargs() -> vapid_private_key + vapid_subject + ttl_seconds
|
|
25
|
+
dispatcher = WebPushDispatcher(**settings.webpush_kwargs())
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Tabela + serviço (recomendado)
|
|
29
|
+
|
|
30
|
+
Para guardar os aparelhos do usuário e entregar com poda automática, o
|
|
31
|
+
SDK traz a **tabela base** `BaseWebPushSubscriptionModel` (uma linha por
|
|
32
|
+
device, `endpoint` único) e o **serviço base** `WebPushSubscriptionService`
|
|
33
|
+
(salva, remove e envia, podando as mortas sozinho). Igual ao padrão de
|
|
34
|
+
auth, o SDK fornece a linha abstrata e o projeto cria a tabela concreta
|
|
35
|
+
com a FK pro seu `UserModel`:
|
|
36
|
+
|
|
37
|
+
```python
|
|
38
|
+
# src/db/models/web_push_subscription.py
|
|
39
|
+
from sqlalchemy import ForeignKey
|
|
40
|
+
from sqlalchemy.orm import Mapped, mapped_column
|
|
41
|
+
from uuid import UUID
|
|
42
|
+
|
|
43
|
+
from tempest_fastapi_sdk import BaseWebPushSubscriptionModel
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class WebPushSubscriptionModel(BaseWebPushSubscriptionModel):
|
|
47
|
+
"""Inscrição Web Push de um device do usuário."""
|
|
48
|
+
|
|
49
|
+
__tablename__ = "web_push_subscriptions"
|
|
50
|
+
|
|
51
|
+
user_id: Mapped[UUID] = mapped_column(
|
|
52
|
+
ForeignKey("users.id", ondelete="CASCADE"),
|
|
53
|
+
nullable=False,
|
|
54
|
+
index=True,
|
|
55
|
+
)
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Monte o serviço com um `BaseRepository` da tabela + o dispatcher VAPID:
|
|
59
|
+
|
|
60
|
+
```python
|
|
61
|
+
# src/api/dependencies/resources.py
|
|
62
|
+
from tempest_fastapi_sdk import BaseRepository, WebPushSubscriptionService
|
|
63
|
+
|
|
64
|
+
from src.core.settings import settings
|
|
65
|
+
from src.db.models import WebPushSubscriptionModel
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def get_push_service(session: AsyncSession) -> WebPushSubscriptionService:
|
|
69
|
+
repo = BaseRepository(session, model=WebPushSubscriptionModel)
|
|
70
|
+
dispatcher = WebPushDispatcher(**settings.webpush_kwargs())
|
|
71
|
+
return WebPushSubscriptionService(repo, dispatcher)
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
O serviço expõe:
|
|
75
|
+
|
|
76
|
+
| Método | O que faz |
|
|
77
|
+
| --- | --- |
|
|
78
|
+
| `subscribe(user_id, subscription, *, user_agent=None)` | Salva a inscrição, **idempotente por `endpoint`** — re-subscribe atualiza, não duplica. |
|
|
79
|
+
| `unsubscribe(endpoint)` | Remove a inscrição (no-op se não existe). |
|
|
80
|
+
| `list_for_user(user_id)` | Lista os devices do usuário. |
|
|
81
|
+
| `notify_user(user_id, payload)` | Envia pra todos os devices e **poda os mortos** (404/410) antes de retornar. Devolve quantos receberam. |
|
|
82
|
+
|
|
83
|
+
## Alinhado com o tempest-react-sdk
|
|
84
|
+
|
|
85
|
+
O `WebPushClient` do [`tempest-react-sdk`](https://github.com/mauriciobenjamin700/tempest-react-sdk)
|
|
86
|
+
chama `onSubscribe(subscription)` e `onUnsubscribe(subscription)` com o
|
|
87
|
+
`PushSubscription.toJSON()` cru. Esse JSON é exatamente o
|
|
88
|
+
`WebPushSubscriptionSchema` (aliasa `expiration_time` ↔ `expirationTime`),
|
|
89
|
+
então o front bate direto nos endpoints abaixo:
|
|
90
|
+
|
|
91
|
+
```python
|
|
92
|
+
# src/api/routers/push.py
|
|
93
|
+
from fastapi import APIRouter, Depends, status
|
|
94
|
+
|
|
95
|
+
from tempest_fastapi_sdk import WebPushSubscriptionSchema, WebPushSubscriptionService
|
|
96
|
+
|
|
97
|
+
router = APIRouter(prefix="/api/push", tags=["push"])
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
@router.post("/subscribe", status_code=status.HTTP_201_CREATED)
|
|
101
|
+
async def subscribe(
|
|
102
|
+
subscription: WebPushSubscriptionSchema,
|
|
103
|
+
user: CurrentUser, # sua dependency de auth
|
|
104
|
+
service: WebPushSubscriptionService = Depends(get_push_service),
|
|
105
|
+
) -> dict[str, str]:
|
|
106
|
+
"""Recebe o onSubscribe do WebPushClient e persiste o device."""
|
|
107
|
+
await service.subscribe(user.id, subscription)
|
|
108
|
+
return {"status": "subscribed"}
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
@router.post("/unsubscribe", status_code=status.HTTP_200_OK)
|
|
112
|
+
async def unsubscribe(
|
|
113
|
+
subscription: WebPushSubscriptionSchema,
|
|
114
|
+
service: WebPushSubscriptionService = Depends(get_push_service),
|
|
115
|
+
) -> dict[str, str]:
|
|
116
|
+
"""Recebe o onUnsubscribe e remove o device."""
|
|
117
|
+
await service.unsubscribe(subscription.endpoint)
|
|
118
|
+
return {"status": "unsubscribed"}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Enviar pra um usuário (todos os devices, poda automática embutida):
|
|
122
|
+
|
|
123
|
+
```python
|
|
124
|
+
delivered: int = await service.notify_user(
|
|
125
|
+
user.id,
|
|
126
|
+
{"title": "Pagamento confirmado", "body": "Pedido aprovado."},
|
|
127
|
+
)
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## Enviar uma notificação (dispatcher direto)
|
|
131
|
+
|
|
132
|
+
O `payload` aceita `WebPushPayloadSchema`, `dict`, `str` ou `bytes`
|
|
133
|
+
(models e dicts viram JSON). Trate `WebPushGoneError` para podar a
|
|
134
|
+
inscrição morta do seu store.
|
|
135
|
+
|
|
136
|
+
```python
|
|
137
|
+
from tempest_fastapi_sdk import (
|
|
138
|
+
WebPushGoneError,
|
|
139
|
+
WebPushPayloadSchema,
|
|
140
|
+
WebPushSubscriptionSchema,
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
async def notify_order_paid(
|
|
145
|
+
subscription: WebPushSubscriptionSchema,
|
|
146
|
+
order_id: str,
|
|
147
|
+
) -> None:
|
|
148
|
+
payload = WebPushPayloadSchema(
|
|
149
|
+
title="Pagamento confirmado",
|
|
150
|
+
body=f"Pedido {order_id} aprovado.",
|
|
151
|
+
icon="/static/icons/order.png",
|
|
152
|
+
data={"orderId": order_id, "url": f"/orders/{order_id}"},
|
|
153
|
+
)
|
|
154
|
+
try:
|
|
155
|
+
await dispatcher.send(subscription, payload)
|
|
156
|
+
except WebPushGoneError:
|
|
157
|
+
await subscriptions_repo.delete_by_endpoint(subscription.endpoint)
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
## Broadcast com poda automática
|
|
161
|
+
|
|
162
|
+
`send_many()` dispara o mesmo payload concorrentemente
|
|
163
|
+
(`asyncio.gather`) e **retorna os endpoints mortos** (404/410) para você
|
|
164
|
+
remover — outras falhas são logadas, não levantadas.
|
|
165
|
+
|
|
166
|
+
```python
|
|
167
|
+
async def broadcast(
|
|
168
|
+
subs: list[WebPushSubscriptionSchema],
|
|
169
|
+
payload: WebPushPayloadSchema,
|
|
170
|
+
) -> None:
|
|
171
|
+
gone: list[str] = await dispatcher.send_many(subs, payload)
|
|
172
|
+
if gone:
|
|
173
|
+
await subscriptions_repo.delete_by_endpoints(gone)
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
!!! warning "Sempre pode as inscrições mortas"
|
|
177
|
+
Inscrições expiram quando o usuário troca de device ou revoga a
|
|
178
|
+
permissão. Ignorar `WebPushGoneError` / o retorno do `send_many`
|
|
179
|
+
acumula endpoints zumbis e desperdiça dispatch. Apague-os assim que
|
|
180
|
+
o push service responder 404/410.
|
|
181
|
+
|
|
182
|
+
## Recap
|
|
183
|
+
|
|
184
|
+
- Instale `[webpush]` e configure `WebPushSettings` (chaves VAPID).
|
|
185
|
+
- Chave pública → frontend; privada → assina os pushes no backend.
|
|
186
|
+
- Tabela `BaseWebPushSubscriptionModel` (1 linha por device, `endpoint` único) + `WebPushSubscriptionService` (`subscribe`/`unsubscribe`/`notify_user`) — o caminho recomendado, com poda automática.
|
|
187
|
+
- O JSON do `WebPushClient` (tempest-react-sdk) é o próprio `WebPushSubscriptionSchema` — `subscribe`/`unsubscribe` batem direto.
|
|
188
|
+
- Caminho baixo nível: `send()` para um destino, `send_many()` para broadcast (retorna mortos); trate `WebPushGoneError` (404/410) podando o store.
|
|
@@ -252,6 +252,8 @@ Gerada automaticamente a partir das docstrings do SDK via [`mkdocstrings`](https
|
|
|
252
252
|
### `tempest_fastapi_sdk.webpush`
|
|
253
253
|
|
|
254
254
|
::: tempest_fastapi_sdk.webpush.dispatcher.WebPushDispatcher
|
|
255
|
+
::: tempest_fastapi_sdk.webpush.service.WebPushSubscriptionService
|
|
256
|
+
::: tempest_fastapi_sdk.db.webpush_subscription_model.BaseWebPushSubscriptionModel
|
|
255
257
|
::: tempest_fastapi_sdk.webpush.schemas.WebPushSubscriptionSchema
|
|
256
258
|
::: tempest_fastapi_sdk.webpush.schemas.WebPushPayloadSchema
|
|
257
259
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "tempest-fastapi-sdk"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.80.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"
|
|
@@ -133,6 +133,7 @@ from tempest_fastapi_sdk.db import (
|
|
|
133
133
|
BaseUserRecoveryCodeModel,
|
|
134
134
|
BaseUserRefreshTokenModel,
|
|
135
135
|
BaseUserTokenModel,
|
|
136
|
+
BaseWebPushSubscriptionModel,
|
|
136
137
|
DatabaseBackup,
|
|
137
138
|
DestructiveMigrationError,
|
|
138
139
|
MFAMixin,
|
|
@@ -149,6 +150,7 @@ from tempest_fastapi_sdk.db import (
|
|
|
149
150
|
make_user_recovery_code_model,
|
|
150
151
|
make_user_refresh_token_model,
|
|
151
152
|
make_user_token_model,
|
|
153
|
+
make_web_push_subscription_model,
|
|
152
154
|
reorder_base_columns_first,
|
|
153
155
|
snapshot_model,
|
|
154
156
|
)
|
|
@@ -334,6 +336,7 @@ from tempest_fastapi_sdk.webpush import (
|
|
|
334
336
|
WebPushKeysSchema,
|
|
335
337
|
WebPushPayloadSchema,
|
|
336
338
|
WebPushSubscriptionSchema,
|
|
339
|
+
WebPushSubscriptionService,
|
|
337
340
|
)
|
|
338
341
|
from tempest_fastapi_sdk.websockets import (
|
|
339
342
|
WebSocketConnection,
|
|
@@ -342,7 +345,7 @@ from tempest_fastapi_sdk.websockets import (
|
|
|
342
345
|
make_websocket_router,
|
|
343
346
|
)
|
|
344
347
|
|
|
345
|
-
__version__: str = "0.
|
|
348
|
+
__version__: str = "0.80.0"
|
|
346
349
|
|
|
347
350
|
__all__: list[str] = [
|
|
348
351
|
"BASE_COLUMN_ORDER",
|
|
@@ -398,6 +401,7 @@ __all__: list[str] = [
|
|
|
398
401
|
"BaseUserRecoveryCodeModel",
|
|
399
402
|
"BaseUserRefreshTokenModel",
|
|
400
403
|
"BaseUserTokenModel",
|
|
404
|
+
"BaseWebPushSubscriptionModel",
|
|
401
405
|
"BodySizeLimitMiddleware",
|
|
402
406
|
"CEPField",
|
|
403
407
|
"CNPJField",
|
|
@@ -561,6 +565,7 @@ __all__: list[str] = [
|
|
|
561
565
|
"WebPushPayloadSchema",
|
|
562
566
|
"WebPushSettings",
|
|
563
567
|
"WebPushSubscriptionSchema",
|
|
568
|
+
"WebPushSubscriptionService",
|
|
564
569
|
"WebSocketConnection",
|
|
565
570
|
"WebSocketHub",
|
|
566
571
|
"WebSocketSettings",
|
|
@@ -626,6 +631,7 @@ __all__: list[str] = [
|
|
|
626
631
|
"make_user_recovery_code_model",
|
|
627
632
|
"make_user_refresh_token_model",
|
|
628
633
|
"make_user_token_model",
|
|
634
|
+
"make_web_push_subscription_model",
|
|
629
635
|
"make_websocket_router",
|
|
630
636
|
"modify_dict",
|
|
631
637
|
"negotiate_locale",
|