identity-plan-kit 0.2.7__tar.gz → 0.2.8__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (176) hide show
  1. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/PKG-INFO +1 -1
  2. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/pyproject.toml +2 -2
  3. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/src/identity_plan_kit/auth/__init__.py +12 -0
  4. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/src/identity_plan_kit/auth/domain/exceptions.py +21 -0
  5. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/src/identity_plan_kit/plans/__init__.py +8 -0
  6. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/src/identity_plan_kit/rbac/domain/exceptions.py +11 -1
  7. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/src/identity_plan_kit/shared/error_formatter.py +10 -8
  8. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/src/identity_plan_kit/shared/exception_handlers.py +93 -2
  9. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/src/identity_plan_kit/shared/exceptions.py +13 -5
  10. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/uv.lock +1 -1
  11. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/.gitignore +0 -0
  12. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/Makefile +0 -0
  13. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/README.md +0 -0
  14. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/alembic/env.py +0 -0
  15. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/alembic/script.py.mako +0 -0
  16. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/alembic/versions/20250124_000000_initial_schema.py +0 -0
  17. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/alembic/versions/20250127_000000_add_password_hash.py +0 -0
  18. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/alembic.ini +0 -0
  19. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/examples/integration/__init__.py +0 -0
  20. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/examples/integration/fastapi_integration.py +0 -0
  21. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/examples/integration/sample_alembic_env.py +0 -0
  22. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/examples/integration/webhook_integration.py +0 -0
  23. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/examples/playing/admin_usage.py +0 -0
  24. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/examples/playing/basic_usage.py +0 -0
  25. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/examples/playing/custom_error_formats.py +0 -0
  26. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/examples/playing/extending_models.html +0 -0
  27. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/examples/playing/extension_example.py +0 -0
  28. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/examples/prod/.env.production.example +0 -0
  29. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/examples/prod/Dockerfile +0 -0
  30. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/examples/prod/docker-compose.yml +0 -0
  31. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/examples/prod/nginx.conf +0 -0
  32. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/examples/prod/production_setup.py +0 -0
  33. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/examples/prod/prometheus.yml +0 -0
  34. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/loadtests/README.md +0 -0
  35. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/loadtests/__init__.py +0 -0
  36. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/loadtests/config.py +0 -0
  37. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/loadtests/locustfile.py +0 -0
  38. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/loadtests/test_auth.py +0 -0
  39. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/loadtests/test_database_stress.py +0 -0
  40. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/loadtests/test_mixed_scenarios.py +0 -0
  41. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/loadtests/test_plans_quota.py +0 -0
  42. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/loadtests/test_quota_direct.py +0 -0
  43. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/loadtests/test_rbac_cache.py +0 -0
  44. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/loadtests/utils.py +0 -0
  45. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/src/identity_plan_kit/__init__.py +0 -0
  46. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/src/identity_plan_kit/admin/__init__.py +0 -0
  47. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/src/identity_plan_kit/admin/auth.py +0 -0
  48. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/src/identity_plan_kit/admin/views.py +0 -0
  49. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/src/identity_plan_kit/auth/dependencies.py +0 -0
  50. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/src/identity_plan_kit/auth/domain/__init__.py +0 -0
  51. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/src/identity_plan_kit/auth/domain/entities.py +0 -0
  52. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/src/identity_plan_kit/auth/dto/__init__.py +0 -0
  53. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/src/identity_plan_kit/auth/dto/requests.py +0 -0
  54. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/src/identity_plan_kit/auth/dto/responses.py +0 -0
  55. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/src/identity_plan_kit/auth/handlers/__init__.py +0 -0
  56. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/src/identity_plan_kit/auth/handlers/oauth_routes.py +0 -0
  57. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/src/identity_plan_kit/auth/models/__init__.py +0 -0
  58. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/src/identity_plan_kit/auth/models/refresh_token.py +0 -0
  59. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/src/identity_plan_kit/auth/models/user.py +0 -0
  60. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/src/identity_plan_kit/auth/models/user_provider.py +0 -0
  61. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/src/identity_plan_kit/auth/repositories/__init__.py +0 -0
  62. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/src/identity_plan_kit/auth/repositories/token_repo.py +0 -0
  63. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/src/identity_plan_kit/auth/repositories/user_repo.py +0 -0
  64. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/src/identity_plan_kit/auth/services/__init__.py +0 -0
  65. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/src/identity_plan_kit/auth/services/auth_service.py +0 -0
  66. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/src/identity_plan_kit/auth/services/oauth_service.py +0 -0
  67. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/src/identity_plan_kit/auth/uow.py +0 -0
  68. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/src/identity_plan_kit/cli.py +0 -0
  69. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/src/identity_plan_kit/config.py +0 -0
  70. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/src/identity_plan_kit/kit.py +0 -0
  71. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/src/identity_plan_kit/migrations.py +0 -0
  72. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/src/identity_plan_kit/plans/cache/__init__.py +0 -0
  73. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/src/identity_plan_kit/plans/cache/plan_cache.py +0 -0
  74. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/src/identity_plan_kit/plans/cache/user_plan_cache.py +0 -0
  75. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/src/identity_plan_kit/plans/dependencies.py +0 -0
  76. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/src/identity_plan_kit/plans/domain/__init__.py +0 -0
  77. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/src/identity_plan_kit/plans/domain/entities.py +0 -0
  78. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/src/identity_plan_kit/plans/domain/exceptions.py +0 -0
  79. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/src/identity_plan_kit/plans/dto/__init__.py +0 -0
  80. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/src/identity_plan_kit/plans/dto/responses.py +0 -0
  81. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/src/identity_plan_kit/plans/dto/usage.py +0 -0
  82. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/src/identity_plan_kit/plans/handlers/__init__.py +0 -0
  83. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/src/identity_plan_kit/plans/handlers/plan_routes.py +0 -0
  84. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/src/identity_plan_kit/plans/models/__init__.py +0 -0
  85. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/src/identity_plan_kit/plans/models/feature.py +0 -0
  86. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/src/identity_plan_kit/plans/models/feature_usage.py +0 -0
  87. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/src/identity_plan_kit/plans/models/plan.py +0 -0
  88. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/src/identity_plan_kit/plans/models/plan_limit.py +0 -0
  89. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/src/identity_plan_kit/plans/models/plan_permission.py +0 -0
  90. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/src/identity_plan_kit/plans/models/user_plan.py +0 -0
  91. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/src/identity_plan_kit/plans/repositories/__init__.py +0 -0
  92. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/src/identity_plan_kit/plans/repositories/plan_repo.py +0 -0
  93. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/src/identity_plan_kit/plans/repositories/usage_repo.py +0 -0
  94. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/src/identity_plan_kit/plans/services/__init__.py +0 -0
  95. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/src/identity_plan_kit/plans/services/plan_service.py +0 -0
  96. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/src/identity_plan_kit/plans/uow.py +0 -0
  97. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/src/identity_plan_kit/rbac/__init__.py +0 -0
  98. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/src/identity_plan_kit/rbac/cache/__init__.py +0 -0
  99. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/src/identity_plan_kit/rbac/cache/permission_cache.py +0 -0
  100. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/src/identity_plan_kit/rbac/dependencies.py +0 -0
  101. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/src/identity_plan_kit/rbac/domain/__init__.py +0 -0
  102. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/src/identity_plan_kit/rbac/domain/entities.py +0 -0
  103. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/src/identity_plan_kit/rbac/models/__init__.py +0 -0
  104. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/src/identity_plan_kit/rbac/models/permission.py +0 -0
  105. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/src/identity_plan_kit/rbac/models/role.py +0 -0
  106. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/src/identity_plan_kit/rbac/models/role_permission.py +0 -0
  107. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/src/identity_plan_kit/rbac/repositories/__init__.py +0 -0
  108. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/src/identity_plan_kit/rbac/repositories/rbac_repo.py +0 -0
  109. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/src/identity_plan_kit/rbac/services/__init__.py +0 -0
  110. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/src/identity_plan_kit/rbac/services/rbac_service.py +0 -0
  111. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/src/identity_plan_kit/rbac/uow.py +0 -0
  112. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/src/identity_plan_kit/shared/__init__.py +0 -0
  113. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/src/identity_plan_kit/shared/audit.py +0 -0
  114. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/src/identity_plan_kit/shared/circuit_breaker.py +0 -0
  115. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/src/identity_plan_kit/shared/cleanup_scheduler.py +0 -0
  116. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/src/identity_plan_kit/shared/database.py +0 -0
  117. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/src/identity_plan_kit/shared/graceful_shutdown.py +0 -0
  118. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/src/identity_plan_kit/shared/health.py +0 -0
  119. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/src/identity_plan_kit/shared/http_utils.py +0 -0
  120. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/src/identity_plan_kit/shared/lockout.py +0 -0
  121. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/src/identity_plan_kit/shared/logging.py +0 -0
  122. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/src/identity_plan_kit/shared/metrics.py +0 -0
  123. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/src/identity_plan_kit/shared/models.py +0 -0
  124. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/src/identity_plan_kit/shared/rate_limiter.py +0 -0
  125. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/src/identity_plan_kit/shared/request_id.py +0 -0
  126. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/src/identity_plan_kit/shared/schemas.py +0 -0
  127. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/src/identity_plan_kit/shared/security.py +0 -0
  128. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/src/identity_plan_kit/shared/state_store.py +0 -0
  129. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/src/identity_plan_kit/shared/uow.py +0 -0
  130. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/src/identity_plan_kit/shared/uuid7.py +0 -0
  131. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/tests/__init__.py +0 -0
  132. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/tests/auth/__init__.py +0 -0
  133. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/tests/auth/test_auth_service.py +0 -0
  134. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/tests/auth/test_circuit_breaker.py +0 -0
  135. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/tests/auth/test_csrf_state.py +0 -0
  136. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/tests/auth/test_dependencies.py +0 -0
  137. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/tests/auth/test_domain_entities.py +0 -0
  138. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/tests/auth/test_http_utils.py +0 -0
  139. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/tests/auth/test_lockout.py +0 -0
  140. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/tests/auth/test_lockout_concurrent.py +0 -0
  141. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/tests/auth/test_oauth_service_resilience.py +0 -0
  142. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/tests/auth/test_security_comprehensive.py +0 -0
  143. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/tests/auth/test_token_security.py +0 -0
  144. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/tests/conftest.py +0 -0
  145. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/tests/integration/__init__.py +0 -0
  146. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/tests/integration/conftest.py +0 -0
  147. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/tests/integration/test_concurrent_limit_merge.py +0 -0
  148. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/tests/integration/test_concurrent_plan_operations.py +0 -0
  149. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/tests/integration/test_concurrent_token_operations.py +0 -0
  150. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/tests/integration/test_concurrent_user_creation.py +0 -0
  151. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/tests/integration/test_concurrent_user_deactivation.py +0 -0
  152. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/tests/integration/test_limit_boundaries.py +0 -0
  153. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/tests/integration/test_plan_cache_race.py +0 -0
  154. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/tests/integration/test_quota_concurrency.py +0 -0
  155. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/tests/integration/test_token_cleanup.py +0 -0
  156. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/tests/integration/test_token_repository.py +0 -0
  157. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/tests/integration/test_usage_periods.py +0 -0
  158. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/tests/integration/test_user_repository.py +0 -0
  159. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/tests/plans/__init__.py +0 -0
  160. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/tests/plans/test_domain_entities.py +0 -0
  161. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/tests/plans/test_period_edge_cases.py +0 -0
  162. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/tests/plans/test_plan_cache_concurrent.py +0 -0
  163. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/tests/plans/test_plan_service.py +0 -0
  164. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/tests/rbac/__init__.py +0 -0
  165. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/tests/rbac/test_permission_cache.py +0 -0
  166. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/tests/rbac/test_permission_cache_concurrent.py +0 -0
  167. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/tests/rbac/test_rbac_cache_stampede.py +0 -0
  168. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/tests/rbac/test_rbac_service.py +0 -0
  169. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/tests/shared/test_audit_pii_masking.py +0 -0
  170. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/tests/shared/test_circuit_breaker_concurrent.py +0 -0
  171. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/tests/shared/test_cleanup_scheduler_concurrent.py +0 -0
  172. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/tests/shared/test_config_validation.py +0 -0
  173. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/tests/shared/test_http_utils_security.py +0 -0
  174. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/tests/shared/test_rate_limiter.py +0 -0
  175. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/tests/shared/test_rate_limiter_concurrent.py +0 -0
  176. {identity_plan_kit-0.2.7 → identity_plan_kit-0.2.8}/tests/shared/test_state_store_concurrent.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: identity-plan-kit
