svc-infra 0.1.614__tar.gz → 0.1.616__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 (301) hide show
  1. {svc_infra-0.1.614 → svc_infra-0.1.616}/PKG-INFO +1 -1
  2. {svc_infra-0.1.614 → svc_infra-0.1.616}/pyproject.toml +3 -2
  3. svc_infra-0.1.616/src/svc_infra/bundled_docs/README.md +5 -0
  4. svc_infra-0.1.616/src/svc_infra/bundled_docs/__init__.py +1 -0
  5. svc_infra-0.1.616/src/svc_infra/bundled_docs/getting-started.md +6 -0
  6. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/cli/__init__.py +4 -0
  7. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/cli/cmds/__init__.py +2 -0
  8. svc_infra-0.1.616/src/svc_infra/cli/cmds/docs/docs_cmds.py +203 -0
  9. {svc_infra-0.1.614 → svc_infra-0.1.616}/README.md +0 -0
  10. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/__init__.py +0 -0
  11. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/apf_payments/README.md +0 -0
  12. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/apf_payments/__init__.py +0 -0
  13. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/apf_payments/alembic.py +0 -0
  14. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/apf_payments/models.py +0 -0
  15. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/apf_payments/provider/__init__.py +0 -0
  16. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/apf_payments/provider/aiydan.py +0 -0
  17. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/apf_payments/provider/base.py +0 -0
  18. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/apf_payments/provider/registry.py +0 -0
  19. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/apf_payments/provider/stripe.py +0 -0
  20. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/apf_payments/schemas.py +0 -0
  21. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/apf_payments/service.py +0 -0
  22. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/apf_payments/settings.py +0 -0
  23. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/api/__init__.py +0 -0
  24. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/api/fastapi/__init__.py +0 -0
  25. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/api/fastapi/apf_payments/__init__.py +0 -0
  26. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/api/fastapi/apf_payments/router.py +0 -0
  27. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/api/fastapi/apf_payments/setup.py +0 -0
  28. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/api/fastapi/auth/__init__.py +0 -0
  29. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/api/fastapi/auth/_cookies.py +0 -0
  30. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/api/fastapi/auth/add.py +0 -0
  31. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/api/fastapi/auth/gaurd.py +0 -0
  32. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/api/fastapi/auth/mfa/__init__.py +0 -0
  33. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/api/fastapi/auth/mfa/models.py +0 -0
  34. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/api/fastapi/auth/mfa/pre_auth.py +0 -0
  35. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/api/fastapi/auth/mfa/router.py +0 -0
  36. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/api/fastapi/auth/mfa/security.py +0 -0
  37. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/api/fastapi/auth/mfa/utils.py +0 -0
  38. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/api/fastapi/auth/mfa/verify.py +0 -0
  39. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/api/fastapi/auth/policy.py +0 -0
  40. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/api/fastapi/auth/providers.py +0 -0
  41. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/api/fastapi/auth/routers/__init__.py +0 -0
  42. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/api/fastapi/auth/routers/account.py +0 -0
  43. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/api/fastapi/auth/routers/apikey_router.py +0 -0
  44. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/api/fastapi/auth/routers/oauth_router.py +0 -0
  45. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/api/fastapi/auth/routers/session_router.py +0 -0
  46. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/api/fastapi/auth/security.py +0 -0
  47. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/api/fastapi/auth/sender.py +0 -0
  48. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/api/fastapi/auth/settings.py +0 -0
  49. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/api/fastapi/auth/state.py +0 -0
  50. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/api/fastapi/cache/__init__.py +0 -0
  51. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/api/fastapi/cache/add.py +0 -0
  52. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/api/fastapi/db/__init__.py +0 -0
  53. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/api/fastapi/db/http.py +0 -0
  54. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/api/fastapi/db/nosql/__init__.py +0 -0
  55. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/api/fastapi/db/nosql/mongo/__init__.py +0 -0
  56. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/api/fastapi/db/nosql/mongo/add.py +0 -0
  57. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/api/fastapi/db/nosql/mongo/crud_router.py +0 -0
  58. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/api/fastapi/db/nosql/mongo/health.py +0 -0
  59. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/api/fastapi/db/sql/README.md +0 -0
  60. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/api/fastapi/db/sql/__init__.py +0 -0
  61. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/api/fastapi/db/sql/add.py +0 -0
  62. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/api/fastapi/db/sql/crud_router.py +0 -0
  63. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/api/fastapi/db/sql/health.py +0 -0
  64. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/api/fastapi/db/sql/session.py +0 -0
  65. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/api/fastapi/db/sql/users.py +0 -0
  66. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/api/fastapi/dependencies/ratelimit.py +0 -0
  67. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/api/fastapi/docs/__init__.py +0 -0
  68. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/api/fastapi/docs/add.py +0 -0
  69. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/api/fastapi/docs/landing.py +0 -0
  70. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/api/fastapi/docs/scoped.py +0 -0
  71. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/api/fastapi/dual/__init__.py +0 -0
  72. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/api/fastapi/dual/dualize.py +0 -0
  73. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/api/fastapi/dual/protected.py +0 -0
  74. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/api/fastapi/dual/public.py +0 -0
  75. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/api/fastapi/dual/router.py +0 -0
  76. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/api/fastapi/dual/utils.py +0 -0
  77. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/api/fastapi/dx.py +0 -0
  78. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/api/fastapi/ease.py +0 -0
  79. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/api/fastapi/http/__init__.py +0 -0
  80. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/api/fastapi/http/concurrency.py +0 -0
  81. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/api/fastapi/http/conditional.py +0 -0
  82. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/api/fastapi/http/deprecation.py +0 -0
  83. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/api/fastapi/middleware/__init__.py +0 -0
  84. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/api/fastapi/middleware/debug.py +0 -0
  85. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/api/fastapi/middleware/errors/__init__.py +0 -0
  86. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/api/fastapi/middleware/errors/catchall.py +0 -0
  87. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/api/fastapi/middleware/errors/exceptions.py +0 -0
  88. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/api/fastapi/middleware/errors/handlers.py +0 -0
  89. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/api/fastapi/middleware/idempotency.py +0 -0
  90. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/api/fastapi/middleware/idempotency_store.py +0 -0
  91. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/api/fastapi/middleware/optimistic_lock.py +0 -0
  92. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/api/fastapi/middleware/ratelimit.py +0 -0
  93. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/api/fastapi/middleware/ratelimit_store.py +0 -0
  94. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/api/fastapi/middleware/request_id.py +0 -0
  95. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/api/fastapi/middleware/request_size_limit.py +0 -0
  96. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/api/fastapi/openapi/__init__.py +0 -0
  97. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/api/fastapi/openapi/apply.py +0 -0
  98. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/api/fastapi/openapi/conventions.py +0 -0
  99. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/api/fastapi/openapi/models.py +0 -0
  100. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/api/fastapi/openapi/mutators.py +0 -0
  101. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/api/fastapi/openapi/pipeline.py +0 -0
  102. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/api/fastapi/openapi/responses.py +0 -0
  103. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/api/fastapi/openapi/security.py +0 -0
  104. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/api/fastapi/ops/add.py +0 -0
  105. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/api/fastapi/pagination.py +0 -0
  106. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/api/fastapi/paths/__init__.py +0 -0
  107. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/api/fastapi/paths/auth.py +0 -0
  108. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/api/fastapi/paths/generic.py +0 -0
  109. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/api/fastapi/paths/prefix.py +0 -0
  110. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/api/fastapi/paths/user.py +0 -0
  111. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/api/fastapi/routers/__init__.py +0 -0
  112. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/api/fastapi/routers/ping.py +0 -0
  113. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/api/fastapi/setup.py +0 -0
  114. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/api/fastapi/tenancy/add.py +0 -0
  115. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/api/fastapi/tenancy/context.py +0 -0
  116. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/app/README.md +0 -0
  117. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/app/__init__.py +0 -0
  118. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/app/env.py +0 -0
  119. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/app/logging/__init__.py +0 -0
  120. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/app/logging/add.py +0 -0
  121. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/app/logging/filter.py +0 -0
  122. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/app/logging/formats.py +0 -0
  123. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/app/root.py +0 -0
  124. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/billing/__init__.py +0 -0
  125. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/billing/models.py +0 -0
  126. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/billing/service.py +0 -0
  127. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/cache/README.md +0 -0
  128. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/cache/__init__.py +0 -0
  129. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/cache/backend.py +0 -0
  130. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/cache/decorators.py +0 -0
  131. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/cache/demo.py +0 -0
  132. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/cache/keys.py +0 -0
  133. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/cache/recache.py +0 -0
  134. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/cache/resources.py +0 -0
  135. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/cache/tags.py +0 -0
  136. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/cache/ttl.py +0 -0
  137. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/cache/utils.py +0 -0
  138. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/cli/__main__.py +0 -0
  139. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/cli/cmds/db/__init__.py +0 -0
  140. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/cli/cmds/db/nosql/__init__.py +0 -0
  141. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/cli/cmds/db/nosql/mongo/README.md +0 -0
  142. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/cli/cmds/db/nosql/mongo/__init__.py +0 -0
  143. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/cli/cmds/db/nosql/mongo/mongo_cmds.py +0 -0
  144. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/cli/cmds/db/nosql/mongo/mongo_scaffold_cmds.py +0 -0
  145. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/cli/cmds/db/sql/__init__.py +0 -0
  146. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/cli/cmds/db/sql/alembic_cmds.py +0 -0
  147. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/cli/cmds/db/sql/sql_export_cmds.py +0 -0
  148. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/cli/cmds/db/sql/sql_scaffold_cmds.py +0 -0
  149. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/cli/cmds/dx/__init__.py +0 -0
  150. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/cli/cmds/dx/dx_cmds.py +0 -0
  151. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/cli/cmds/help.py +0 -0
  152. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/cli/cmds/jobs/__init__.py +0 -0
  153. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/cli/cmds/jobs/jobs_cmds.py +0 -0
  154. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/cli/cmds/obs/__init__.py +0 -0
  155. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/cli/cmds/obs/obs_cmds.py +0 -0
  156. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/cli/cmds/sdk/__init__.py +0 -0
  157. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/cli/cmds/sdk/sdk_cmds.py +0 -0
  158. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/cli/foundation/__init__.py +0 -0
  159. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/cli/foundation/runner.py +0 -0
  160. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/cli/foundation/typer_bootstrap.py +0 -0
  161. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/data/add.py +0 -0
  162. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/data/backup.py +0 -0
  163. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/data/erasure.py +0 -0
  164. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/data/fixtures.py +0 -0
  165. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/data/retention.py +0 -0
  166. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/db/__init__.py +0 -0
  167. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/db/crud_schema.py +0 -0
  168. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/db/inbox.py +0 -0
  169. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/db/nosql/__init__.py +0 -0
  170. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/db/nosql/base.py +0 -0
  171. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/db/nosql/constants.py +0 -0
  172. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/db/nosql/core.py +0 -0
  173. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/db/nosql/indexes.py +0 -0
  174. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/db/nosql/management.py +0 -0
  175. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/db/nosql/mongo/README.md +0 -0
  176. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/db/nosql/mongo/__init__.py +0 -0
  177. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/db/nosql/mongo/client.py +0 -0
  178. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/db/nosql/mongo/settings.py +0 -0
  179. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/db/nosql/mongo/templates/__init__.py +0 -0
  180. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/db/nosql/mongo/templates/documents.py.tmpl +0 -0
  181. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/db/nosql/mongo/templates/resources.py.tmpl +0 -0
  182. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/db/nosql/mongo/templates/schemas.py.tmpl +0 -0
  183. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/db/nosql/repository.py +0 -0
  184. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/db/nosql/resource.py +0 -0
  185. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/db/nosql/scaffold.py +0 -0
  186. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/db/nosql/service.py +0 -0
  187. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/db/nosql/service_with_hooks.py +0 -0
  188. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/db/nosql/types.py +0 -0
  189. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/db/nosql/utils.py +0 -0
  190. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/db/outbox.py +0 -0
  191. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/db/sql/README.md +0 -0
  192. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/db/sql/__init__.py +0 -0
  193. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/db/sql/apikey.py +0 -0
  194. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/db/sql/authref.py +0 -0
  195. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/db/sql/base.py +0 -0
  196. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/db/sql/constants.py +0 -0
  197. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/db/sql/core.py +0 -0
  198. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/db/sql/management.py +0 -0
  199. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/db/sql/repository.py +0 -0
  200. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/db/sql/resource.py +0 -0
  201. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/db/sql/scaffold.py +0 -0
  202. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/db/sql/service.py +0 -0
  203. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/db/sql/service_with_hooks.py +0 -0
  204. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/db/sql/templates/__init__.py +0 -0
  205. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/db/sql/templates/models_schemas/__init__.py +0 -0
  206. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/db/sql/templates/models_schemas/auth/models.py.tmpl +0 -0
  207. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/db/sql/templates/models_schemas/auth/schemas.py.tmpl +0 -0
  208. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/db/sql/templates/models_schemas/entity/models.py.tmpl +0 -0
  209. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/db/sql/templates/models_schemas/entity/schemas.py.tmpl +0 -0
  210. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/db/sql/templates/setup/__init__.py +0 -0
  211. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/db/sql/templates/setup/alembic.ini.tmpl +0 -0
  212. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/db/sql/templates/setup/env_async.py.tmpl +0 -0
  213. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/db/sql/templates/setup/env_sync.py.tmpl +0 -0
  214. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/db/sql/templates/setup/script.py.mako.tmpl +0 -0
  215. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/db/sql/tenant.py +0 -0
  216. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/db/sql/types.py +0 -0
  217. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/db/sql/uniq.py +0 -0
  218. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/db/sql/uniq_hooks.py +0 -0
  219. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/db/sql/utils.py +0 -0
  220. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/db/sql/versioning.py +0 -0
  221. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/db/utils.py +0 -0
  222. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/dx/add.py +0 -0
  223. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/dx/changelog.py +0 -0
  224. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/dx/checks.py +0 -0
  225. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/jobs/builtins/outbox_processor.py +0 -0
  226. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/jobs/builtins/webhook_delivery.py +0 -0
  227. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/jobs/easy.py +0 -0
  228. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/jobs/loader.py +0 -0
  229. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/jobs/queue.py +0 -0
  230. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/jobs/redis_queue.py +0 -0
  231. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/jobs/scheduler.py +0 -0
  232. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/jobs/worker.py +0 -0
  233. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/mcp/__init__.py +0 -0
  234. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/mcp/svc_infra_mcp.py +0 -0
  235. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/obs/README.md +0 -0
  236. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/obs/__init__.py +0 -0
  237. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/obs/add.py +0 -0
  238. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/obs/cloud_dash.py +0 -0
  239. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/obs/grafana/dashboards/http-overview.json +0 -0
  240. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/obs/metrics/__init__.py +0 -0
  241. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/obs/metrics/asgi.py +0 -0
  242. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/obs/metrics/base.py +0 -0
  243. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/obs/metrics/http.py +0 -0
  244. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/obs/metrics/sqlalchemy.py +0 -0
  245. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/obs/metrics.py +0 -0
  246. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/obs/providers/__init__.py +0 -0
  247. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/obs/providers/compose_cloud/__init__.py +0 -0
  248. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/obs/providers/compose_cloud/templates/__init__.py +0 -0
  249. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/obs/providers/compose_cloud/templates/agent.yaml.tmpl +0 -0
  250. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/obs/providers/compose_cloud/templates/docker-compose.cloud.yml.tmpl +0 -0
  251. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/obs/providers/grafana/__init__.py +0 -0
  252. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/obs/providers/grafana/dashboards/00_overview.json +0 -0
  253. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/obs/providers/grafana/dashboards/10_http.json +0 -0
  254. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/obs/providers/grafana/dashboards/20_db.json +0 -0
  255. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/obs/providers/grafana/dashboards/30_runtime.json +0 -0
  256. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/obs/providers/grafana/dashboards/40_clients.json +0 -0
  257. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/obs/providers/grafana/dashboards/__init__.py +0 -0
  258. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/obs/providers/grafana/templates/__init__.py +0 -0
  259. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/obs/providers/grafana/templates/docker-compose.yml.tmpl +0 -0
  260. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/obs/providers/grafana/templates/prometheus.yml.tmpl +0 -0
  261. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/obs/providers/grafana/templates/provisioning/__init__.py +0 -0
  262. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/obs/providers/grafana/templates/provisioning/dashboards.yml +0 -0
  263. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/obs/providers/grafana/templates/provisioning/datasource.yml +0 -0
  264. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/obs/settings.py +0 -0
  265. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/obs/templates/grafana_dashboard.json +0 -0
  266. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/obs/templates/prometheus_rules.yml +0 -0
  267. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/obs/templates/sidecars/__init__.py +0 -0
  268. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/obs/templates/sidecars/compose/__init__.py +0 -0
  269. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/obs/templates/sidecars/compose/agent.yaml +0 -0
  270. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/obs/templates/sidecars/compose/docker-compose.yml +0 -0
  271. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/obs/templates/sidecars/fly/__init__.py +0 -0
  272. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/obs/templates/sidecars/fly/agent.yaml +0 -0
  273. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/obs/templates/sidecars/fly/fly.toml.fragment +0 -0
  274. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/obs/templates/sidecars/k8s/__init__.py +0 -0
  275. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/obs/templates/sidecars/k8s/configmap.yaml +0 -0
  276. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/obs/templates/sidecars/k8s/deployment.yaml +0 -0
  277. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/obs/templates/sidecars/railway/Dockerfile +0 -0
  278. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/obs/templates/sidecars/railway/README.md +0 -0
  279. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/obs/templates/sidecars/railway/__init__.py +0 -0
  280. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/obs/templates/sidecars/railway/agent.yaml +0 -0
  281. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/py.typed +0 -0
  282. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/security/add.py +0 -0
  283. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/security/audit.py +0 -0
  284. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/security/audit_service.py +0 -0
  285. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/security/headers.py +0 -0
  286. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/security/hibp.py +0 -0
  287. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/security/jwt_rotation.py +0 -0
  288. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/security/lockout.py +0 -0
  289. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/security/models.py +0 -0
  290. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/security/org_invites.py +0 -0
  291. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/security/passwords.py +0 -0
  292. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/security/permissions.py +0 -0
  293. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/security/session.py +0 -0
  294. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/security/signed_cookies.py +0 -0
  295. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/utils.py +0 -0
  296. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/webhooks/__init__.py +0 -0
  297. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/webhooks/add.py +0 -0
  298. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/webhooks/fastapi.py +0 -0
  299. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/webhooks/router.py +0 -0
  300. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/webhooks/service.py +0 -0
  301. {svc_infra-0.1.614 → svc_infra-0.1.616}/src/svc_infra/webhooks/signing.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: svc-infra
