csrd-utils 0.3.97__tar.gz → 0.3.100__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.
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/PKG-INFO +1 -1
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/pyproject.toml +1 -1
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/v2/compose/augments.py +87 -1
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/v2/compose/presets.py +4 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/v2/compose/scaffolder.py +29 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/v2/compose/service_renderers.py +57 -36
- csrd_utils-0.3.100/src/csrd_utils/v2/templates/augments/crud-scaffold/dependencies/${entity_name_snake}_repository.py.template +21 -0
- csrd_utils-0.3.100/src/csrd_utils/v2/templates/augments/crud-scaffold/migrations_${entity_name_snake}.py.template +26 -0
- csrd_utils-0.3.100/src/csrd_utils/v2/templates/augments/crud-scaffold/models/${entity_name_snake}.py.template +28 -0
- csrd_utils-0.3.100/src/csrd_utils/v2/templates/augments/crud-scaffold/repositories/${entity_name_snake}_repository.py.template +65 -0
- csrd_utils-0.3.100/src/csrd_utils/v2/templates/augments/crud-scaffold/views/${entity_name_snake}_view.py.template +67 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/v2/templates/augments/jwt-auth-provider/dependencies/db.py.template +20 -2
- csrd_utils-0.3.100/src/csrd_utils/v2/templates/augments/jwt-auth-provider/dependencies/token_service.py +22 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/v2/templates/augments/jwt-auth-provider/repositories/user_repository.py +5 -1
- csrd_utils-0.3.100/src/csrd_utils/v2/templates/augments/jwt-auth-provider/services/token_service.py +91 -0
- csrd_utils-0.3.100/src/csrd_utils/v2/templates/augments/jwt-auth-provider/views/auth_view.py +40 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/v2/templates/augments/jwt-auth-provider/views/jwks_view.py +2 -6
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/v2/templates/augments/jwt-auth-provider/views/users_view.py +1 -4
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/v2/templates/service/{{cookiecutter.__service_name_snake}}/__init__.py +1 -0
- csrd_utils-0.3.97/src/csrd_utils/v2/templates/augments/jwt-auth-provider/views/auth_view.py +0 -115
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/.gitignore +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/README.md +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/__init__.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/__main__.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/audit.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/augmentor.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/cluster.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/doctor.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/features/caching/conftest.fragment.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/features/caching/docker-compose.fragment.yaml +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/features/caching/manifest.yaml +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/features/caching/requirements.fragment +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/features/caching/settings.fragment.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/features/caching/src/app/cache.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/features/caching/tests/test_cache.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/features/logging/conftest.fragment.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/features/logging/manifest.yaml +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/features/logging/requirements.fragment +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/features/logging/settings.fragment.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/features/logging/src/app/middleware/logging.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/features/logging/tests/test_logging_middleware.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/features/metrics/conftest.fragment.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/features/metrics/docker-compose.fragment.yaml +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/features/metrics/manifest.yaml +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/features/metrics/requirements.fragment +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/features/metrics/settings.fragment.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/features/metrics/src/app/middleware/metrics.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/features/metrics/tests/test_metrics_middleware.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/features/tracing/conftest.fragment.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/features/tracing/manifest.yaml +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/features/tracing/requirements.fragment +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/features/tracing/settings.fragment.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/features/tracing/src/app/middleware/tracing.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/features/tracing/tests/test_tracing_middleware.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/features/workers/conftest.fragment.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/features/workers/docker-compose.fragment.yaml +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/features/workers/manifest.yaml +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/features/workers/requirements.fragment +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/features/workers/settings.fragment.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/features/workers/src/app/workers/__init__.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/features/workers/src/app/workers/celery_app.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/features/workers/src/app/workers/tasks.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/features/workers/tests/test_workers.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/fragments.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/generator.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/resources.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/templates/cookiecutter-service/README.md +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/templates/cookiecutter-service/cookiecutter.json +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/templates/cookiecutter-service/hooks/post_gen_project.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/.cookiecutterignore +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/.dockerignore +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/Dockerfile +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/README.md +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/__init__.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/cache.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/delegates/__init__.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/delegates/upstreams.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/dependencies/__init__.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/dependencies/auth_service.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/dependencies/delegates.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/dependencies/item_repository.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/dependencies/worker_broker.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/docker-compose.yml +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/middleware/__init__.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/middleware/logging.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/repositories/__init__.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/repositories/item_repository.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/requirements.txt +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/settings.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/tests/__init__.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/tests/acceptance/__init__.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/tests/acceptance/test_logging_middleware.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/tests/conftest.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/tests/test_items.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/tests/unit/__init__.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/tests/unit/test_cache.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/tests/unit/test_database_settings.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/tests/unit/test_delegates.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/tests/unit/test_settings_contracts.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/tests/unit/test_worker_broker.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/views/__init__.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/views/unversioned/__init__.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/views/unversioned/health_view.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/views/unversioned/items_view.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/workers/__init__.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/workers/tasks.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/templates/platform-app-service/cookiecutter.json +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/.dockerignore +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/Dockerfile +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/README.md +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/__init__.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/delegates/__init__.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/delegates/auth_delegate.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/delegates/identity_delegate.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/dependencies/__init__.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/dependencies/auth_passthrough.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/dependencies/auth_service.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/dependencies/item_repository.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/models/__init__.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/models/auth_service.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/models/items.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/repositories/__init__.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/repositories/item_repository.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/requirements.txt +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/settings.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/views/__init__.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/views/unversioned/__init__.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/views/unversioned/auth_service_view.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/views/unversioned/health_view.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/views/unversioned/items_view.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/templates/platform-auth-service/cookiecutter.json +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/templates/platform-auth-service/{{cookiecutter.__service_name_snake}}/.dockerignore +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/templates/platform-auth-service/{{cookiecutter.__service_name_snake}}/Dockerfile +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/templates/platform-auth-service/{{cookiecutter.__service_name_snake}}/README.md +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/templates/platform-auth-service/{{cookiecutter.__service_name_snake}}/__init__.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/templates/platform-auth-service/{{cookiecutter.__service_name_snake}}/dependencies/__init__.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/templates/platform-auth-service/{{cookiecutter.__service_name_snake}}/models/__init__.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/templates/platform-auth-service/{{cookiecutter.__service_name_snake}}/models/auth.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/templates/platform-auth-service/{{cookiecutter.__service_name_snake}}/repositories/__init__.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/templates/platform-auth-service/{{cookiecutter.__service_name_snake}}/repositories/token_repository.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/templates/platform-auth-service/{{cookiecutter.__service_name_snake}}/requirements.txt +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/templates/platform-auth-service/{{cookiecutter.__service_name_snake}}/settings.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/templates/platform-auth-service/{{cookiecutter.__service_name_snake}}/views/__init__.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/templates/platform-auth-service/{{cookiecutter.__service_name_snake}}/views/unversioned/__init__.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/templates/platform-auth-service/{{cookiecutter.__service_name_snake}}/views/unversioned/auth_view.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/templates/platform-auth-service/{{cookiecutter.__service_name_snake}}/views/unversioned/health_view.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/templates/platform-identity-service/cookiecutter.json +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/templates/platform-identity-service/{{cookiecutter.__service_name_snake}}/.dockerignore +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/templates/platform-identity-service/{{cookiecutter.__service_name_snake}}/Dockerfile +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/templates/platform-identity-service/{{cookiecutter.__service_name_snake}}/README.md +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/templates/platform-identity-service/{{cookiecutter.__service_name_snake}}/__init__.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/templates/platform-identity-service/{{cookiecutter.__service_name_snake}}/dependencies/__init__.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/templates/platform-identity-service/{{cookiecutter.__service_name_snake}}/models/__init__.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/templates/platform-identity-service/{{cookiecutter.__service_name_snake}}/models/users.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/templates/platform-identity-service/{{cookiecutter.__service_name_snake}}/repositories/__init__.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/templates/platform-identity-service/{{cookiecutter.__service_name_snake}}/repositories/user_repository.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/templates/platform-identity-service/{{cookiecutter.__service_name_snake}}/requirements.txt +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/templates/platform-identity-service/{{cookiecutter.__service_name_snake}}/settings.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/templates/platform-identity-service/{{cookiecutter.__service_name_snake}}/views/__init__.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/templates/platform-identity-service/{{cookiecutter.__service_name_snake}}/views/unversioned/__init__.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/templates/platform-identity-service/{{cookiecutter.__service_name_snake}}/views/unversioned/health_view.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/templates/platform-identity-service/{{cookiecutter.__service_name_snake}}/views/unversioned/users_view.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/v2/AGENTS.md +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/v2/__init__.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/v2/compose/__init__.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/v2/compose/git.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/v2/compose/infra.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/v2/compose/loader.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/v2/compose/operations.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/v2/compose/renderer.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/v2/compose/yaml_editor.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/v2/generate/__init__.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/v2/generate/handlers.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/v2/generate/helpers.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/v2/generate/menu.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/v2/models/__init__.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/v2/models/base.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/v2/models/spec.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/v2/models/types.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/v2/templates/augments/auth-passthrough/delegates/auth_delegate.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/v2/templates/augments/auth-passthrough/dependencies/auth_passthrough.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/v2/templates/augments/auth-passthrough/models/auth_passthrough.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/v2/templates/augments/auth-passthrough/views/auth_passthrough_view.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/v2/templates/augments/db-config/dependencies/db.py.template +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/v2/templates/augments/db-config/migrations.py.template +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/v2/templates/augments/jwt-auth-consumer/dependencies/auth.py.template +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/v2/templates/augments/jwt-auth-provider/migrations.py.template +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/v2/templates/augments/jwt-auth-provider/models/auth.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/v2/templates/augments/jwt-auth-provider/models/jwks.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/v2/templates/augments/jwt-auth-provider/models/users.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/v2/templates/service/cookiecutter.json +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/v2/templates/service/{{cookiecutter.__service_name_snake}}/Dockerfile +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/v2/templates/service/{{cookiecutter.__service_name_snake}}/README.md +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/v2/templates/service/{{cookiecutter.__service_name_snake}}/dependencies/__init__.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/v2/templates/service/{{cookiecutter.__service_name_snake}}/models/__init__.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/v2/templates/service/{{cookiecutter.__service_name_snake}}/models/health.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/v2/templates/service/{{cookiecutter.__service_name_snake}}/requirements.txt +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/v2/templates/service/{{cookiecutter.__service_name_snake}}/settings.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/v2/templates/service/{{cookiecutter.__service_name_snake}}/tests/__init__.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/v2/templates/service/{{cookiecutter.__service_name_snake}}/tests/conftest.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/v2/templates/service/{{cookiecutter.__service_name_snake}}/tests/test_health.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/v2/templates/service/{{cookiecutter.__service_name_snake}}/views/__init__.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/csrd_utils/v2/templates/service/{{cookiecutter.__service_name_snake}}/views/health_view.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/tui_wizard/__init__.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/tui_wizard/exceptions.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/tui_wizard/menu.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/tui_wizard/models.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/tui_wizard/prompts.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/tui_wizard/terminal.py +0 -0
- {csrd_utils-0.3.97 → csrd_utils-0.3.100}/src/tui_wizard/wizard.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: csrd-utils
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.100
|
|
4
4
|
Summary: CLI utilities for csrd service generation and feature augmentation
|
|
5
5
|
Project-URL: Repository, https://github.com/csrd-api/fastapi-common
|
|
6
6
|
Project-URL: Documentation, https://github.com/csrd-api/fastapi-common/tree/main/packages/utils
|
|
@@ -13,6 +13,44 @@ from dataclasses import dataclass, field
|
|
|
13
13
|
from typing import Literal
|
|
14
14
|
|
|
15
15
|
|
|
16
|
+
@dataclass(frozen=True)
|
|
17
|
+
class RouterDescriptor:
|
|
18
|
+
"""Describes a router contributed by an augment.
|
|
19
|
+
|
|
20
|
+
Parameters
|
|
21
|
+
----------
|
|
22
|
+
import_path
|
|
23
|
+
Dot-path relative to the service package, e.g.
|
|
24
|
+
``".views.auth_passthrough_view"``.
|
|
25
|
+
attr
|
|
26
|
+
Name of the router attribute in the module, e.g. ``"router"``.
|
|
27
|
+
alias
|
|
28
|
+
Import alias used in ``__init__.py``, e.g.
|
|
29
|
+
``"auth_passthrough_router"``.
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
import_path: str
|
|
33
|
+
attr: str = "router"
|
|
34
|
+
alias: str = ""
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
@dataclass(frozen=True)
|
|
38
|
+
class MiddlewareDescriptor:
|
|
39
|
+
"""Describes middleware contributed by an augment."""
|
|
40
|
+
|
|
41
|
+
import_path: str
|
|
42
|
+
class_name: str
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
@dataclass(frozen=True)
|
|
46
|
+
class ExceptionHandlerDescriptor:
|
|
47
|
+
"""Describes an exception handler contributed by an augment."""
|
|
48
|
+
|
|
49
|
+
import_path: str
|
|
50
|
+
handler_name: str
|
|
51
|
+
exception_class: str = "Exception"
|
|
52
|
+
|
|
53
|
+
|
|
16
54
|
@dataclass(frozen=True)
|
|
17
55
|
class AugmentDescriptor:
|
|
18
56
|
"""Complete description of an augment capability.
|
|
@@ -81,6 +119,15 @@ class AugmentDescriptor:
|
|
|
81
119
|
# service with this role. ``None`` means no scaffolding.
|
|
82
120
|
applies_to_role: str | None = None
|
|
83
121
|
|
|
122
|
+
# Routers to wire into __init__.py via include_router
|
|
123
|
+
routers: list[RouterDescriptor] = field(default_factory=list)
|
|
124
|
+
|
|
125
|
+
# Middleware to add to the app
|
|
126
|
+
middleware: list[MiddlewareDescriptor] = field(default_factory=list)
|
|
127
|
+
|
|
128
|
+
# Exception handlers to register on the app
|
|
129
|
+
exception_handlers: list[ExceptionHandlerDescriptor] = field(default_factory=list)
|
|
130
|
+
|
|
84
131
|
|
|
85
132
|
# ---------------------------------------------------------------------------
|
|
86
133
|
# Registry
|
|
@@ -102,6 +149,20 @@ AUGMENT_REGISTRY: dict[str, AugmentDescriptor] = {
|
|
|
102
149
|
],
|
|
103
150
|
template_dir="jwt-auth-provider",
|
|
104
151
|
applies_to_role="auth",
|
|
152
|
+
routers=[
|
|
153
|
+
RouterDescriptor(
|
|
154
|
+
import_path=".views.auth_view",
|
|
155
|
+
alias="auth_router",
|
|
156
|
+
),
|
|
157
|
+
RouterDescriptor(
|
|
158
|
+
import_path=".views.users_view",
|
|
159
|
+
alias="users_router",
|
|
160
|
+
),
|
|
161
|
+
RouterDescriptor(
|
|
162
|
+
import_path=".views.jwks_view",
|
|
163
|
+
alias="jwks_router",
|
|
164
|
+
),
|
|
165
|
+
],
|
|
105
166
|
),
|
|
106
167
|
# ── Service-scope ──────────────────────────────────────────────
|
|
107
168
|
"db-config": AugmentDescriptor(
|
|
@@ -138,7 +199,12 @@ AUGMENT_REGISTRY: dict[str, AugmentDescriptor] = {
|
|
|
138
199
|
requires_workspace_augment="jwt-auth-provider",
|
|
139
200
|
packages=["csrd-delegate", "csrd-models"],
|
|
140
201
|
template_dir="auth-passthrough",
|
|
141
|
-
|
|
202
|
+
routers=[
|
|
203
|
+
RouterDescriptor(
|
|
204
|
+
import_path=".views.auth_passthrough_view",
|
|
205
|
+
alias="auth_passthrough_router",
|
|
206
|
+
),
|
|
207
|
+
],
|
|
142
208
|
),
|
|
143
209
|
"context-logging": AugmentDescriptor(
|
|
144
210
|
name="context-logging",
|
|
@@ -146,6 +212,12 @@ AUGMENT_REGISTRY: dict[str, AugmentDescriptor] = {
|
|
|
146
212
|
description="Request context middleware and structured logging",
|
|
147
213
|
packages=["csrd-logging", "csrd-context"],
|
|
148
214
|
template_dir="context-logging",
|
|
215
|
+
middleware=[
|
|
216
|
+
MiddlewareDescriptor(
|
|
217
|
+
import_path="csrd.context.middleware",
|
|
218
|
+
class_name="RequestContextMiddleware",
|
|
219
|
+
),
|
|
220
|
+
],
|
|
149
221
|
),
|
|
150
222
|
"service-layer": AugmentDescriptor(
|
|
151
223
|
name="service-layer",
|
|
@@ -153,6 +225,20 @@ AUGMENT_REGISTRY: dict[str, AugmentDescriptor] = {
|
|
|
153
225
|
description="BaseService + ServiceError hierarchy + exception handler",
|
|
154
226
|
packages=["csrd-service", "csrd-models"],
|
|
155
227
|
template_dir="service-layer",
|
|
228
|
+
exception_handlers=[
|
|
229
|
+
ExceptionHandlerDescriptor(
|
|
230
|
+
import_path="csrd.service",
|
|
231
|
+
handler_name="service_exception_handler",
|
|
232
|
+
),
|
|
233
|
+
],
|
|
234
|
+
),
|
|
235
|
+
"crud-scaffold": AugmentDescriptor(
|
|
236
|
+
name="crud-scaffold",
|
|
237
|
+
scope="service",
|
|
238
|
+
description="CRUD endpoints for a named entity with token-guarded views",
|
|
239
|
+
packages=[], # db-config + jwt-auth-consumer cover dependencies
|
|
240
|
+
template_dir="crud-scaffold",
|
|
241
|
+
routers=[], # routers are dynamic per entity — wired via options
|
|
156
242
|
),
|
|
157
243
|
}
|
|
158
244
|
|
|
@@ -35,6 +35,10 @@ PRESET_REGISTRY: dict[str, PresetDefinition] = {
|
|
|
35
35
|
ServiceAugment(name="jwt-auth-consumer"),
|
|
36
36
|
ServiceAugment(name="auth-passthrough"),
|
|
37
37
|
ServiceAugment(name="db-config"),
|
|
38
|
+
ServiceAugment(
|
|
39
|
+
name="crud-scaffold",
|
|
40
|
+
options={"entity_name": "item"},
|
|
41
|
+
),
|
|
38
42
|
],
|
|
39
43
|
),
|
|
40
44
|
ServiceNode(
|
|
@@ -139,6 +139,33 @@ def _augment_template_vars(
|
|
|
139
139
|
"port": str(service.port),
|
|
140
140
|
}
|
|
141
141
|
|
|
142
|
+
# Auto-pass augment options as template variables
|
|
143
|
+
for key, value in augment.options.items():
|
|
144
|
+
if isinstance(value, str):
|
|
145
|
+
variables[key] = value
|
|
146
|
+
|
|
147
|
+
# Derive entity name variants for crud-scaffold
|
|
148
|
+
if augment.name == "crud-scaffold":
|
|
149
|
+
entity_raw = augment.options.get("entity_name", "item")
|
|
150
|
+
entity = entity_raw if isinstance(entity_raw, str) else entity_raw[0]
|
|
151
|
+
snake = entity.replace("-", "_").lower()
|
|
152
|
+
pascal = "".join(w.capitalize() for w in snake.split("_"))
|
|
153
|
+
plural_raw = augment.options.get("entity_name_plural", snake + "s")
|
|
154
|
+
plural = plural_raw if isinstance(plural_raw, str) else plural_raw[0]
|
|
155
|
+
variables["entity_name"] = entity
|
|
156
|
+
variables["entity_name_snake"] = snake
|
|
157
|
+
variables["entity_name_pascal"] = pascal
|
|
158
|
+
variables["entity_name_plural"] = plural
|
|
159
|
+
|
|
160
|
+
# SQL dialect for migration (same logic as db-config)
|
|
161
|
+
db = detect_configured_db({n.type for n in spec.infra})
|
|
162
|
+
if db == "postgres":
|
|
163
|
+
variables["sql_auto_id"] = "SERIAL PRIMARY KEY"
|
|
164
|
+
elif db == "mariadb":
|
|
165
|
+
variables["sql_auto_id"] = "INTEGER PRIMARY KEY AUTO_INCREMENT"
|
|
166
|
+
else:
|
|
167
|
+
variables["sql_auto_id"] = "INTEGER PRIMARY KEY AUTOINCREMENT"
|
|
168
|
+
|
|
142
169
|
# Database adapter variables — shared by db-config and jwt-auth-provider
|
|
143
170
|
if augment.name in ("db-config", "jwt-auth-provider"):
|
|
144
171
|
db = detect_configured_db({n.type for n in spec.infra})
|
|
@@ -258,6 +285,8 @@ def scaffold_augment(
|
|
|
258
285
|
continue
|
|
259
286
|
|
|
260
287
|
relative = template_file.relative_to(template_dir)
|
|
288
|
+
# Apply template substitution to file path (e.g. $entity_name_snake.py → item.py)
|
|
289
|
+
relative = Path(Template(str(relative)).safe_substitute(variables))
|
|
261
290
|
dest = svc_dest / relative
|
|
262
291
|
|
|
263
292
|
# Strip .template suffix so e.g. db.py.template → db.py
|
|
@@ -8,7 +8,7 @@ separate scaffolded files (views, repositories, services, dependencies).
|
|
|
8
8
|
import re
|
|
9
9
|
|
|
10
10
|
from ..models import ComposeSpec, ServiceNode
|
|
11
|
-
from .augments import AUGMENT_REGISTRY
|
|
11
|
+
from .augments import AUGMENT_REGISTRY, AugmentDescriptor
|
|
12
12
|
from .infra import INFRA_REGISTRY, detect_configured_db
|
|
13
13
|
|
|
14
14
|
# Pattern to extract default from docker-compose interpolation: ${VAR:-default}
|
|
@@ -254,11 +254,21 @@ def render_settings(svc: ServiceNode, spec: ComposeSpec) -> str:
|
|
|
254
254
|
|
|
255
255
|
def render_init(svc: ServiceNode, spec: ComposeSpec) -> str:
|
|
256
256
|
"""Render ``__init__.py`` with ``build_app()`` + augment middleware/handlers."""
|
|
257
|
-
augment_names = {a.name for a in svc.augments}
|
|
258
|
-
ws_augment_names = {a.name for a in spec.workspace.augments}
|
|
259
257
|
|
|
260
|
-
#
|
|
261
|
-
|
|
258
|
+
# Collect all augment descriptors that apply to this service
|
|
259
|
+
descriptors: list[tuple[str, AugmentDescriptor]] = []
|
|
260
|
+
|
|
261
|
+
# Workspace augments targeting this service's role
|
|
262
|
+
for ws_aug in spec.workspace.augments:
|
|
263
|
+
desc = AUGMENT_REGISTRY.get(ws_aug.name)
|
|
264
|
+
if desc is not None and desc.applies_to_role == svc.role:
|
|
265
|
+
descriptors.append((ws_aug.name, desc))
|
|
266
|
+
|
|
267
|
+
# Service-scope augments
|
|
268
|
+
for augment in svc.augments:
|
|
269
|
+
desc = AUGMENT_REGISTRY.get(augment.name)
|
|
270
|
+
if desc is not None:
|
|
271
|
+
descriptors.append((augment.name, desc))
|
|
262
272
|
|
|
263
273
|
# Collect imports
|
|
264
274
|
imports = [
|
|
@@ -275,26 +285,39 @@ def render_init(svc: ServiceNode, spec: ComposeSpec) -> str:
|
|
|
275
285
|
"from .views import app as unversioned_app",
|
|
276
286
|
]
|
|
277
287
|
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
)
|
|
286
|
-
|
|
287
|
-
if "context-logging" in augment_names:
|
|
288
|
-
imports.append("")
|
|
289
|
-
imports.append("from csrd.context.middleware import RequestContextMiddleware")
|
|
290
|
-
|
|
291
|
-
if "auth-passthrough" in augment_names:
|
|
292
|
-
imports.append("")
|
|
293
|
-
imports.append("from .views.auth_passthrough_view import router as auth_passthrough_router")
|
|
288
|
+
# Router imports (from descriptors)
|
|
289
|
+
router_aliases: list[str] = []
|
|
290
|
+
for _name, desc in descriptors:
|
|
291
|
+
for r in desc.routers:
|
|
292
|
+
alias = r.alias or r.import_path.rsplit(".", 1)[-1] + "_router"
|
|
293
|
+
imports.append(f"from {r.import_path} import {r.attr} as {alias}")
|
|
294
|
+
router_aliases.append(alias)
|
|
294
295
|
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
296
|
+
# Dynamic routers from crud-scaffold augments (entity-name-based)
|
|
297
|
+
for augment in svc.augments:
|
|
298
|
+
if augment.name == "crud-scaffold":
|
|
299
|
+
entity_raw = augment.options.get("entity_name", "item")
|
|
300
|
+
entity = entity_raw if isinstance(entity_raw, str) else entity_raw[0]
|
|
301
|
+
snake = entity.replace("-", "_").lower()
|
|
302
|
+
alias = f"{snake}_router"
|
|
303
|
+
imports.append(f"from .views.{snake}_view import router as {alias}")
|
|
304
|
+
router_aliases.append(alias)
|
|
305
|
+
|
|
306
|
+
# Middleware imports
|
|
307
|
+
middleware_classes: list[str] = []
|
|
308
|
+
for _name, desc in descriptors:
|
|
309
|
+
for m in desc.middleware:
|
|
310
|
+
imports.append("")
|
|
311
|
+
imports.append(f"from {m.import_path} import {m.class_name}")
|
|
312
|
+
middleware_classes.append(m.class_name)
|
|
313
|
+
|
|
314
|
+
# Exception handler imports
|
|
315
|
+
handler_pairs: list[tuple[str, str]] = [] # (exception_class, handler_name)
|
|
316
|
+
for _name, desc in descriptors:
|
|
317
|
+
for eh in desc.exception_handlers:
|
|
318
|
+
imports.append("")
|
|
319
|
+
imports.append(f"from {eh.import_path} import {eh.handler_name}")
|
|
320
|
+
handler_pairs.append((eh.exception_class, eh.handler_name))
|
|
298
321
|
|
|
299
322
|
# Build app body
|
|
300
323
|
body = [
|
|
@@ -303,14 +326,10 @@ def render_init(svc: ServiceNode, spec: ComposeSpec) -> str:
|
|
|
303
326
|
"def build_app() -> FastAPI:",
|
|
304
327
|
]
|
|
305
328
|
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
body.append("")
|
|
311
|
-
|
|
312
|
-
if "auth-passthrough" in augment_names:
|
|
313
|
-
body.append(" unversioned_app.include_router(auth_passthrough_router)")
|
|
329
|
+
# Wire routers
|
|
330
|
+
if router_aliases:
|
|
331
|
+
for alias in router_aliases:
|
|
332
|
+
body.append(f" unversioned_app.include_router({alias})")
|
|
314
333
|
body.append("")
|
|
315
334
|
|
|
316
335
|
body.extend(
|
|
@@ -329,13 +348,15 @@ def render_init(svc: ServiceNode, spec: ComposeSpec) -> str:
|
|
|
329
348
|
]
|
|
330
349
|
)
|
|
331
350
|
|
|
332
|
-
|
|
351
|
+
# Wire middleware
|
|
352
|
+
for cls in middleware_classes:
|
|
333
353
|
body.append("")
|
|
334
|
-
body.append(" app.add_middleware(
|
|
354
|
+
body.append(f" app.add_middleware({cls})")
|
|
335
355
|
|
|
336
|
-
|
|
356
|
+
# Wire exception handlers
|
|
357
|
+
for exc_cls, handler in handler_pairs:
|
|
337
358
|
body.append("")
|
|
338
|
-
body.append(" app.add_exception_handler(
|
|
359
|
+
body.append(f" app.add_exception_handler({exc_cls}, {handler})")
|
|
339
360
|
|
|
340
361
|
body.extend(
|
|
341
362
|
[
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"""${entity_name_pascal} repository dependency.
|
|
2
|
+
|
|
3
|
+
This file is scaffolded once and never overwritten.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from typing import Annotated
|
|
7
|
+
|
|
8
|
+
from fastapi import Depends
|
|
9
|
+
|
|
10
|
+
from ..repositories.${entity_name_snake}_repository import ${entity_name_pascal}Repository
|
|
11
|
+
from .db import Adapter
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def _${entity_name_snake}_repository_factory(adapter: Adapter) -> ${entity_name_pascal}Repository:
|
|
15
|
+
"""Create a ``${entity_name_pascal}Repository`` backed by the database adapter."""
|
|
16
|
+
return ${entity_name_pascal}Repository(adapter)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
${entity_name_pascal}Repo = Annotated[${entity_name_pascal}Repository, Depends(_${entity_name_snake}_repository_factory)]
|
|
20
|
+
|
|
21
|
+
__all__ = ("${entity_name_pascal}Repo",)
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"""Migration for the ${entity_name_plural} table.
|
|
2
|
+
|
|
3
|
+
Import this into your ``migrations.py`` and append to the migrations list:
|
|
4
|
+
|
|
5
|
+
from .migrations_${entity_name_snake} import ${entity_name_snake}_migration
|
|
6
|
+
migrations.append(${entity_name_snake}_migration)
|
|
7
|
+
|
|
8
|
+
This file is scaffolded once and never overwritten.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from csrd.migration import Migration
|
|
12
|
+
|
|
13
|
+
${entity_name_snake}_migration = Migration(
|
|
14
|
+
version="${entity_name_snake}_001",
|
|
15
|
+
description="Create ${entity_name_plural} table",
|
|
16
|
+
up=(
|
|
17
|
+
"CREATE TABLE IF NOT EXISTS ${entity_name_plural} ("
|
|
18
|
+
" id TEXT PRIMARY KEY,"
|
|
19
|
+
" name TEXT NOT NULL,"
|
|
20
|
+
" created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP"
|
|
21
|
+
")"
|
|
22
|
+
),
|
|
23
|
+
down="DROP TABLE IF EXISTS ${entity_name_plural}",
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
__all__ = ("${entity_name_snake}_migration",)
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"""${entity_name_pascal} models for CRUD operations."""
|
|
2
|
+
|
|
3
|
+
from csrd.models import BaseModel
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Create${entity_name_pascal}Request(BaseModel):
|
|
7
|
+
"""Request body for creating a new ${entity_name}."""
|
|
8
|
+
|
|
9
|
+
name: str
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class Update${entity_name_pascal}Request(BaseModel):
|
|
13
|
+
"""Request body for updating an existing ${entity_name}."""
|
|
14
|
+
|
|
15
|
+
name: str
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class ${entity_name_pascal}Response(BaseModel):
|
|
19
|
+
"""Response model for a single ${entity_name}."""
|
|
20
|
+
|
|
21
|
+
id: str
|
|
22
|
+
name: str
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class ${entity_name_pascal}ListResponse(BaseModel):
|
|
26
|
+
"""Response model for a list of ${entity_name_plural}."""
|
|
27
|
+
|
|
28
|
+
items: list[${entity_name_pascal}Response]
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"""${entity_name_pascal} repository — CRUD operations.
|
|
2
|
+
|
|
3
|
+
This file is scaffolded once and never overwritten.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import uuid
|
|
7
|
+
|
|
8
|
+
from fastapi import HTTPException
|
|
9
|
+
|
|
10
|
+
from csrd.repository import BaseRepository
|
|
11
|
+
|
|
12
|
+
from ..models.${entity_name_snake} import (
|
|
13
|
+
${entity_name_pascal}ListResponse,
|
|
14
|
+
${entity_name_pascal}Response,
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class ${entity_name_pascal}Repository(BaseRepository):
|
|
19
|
+
"""CRUD storage for ${entity_name_plural}."""
|
|
20
|
+
|
|
21
|
+
async def create(self, name: str) -> ${entity_name_pascal}Response:
|
|
22
|
+
"""Create a new ${entity_name}."""
|
|
23
|
+
entity_id = str(uuid.uuid4())
|
|
24
|
+
await self.execute(
|
|
25
|
+
"INSERT INTO ${entity_name_plural} (id, name) VALUES (:id, :name)",
|
|
26
|
+
{"id": entity_id, "name": name},
|
|
27
|
+
)
|
|
28
|
+
return ${entity_name_pascal}Response(id=entity_id, name=name)
|
|
29
|
+
|
|
30
|
+
async def get_by_id(self, entity_id: str) -> ${entity_name_pascal}Response:
|
|
31
|
+
"""Get a ${entity_name} by ID. Raises 404 if not found."""
|
|
32
|
+
return await self.require_one(
|
|
33
|
+
"SELECT id, name FROM ${entity_name_plural} WHERE id = :id",
|
|
34
|
+
{"id": entity_id},
|
|
35
|
+
model=${entity_name_pascal}Response,
|
|
36
|
+
detail="${entity_name_pascal} not found",
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
async def list_all(self) -> ${entity_name_pascal}ListResponse:
|
|
40
|
+
"""List all ${entity_name_plural}."""
|
|
41
|
+
rows = await self.fetch_all(
|
|
42
|
+
"SELECT id, name FROM ${entity_name_plural} ORDER BY name",
|
|
43
|
+
)
|
|
44
|
+
items = [self.apply_model(row, model=${entity_name_pascal}Response) for row in rows]
|
|
45
|
+
return ${entity_name_pascal}ListResponse(items=items)
|
|
46
|
+
|
|
47
|
+
async def update(self, entity_id: str, name: str) -> ${entity_name_pascal}Response:
|
|
48
|
+
"""Update a ${entity_name}. Raises 404 if not found."""
|
|
49
|
+
await self.get_by_id(entity_id) # ensures exists
|
|
50
|
+
await self.execute(
|
|
51
|
+
"UPDATE ${entity_name_plural} SET name = :name WHERE id = :id",
|
|
52
|
+
{"id": entity_id, "name": name},
|
|
53
|
+
)
|
|
54
|
+
return ${entity_name_pascal}Response(id=entity_id, name=name)
|
|
55
|
+
|
|
56
|
+
async def delete(self, entity_id: str) -> None:
|
|
57
|
+
"""Delete a ${entity_name}. Raises 404 if not found."""
|
|
58
|
+
await self.get_by_id(entity_id) # ensures exists
|
|
59
|
+
await self.execute(
|
|
60
|
+
"DELETE FROM ${entity_name_plural} WHERE id = :id",
|
|
61
|
+
{"id": entity_id},
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
__all__ = ("${entity_name_pascal}Repository",)
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"""${entity_name_pascal} CRUD endpoints — token-guarded.
|
|
2
|
+
|
|
3
|
+
This file is scaffolded once and never overwritten.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from fastapi import APIRouter, Security
|
|
7
|
+
|
|
8
|
+
from ..dependencies.auth import auth_dep
|
|
9
|
+
from ..dependencies.${entity_name_snake}_repository import ${entity_name_pascal}Repo
|
|
10
|
+
from ..models.${entity_name_snake} import (
|
|
11
|
+
Create${entity_name_pascal}Request,
|
|
12
|
+
${entity_name_pascal}ListResponse,
|
|
13
|
+
${entity_name_pascal}Response,
|
|
14
|
+
Update${entity_name_pascal}Request,
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
router = APIRouter(prefix="/api/${entity_name_plural}", tags=["${entity_name_plural}"])
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@router.get("", response_model=${entity_name_pascal}ListResponse)
|
|
21
|
+
async def list_${entity_name_plural}(
|
|
22
|
+
repo: ${entity_name_pascal}Repo,
|
|
23
|
+
_claims=Security(auth_dep),
|
|
24
|
+
) -> ${entity_name_pascal}ListResponse:
|
|
25
|
+
"""List all ${entity_name_plural}."""
|
|
26
|
+
return await repo.list_all()
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
@router.get("/{entity_id}", response_model=${entity_name_pascal}Response)
|
|
30
|
+
async def get_${entity_name_snake}(
|
|
31
|
+
entity_id: str,
|
|
32
|
+
repo: ${entity_name_pascal}Repo,
|
|
33
|
+
_claims=Security(auth_dep),
|
|
34
|
+
) -> ${entity_name_pascal}Response:
|
|
35
|
+
"""Get a ${entity_name} by ID."""
|
|
36
|
+
return await repo.get_by_id(entity_id)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
@router.post("", status_code=201, response_model=${entity_name_pascal}Response)
|
|
40
|
+
async def create_${entity_name_snake}(
|
|
41
|
+
body: Create${entity_name_pascal}Request,
|
|
42
|
+
repo: ${entity_name_pascal}Repo,
|
|
43
|
+
_claims=Security(auth_dep),
|
|
44
|
+
) -> ${entity_name_pascal}Response:
|
|
45
|
+
"""Create a new ${entity_name}."""
|
|
46
|
+
return await repo.create(body.name)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
@router.put("/{entity_id}", response_model=${entity_name_pascal}Response)
|
|
50
|
+
async def update_${entity_name_snake}(
|
|
51
|
+
entity_id: str,
|
|
52
|
+
body: Update${entity_name_pascal}Request,
|
|
53
|
+
repo: ${entity_name_pascal}Repo,
|
|
54
|
+
_claims=Security(auth_dep),
|
|
55
|
+
) -> ${entity_name_pascal}Response:
|
|
56
|
+
"""Update an existing ${entity_name}."""
|
|
57
|
+
return await repo.update(entity_id, body.name)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
@router.delete("/{entity_id}", status_code=204)
|
|
61
|
+
async def delete_${entity_name_snake}(
|
|
62
|
+
entity_id: str,
|
|
63
|
+
repo: ${entity_name_pascal}Repo,
|
|
64
|
+
_claims=Security(auth_dep),
|
|
65
|
+
) -> None:
|
|
66
|
+
"""Delete a ${entity_name}."""
|
|
67
|
+
await repo.delete(entity_id)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"""Database and
|
|
1
|
+
"""Database, repository, and key ring dependencies for the auth service.
|
|
2
2
|
|
|
3
3
|
This file is scaffolded once and never overwritten.
|
|
4
4
|
"""
|
|
@@ -7,6 +7,8 @@ from typing import Annotated
|
|
|
7
7
|
|
|
8
8
|
from fastapi import Depends
|
|
9
9
|
|
|
10
|
+
from csrd.auth import KeyRingManager
|
|
11
|
+
|
|
10
12
|
$db_adapter_import
|
|
11
13
|
|
|
12
14
|
from ..repositories.user_repository import UserRepository
|
|
@@ -43,4 +45,20 @@ def _user_repository_factory(adapter: Adapter) -> UserRepository:
|
|
|
43
45
|
|
|
44
46
|
UserRepo = Annotated[UserRepository, Depends(_user_repository_factory)]
|
|
45
47
|
|
|
46
|
-
|
|
48
|
+
|
|
49
|
+
async def _key_ring_factory(adapter: Adapter, settings: Settings) -> KeyRingManager:
|
|
50
|
+
"""Create and initialize a ``KeyRingManager`` for JWT signing."""
|
|
51
|
+
key_ring = KeyRingManager(
|
|
52
|
+
adapter=adapter,
|
|
53
|
+
key_size=settings.jwt_key_size,
|
|
54
|
+
rotation_interval=settings.jwt_key_rotation_interval,
|
|
55
|
+
retention_period=settings.jwt_key_retention_period,
|
|
56
|
+
token_ttl=settings.jwt_ttl_seconds,
|
|
57
|
+
)
|
|
58
|
+
await key_ring.initialize()
|
|
59
|
+
return key_ring
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
KeyRing = Annotated[KeyRingManager, Depends(_key_ring_factory)]
|
|
63
|
+
|
|
64
|
+
__all__ = ("Adapter", "KeyRing", "UserRepo")
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"""Token service dependency for the auth service.
|
|
2
|
+
|
|
3
|
+
This file is scaffolded once and never overwritten.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from typing import Annotated
|
|
7
|
+
|
|
8
|
+
from fastapi import Depends
|
|
9
|
+
|
|
10
|
+
from ..services.token_service import TokenService
|
|
11
|
+
from . import Settings
|
|
12
|
+
from .db import KeyRing
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def _token_service_factory(key_ring: KeyRing, settings: Settings) -> TokenService:
|
|
16
|
+
"""Create a ``TokenService`` with the key ring and settings."""
|
|
17
|
+
return TokenService(key_ring, settings)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
TokenSvc = Annotated[TokenService, Depends(_token_service_factory)]
|
|
21
|
+
|
|
22
|
+
__all__ = ("TokenSvc",)
|
|
@@ -21,7 +21,11 @@ class UserRepository(BaseRepository):
|
|
|
21
21
|
# ── User CRUD ────────────────────────────────────────────────────
|
|
22
22
|
|
|
23
23
|
async def create_user(self, username: str, password: str) -> UserResponse:
|
|
24
|
-
"""Create a new user with hashed credentials."""
|
|
24
|
+
"""Create a new user with hashed credentials. Raises 409 if exists."""
|
|
25
|
+
existing = await self.get_user_by_username(username)
|
|
26
|
+
if existing is not None:
|
|
27
|
+
raise HTTPException(status_code=409, detail="Username already taken")
|
|
28
|
+
|
|
25
29
|
user_id = str(uuid.uuid4())
|
|
26
30
|
await self.execute(
|
|
27
31
|
"INSERT INTO users (id, username) VALUES (:id, :username)",
|