svc-infra 0.1.598__tar.gz → 0.1.600__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.

Potentially problematic release.


This version of svc-infra might be problematic. Click here for more details.

Files changed (278) hide show
  1. svc_infra-0.1.600/PKG-INFO +128 -0
  2. svc_infra-0.1.600/README.md +51 -0
  3. {svc_infra-0.1.598 → svc_infra-0.1.600}/pyproject.toml +1 -1
  4. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/api/fastapi/auth/gaurd.py +2 -2
  5. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/obs/README.md +2 -0
  6. svc_infra-0.1.600/src/svc_infra/security/add.py +201 -0
  7. svc_infra-0.1.600/src/svc_infra/webhooks/__init__.py +16 -0
  8. svc_infra-0.1.600/src/svc_infra/webhooks/add.py +322 -0
  9. svc_infra-0.1.598/PKG-INFO +0 -80
  10. svc_infra-0.1.598/README.md +0 -3
  11. svc_infra-0.1.598/src/svc_infra/webhooks/__init__.py +0 -1
  12. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/__init__.py +0 -0
  13. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/apf_payments/README.md +0 -0
  14. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/apf_payments/__init__.py +0 -0
  15. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/apf_payments/alembic.py +0 -0
  16. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/apf_payments/models.py +0 -0
  17. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/apf_payments/provider/__init__.py +0 -0
  18. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/apf_payments/provider/aiydan.py +0 -0
  19. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/apf_payments/provider/base.py +0 -0
  20. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/apf_payments/provider/registry.py +0 -0
  21. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/apf_payments/provider/stripe.py +0 -0
  22. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/apf_payments/schemas.py +0 -0
  23. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/apf_payments/service.py +0 -0
  24. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/apf_payments/settings.py +0 -0
  25. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/api/__init__.py +0 -0
  26. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/api/fastapi/__init__.py +0 -0
  27. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/api/fastapi/apf_payments/__init__.py +0 -0
  28. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/api/fastapi/apf_payments/router.py +0 -0
  29. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/api/fastapi/apf_payments/setup.py +0 -0
  30. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/api/fastapi/auth/__init__.py +0 -0
  31. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/api/fastapi/auth/_cookies.py +0 -0
  32. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/api/fastapi/auth/add.py +0 -0
  33. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/api/fastapi/auth/mfa/__init__.py +0 -0
  34. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/api/fastapi/auth/mfa/models.py +0 -0
  35. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/api/fastapi/auth/mfa/pre_auth.py +0 -0
  36. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/api/fastapi/auth/mfa/router.py +0 -0
  37. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/api/fastapi/auth/mfa/security.py +0 -0
  38. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/api/fastapi/auth/mfa/utils.py +0 -0
  39. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/api/fastapi/auth/mfa/verify.py +0 -0
  40. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/api/fastapi/auth/policy.py +0 -0
  41. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/api/fastapi/auth/providers.py +0 -0
  42. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/api/fastapi/auth/routers/__init__.py +0 -0
  43. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/api/fastapi/auth/routers/account.py +0 -0
  44. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/api/fastapi/auth/routers/apikey_router.py +0 -0
  45. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/api/fastapi/auth/routers/oauth_router.py +0 -0
  46. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/api/fastapi/auth/routers/session_router.py +0 -0
  47. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/api/fastapi/auth/security.py +0 -0
  48. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/api/fastapi/auth/sender.py +0 -0
  49. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/api/fastapi/auth/settings.py +0 -0
  50. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/api/fastapi/auth/state.py +0 -0
  51. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/api/fastapi/cache/__init__.py +0 -0
  52. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/api/fastapi/cache/add.py +0 -0
  53. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/api/fastapi/db/__init__.py +0 -0
  54. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/api/fastapi/db/http.py +0 -0
  55. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/api/fastapi/db/nosql/__init__.py +0 -0
  56. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/api/fastapi/db/nosql/mongo/__init__.py +0 -0
  57. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/api/fastapi/db/nosql/mongo/add.py +0 -0
  58. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/api/fastapi/db/nosql/mongo/crud_router.py +0 -0
  59. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/api/fastapi/db/nosql/mongo/health.py +0 -0
  60. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/api/fastapi/db/sql/README.md +0 -0
  61. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/api/fastapi/db/sql/__init__.py +0 -0
  62. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/api/fastapi/db/sql/add.py +0 -0
  63. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/api/fastapi/db/sql/crud_router.py +0 -0
  64. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/api/fastapi/db/sql/health.py +0 -0
  65. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/api/fastapi/db/sql/session.py +0 -0
  66. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/api/fastapi/db/sql/users.py +0 -0
  67. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/api/fastapi/dependencies/ratelimit.py +0 -0
  68. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/api/fastapi/docs/__init__.py +0 -0
  69. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/api/fastapi/docs/landing.py +0 -0
  70. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/api/fastapi/docs/scoped.py +0 -0
  71. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/api/fastapi/dual/__init__.py +0 -0
  72. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/api/fastapi/dual/dualize.py +0 -0
  73. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/api/fastapi/dual/protected.py +0 -0
  74. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/api/fastapi/dual/public.py +0 -0
  75. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/api/fastapi/dual/router.py +0 -0
  76. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/api/fastapi/dual/utils.py +0 -0
  77. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/api/fastapi/dx.py +0 -0
  78. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/api/fastapi/ease.py +0 -0
  79. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/api/fastapi/http/__init__.py +0 -0
  80. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/api/fastapi/http/concurrency.py +0 -0
  81. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/api/fastapi/http/conditional.py +0 -0
  82. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/api/fastapi/http/deprecation.py +0 -0
  83. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/api/fastapi/middleware/__init__.py +0 -0
  84. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/api/fastapi/middleware/debug.py +0 -0
  85. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/api/fastapi/middleware/errors/__init__.py +0 -0
  86. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/api/fastapi/middleware/errors/catchall.py +0 -0
  87. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/api/fastapi/middleware/errors/exceptions.py +0 -0
  88. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/api/fastapi/middleware/errors/handlers.py +0 -0
  89. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/api/fastapi/middleware/idempotency.py +0 -0
  90. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/api/fastapi/middleware/idempotency_store.py +0 -0
  91. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/api/fastapi/middleware/optimistic_lock.py +0 -0
  92. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/api/fastapi/middleware/ratelimit.py +0 -0
  93. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/api/fastapi/middleware/ratelimit_store.py +0 -0
  94. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/api/fastapi/middleware/request_id.py +0 -0
  95. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/api/fastapi/middleware/request_size_limit.py +0 -0
  96. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/api/fastapi/openapi/__init__.py +0 -0
  97. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/api/fastapi/openapi/apply.py +0 -0
  98. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/api/fastapi/openapi/conventions.py +0 -0
  99. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/api/fastapi/openapi/models.py +0 -0
  100. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/api/fastapi/openapi/mutators.py +0 -0
  101. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/api/fastapi/openapi/pipeline.py +0 -0
  102. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/api/fastapi/openapi/responses.py +0 -0
  103. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/api/fastapi/openapi/security.py +0 -0
  104. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/api/fastapi/pagination.py +0 -0
  105. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/api/fastapi/paths/__init__.py +0 -0
  106. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/api/fastapi/paths/auth.py +0 -0
  107. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/api/fastapi/paths/generic.py +0 -0
  108. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/api/fastapi/paths/prefix.py +0 -0
  109. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/api/fastapi/paths/user.py +0 -0
  110. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/api/fastapi/routers/__init__.py +0 -0
  111. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/api/fastapi/routers/ping.py +0 -0
  112. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/api/fastapi/setup.py +0 -0
  113. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/app/README.md +0 -0
  114. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/app/__init__.py +0 -0
  115. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/app/env.py +0 -0
  116. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/app/logging/__init__.py +0 -0
  117. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/app/logging/add.py +0 -0
  118. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/app/logging/filter.py +0 -0
  119. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/app/logging/formats.py +0 -0
  120. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/app/root.py +0 -0
  121. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/cache/README.md +0 -0
  122. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/cache/__init__.py +0 -0
  123. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/cache/backend.py +0 -0
  124. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/cache/decorators.py +0 -0
  125. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/cache/demo.py +0 -0
  126. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/cache/keys.py +0 -0
  127. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/cache/recache.py +0 -0
  128. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/cache/resources.py +0 -0
  129. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/cache/tags.py +0 -0
  130. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/cache/ttl.py +0 -0
  131. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/cache/utils.py +0 -0
  132. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/cli/__init__.py +0 -0
  133. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/cli/__main__.py +0 -0
  134. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/cli/cmds/__init__.py +0 -0
  135. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/cli/cmds/db/__init__.py +0 -0
  136. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/cli/cmds/db/nosql/__init__.py +0 -0
  137. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/cli/cmds/db/nosql/mongo/README.md +0 -0
  138. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/cli/cmds/db/nosql/mongo/__init__.py +0 -0
  139. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/cli/cmds/db/nosql/mongo/mongo_cmds.py +0 -0
  140. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/cli/cmds/db/nosql/mongo/mongo_scaffold_cmds.py +0 -0
  141. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/cli/cmds/db/sql/__init__.py +0 -0
  142. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/cli/cmds/db/sql/alembic_cmds.py +0 -0
  143. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/cli/cmds/db/sql/sql_scaffold_cmds.py +0 -0
  144. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/cli/cmds/help.py +0 -0
  145. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/cli/cmds/jobs/__init__.py +0 -0
  146. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/cli/cmds/jobs/jobs_cmds.py +0 -0
  147. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/cli/cmds/obs/__init__.py +0 -0
  148. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/cli/cmds/obs/obs_cmds.py +0 -0
  149. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/cli/foundation/__init__.py +0 -0
  150. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/cli/foundation/runner.py +0 -0
  151. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/cli/foundation/typer_bootstrap.py +0 -0
  152. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/db/__init__.py +0 -0
  153. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/db/crud_schema.py +0 -0
  154. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/db/inbox.py +0 -0
  155. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/db/nosql/__init__.py +0 -0
  156. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/db/nosql/base.py +0 -0
  157. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/db/nosql/constants.py +0 -0
  158. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/db/nosql/core.py +0 -0
  159. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/db/nosql/indexes.py +0 -0
  160. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/db/nosql/management.py +0 -0
  161. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/db/nosql/mongo/README.md +0 -0
  162. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/db/nosql/mongo/__init__.py +0 -0
  163. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/db/nosql/mongo/client.py +0 -0
  164. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/db/nosql/mongo/settings.py +0 -0
  165. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/db/nosql/mongo/templates/__init__.py +0 -0
  166. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/db/nosql/mongo/templates/documents.py.tmpl +0 -0
  167. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/db/nosql/mongo/templates/resources.py.tmpl +0 -0
  168. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/db/nosql/mongo/templates/schemas.py.tmpl +0 -0
  169. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/db/nosql/repository.py +0 -0
  170. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/db/nosql/resource.py +0 -0
  171. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/db/nosql/scaffold.py +0 -0
  172. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/db/nosql/service.py +0 -0
  173. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/db/nosql/service_with_hooks.py +0 -0
  174. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/db/nosql/types.py +0 -0
  175. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/db/nosql/utils.py +0 -0
  176. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/db/outbox.py +0 -0
  177. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/db/sql/README.md +0 -0
  178. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/db/sql/__init__.py +0 -0
  179. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/db/sql/apikey.py +0 -0
  180. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/db/sql/authref.py +0 -0
  181. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/db/sql/base.py +0 -0
  182. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/db/sql/constants.py +0 -0
  183. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/db/sql/core.py +0 -0
  184. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/db/sql/management.py +0 -0
  185. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/db/sql/repository.py +0 -0
  186. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/db/sql/resource.py +0 -0
  187. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/db/sql/scaffold.py +0 -0
  188. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/db/sql/service.py +0 -0
  189. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/db/sql/service_with_hooks.py +0 -0
  190. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/db/sql/templates/__init__.py +0 -0
  191. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/db/sql/templates/models_schemas/__init__.py +0 -0
  192. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/db/sql/templates/models_schemas/auth/models.py.tmpl +0 -0
  193. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/db/sql/templates/models_schemas/auth/schemas.py.tmpl +0 -0
  194. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/db/sql/templates/models_schemas/entity/models.py.tmpl +0 -0
  195. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/db/sql/templates/models_schemas/entity/schemas.py.tmpl +0 -0
  196. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/db/sql/templates/setup/__init__.py +0 -0
  197. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/db/sql/templates/setup/alembic.ini.tmpl +0 -0
  198. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/db/sql/templates/setup/env_async.py.tmpl +0 -0
  199. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/db/sql/templates/setup/env_sync.py.tmpl +0 -0
  200. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/db/sql/templates/setup/script.py.mako.tmpl +0 -0
  201. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/db/sql/types.py +0 -0
  202. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/db/sql/uniq.py +0 -0
  203. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/db/sql/uniq_hooks.py +0 -0
  204. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/db/sql/utils.py +0 -0
  205. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/db/sql/versioning.py +0 -0
  206. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/db/utils.py +0 -0
  207. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/jobs/builtins/outbox_processor.py +0 -0
  208. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/jobs/builtins/webhook_delivery.py +0 -0
  209. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/jobs/easy.py +0 -0
  210. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/jobs/loader.py +0 -0
  211. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/jobs/queue.py +0 -0
  212. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/jobs/redis_queue.py +0 -0
  213. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/jobs/scheduler.py +0 -0
  214. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/jobs/worker.py +0 -0
  215. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/mcp/__init__.py +0 -0
  216. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/mcp/svc_infra_mcp.py +0 -0
  217. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/obs/__init__.py +0 -0
  218. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/obs/add.py +0 -0
  219. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/obs/cloud_dash.py +0 -0
  220. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/obs/metrics/__init__.py +0 -0
  221. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/obs/metrics/asgi.py +0 -0
  222. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/obs/metrics/base.py +0 -0
  223. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/obs/metrics/http.py +0 -0
  224. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/obs/metrics/sqlalchemy.py +0 -0
  225. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/obs/metrics.py +0 -0
  226. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/obs/providers/__init__.py +0 -0
  227. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/obs/providers/compose_cloud/__init__.py +0 -0
  228. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/obs/providers/compose_cloud/templates/__init__.py +0 -0
  229. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/obs/providers/compose_cloud/templates/agent.yaml.tmpl +0 -0
  230. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/obs/providers/compose_cloud/templates/docker-compose.cloud.yml.tmpl +0 -0
  231. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/obs/providers/grafana/__init__.py +0 -0
  232. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/obs/providers/grafana/dashboards/00_overview.json +0 -0
  233. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/obs/providers/grafana/dashboards/10_http.json +0 -0
  234. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/obs/providers/grafana/dashboards/20_db.json +0 -0
  235. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/obs/providers/grafana/dashboards/30_runtime.json +0 -0
  236. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/obs/providers/grafana/dashboards/40_clients.json +0 -0
  237. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/obs/providers/grafana/dashboards/__init__.py +0 -0
  238. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/obs/providers/grafana/templates/__init__.py +0 -0
  239. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/obs/providers/grafana/templates/docker-compose.yml.tmpl +0 -0
  240. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/obs/providers/grafana/templates/prometheus.yml.tmpl +0 -0
  241. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/obs/providers/grafana/templates/provisioning/__init__.py +0 -0
  242. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/obs/providers/grafana/templates/provisioning/dashboards.yml +0 -0
  243. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/obs/providers/grafana/templates/provisioning/datasource.yml +0 -0
  244. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/obs/settings.py +0 -0
  245. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/obs/templates/grafana_dashboard.json +0 -0
  246. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/obs/templates/prometheus_rules.yml +0 -0
  247. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/obs/templates/sidecars/__init__.py +0 -0
  248. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/obs/templates/sidecars/compose/__init__.py +0 -0
  249. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/obs/templates/sidecars/compose/agent.yaml +0 -0
  250. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/obs/templates/sidecars/compose/docker-compose.yml +0 -0
  251. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/obs/templates/sidecars/fly/__init__.py +0 -0
  252. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/obs/templates/sidecars/fly/agent.yaml +0 -0
  253. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/obs/templates/sidecars/fly/fly.toml.fragment +0 -0
  254. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/obs/templates/sidecars/k8s/__init__.py +0 -0
  255. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/obs/templates/sidecars/k8s/configmap.yaml +0 -0
  256. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/obs/templates/sidecars/k8s/deployment.yaml +0 -0
  257. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/obs/templates/sidecars/railway/Dockerfile +0 -0
  258. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/obs/templates/sidecars/railway/README.md +0 -0
  259. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/obs/templates/sidecars/railway/__init__.py +0 -0
  260. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/obs/templates/sidecars/railway/agent.yaml +0 -0
  261. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/py.typed +0 -0
  262. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/security/audit.py +0 -0
  263. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/security/audit_service.py +0 -0
  264. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/security/headers.py +0 -0
  265. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/security/hibp.py +0 -0
  266. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/security/jwt_rotation.py +0 -0
  267. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/security/lockout.py +0 -0
  268. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/security/models.py +0 -0
  269. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/security/org_invites.py +0 -0
  270. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/security/passwords.py +0 -0
  271. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/security/permissions.py +0 -0
  272. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/security/session.py +0 -0
  273. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/security/signed_cookies.py +0 -0
  274. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/utils.py +0 -0
  275. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/webhooks/fastapi.py +0 -0
  276. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/webhooks/router.py +0 -0
  277. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/webhooks/service.py +0 -0
  278. {svc_infra-0.1.598 → svc_infra-0.1.600}/src/svc_infra/webhooks/signing.py +0 -0