3
- Version: 0.1.614
3
+ Version: 0.1.616
4
4
  Summary: Infrastructure for building and deploying prod-ready services
5
5
  License: MIT
6
6
  Keywords: fastapi,sqlalchemy,alembic,auth,infra,async,pydantic
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "svc-infra"
3
- version = "0.1.614"
3
+ version = "0.1.616"
4
4
  description = "Infrastructure for building and deploying prod-ready services"
5
5
  authors = ["Ali Khatami <aliikhatami94@gmail.com>"]
6
6
  license = "MIT"
@@ -12,7 +12,8 @@ include = [
12
12
  "src/svc_infra/db/templates/**/*",
13
13
  "src/svc_infra/obs/templates/**/*",
14
14
  "src/svc_infra/obs/grafana/templates/**/*",
15
- "src/svc_infra/obs/grafana/dashboards/**/*"
15
+ "src/svc_infra/obs/grafana/dashboards/**/*",
16
+ "src/svc_infra/bundled_docs/**/*"
16
17
  ]
17
18
 
18
19
  classifiers = [
@@ -0,0 +1,5 @@
1
+ # Bundled Docs
2
+
3
+ This directory contains a minimal set of Markdown files that the `svc-infra docs` CLI can fall back to when the project running the CLI doesn't have a local `docs/` directory.
4
+
5
+ You can add more topics here as needed; each `*.md` file becomes a topic named after its stem (e.g., `getting-started.md` -> `getting-started`).
@@ -0,0 +1 @@
1
+ # Bundled docs package for zip-safe importlib.resources access
@@ -0,0 +1,6 @@
1
+ # Getting Started
2
+
3
+ Welcome to svc-infra docs. Use `svc-infra docs list` to see topics.
4
+
5
+ - This content is bundled with the package.
6
+ - If your project doesn't have a local `docs/` folder, you'll still see this.
@@ -6,6 +6,7 @@ from svc_infra.cli.cmds import (
6
6
  _HELP,
7
7
  jobs_app,
8
8
  register_alembic,
9
+ register_docs,
9
10
  register_dx,
10
11
  register_mongo,
11
12
  register_mongo_scaffold,
@@ -40,6 +41,9 @@ app.add_typer(jobs_app, name="jobs")
40
41
  # -- sdk commands ---
41
42
  register_sdk(app)
42
43
 
44
+ # -- docs commands ---
45
+ register_docs(app)
46
+
43
47
 
44
48
  def main():
45
49
  app()
@@ -5,6 +5,7 @@ from svc_infra.cli.cmds.db.nosql.mongo.mongo_scaffold_cmds import (
5
5
  from svc_infra.cli.cmds.db.sql.alembic_cmds import register as register_alembic
6
6
  from svc_infra.cli.cmds.db.sql.sql_export_cmds import register as register_sql_export
7
7
  from svc_infra.cli.cmds.db.sql.sql_scaffold_cmds import register as register_sql_scaffold
8
+ from svc_infra.cli.cmds.docs.docs_cmds import register as register_docs
8
9
  from svc_infra.cli.cmds.dx import register_dx
9
10
  from svc_infra.cli.cmds.jobs.jobs_cmds import app as jobs_app
10
11
  from svc_infra.cli.cmds.obs.obs_cmds import register as register_obs
@@ -22,5 +23,6 @@ __all__ = [
22
23
  "jobs_app",
23
24
  "register_sdk",
24
25
  "register_dx",
26
+ "register_docs",
25
27
  "_HELP",
26
28
  ]
@@ -0,0 +1,203 @@
1
+ from __future__ import annotations
2
+
3
+ import os
4
+ from pathlib import Path
5
+ from typing import Dict, List
6
+
7
+ import click
8
+ import typer
9
+ from typer.core import TyperGroup
10
+
11
+ from svc_infra.app.root import resolve_project_root
12
+
13
+
14
+ def _discover_fs_topics(docs_dir: Path) -> Dict[str, Path]:
15
+ topics: Dict[str, Path] = {}
16
+ if docs_dir.exists() and docs_dir.is_dir():
17
+ for p in sorted(docs_dir.glob("*.md")):
18
+ if p.is_file():
19
+ topics[p.stem.replace(" ", "-")] = p
20
+ return topics
21
+
22
+
23
+ def _discover_pkg_topics() -> Dict[str, object]:
24
+ topics: Dict[str, object] = {}
25
+ try:
26
+ import importlib.resources as ir
27
+
28
+ pkg_docs = ir.files("svc_infra.bundled_docs")
29
+ for res in pkg_docs.iterdir():
30
+ if res.name.endswith(".md"):
31
+ topics[Path(res.name).stem.replace(" ", "-")] = res
32
+ except Exception:
33
+ pass
34
+ return topics
35
+
36
+
37
+ def _resolve_docs_dir(ctx: click.Context) -> Path | None:
38
+ # CLI option takes precedence; walk up parent contexts because Typer
39
+ # executes subcommands in child contexts that do not inherit params.
40
+ current: click.Context | None = ctx
41
+ while current is not None:
42
+ docs_dir = (current.params or {}).get("docs_dir")
43
+ if docs_dir:
44
+ path = docs_dir if isinstance(docs_dir, Path) else Path(docs_dir)
45
+ path = path.expanduser()
46
+ if path.exists():
47
+ return path
48
+ current = current.parent
49
+ # Env var next
50
+ env_dir = os.getenv("SVC_INFRA_DOCS_DIR")
51
+ if env_dir:
52
+ p = Path(env_dir).expanduser()
53
+ if p.exists():
54
+ return p
55
+ # Project docs
56
+ root = resolve_project_root()
57
+ proj_docs = root / "docs"
58
+ if proj_docs.exists():
59
+ return proj_docs
60
+ return None
61
+
62
+
63
+ class DocsGroup(TyperGroup):
64
+ def list_commands(self, ctx: click.Context) -> List[str]:
65
+ names: List[str] = list(super().list_commands(ctx) or [])
66
+ dir_to_use = _resolve_docs_dir(ctx)
67
+ fs = _discover_fs_topics(dir_to_use) if dir_to_use else {}
68
+ pkg = _discover_pkg_topics() if not fs else {}
69
+ names.extend(fs.keys())
70
+ names.extend(pkg.keys())
71
+ # Deduplicate and sort
72
+ uniq = sorted({*names})
73
+ return uniq
74
+
75
+ def get_command(self, ctx: click.Context, name: str) -> click.Command | None:
76
+ # Built-ins first (e.g., list)
77
+ cmd = super().get_command(ctx, name)
78
+ if cmd is not None:
79
+ return cmd
80
+
81
+ # Dynamic topic resolution
82
+ dir_to_use = _resolve_docs_dir(ctx)
83
+ fs = _discover_fs_topics(dir_to_use) if dir_to_use else {}
84
+ if name in fs:
85
+ file_path = fs[name]
86
+
87
+ @click.command(name=name)
88
+ def _show_fs() -> None:
89
+ click.echo(file_path.read_text(encoding="utf-8", errors="replace"))
90
+
91
+ return _show_fs
92
+
93
+ if not fs:
94
+ pkg = _discover_pkg_topics()
95
+ if name in pkg:
96
+ res = pkg[name]
97
+
98
+ @click.command(name=name)
99
+ def _show_pkg() -> None:
100
+ try:
101
+ import importlib.resources as ir
102
+
103
+ content = getattr(res, "read_text", None)
104
+ if callable(content):
105
+ text = content(encoding="utf-8", errors="replace")
106
+ else:
107
+ with ir.as_file(res) as p:
108
+ text = Path(p).read_text(encoding="utf-8", errors="replace")
109
+ click.echo(text)
110
+ except Exception as e: # pragma: no cover
111
+ raise click.ClickException(f"Failed to load bundled doc: {e}")
112
+
113
+ return _show_pkg
114
+
115
+ return None
116
+
117
+
118
+ def register(app: typer.Typer) -> None:
119
+ """Register the `docs` command group with dynamic topic subcommands."""
120
+
121
+ docs_app = typer.Typer(no_args_is_help=True, add_completion=False, cls=DocsGroup)
122
+
123
+ @docs_app.callback(invoke_without_command=True)
124
+ def _docs_options(
125
+ docs_dir: Path | None = typer.Option(
126
+ None,
127
+ "--docs-dir",
128
+ help="Path to a docs directory to read from (overrides env/project root)",
129
+ ),
130
+ topic: str | None = typer.Option(None, "--topic", help="Topic to show directly"),
131
+ ) -> None:
132
+ """Support --docs-dir and --topic at group level."""
133
+ if topic:
134
+ ctx = click.get_current_context()
135
+ dir_to_use = _resolve_docs_dir(ctx)
136
+ fs = _discover_fs_topics(dir_to_use) if dir_to_use else {}
137
+ if topic in fs:
138
+ typer.echo(fs[topic].read_text(encoding="utf-8", errors="replace"))
139
+ raise typer.Exit(code=0)
140
+ if not fs:
141
+ pkg = _discover_pkg_topics()
142
+ if topic in pkg:
143
+ try:
144
+ import importlib.resources as ir
145
+
146
+ res = pkg[topic]
147
+ content = getattr(res, "read_text", None)
148
+ if callable(content):
149
+ text = content(encoding="utf-8", errors="replace")
150
+ else:
151
+ with ir.as_file(res) as p:
152
+ text = Path(p).read_text(encoding="utf-8", errors="replace")
153
+ typer.echo(text)
154
+ raise typer.Exit(code=0)
155
+ except Exception as e: # pragma: no cover
156
+ raise typer.BadParameter(f"Failed to load bundled topic '{topic}': {e}")
157
+ raise typer.BadParameter(f"Unknown topic: {topic}")
158
+
159
+ @docs_app.command("list", help="List available documentation topics")
160
+ def list_topics() -> None:
161
+ ctx = click.get_current_context()
162
+ root = resolve_project_root()
163
+ dir_to_use = _resolve_docs_dir(ctx)
164
+ fs = _discover_fs_topics(dir_to_use) if dir_to_use else {}
165
+ pkg = _discover_pkg_topics() if not fs else {}
166
+ for name, path in fs.items():
167
+ try:
168
+ rel = path.relative_to(root)
169
+ typer.echo(f"{name}\t{rel}")
170
+ except Exception:
171
+ typer.echo(f"{name}\t{path}")
172
+ for name in sorted(pkg.keys()):
173
+ typer.echo(f"{name}\t(bundled)")
174
+
175
+ # Also support a generic "show" command
176
+ @docs_app.command("show", help="Show docs for a topic (alternative to dynamic subcommand)")
177
+ def show(topic: str) -> None:
178
+ ctx = click.get_current_context()
179
+ dir_to_use = _resolve_docs_dir(ctx)
180
+ fs = _discover_fs_topics(dir_to_use) if dir_to_use else {}
181
+ if topic in fs:
182
+ typer.echo(fs[topic].read_text(encoding="utf-8", errors="replace"))
183
+ return
184
+ if not fs:
185
+ pkg = _discover_pkg_topics()
186
+ if topic in pkg:
187
+ try:
188
+ import importlib.resources as ir
189
+
190
+ res = pkg[topic]
191
+ content = getattr(res, "read_text", None)
192
+ if callable(content):
193
+ text = content(encoding="utf-8", errors="replace")
194
+ else:
195
+ with ir.as_file(res) as p:
196
+ text = Path(p).read_text(encoding="utf-8", errors="replace")
197
+ typer.echo(text)
198
+ return
199
+ except Exception as e: # pragma: no cover
200
+ raise typer.BadParameter(f"Failed to load bundled topic '{topic}': {e}")
201
+ raise typer.BadParameter(f"Unknown topic: {topic}")
202
+
203
+ app.add_typer(docs_app, name="docs")
File without changes