3
- Version: 0.2.7
3
+ Version: 0.2.8
4
4
  Summary: Modern FastAPI library for authentication, RBAC, subscription plans, and usage tracking
5
5
  Author-email: harut <harut.avetisyan2002@gmail.com>
6
6
  License: MIT
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "identity-plan-kit"
3
- version = "0.2.7"
3
+ version = "0.2.8"
4
4
  description = "Modern FastAPI library for authentication, RBAC, subscription plans, and usage tracking"
5
5
  readme = "README.md"
6
6
  authors = [
@@ -140,7 +140,7 @@ testpaths = ["tests"]
140
140
  addopts = "-v --tb=short"
141
141
 
142
142
  [tool.bumpversion]
143
- current_version = "0.2.7"
143
+ current_version = "0.2.8"
144
144
  parse = "(?P<major>\\d+)\\.(?P<minor>\\d+)\\.(?P<patch>\\d+)"
145
145
  serialize = ["{major}.{minor}.{patch}"]
146
146
  tag = true
@@ -5,8 +5,14 @@ from identity_plan_kit.auth.domain.entities import RefreshToken, User, UserProvi
5
5
  from identity_plan_kit.auth.domain.exceptions import (
6
6
  AuthError,
7
7
  InvalidCredentialsError,
8
+ OAuthError,
8
9
  PasswordValidationError,
10
+ ProviderNotConfiguredError,
11
+ RefreshTokenExpiredError,
12
+ RefreshTokenInvalidError,
13
+ RefreshTokenMissingError,
9
14
  TokenExpiredError,
15
+ TokenInvalidError,
10
16
  UserInactiveError,
11
17
  UserNotFoundError,
12
18
  )
@@ -22,12 +28,18 @@ __all__ = [
22
28
  # Dependencies
23
29
  "CurrentUser",
24
30
  "InvalidCredentialsError",
31
+ "OAuthError",
25
32
  "OptionalUser",
26
33
  "PasswordValidationError",
34
+ "ProviderNotConfiguredError",
27
35
  "RefreshToken",
36
+ "RefreshTokenExpiredError",
37
+ "RefreshTokenInvalidError",
38
+ "RefreshTokenMissingError",
28
39
  # Repositories (for direct use with external sessions)
29
40
  "RefreshTokenRepository",
30
41
  "TokenExpiredError",
42
+ "TokenInvalidError",
31
43
  # Entities
32
44
  "User",
33
45
  "UserInactiveError",
@@ -35,6 +35,27 @@ class TokenInvalidError(AuthError):
35
35
  message = "Invalid token"
36
36
 
37
37
 
38
+ class RefreshTokenMissingError(AuthError):
39
+ """Refresh token not provided."""
40
+
41
+ code = "REFRESH_TOKEN_MISSING"
42
+ message = "Refresh token not provided"
43
+
44
+
45
+ class RefreshTokenInvalidError(AuthError):
46
+ """Refresh token is invalid."""
47
+
48
+ code = "REFRESH_TOKEN_INVALID"
49
+ message = "Invalid refresh token"
50
+
51
+
52
+ class RefreshTokenExpiredError(AuthError):
53
+ """Refresh token has expired."""
54
+
55
+ code = "REFRESH_TOKEN_EXPIRED"
56
+ message = "Refresh token has expired"
57
+
58
+
38
59
  class UserNotFoundError(NotFoundError):
39
60
  """User not found."""
40
61
 
@@ -9,6 +9,10 @@ from identity_plan_kit.plans.domain.entities import Feature, Plan, PlanLimit, Us
9
9
  from identity_plan_kit.plans.domain.exceptions import (
10
10
  FeatureNotAvailableError,
11
11
  FeatureNotFoundError,
12
+ InvalidCustomLimitsError,
13
+ InvalidPlanDatesError,
14
+ PlanAssignmentError,
15
+ PlanAuthorizationError,
12
16
  PlanExpiredError,
13
17
  PlanNotFoundError,
14
18
  QuotaExceededError,
@@ -26,7 +30,11 @@ __all__ = [
26
30
  # Exceptions
27
31
  "FeatureNotAvailableError",
28
32
  "FeatureNotFoundError",
33
+ "InvalidCustomLimitsError",
34
+ "InvalidPlanDatesError",
29
35
  "Plan",
36
+ "PlanAssignmentError",
37
+ "PlanAuthorizationError",
30
38
  "PlanExpiredError",
31
39
  "PlanLimit",
32
40
  "PlanNotFoundError",
@@ -21,10 +21,20 @@ class PermissionDeniedError(RBACError):
21
21
  permission: str | None = None,
22
22
  message: str | None = None,
23
23
  ) -> None:
24
- self.permission = permission
24
+ self._permission = permission
25
25
  msg = message or (f"Permission denied: {permission}" if permission else "Permission denied")
26
26
  super().__init__(message=msg, details={"permission": permission} if permission else None)
27
27
 
28
+ @property
29
+ def permission(self) -> str | None:
30
+ """Get the permission code."""
31
+ return self._permission
32
+
33
+ @property
34
+ def permission_code(self) -> str | None:
35
+ """Alias for permission to support permission_code naming convention."""
36
+ return self._permission
37
+
28
38
 
29
39
  class RoleNotFoundError(NotFoundError):
30
40
  """Role not found."""
@@ -113,10 +113,11 @@ class DefaultErrorFormatter(ErrorFormatter):
113
113
  Produces responses in the format:
114
114
  ```json
115
115
  {
116
+ "success": false,
116
117
  "error": {
117
118
  "code": "ERROR_CODE",
118
119
  "message": "Human-readable message",
119
- "details": { ... }
120
+ "context": { ... }
120
121
  }
121
122
  }
122
123
  ```
@@ -131,15 +132,16 @@ class DefaultErrorFormatter(ErrorFormatter):
131
132
  details: dict[str, Any] | None = None,
132
133
  ) -> dict[str, Any]:
133
134
  """Format error in the default library format."""
134
- content: dict[str, Any] = {
135
- "error": {
136
- "code": code,
137
- "message": message,
138
- }
135
+ error_content: dict[str, Any] = {
136
+ "code": code,
137
+ "message": message,
139
138
  }
140
139
  if details:
141
- content["error"]["details"] = details
142
- return content
140
+ error_content["context"] = details
141
+ return {
142
+ "success": False,
143
+ "error": error_content,
144
+ }
143
145
 
144
146
  def create_response(
145
147
  self,
@@ -9,6 +9,10 @@ from fastapi.responses import JSONResponse
9
9
 
10
10
  from identity_plan_kit.auth.domain.exceptions import (
11
11
  AuthError,
12
+ OAuthError,
13
+ RefreshTokenExpiredError,
14
+ RefreshTokenInvalidError,
15
+ RefreshTokenMissingError,
12
16
  TokenExpiredError,
13
17
  TokenInvalidError,
14
18
  UserInactiveError,
@@ -16,6 +20,7 @@ from identity_plan_kit.auth.domain.exceptions import (
16
20
  )
17
21
  from identity_plan_kit.plans.domain.exceptions import (
18
22
  FeatureNotAvailableError,
23
+ PlanAuthorizationError,
19
24
  PlanExpiredError,
20
25
  PlanNotFoundError,
21
26
  QuotaExceededError,
@@ -183,6 +188,59 @@ async def token_invalid_handler(request: Request, exc: TokenInvalidError) -> JSO
183
188
  )
184
189
 
185
190
 
191
+ async def refresh_token_missing_handler(
192
+ request: Request, exc: RefreshTokenMissingError
193
+ ) -> JSONResponse:
194
+ """Handle missing refresh token errors."""
195
+ return create_error_response(
196
+ request=request,
197
+ status_code=401,
198
+ code=exc.code,
199
+ message="Refresh token not provided. Please log in again.",
200
+ )
201
+
202
+
203
+ async def refresh_token_invalid_handler(
204
+ request: Request, exc: RefreshTokenInvalidError
205
+ ) -> JSONResponse:
206
+ """Handle invalid refresh token errors."""
207
+ return create_error_response(
208
+ request=request,
209
+ status_code=401,
210
+ code=exc.code,
211
+ message="Invalid refresh token. Please log in again.",
212
+ )
213
+
214
+
215
+ async def refresh_token_expired_handler(
216
+ request: Request, exc: RefreshTokenExpiredError
217
+ ) -> JSONResponse:
218
+ """Handle expired refresh token errors."""
219
+ return create_error_response(
220
+ request=request,
221
+ status_code=401,
222
+ code=exc.code,
223
+ message="Refresh token has expired. Please log in again.",
224
+ )
225
+
226
+
227
+ async def oauth_error_handler(request: Request, exc: OAuthError) -> JSONResponse:
228
+ """Handle OAuth errors."""
229
+ logger.warning(
230
+ "oauth_error",
231
+ error_code=exc.code,
232
+ provider=exc.provider,
233
+ path=request.url.path,
234
+ )
235
+ return create_error_response(
236
+ request=request,
237
+ status_code=401,
238
+ code=exc.code,
239
+ message=exc.message,
240
+ details={"provider": exc.provider} if exc.provider else None,
241
+ )
242
+
243
+
186
244
  async def user_inactive_handler(request: Request, exc: UserInactiveError) -> JSONResponse:
187
245
  """Handle inactive user errors."""
188
246
  return create_error_response(
@@ -205,9 +263,10 @@ async def user_not_found_handler(request: Request, exc: UserNotFoundError) -> JS
205
263
 
206
264
  async def permission_denied_handler(request: Request, exc: PermissionDeniedError) -> JSONResponse:
207
265
  """Handle permission denied errors."""
266
+ permission = exc.permission_code
208
267
  logger.warning(
209
268
  "permission_denied",
210
- permission=exc.permission_code,
269
+ permission=permission,
211
270
  path=request.url.path,
212
271
  )
213
272
  return create_error_response(
@@ -215,7 +274,7 @@ async def permission_denied_handler(request: Request, exc: PermissionDeniedError
215
274
  status_code=403,
216
275
  code=exc.code,
217
276
  message=exc.message,
218
- details={"permission": exc.permission_code} if exc.permission_code else None,
277
+ details={"permission": permission} if permission else None,
219
278
  )
220
279
 
221
280
 
@@ -297,6 +356,33 @@ async def plan_not_found_handler(request: Request, exc: PlanNotFoundError) -> JS
297
356
  )
298
357
 
299
358
 
359
+ async def plan_authorization_error_handler(
360
+ request: Request,
361
+ exc: PlanAuthorizationError,
362
+ ) -> JSONResponse:
363
+ """Handle plan authorization errors.
364
+
365
+ Raised when a plan operation is not authorized (e.g., unauthorized plan assignment).
366
+ """
367
+ logger.warning(
368
+ "plan_authorization_error",
369
+ operation=exc.operation,
370
+ target_user_id=exc.target_user_id,
371
+ caller_user_id=exc.caller_user_id,
372
+ path=request.url.path,
373
+ )
374
+ return create_error_response(
375
+ request=request,
376
+ status_code=403,
377
+ code=exc.code,
378
+ message=exc.message,
379
+ details={
380
+ "operation": exc.operation,
381
+ "target_user_id": exc.target_user_id,
382
+ },
383
+ )
384
+
385
+
300
386
  async def http_exception_handler(request: Request, exc: HTTPException) -> JSONResponse:
301
387
  """
302
388
  Handle FastAPI HTTPException errors.
@@ -478,6 +564,10 @@ def register_exception_handlers(
478
564
  # Auth errors
479
565
  app.add_exception_handler(TokenExpiredError, token_expired_handler)
480
566
  app.add_exception_handler(TokenInvalidError, token_invalid_handler)
567
+ app.add_exception_handler(RefreshTokenMissingError, refresh_token_missing_handler)
568
+ app.add_exception_handler(RefreshTokenInvalidError, refresh_token_invalid_handler)
569
+ app.add_exception_handler(RefreshTokenExpiredError, refresh_token_expired_handler)
570
+ app.add_exception_handler(OAuthError, oauth_error_handler)
481
571
  app.add_exception_handler(UserInactiveError, user_inactive_handler)
482
572
  app.add_exception_handler(UserNotFoundError, user_not_found_handler)
483
573
  app.add_exception_handler(AuthError, auth_error_handler)
@@ -492,6 +582,7 @@ def register_exception_handlers(
492
582
  app.add_exception_handler(FeatureNotAvailableError, feature_not_available_handler)
493
583
  app.add_exception_handler(UserPlanNotFoundError, user_plan_not_found_handler)
494
584
  app.add_exception_handler(PlanNotFoundError, plan_not_found_handler)
585
+ app.add_exception_handler(PlanAuthorizationError, plan_authorization_error_handler)
495
586
 
496
587
  # Base error (catch-all for domain errors)
497
588
  app.add_exception_handler(BaseError, base_error_handler)
@@ -23,14 +23,22 @@ class BaseError(Exception):
23
23
  self.details = details
24
24
  super().__init__(self.message)
25
25
 
26
+ @property
27
+ def context(self) -> dict[str, Any] | None:
28
+ """Alias for details to support context naming convention."""
29
+ return self.details
30
+
26
31
  def to_dict(self) -> dict[str, Any]:
27
32
  """Convert exception to error response dict."""
33
+ error_content: dict[str, Any] = {
34
+ "code": self.code,
35
+ "message": self.message,
36
+ }
37
+ if self.details:
38
+ error_content["context"] = self.details
28
39
  return {
29
- "error": {
30
- "code": self.code,
31
- "message": self.message,
32
- "details": self.details,
33
- }
40
+ "success": False,
41
+ "error": error_content,
34
42
  }
35
43
 
36
44
 
@@ -962,7 +962,7 @@ wheels = [
962
962
 
963
963
  [[package]]
964
964
  name = "identity-plan-kit"
965
- version = "0.2.6"
965
+ version = "0.2.7"
966
966
  source = { editable = "." }
967
967
  dependencies = [
968
968
  { name = "alembic" },