@@ -0,0 +1,128 @@
1
+ Metadata-Version: 2.3
2
+ Name: svc-infra
3
+ Version: 0.1.600
4
+ Summary: Infrastructure for building and deploying prod-ready services
5
+ License: MIT
6
+ Keywords: fastapi,sqlalchemy,alembic,auth,infra,async,pydantic
7
+ Author: Ali Khatami
8
+ Author-email: aliikhatami94@gmail.com
9
+ Requires-Python: >=3.11,<4.0
10
+ Classifier: Development Status :: 4 - Beta
11
+ Classifier: Framework :: FastAPI
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Programming Language :: Python :: 3.13
18
+ Classifier: Programming Language :: Python :: 3 :: Only
19
+ Classifier: Typing :: Typed
20
+ Provides-Extra: duckdb
21
+ Provides-Extra: metrics
22
+ Provides-Extra: mssql
23
+ Provides-Extra: mysql
24
+ Provides-Extra: pg
25
+ Provides-Extra: pg2
26
+ Provides-Extra: redshift
27
+ Provides-Extra: snowflake
28
+ Provides-Extra: sqlite
29
+ Requires-Dist: adyen (>=13.4.0,<14.0.0)
30
+ Requires-Dist: ai-infra (>=0.1.63,<0.2.0)
31
+ Requires-Dist: aiosqlite (>=0.20.0,<0.21.0) ; extra == "sqlite"
32
+ Requires-Dist: alembic (>=1.13.2,<2.0.0)
33
+ Requires-Dist: asyncpg (>=0.30.0,<0.31.0) ; extra == "pg"
34
+ Requires-Dist: authlib (>=1.6.2,<2.0.0)
35
+ Requires-Dist: cashews[redis] (>=7.4.1,<8.0.0)
36
+ Requires-Dist: duckdb (>=1.1.3,<2.0.0) ; extra == "duckdb"
37
+ Requires-Dist: email-validator (>=2.2.0,<3.0.0)
38
+ Requires-Dist: fastapi (>=0.116.1,<0.117.0)
39
+ Requires-Dist: fastapi-users-db-sqlalchemy (>=7.0.0,<8.0.0)
40
+ Requires-Dist: fastapi-users[oauth] (>=14.0.1,<15.0.0)
41
+ Requires-Dist: greenlet (>=3,<4)
42
+ Requires-Dist: httpx (>=0.28.1,<0.29.0)
43
+ Requires-Dist: httpx-oauth (>=0.16.1,<0.17.0)
44
+ Requires-Dist: itsdangerous (>=2.2.0,<3.0.0)
45
+ Requires-Dist: mcp (>=1.13.0,<2.0.0)
46
+ Requires-Dist: motor (>=3.7.1,<4.0.0)
47
+ Requires-Dist: mysqlclient (>=2.2.4,<3.0.0) ; extra == "mysql"
48
+ Requires-Dist: opentelemetry-exporter-otlp (>=1.36.0,<2.0.0)
49
+ Requires-Dist: opentelemetry-instrumentation-fastapi (>=0.57b0,<0.58)
50
+ Requires-Dist: opentelemetry-instrumentation-httpx (>=0.57b0,<0.58)
51
+ Requires-Dist: opentelemetry-instrumentation-requests (>=0.57b0,<0.58)
52
+ Requires-Dist: opentelemetry-instrumentation-sqlalchemy (>=0.57b0,<0.58)
53
+ Requires-Dist: opentelemetry-propagator-b3 (>=1.36.0,<2.0.0)
54
+ Requires-Dist: opentelemetry-sdk (>=1.36.0,<2.0.0)
55
+ Requires-Dist: passlib[bcrypt] (>=1.7.4,<2.0.0)
56
+ Requires-Dist: pre-commit (>=4.3.0,<5.0.0)
57
+ Requires-Dist: prometheus-client (>=0.22.1,<0.23.0) ; extra == "metrics"
58
+ Requires-Dist: psycopg2-binary (>=2.9.10,<3.0.0) ; extra == "pg2"
59
+ Requires-Dist: psycopg[binary] (>=3.2.10,<4.0.0) ; extra == "pg"
60
+ Requires-Dist: pydantic-settings (>=2.10.1,<3.0.0)
61
+ Requires-Dist: pymysql (>=1.1.1,<2.0.0) ; extra == "mysql"
62
+ Requires-Dist: pyodbc (>=5.1.0,<6.0.0) ; extra == "mssql"
63
+ Requires-Dist: pyotp (>=2.9.0,<3.0.0)
64
+ Requires-Dist: python-dotenv (>=1.1.1,<2.0.0)
65
+ Requires-Dist: redis (>=6.4.0,<7.0.0)
66
+ Requires-Dist: redshift-connector (>=2.0.918,<3.0.0) ; extra == "redshift"
67
+ Requires-Dist: snowflake-connector-python (>=3.12.0,<4.0.0) ; extra == "snowflake"
68
+ Requires-Dist: sqlalchemy[asyncio] (>=2.0.43,<3.0.0)
69
+ Requires-Dist: stripe (>=13.0.1,<14.0.0)
70
+ Requires-Dist: typer (>=0.16.1,<0.17.0)
71
+ Project-URL: Documentation, https://github.com/your-org/svc-infra#readme
72
+ Project-URL: Homepage, https://github.com/your-org/svc-infra
73
+ Project-URL: Issues, https://github.com/your-org/svc-infra/issues
74
+ Project-URL: Repository, https://github.com/your-org/svc-infra
75
+ Description-Content-Type: text/markdown
76
+
77
+ # svc-infra
78
+
79
+ [![PyPI](https://img.shields.io/pypi/v/svc-infra.svg)](https://pypi.org/project/svc-infra/)
80
+ [![Docs](https://img.shields.io/badge/docs-reference-blue)](docs/)
81
+
82
+ svc-infra packages the shared building blocks we use to ship production FastAPI services fast—HTTP APIs with secure auth, durable persistence, background execution, cache, observability, and webhook plumbing that all share the same batteries-included defaults.
83
+
84
+ ## Helper index
85
+
86
+ | Helper | What it covers | Guide |
87
+ | --- | --- | --- |
88
+ | API | FastAPI bootstrap, envelopes, middleware, docs wiring | [FastAPI guide](docs/api.md) |
89
+ | Auth | Sessions, OAuth/OIDC, MFA, SMTP delivery | [Auth settings](docs/auth.md) |
90
+ | Database | SQL + Mongo wiring, Alembic helpers, inbox/outbox patterns | [Database guide](docs/database.md) |
91
+ | Jobs | JobQueue, scheduler, CLI worker | [Jobs quickstart](docs/jobs.md) |
92
+ | Cache | cashews decorators, namespace management, TTL helpers | [Cache guide](docs/cache.md) |
93
+ | Observability | Prometheus middleware, Grafana automation, OTEL hooks | [Observability guide](docs/observability.md) |
94
+ | Webhooks | Subscription store, signing, retry worker | [Webhooks framework](docs/webhooks.md) |
95
+ | Security | Password policy, lockout, signed cookies, headers | [Security hardening](docs/security.md) |
96
+
97
+ ## Minimal FastAPI bootstrap
98
+
99
+ ```python
100
+ from fastapi import Depends
101
+ from svc_infra.api.fastapi.ease import easy_service_app
102
+ from svc_infra.api.fastapi.db.sql.add import add_sql_db
103
+ from svc_infra.cache import init_cache
104
+ from svc_infra.jobs.easy import easy_jobs
105
+ from svc_infra.webhooks.fastapi import require_signature
106
+
107
+ app = easy_service_app(name="Billing", release="1.2.3")
108
+ add_sql_db(app) # reads SQL_URL / DB_* envs
109
+ init_cache() # honors CACHE_PREFIX / CACHE_VERSION
110
+ queue, scheduler = easy_jobs() # switches via JOBS_DRIVER / REDIS_URL
111
+
112
+ @app.post("/webhooks/billing")
113
+ async def handle_webhook(payload = Depends(require_signature(lambda: ["current", "next"]))):
114
+ queue.enqueue("process-billing-webhook", payload)
115
+ return {"status": "queued"}
116
+ ```
117
+
118
+ ## Environment switches
119
+
120
+ - **API** – toggle logging/observability and docs exposure with `ENABLE_LOGGING`, `LOG_LEVEL`, `LOG_FORMAT`, `ENABLE_OBS`, `METRICS_PATH`, `OBS_SKIP_PATHS`, and `CORS_ALLOW_ORIGINS`. 【F:src/svc_infra/api/fastapi/ease.py†L67-L111】【F:src/svc_infra/api/fastapi/setup.py†L47-L88】
121
+ - **Auth** – configure JWT secrets, SMTP, cookies, and policy using the `AUTH_…` settings family (e.g., `AUTH_JWT__SECRET`, `AUTH_SMTP_HOST`, `AUTH_SESSION_COOKIE_SECURE`). 【F:src/svc_infra/api/fastapi/auth/settings.py†L23-L91】
122
+ - **Database** – set connection URLs or components via `SQL_URL`/`SQL_URL_FILE`, `DB_DIALECT`, `DB_HOST`, `DB_USER`, `DB_PASSWORD`, plus Mongo knobs like `MONGO_URL`, `MONGO_DB`, and `MONGO_URL_FILE`. 【F:src/svc_infra/api/fastapi/db/sql/add.py†L55-L114】【F:src/svc_infra/db/sql/utils.py†L85-L206】【F:src/svc_infra/db/nosql/mongo/settings.py†L9-L13】【F:src/svc_infra/db/nosql/utils.py†L56-L113】
123
+ - **Jobs** – choose the queue backend with `JOBS_DRIVER` and provide Redis via `REDIS_URL`; interval schedules can be declared with `JOBS_SCHEDULE_JSON`. 【F:src/svc_infra/jobs/easy.py†L11-L27】【F:docs/jobs.md†L11-L48】
124
+ - **Cache** – namespace keys and lifetimes through `CACHE_PREFIX`, `CACHE_VERSION`, and TTL overrides `CACHE_TTL_DEFAULT`, `CACHE_TTL_SHORT`, `CACHE_TTL_LONG`. 【F:src/svc_infra/cache/README.md†L20-L173】【F:src/svc_infra/cache/ttl.py†L26-L55】
125
+ - **Observability** – turn metrics on/off or adjust scrape paths with `ENABLE_OBS`, `METRICS_PATH`, `OBS_SKIP_PATHS`, and Prometheus/Grafana flags like `SVC_INFRA_DISABLE_PROMETHEUS`, `SVC_INFRA_RATE_WINDOW`, `SVC_INFRA_DASHBOARD_REFRESH`, `SVC_INFRA_DASHBOARD_RANGE`. 【F:src/svc_infra/api/fastapi/ease.py†L67-L111】【F:src/svc_infra/obs/metrics/asgi.py†L49-L206】【F:src/svc_infra/obs/cloud_dash.py†L85-L108】
126
+ - **Webhooks** – reuse the jobs envs (`JOBS_DRIVER`, `REDIS_URL`) for the delivery worker and queue configuration. 【F:docs/webhooks.md†L32-L53】
127
+ - **Security** – enforce password policy, MFA, and rotation with auth prefixes such as `AUTH_PASSWORD_MIN_LENGTH`, `AUTH_PASSWORD_REQUIRE_SYMBOL`, `AUTH_JWT__SECRET`, and `AUTH_JWT__OLD_SECRETS`. 【F:docs/security.md†L24-L70】
128
+
@@ -0,0 +1,51 @@
1
+ # svc-infra
2
+
3
+ [![PyPI](https://img.shields.io/pypi/v/svc-infra.svg)](https://pypi.org/project/svc-infra/)
4
+ [![Docs](https://img.shields.io/badge/docs-reference-blue)](docs/)
5
+
6
+ svc-infra packages the shared building blocks we use to ship production FastAPI services fast—HTTP APIs with secure auth, durable persistence, background execution, cache, observability, and webhook plumbing that all share the same batteries-included defaults.
7
+
8
+ ## Helper index
9
+
10
+ | Helper | What it covers | Guide |
11
+ | --- | --- | --- |
12
+ | API | FastAPI bootstrap, envelopes, middleware, docs wiring | [FastAPI guide](docs/api.md) |
13
+ | Auth | Sessions, OAuth/OIDC, MFA, SMTP delivery | [Auth settings](docs/auth.md) |
14
+ | Database | SQL + Mongo wiring, Alembic helpers, inbox/outbox patterns | [Database guide](docs/database.md) |
15
+ | Jobs | JobQueue, scheduler, CLI worker | [Jobs quickstart](docs/jobs.md) |
16
+ | Cache | cashews decorators, namespace management, TTL helpers | [Cache guide](docs/cache.md) |
17
+ | Observability | Prometheus middleware, Grafana automation, OTEL hooks | [Observability guide](docs/observability.md) |
18
+ | Webhooks | Subscription store, signing, retry worker | [Webhooks framework](docs/webhooks.md) |
19
+ | Security | Password policy, lockout, signed cookies, headers | [Security hardening](docs/security.md) |
20
+
21
+ ## Minimal FastAPI bootstrap
22
+
23
+ ```python
24
+ from fastapi import Depends
25
+ from svc_infra.api.fastapi.ease import easy_service_app
26
+ from svc_infra.api.fastapi.db.sql.add import add_sql_db
27
+ from svc_infra.cache import init_cache
28
+ from svc_infra.jobs.easy import easy_jobs
29
+ from svc_infra.webhooks.fastapi import require_signature
30
+
31
+ app = easy_service_app(name="Billing", release="1.2.3")
32
+ add_sql_db(app) # reads SQL_URL / DB_* envs
33
+ init_cache() # honors CACHE_PREFIX / CACHE_VERSION
34
+ queue, scheduler = easy_jobs() # switches via JOBS_DRIVER / REDIS_URL
35
+
36
+ @app.post("/webhooks/billing")
37
+ async def handle_webhook(payload = Depends(require_signature(lambda: ["current", "next"]))):
38
+ queue.enqueue("process-billing-webhook", payload)
39
+ return {"status": "queued"}
40
+ ```
41
+
42
+ ## Environment switches
43
+
44
+ - **API** – toggle logging/observability and docs exposure with `ENABLE_LOGGING`, `LOG_LEVEL`, `LOG_FORMAT`, `ENABLE_OBS`, `METRICS_PATH`, `OBS_SKIP_PATHS`, and `CORS_ALLOW_ORIGINS`. 【F:src/svc_infra/api/fastapi/ease.py†L67-L111】【F:src/svc_infra/api/fastapi/setup.py†L47-L88】
45
+ - **Auth** – configure JWT secrets, SMTP, cookies, and policy using the `AUTH_…` settings family (e.g., `AUTH_JWT__SECRET`, `AUTH_SMTP_HOST`, `AUTH_SESSION_COOKIE_SECURE`). 【F:src/svc_infra/api/fastapi/auth/settings.py†L23-L91】
46
+ - **Database** – set connection URLs or components via `SQL_URL`/`SQL_URL_FILE`, `DB_DIALECT`, `DB_HOST`, `DB_USER`, `DB_PASSWORD`, plus Mongo knobs like `MONGO_URL`, `MONGO_DB`, and `MONGO_URL_FILE`. 【F:src/svc_infra/api/fastapi/db/sql/add.py†L55-L114】【F:src/svc_infra/db/sql/utils.py†L85-L206】【F:src/svc_infra/db/nosql/mongo/settings.py†L9-L13】【F:src/svc_infra/db/nosql/utils.py†L56-L113】
47
+ - **Jobs** – choose the queue backend with `JOBS_DRIVER` and provide Redis via `REDIS_URL`; interval schedules can be declared with `JOBS_SCHEDULE_JSON`. 【F:src/svc_infra/jobs/easy.py†L11-L27】【F:docs/jobs.md†L11-L48】
48
+ - **Cache** – namespace keys and lifetimes through `CACHE_PREFIX`, `CACHE_VERSION`, and TTL overrides `CACHE_TTL_DEFAULT`, `CACHE_TTL_SHORT`, `CACHE_TTL_LONG`. 【F:src/svc_infra/cache/README.md†L20-L173】【F:src/svc_infra/cache/ttl.py†L26-L55】
49
+ - **Observability** – turn metrics on/off or adjust scrape paths with `ENABLE_OBS`, `METRICS_PATH`, `OBS_SKIP_PATHS`, and Prometheus/Grafana flags like `SVC_INFRA_DISABLE_PROMETHEUS`, `SVC_INFRA_RATE_WINDOW`, `SVC_INFRA_DASHBOARD_REFRESH`, `SVC_INFRA_DASHBOARD_RANGE`. 【F:src/svc_infra/api/fastapi/ease.py†L67-L111】【F:src/svc_infra/obs/metrics/asgi.py†L49-L206】【F:src/svc_infra/obs/cloud_dash.py†L85-L108】
50
+ - **Webhooks** – reuse the jobs envs (`JOBS_DRIVER`, `REDIS_URL`) for the delivery worker and queue configuration. 【F:docs/webhooks.md†L32-L53】
51
+ - **Security** – enforce password policy, MFA, and rotation with auth prefixes such as `AUTH_PASSWORD_MIN_LENGTH`, `AUTH_PASSWORD_REQUIRE_SYMBOL`, `AUTH_JWT__SECRET`, and `AUTH_JWT__OLD_SECRETS`. 【F:docs/security.md†L24-L70】
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "svc-infra"
3
- version = "0.1.598"
3
+ version = "0.1.600"
4
4
  description = "Infrastructure for building and deploying prod-ready services"
5
5
  authors = ["Ali Khatami <aliikhatami94@gmail.com>"]
6
6
  license = "MIT"
@@ -12,6 +12,7 @@ from fastapi_users.password import PasswordHelper
12
12
  from svc_infra.api.fastapi.auth._cookies import compute_cookie_params
13
13
  from svc_infra.api.fastapi.auth.policy import AuthPolicy, DefaultAuthPolicy
14
14
  from svc_infra.api.fastapi.auth.settings import get_auth_settings
15
+ from svc_infra.api.fastapi.db.sql.session import SqlSessionDep
15
16
  from svc_infra.api.fastapi.dual.public import public_router
16
17
 
17
18
  _pwd = PasswordHelper()
@@ -66,19 +67,18 @@ def auth_session_router(
66
67
  router = public_router()
67
68
  policy = auth_policy or DefaultAuthPolicy(get_auth_settings())
68
69
 
69
- from svc_infra.api.fastapi.db.sql import SqlSessionDep
70
70
  from svc_infra.security.lockout import get_lockout_status, record_attempt
71
71
 
72
72
  @router.post("/login", name="auth:jwt.login")
73
73
  async def login(
74
74
  request: Request,
75
+ session: SqlSessionDep,
75
76
  username: str = Form(...),
76
77
  password: str = Form(...),
77
78
  scope: str = Form(""),
78
79
  client_id: str | None = Form(None),
79
80
  client_secret: str | None = Form(None),
80
81
  user_manager=Depends(fapi.get_user_manager),
81
- session: SqlSessionDep = Depends(),
82
82
  ):
83
83
  strategy = auth_backend.get_strategy()
84
84
  email = username.strip().lower()
@@ -8,6 +8,8 @@ This guide shows you how to turn on metrics + dashboards in three easy modes:
8
8
 
9
9
  It's "one button": run `svc-infra obs-up` and you're good. The CLI will read your `.env` automatically and do the right thing.
10
10
 
11
+ > ℹ️ A complete list of observability-related environment variables lives in [Environment Reference](../../../docs/environment.md).
12
+
11
13
  ---
12
14
 
13
15
  ## 0) Install & instrument your app (once)
@@ -0,0 +1,201 @@
1
+ from __future__ import annotations
2
+
3
+ import os
4
+ from collections.abc import Mapping
5
+ from typing import Iterable
6
+
7
+ from fastapi import FastAPI
8
+ from fastapi.middleware.cors import CORSMiddleware
9
+ from starlette.middleware.sessions import SessionMiddleware
10
+
11
+ from svc_infra.security.headers import SECURE_DEFAULTS, SecurityHeadersMiddleware
12
+
13
+ DEFAULT_SESSION_SECRET = "svc-dev-secret-change-me"
14
+
15
+
16
+ def _parse_bool(value: str | None) -> bool | None:
17
+ if value is None:
18
+ return None
19
+ lowered = value.strip().lower()
20
+ if lowered in {"1", "true", "yes", "on"}:
21
+ return True
22
+ if lowered in {"0", "false", "no", "off"}:
23
+ return False
24
+ return None
25
+
26
+
27
+ def _normalize_origins(value: Iterable[str] | str | None) -> list[str]:
28
+ if value is None:
29
+ return []
30
+ if isinstance(value, str):
31
+ parts = [p.strip() for p in value.split(",")]
32
+ else:
33
+ parts = [str(v).strip() for v in value]
34
+ return [p for p in parts if p]
35
+
36
+
37
+ def _resolve_cors_origins(
38
+ provided: Iterable[str] | str | None,
39
+ env: Mapping[str, str],
40
+ ) -> list[str]:
41
+ if provided is not None:
42
+ return _normalize_origins(provided)
43
+ return _normalize_origins(env.get("CORS_ALLOW_ORIGINS"))
44
+
45
+
46
+ def _resolve_allow_credentials(
47
+ allow_credentials: bool,
48
+ env: Mapping[str, str],
49
+ ) -> bool:
50
+ env_value = _parse_bool(env.get("CORS_ALLOW_CREDENTIALS"))
51
+ if env_value is None:
52
+ return allow_credentials
53
+ # Allow explicit overrides via function arguments.
54
+ if allow_credentials is not True:
55
+ return allow_credentials
56
+ return env_value
57
+
58
+
59
+ def _configure_cors(
60
+ app: FastAPI,
61
+ *,
62
+ cors_origins: Iterable[str] | str | None,
63
+ allow_credentials: bool,
64
+ env: Mapping[str, str],
65
+ ) -> None:
66
+ origins = _resolve_cors_origins(cors_origins, env)
67
+ if not origins:
68
+ return
69
+
70
+ allow_methods = _normalize_origins(env.get("CORS_ALLOW_METHODS")) or ["*"]
71
+ allow_headers = _normalize_origins(env.get("CORS_ALLOW_HEADERS")) or ["*"]
72
+
73
+ credentials = _resolve_allow_credentials(allow_credentials, env)
74
+
75
+ wildcard_origins = "*" in origins
76
+
77
+ cors_kwargs: dict[str, object] = {
78
+ "allow_credentials": credentials,
79
+ "allow_methods": allow_methods,
80
+ "allow_headers": allow_headers,
81
+ "allow_origins": ["*"] if wildcard_origins else origins,
82
+ }
83
+ origin_regex = env.get("CORS_ALLOW_ORIGIN_REGEX")
84
+ if wildcard_origins:
85
+ cors_kwargs["allow_origin_regex"] = origin_regex or ".*"
86
+ else:
87
+ if origin_regex:
88
+ cors_kwargs["allow_origin_regex"] = origin_regex
89
+
90
+ app.add_middleware(CORSMiddleware, **cors_kwargs)
91
+
92
+
93
+ def _configure_security_headers(
94
+ app: FastAPI,
95
+ *,
96
+ overrides: dict[str, str] | None,
97
+ enable_hsts_preload: bool | None,
98
+ ) -> None:
99
+ merged_overrides = dict(overrides or {})
100
+ if enable_hsts_preload is not None:
101
+ current = merged_overrides.get(
102
+ "Strict-Transport-Security",
103
+ SECURE_DEFAULTS["Strict-Transport-Security"],
104
+ )
105
+ directives = [p.strip() for p in current.split(";") if p.strip()]
106
+ directives = [d for d in directives if d.lower() != "preload"]
107
+ if enable_hsts_preload:
108
+ directives.append("preload")
109
+ merged_overrides["Strict-Transport-Security"] = "; ".join(directives)
110
+
111
+ app.add_middleware(SecurityHeadersMiddleware, overrides=merged_overrides)
112
+
113
+
114
+ def _should_add_session_middleware(app: FastAPI) -> bool:
115
+ return not any(m.cls is SessionMiddleware for m in app.user_middleware)
116
+
117
+
118
+ def _configure_session_middleware(
119
+ app: FastAPI,
120
+ *,
121
+ env: Mapping[str, str],
122
+ install: bool,
123
+ secret_key: str | None,
124
+ session_cookie: str,
125
+ max_age: int,
126
+ same_site: str,
127
+ https_only: bool | None,
128
+ ) -> None:
129
+ if not install or not _should_add_session_middleware(app):
130
+ return
131
+
132
+ secret = secret_key or env.get("SESSION_SECRET") or DEFAULT_SESSION_SECRET
133
+ https_env = _parse_bool(env.get("SESSION_COOKIE_SECURE"))
134
+ effective_https_only = (
135
+ https_only if https_only is not None else (https_env if https_env is not None else False)
136
+ )
137
+ same_site_env = env.get("SESSION_COOKIE_SAMESITE")
138
+ same_site_value = same_site_env.strip() if same_site_env else same_site
139
+
140
+ max_age_env = env.get("SESSION_COOKIE_MAX_AGE_SECONDS")
141
+ try:
142
+ max_age_value = int(max_age_env) if max_age_env is not None else max_age
143
+ except ValueError:
144
+ max_age_value = max_age
145
+
146
+ session_cookie_env = env.get("SESSION_COOKIE_NAME")
147
+ session_cookie_value = session_cookie_env.strip() if session_cookie_env else session_cookie
148
+
149
+ app.add_middleware(
150
+ SessionMiddleware,
151
+ secret_key=secret,
152
+ session_cookie=session_cookie_value,
153
+ max_age=max_age_value,
154
+ same_site=same_site_value,
155
+ https_only=effective_https_only,
156
+ )
157
+
158
+
159
+ def add_security(
160
+ app: FastAPI,
161
+ *,
162
+ cors_origins: Iterable[str] | str | None = None,
163
+ headers_overrides: dict[str, str] | None = None,
164
+ allow_credentials: bool = True,
165
+ env: Mapping[str, str] = os.environ,
166
+ enable_hsts_preload: bool | None = None,
167
+ install_session_middleware: bool = False,
168
+ session_secret_key: str | None = None,
169
+ session_cookie_name: str = "svc_session",
170
+ session_cookie_max_age_seconds: int = 4 * 3600,
171
+ session_cookie_samesite: str = "lax",
172
+ session_cookie_https_only: bool | None = None,
173
+ ) -> None:
174
+ """Install security middlewares with svc-infra defaults."""
175
+
176
+ _configure_security_headers(
177
+ app,
178
+ overrides=headers_overrides,
179
+ enable_hsts_preload=enable_hsts_preload,
180
+ )
181
+ _configure_cors(
182
+ app,
183
+ cors_origins=cors_origins,
184
+ allow_credentials=allow_credentials,
185
+ env=env,
186
+ )
187
+ _configure_session_middleware(
188
+ app,
189
+ env=env,
190
+ install=install_session_middleware,
191
+ secret_key=session_secret_key,
192
+ session_cookie=session_cookie_name,
193
+ max_age=session_cookie_max_age_seconds,
194
+ same_site=session_cookie_samesite,
195
+ https_only=session_cookie_https_only,
196
+ )
197
+
198
+
199
+ __all__ = [
200
+ "add_security",
201
+ ]
@@ -0,0 +1,16 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import TYPE_CHECKING
4
+
5
+ if TYPE_CHECKING: # pragma: no cover - for type checkers only
6
+ from .add import add_webhooks
7
+
8
+ __all__ = ["add_webhooks"]
9
+
10
+
11
+ def __getattr__(name: str):
12
+ if name == "add_webhooks":
13
+ from .add import add_webhooks
14
+
15
+ return add_webhooks
16
+ raise AttributeError(f"module {__name__!r} has no attribute {name!r}")