fastapi-startkit 0.49.0__tar.gz → 0.51.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (346) hide show
  1. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/PKG-INFO +61 -1
  2. fastapi_startkit-0.51.0/README.md +58 -0
  3. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/pyproject.toml +3 -2
  4. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/application.py +2 -0
  5. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/container/container.py +4 -7
  6. fastapi_startkit-0.51.0/src/fastapi_startkit/events/__init__.py +13 -0
  7. fastapi_startkit-0.51.0/src/fastapi_startkit/events/dispatcher.py +141 -0
  8. fastapi_startkit-0.51.0/src/fastapi_startkit/events/fake.py +79 -0
  9. fastapi_startkit-0.51.0/src/fastapi_startkit/events/helpers.py +19 -0
  10. fastapi_startkit-0.51.0/src/fastapi_startkit/events/listener.py +16 -0
  11. fastapi_startkit-0.51.0/src/fastapi_startkit/events/provider.py +31 -0
  12. fastapi_startkit-0.51.0/src/fastapi_startkit/facades/Event.py +5 -0
  13. fastapi_startkit-0.51.0/src/fastapi_startkit/facades/Event.pyi +41 -0
  14. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/facades/__init__.py +1 -0
  15. fastapi_startkit-0.51.0/src/fastapi_startkit/fastapi/__init__.py +15 -0
  16. fastapi_startkit-0.51.0/src/fastapi_startkit/fastapi/events.py +29 -0
  17. fastapi_startkit-0.51.0/src/fastapi_startkit/fastapi/middleware.py +54 -0
  18. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/fastapi/providers/fastapi_provider.py +13 -1
  19. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/connections/factory.py +35 -14
  20. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/models/attribute.py +5 -0
  21. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/models/builder.py +53 -1
  22. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/models/model.py +37 -4
  23. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/relationships/BelongsToMany.py +28 -45
  24. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/relationships/MorphMany.py +23 -21
  25. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/relationships/MorphOne.py +21 -17
  26. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/relationships/MorphToMany.py +12 -8
  27. fastapi_startkit-0.51.0/src/fastapi_startkit/py.typed +0 -0
  28. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/support/providers/provider.py +3 -2
  29. fastapi_startkit-0.49.0/src/fastapi_startkit/fastapi/__init__.py +0 -6
  30. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/.DS_Store +0 -0
  31. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/__init__.py +0 -0
  32. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/ai/__init__.py +0 -0
  33. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/ai/agent.py +0 -0
  34. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/ai/audio.py +0 -0
  35. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/ai/audio_factory.py +0 -0
  36. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/ai/config/ai.py +0 -0
  37. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/ai/config/config.py +0 -0
  38. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/ai/decorators.py +0 -0
  39. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/ai/document.py +0 -0
  40. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/ai/fakes.py +0 -0
  41. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/ai/image.py +0 -0
  42. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/ai/image_factory.py +0 -0
  43. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/ai/lab.py +0 -0
  44. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/ai/model_builder.py +0 -0
  45. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/ai/pipeline.py +0 -0
  46. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/ai/providers/__init__.py +0 -0
  47. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/ai/providers/ai_provider.py +0 -0
  48. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/ai/response.py +0 -0
  49. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/ai/runner.py +0 -0
  50. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/ai/testing.py +0 -0
  51. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/broadcasting/__init__.py +0 -0
  52. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/broadcasting/auth.py +0 -0
  53. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/broadcasting/channels.py +0 -0
  54. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/broadcasting/config.py +0 -0
  55. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/broadcasting/drivers/__init__.py +0 -0
  56. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/broadcasting/drivers/log_driver.py +0 -0
  57. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/broadcasting/drivers/reverb_driver.py +0 -0
  58. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/broadcasting/event.py +0 -0
  59. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/broadcasting/helpers.py +0 -0
  60. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/broadcasting/manager.py +0 -0
  61. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/broadcasting/provider.py +0 -0
  62. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/broadcasting/reverb/__init__.py +0 -0
  63. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/broadcasting/reverb/channel_manager.py +0 -0
  64. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/broadcasting/reverb/connection.py +0 -0
  65. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/broadcasting/reverb/server.py +0 -0
  66. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/broadcasting/stubs/__init__.py +0 -0
  67. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/broadcasting/stubs/channels.py +0 -0
  68. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/carbon/__init__.py +0 -0
  69. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/carbon/carbon.py +0 -0
  70. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/config/__init__.py +0 -0
  71. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/config/app.py +0 -0
  72. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/configuration/Configuration.py +0 -0
  73. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/configuration/__init__.py +0 -0
  74. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/configuration/config.py +0 -0
  75. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/configuration/helpers.py +0 -0
  76. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/configuration/providers/ConfigurationProvider.py +0 -0
  77. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/configuration/providers/__init__.py +0 -0
  78. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/console/__init__.py +0 -0
  79. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/console/application.py +0 -0
  80. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/console/can_override_config.py +0 -0
  81. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/console/can_override_default_options.py +0 -0
  82. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/console/command.py +0 -0
  83. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/console/publish_command.py +0 -0
  84. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/container/__init__.py +0 -0
  85. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/environment/__init__.py +0 -0
  86. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/environment/environment.py +0 -0
  87. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/exceptions/__init__.py +0 -0
  88. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/exceptions/exceptions.py +0 -0
  89. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/exceptions/handler.py +0 -0
  90. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/facades/AI.py +0 -0
  91. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/facades/AI.pyi +0 -0
  92. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/facades/Cache.py +0 -0
  93. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/facades/Config.py +0 -0
  94. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/facades/Config.pyi +0 -0
  95. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/facades/Dump.py +0 -0
  96. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/facades/Dump.pyi +0 -0
  97. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/facades/Facade.py +0 -0
  98. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/facades/Gate.py +0 -0
  99. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/facades/Gate.pyi +0 -0
  100. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/facades/Hash.py +0 -0
  101. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/facades/Hash.pyi +0 -0
  102. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/facades/Loader.py +0 -0
  103. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/facades/Loader.pyi +0 -0
  104. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/facades/Mail.py +0 -0
  105. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/facades/Mail.pyi +0 -0
  106. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/facades/Notification.py +0 -0
  107. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/facades/Notification.pyi +0 -0
  108. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/facades/Queue.py +0 -0
  109. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/facades/Queue.pyi +0 -0
  110. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/facades/RateLimiter.py +0 -0
  111. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/facades/RateLimiter.pyi +0 -0
  112. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/facades/Request.py +0 -0
  113. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/facades/Request.pyi +0 -0
  114. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/facades/Response.py +0 -0
  115. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/facades/Response.pyi +0 -0
  116. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/facades/Session.py +0 -0
  117. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/facades/Session.pyi +0 -0
  118. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/facades/Url.py +0 -0
  119. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/facades/Url.pyi +0 -0
  120. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/facades/View.py +0 -0
  121. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/facades/View.pyi +0 -0
  122. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/facades/Vite.py +0 -0
  123. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/facades/Vite.pyi +0 -0
  124. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/fastapi/commands/__init__.py +0 -0
  125. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/fastapi/commands/serve_command.py +0 -0
  126. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/fastapi/config/__init__.py +0 -0
  127. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/fastapi/config/fastapi.py +0 -0
  128. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/fastapi/exceptions.py +0 -0
  129. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/fastapi/requests/model.py +0 -0
  130. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/fastapi/routers/router.py +0 -0
  131. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/fastapi/testing/__init__.py +0 -0
  132. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/fastapi/testing/assertable_json.py +0 -0
  133. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/fastapi/testing/test_case.py +0 -0
  134. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/fastapi/testing/test_response.py +0 -0
  135. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/foundation/app_provider.py +0 -0
  136. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/inertia/__init__.py +0 -0
  137. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/inertia/constant.py +0 -0
  138. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/inertia/context.py +0 -0
  139. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/inertia/inertia.py +0 -0
  140. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/inertia/middleware.py +0 -0
  141. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/inertia/props/props.py +0 -0
  142. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/inertia/provider.py +0 -0
  143. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/jsonapi/__init__.py +0 -0
  144. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/jsonapi/response.py +0 -0
  145. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/loader/Loader.py +0 -0
  146. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/loader/__init__.py +0 -0
  147. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/logging/ChannelFactory.py +0 -0
  148. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/logging/__init__.py +0 -0
  149. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/logging/channels/BaseChannel.py +0 -0
  150. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/logging/channels/DailyChannel.py +0 -0
  151. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/logging/channels/MultiBaseChannel.py +0 -0
  152. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/logging/channels/SingleChannel.py +0 -0
  153. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/logging/channels/SlackChannel.py +0 -0
  154. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/logging/channels/StackChannel.py +0 -0
  155. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/logging/channels/SyslogChannel.py +0 -0
  156. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/logging/channels/TerminalChannel.py +0 -0
  157. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/logging/channels/__init__.py +0 -0
  158. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/logging/config/__init__.py +0 -0
  159. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/logging/config/channels.py +0 -0
  160. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/logging/config/logging.py +0 -0
  161. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/logging/drivers/BaseDriver.py +0 -0
  162. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/logging/drivers/LogSingleDriver.py +0 -0
  163. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/logging/drivers/LogSlackDriver.py +0 -0
  164. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/logging/drivers/LogSyslogDriver.py +0 -0
  165. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/logging/drivers/LogTerminalDriver.py +0 -0
  166. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/logging/drivers/__init__.py +0 -0
  167. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/logging/factory.py +0 -0
  168. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/logging/file.py +0 -0
  169. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/logging/handler.py +0 -0
  170. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/logging/listeners.py +0 -0
  171. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/logging/logger.py +0 -0
  172. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/logging/managers/LoggingManager.py +0 -0
  173. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/logging/managers/__init__.py +0 -0
  174. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/logging/providers/__init__.py +0 -0
  175. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/logging/providers/log_provider.py +0 -0
  176. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/__init__.py +0 -0
  177. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/collection/Collection.py +0 -0
  178. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/collection/__init__.py +0 -0
  179. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/commands/DBMigrateCommand.py +0 -0
  180. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/commands/DBSeedCommand.py +0 -0
  181. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/commands/MakeMigrationCommand.py +0 -0
  182. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/commands/MakeModelCommand.py +0 -0
  183. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/commands/MakeModelDocstringCommand.py +0 -0
  184. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/commands/MakeObserverCommand.py +0 -0
  185. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/commands/MakeSeedCommand.py +0 -0
  186. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/commands/MigrateFreshCommand.py +0 -0
  187. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/commands/MigrateRefreshCommand.py +0 -0
  188. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/commands/MigrateResetCommand.py +0 -0
  189. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/commands/MigrateRollbackCommand.py +0 -0
  190. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/commands/MigrateStatusCommand.py +0 -0
  191. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/commands/ShellCommand.py +0 -0
  192. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/commands/__init__.py +0 -0
  193. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/commands/stubs/create_migration.stub +0 -0
  194. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/commands/stubs/create_seed.stub +0 -0
  195. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/commands/stubs/model.stub +0 -0
  196. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/commands/stubs/observer.stub +0 -0
  197. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/commands/stubs/table_migration.stub +0 -0
  198. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/config/__init__.py +0 -0
  199. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/config/config.py +0 -0
  200. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/config/database.py +0 -0
  201. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/connections/connection.py +0 -0
  202. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/connections/manager.py +0 -0
  203. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/connections/mysql_connection.py +0 -0
  204. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/connections/postgres_connection.py +0 -0
  205. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/connections/sqlite_connection.py +0 -0
  206. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/exceptions.py +0 -0
  207. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/expressions/__init__.py +0 -0
  208. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/expressions/expressions.py +0 -0
  209. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/facades/DB.py +0 -0
  210. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/facades/Schema.py +0 -0
  211. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/facades/__init__.py +0 -0
  212. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/factory/__init__.py +0 -0
  213. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/factory/factory.py +0 -0
  214. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/helpers/__init__.py +0 -0
  215. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/helpers/misc.py +0 -0
  216. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/migrations/Migration.py +0 -0
  217. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/migrations/Migrator.py +0 -0
  218. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/migrations/__init__.py +0 -0
  219. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/models/MigrationModel.py +0 -0
  220. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/models/__init__.py +0 -0
  221. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/models/caster.py +0 -0
  222. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/models/fields.py +0 -0
  223. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/models/observer.py +0 -0
  224. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/models/pivot.py +0 -0
  225. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/models/registry.py +0 -0
  226. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/models/relationship.py +0 -0
  227. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/observers/ObservesEvents.py +0 -0
  228. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/observers/__init__.py +0 -0
  229. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/pagination/BasePaginator.py +0 -0
  230. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/pagination/LengthAwarePaginator.py +0 -0
  231. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/pagination/SimplePaginator.py +0 -0
  232. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/pagination/__init__.py +0 -0
  233. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/providers/DatabaseProvider.py +0 -0
  234. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/providers/__init__.py +0 -0
  235. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/query/EagerLoadMixin.py +0 -0
  236. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/query/EagerRelation.py +0 -0
  237. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/query/__init__.py +0 -0
  238. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/query/grammars/BaseGrammar.py +0 -0
  239. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/query/grammars/MSSQLGrammar.py +0 -0
  240. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/query/grammars/MySQLGrammar.py +0 -0
  241. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/query/grammars/PostgresGrammar.py +0 -0
  242. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/query/grammars/SQLiteGrammar.py +0 -0
  243. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/query/grammars/__init__.py +0 -0
  244. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/query/processors/MSSQLPostProcessor.py +0 -0
  245. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/query/processors/MySQLPostProcessor.py +0 -0
  246. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/query/processors/PostgresPostProcessor.py +0 -0
  247. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/query/processors/SQLitePostProcessor.py +0 -0
  248. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/query/processors/__init__.py +0 -0
  249. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/query/support.py +0 -0
  250. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/relationships/BaseRelationship.py +0 -0
  251. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/relationships/BelongsTo.py +0 -0
  252. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/relationships/HasMany.py +0 -0
  253. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/relationships/HasManyThrough.py +0 -0
  254. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/relationships/HasOne.py +0 -0
  255. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/relationships/HasOneThrough.py +0 -0
  256. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/relationships/MorphTo.py +0 -0
  257. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/relationships/__init__.py +0 -0
  258. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/schema/Blueprint.py +0 -0
  259. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/schema/Column.py +0 -0
  260. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/schema/ColumnDiff.py +0 -0
  261. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/schema/Constraint.py +0 -0
  262. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/schema/ForeignKeyConstraint.py +0 -0
  263. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/schema/Index.py +0 -0
  264. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/schema/Table.py +0 -0
  265. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/schema/TableDiff.py +0 -0
  266. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/schema/__init__.py +0 -0
  267. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/schema/platforms/MSSQLPlatform.py +0 -0
  268. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/schema/platforms/MySQLPlatform.py +0 -0
  269. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/schema/platforms/Platform.py +0 -0
  270. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/schema/platforms/PostgresPlatform.py +0 -0
  271. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/schema/platforms/SQLitePlatform.py +0 -0
  272. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/schema/platforms/__init__.py +0 -0
  273. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/schema/schema.py +0 -0
  274. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/seeders/Seeder.py +0 -0
  275. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/seeders/__init__.py +0 -0
  276. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/stubs/create-migration.html +0 -0
  277. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/stubs/table-migration.html +0 -0
  278. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/testing/__init__.py +0 -0
  279. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm/testing/transaction.py +0 -0
  280. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm.backup/.pytest_cache/.gitignore +0 -0
  281. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm.backup/.pytest_cache/CACHEDIR.TAG +0 -0
  282. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm.backup/.pytest_cache/README.md +0 -0
  283. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm.backup/.pytest_cache/v/cache/lastfailed +0 -0
  284. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/masoniteorm.backup/.pytest_cache/v/cache/nodeids +0 -0
  285. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/mcp/__init__.py +0 -0
  286. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/mcp/argument.py +0 -0
  287. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/mcp/prompt.py +0 -0
  288. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/mcp/protocol.py +0 -0
  289. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/mcp/providers/__init__.py +0 -0
  290. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/mcp/providers/mcp_provider.py +0 -0
  291. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/mcp/request.py +0 -0
  292. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/mcp/resource.py +0 -0
  293. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/mcp/response.py +0 -0
  294. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/mcp/server.py +0 -0
  295. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/mcp/tool.py +0 -0
  296. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/process/__init__.py +0 -0
  297. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/process/exception.py +0 -0
  298. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/process/fake.py +0 -0
  299. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/process/process.py +0 -0
  300. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/process/result.py +0 -0
  301. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/skills/__init__.py +0 -0
  302. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/skills/adapters/__init__.py +0 -0
  303. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/skills/adapters/base.py +0 -0
  304. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/skills/adapters/claude.py +0 -0
  305. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/skills/adapters/gemini.py +0 -0
  306. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/skills/commands/__init__.py +0 -0
  307. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/skills/commands/skills.py +0 -0
  308. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/skills/parser.py +0 -0
  309. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/skills/provider.py +0 -0
  310. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/skills/registry.py +0 -0
  311. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/skills/stubs/.ai/fastapi-startkit/database/SKILL.md +0 -0
  312. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/skills/stubs/.ai/fastapi-startkit/fastapi/SKILL.md +0 -0
  313. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/skills/stubs/.ai/fastapi-startkit/inertia/SKILL.md +0 -0
  314. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/storage/__init__.py +0 -0
  315. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/storage/config/__init__.py +0 -0
  316. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/storage/config/storage.py +0 -0
  317. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/storage/data/mime.types +0 -0
  318. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/storage/drivers/__init__.py +0 -0
  319. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/storage/drivers/fake.py +0 -0
  320. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/storage/drivers/local.py +0 -0
  321. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/storage/drivers/s3.py +0 -0
  322. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/storage/file.py +0 -0
  323. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/storage/filestream.py +0 -0
  324. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/storage/helper.py +0 -0
  325. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/storage/providers/provider.py +0 -0
  326. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/storage/storage.py +0 -0
  327. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/support/__init__.py +0 -0
  328. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/support/collection.py +0 -0
  329. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/support/dataclass.py +0 -0
  330. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/support/providers/__init__.py +0 -0
  331. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/support/string.py +0 -0
  332. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/support/uri.py +0 -0
  333. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/testing/__init__.py +0 -0
  334. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/testing/test_case.py +0 -0
  335. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/utils/structures.py +0 -0
  336. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/vite/__init__.py +0 -0
  337. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/vite/config/vite.py +0 -0
  338. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/vite/exceptions.py +0 -0
  339. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/vite/providers/provider.py +0 -0
  340. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/vite/stubs/package.json +0 -0
  341. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/vite/stubs/resources/css/app.css +0 -0
  342. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/vite/stubs/resources/js/app.ts +0 -0
  343. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/vite/stubs/resources/templates/index.html +0 -0
  344. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/vite/stubs/tsconfig.json +0 -0
  345. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/vite/stubs/vite.config.ts +0 -0
  346. {fastapi_startkit-0.49.0 → fastapi_startkit-0.51.0}/src/fastapi_startkit/vite/vite.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: fastapi-startkit
3
- Version: 0.49.0
3
+ Version: 0.51.0
4
4
  Summary: A modular, provider-driven framework for building async Python web applications with FastAPI — bundling a service container, configuration system, an async-first ORM, facades, and a Cleo-powered console.
5
5
  Keywords: fastapi,framework,async,web,asgi,orm,sqlalchemy,pydantic,ioc-container,dependency-injection,service-provider,cli,console,configuration,microservices,starter-kit,boilerplate
6
6
  Author: Bedram Tamang
@@ -46,3 +46,63 @@ Provides-Extra: mysql
46
46
  Provides-Extra: postgres
47
47
  Provides-Extra: sqlite
48
48
  Provides-Extra: vite
49
+ Description-Content-Type: text/markdown
50
+
51
+ # FastAPI Startkit
52
+
53
+ [![codecov](https://codecov.io/gh/fastapi-startkit/fastapi-startkit-framework/graph/badge.svg)](https://codecov.io/gh/fastapi-startkit/fastapi-startkit-framework)
54
+ [![PyPI version](https://img.shields.io/pypi/v/fastapi-startkit.svg)](https://pypi.org/project/fastapi-startkit/)
55
+ [![Python versions](https://img.shields.io/pypi/pyversions/fastapi-startkit.svg)](https://pypi.org/project/fastapi-startkit/)
56
+
57
+ A modular, provider-driven framework for building Python applications with FastAPI. It bundles a
58
+ service container, configuration system, an async-first ORM, facades, and a Cleo-powered console into
59
+ a single cohesive foundation.
60
+
61
+ ## Installation
62
+
63
+ ```bash
64
+ pip install fastapi-startkit
65
+ ```
66
+
67
+ Optional extras enable additional capabilities:
68
+
69
+ ```bash
70
+ fastapi-startkit[fastapi] # FastAPI + Starlette
71
+ fastapi-startkit[database] # SQLAlchemy async ORM
72
+ fastapi-startkit[vite] # Jinja2 for Vite integration
73
+ ```
74
+
75
+ ## Features
76
+
77
+ - **Service container** — IoC container with `bind`/`make`/`resolve` auto-wiring and lifecycle hooks.
78
+ - **Configuration** — dataclass-based config sourced from the environment with dotted-key access.
79
+ - **Providers** — two-phase (`register` / `boot`) service registration.
80
+ - **Routing** — a `Router` wrapper around FastAPI's `APIRouter` with a `resource()` CRUD shortcut.
81
+ - **ORM** — async-first Masonite ORM fork on SQLAlchemy async, with relationships and migrations.
82
+ - **Facades** — static-like access to container-resolved services (`Config`, `Auth`, ...).
83
+ - **Console** — Cleo-based CLI (`artisan`) for migrations, seeders, and code generation.
84
+
85
+ ## Documentation
86
+
87
+ Full documentation is available at
88
+ [fastapi-startkit.github.io](https://fastapi-startkit.github.io).
89
+
90
+ ## Development
91
+
92
+ ```bash
93
+ # Install dependencies
94
+ uv sync --group dev --extra database --extra sqlite --extra fastapi --extra vite --extra postgres
95
+
96
+ # Run the test suite
97
+ uv run pytest tests/ -v
98
+
99
+ # Run tests with coverage
100
+ uv run pytest --cov --cov-report=term-missing
101
+ ```
102
+
103
+ Coverage is collected in CI and reported to
104
+ [Codecov](https://codecov.io/gh/fastapi-startkit/fastapi-startkit-framework).
105
+
106
+ ## License
107
+
108
+ See the repository root for license details.
@@ -0,0 +1,58 @@
1
+ # FastAPI Startkit
2
+
3
+ [![codecov](https://codecov.io/gh/fastapi-startkit/fastapi-startkit-framework/graph/badge.svg)](https://codecov.io/gh/fastapi-startkit/fastapi-startkit-framework)
4
+ [![PyPI version](https://img.shields.io/pypi/v/fastapi-startkit.svg)](https://pypi.org/project/fastapi-startkit/)
5
+ [![Python versions](https://img.shields.io/pypi/pyversions/fastapi-startkit.svg)](https://pypi.org/project/fastapi-startkit/)
6
+
7
+ A modular, provider-driven framework for building Python applications with FastAPI. It bundles a
8
+ service container, configuration system, an async-first ORM, facades, and a Cleo-powered console into
9
+ a single cohesive foundation.
10
+
11
+ ## Installation
12
+
13
+ ```bash
14
+ pip install fastapi-startkit
15
+ ```
16
+
17
+ Optional extras enable additional capabilities:
18
+
19
+ ```bash
20
+ fastapi-startkit[fastapi] # FastAPI + Starlette
21
+ fastapi-startkit[database] # SQLAlchemy async ORM
22
+ fastapi-startkit[vite] # Jinja2 for Vite integration
23
+ ```
24
+
25
+ ## Features
26
+
27
+ - **Service container** — IoC container with `bind`/`make`/`resolve` auto-wiring and lifecycle hooks.
28
+ - **Configuration** — dataclass-based config sourced from the environment with dotted-key access.
29
+ - **Providers** — two-phase (`register` / `boot`) service registration.
30
+ - **Routing** — a `Router` wrapper around FastAPI's `APIRouter` with a `resource()` CRUD shortcut.
31
+ - **ORM** — async-first Masonite ORM fork on SQLAlchemy async, with relationships and migrations.
32
+ - **Facades** — static-like access to container-resolved services (`Config`, `Auth`, ...).
33
+ - **Console** — Cleo-based CLI (`artisan`) for migrations, seeders, and code generation.
34
+
35
+ ## Documentation
36
+
37
+ Full documentation is available at
38
+ [fastapi-startkit.github.io](https://fastapi-startkit.github.io).
39
+
40
+ ## Development
41
+
42
+ ```bash
43
+ # Install dependencies
44
+ uv sync --group dev --extra database --extra sqlite --extra fastapi --extra vite --extra postgres
45
+
46
+ # Run the test suite
47
+ uv run pytest tests/ -v
48
+
49
+ # Run tests with coverage
50
+ uv run pytest --cov --cov-report=term-missing
51
+ ```
52
+
53
+ Coverage is collected in CI and reported to
54
+ [Codecov](https://codecov.io/gh/fastapi-startkit/fastapi-startkit-framework).
55
+
56
+ ## License
57
+
58
+ See the repository root for license details.
@@ -1,7 +1,8 @@
1
1
  [project]
2
2
  name = "fastapi-startkit"
3
- version = "0.49.0"
3
+ version = "0.51.0"
4
4
  description = "A modular, provider-driven framework for building async Python web applications with FastAPI — bundling a service container, configuration system, an async-first ORM, facades, and a Cleo-powered console."
5
+ readme = "README.md"
5
6
  keywords = [
6
7
  "fastapi",
7
8
  "framework",
@@ -148,7 +149,7 @@ omit = [
148
149
  [tool.coverage.report]
149
150
  show_missing = true
150
151
  skip_covered = false
151
- fail_under = 68
152
+ fail_under = 80
152
153
  exclude_lines = [
153
154
  "pragma: no cover",
154
155
  "if TYPE_CHECKING:",
@@ -8,6 +8,7 @@ from typing import Type, Callable, Any, List, TypeVar, Generic
8
8
  from .config import AppConfig
9
9
  from .configuration.providers import ConfigurationProvider
10
10
  from .container import Container
11
+ from .events import EventServiceProvider
11
12
  from .environment.environment import Environment
12
13
 
13
14
  if TYPE_CHECKING:
@@ -27,6 +28,7 @@ TConfig = TypeVar("TConfig", bound=AppConfig)
27
28
  class Application(Container, Generic[TConfig]):
28
29
  DEFAULT_PROVIDERS = [
29
30
  ConfigurationProvider,
31
+ EventServiceProvider,
30
32
  AppProvider,
31
33
  ]
32
34
 
@@ -1,6 +1,7 @@
1
1
  """Core of the IOC Container."""
2
2
 
3
3
  import inspect
4
+ from typing import Any
4
5
 
5
6
  from ..exceptions import (
6
7
  ContainerError,
@@ -42,15 +43,13 @@ class Container:
42
43
  self.swaps = {}
43
44
  self._remembered = {}
44
45
 
45
- def bind(self, name, class_obj):
46
+ def bind(self, name: str | type, class_obj: Any) -> None:
46
47
  """Bind classes into the container with a key value pair.
47
48
 
48
49
  Arguments:
49
- name {string} -- Name of the key you want to bind the object to
50
+ name {string | type} -- Key to bind the object to; a class object is
51
+ accepted for class-keyed bindings (mirrors make()'s class-key support)
50
52
  class_obj {object} -- The object you want to bind
51
-
52
- Returns:
53
- self
54
53
  """
55
54
  if inspect.ismodule(class_obj):
56
55
  raise StrictContainerException(
@@ -63,8 +62,6 @@ class Container:
63
62
  self.fire_hook("bind", name, class_obj)
64
63
  self.objects.update({name: class_obj})
65
64
 
66
- return self
67
-
68
65
  def unbind(self, name):
69
66
  """Unbind classes from the container from a key.
70
67
 
@@ -0,0 +1,13 @@
1
+ from .dispatcher import Dispatcher
2
+ from .fake import EventFake
3
+ from .helpers import event
4
+ from .listener import Listener
5
+ from .provider import EventServiceProvider
6
+
7
+ __all__ = [
8
+ "Dispatcher",
9
+ "EventFake",
10
+ "EventServiceProvider",
11
+ "Listener",
12
+ "event",
13
+ ]
@@ -0,0 +1,141 @@
1
+ """Application event dispatcher.
2
+
3
+ An async-aware, Laravel-style event dispatcher. Events are plain classes;
4
+ listeners are callables or classes exposing a ``handle`` method. Both sync and
5
+ coroutine listeners are supported — coroutine results are awaited transparently.
6
+ """
7
+
8
+ import inspect
9
+ from fnmatch import fnmatchcase
10
+ from typing import TYPE_CHECKING, Any, Callable, cast, overload
11
+
12
+ if TYPE_CHECKING:
13
+ from ..container import Container
14
+ from .fake import EventFake
15
+
16
+
17
+ class Dispatcher:
18
+ def __init__(self, container: "Container | None" = None):
19
+ self._container = container
20
+ self._listeners: dict[str, list] = {}
21
+
22
+ @overload
23
+ def listen(self, events, listener: None = None) -> Callable: ...
24
+
25
+ @overload
26
+ def listen(self, events, listener: Callable) -> None: ...
27
+
28
+ def listen(self, events, listener: Callable | None = None):
29
+ """Register a listener for one or more events.
30
+
31
+ ``events`` may be an event class, a string name, or a list of either.
32
+ String names may contain ``*`` wildcards (e.g. ``"user.*"``) — the
33
+ listener then fires for any matching event name. Used as a decorator
34
+ when ``listener`` is omitted.
35
+ """
36
+ if listener is None:
37
+
38
+ def decorator(func: Callable) -> Callable:
39
+ self.listen(events, func)
40
+ return func
41
+
42
+ return decorator
43
+
44
+ for name in self._event_names(events):
45
+ self._listeners.setdefault(name, []).append(listener)
46
+ return None
47
+
48
+ def has_listeners(self, event) -> bool:
49
+ return bool(self._get_listeners(self._event_key(event)))
50
+
51
+ def forget(self, event) -> None:
52
+ """Remove all listeners registered for a given event."""
53
+ self._listeners.pop(self._event_key(event), None)
54
+
55
+ def flush(self) -> None:
56
+ """Remove every registered listener."""
57
+ self._listeners.clear()
58
+
59
+ async def dispatch(self, event, payload=None, halt: bool = False):
60
+ """Fire an event and call its listeners in registration order.
61
+
62
+ Returns the list of listener responses. When ``halt`` is true, the first
63
+ non-``None`` response is returned immediately. A listener returning
64
+ ``False`` stops propagation to later listeners.
65
+ """
66
+ name, args = self._parse_event_payload(event, payload)
67
+
68
+ responses: list[Any] = []
69
+ for listener in self._get_listeners(name):
70
+ response = await self._call_listener(listener, args)
71
+
72
+ if halt and response is not None:
73
+ return response
74
+
75
+ if response is False:
76
+ break
77
+
78
+ responses.append(response)
79
+
80
+ return None if halt else responses
81
+
82
+ async def until(self, event, payload=None):
83
+ """Dispatch an event, returning the first non-``None`` listener response."""
84
+ return await self.dispatch(event, payload, halt=True)
85
+
86
+ def fake(self, events_to_fake=None) -> "EventFake":
87
+ """Swap the container's dispatcher for a recording fake (testing helper)."""
88
+ from .fake import EventFake
89
+
90
+ fake = EventFake(cast("Dispatcher", self), events_to_fake)
91
+ if self._container is not None:
92
+ self._container.bind("events", fake)
93
+ return fake
94
+
95
+ def _event_names(self, events) -> list[str]:
96
+ items = events if isinstance(events, (list, tuple)) else [events]
97
+ return [self._event_key(event) for event in items]
98
+
99
+ def _get_listeners(self, name: str) -> list:
100
+ """All listeners for an event name: exact matches first, then any
101
+ wildcard-pattern listeners whose pattern matches the name."""
102
+ listeners = list(self._listeners.get(name, []))
103
+ for pattern, pattern_listeners in self._listeners.items():
104
+ if pattern != name and "*" in pattern and fnmatchcase(name, pattern):
105
+ listeners.extend(pattern_listeners)
106
+ return listeners
107
+
108
+ def _event_key(self, event) -> str:
109
+ if isinstance(event, str):
110
+ return event
111
+ cls = event if inspect.isclass(event) else type(event)
112
+ return f"{cls.__module__}.{cls.__qualname__}"
113
+
114
+ def _parse_event_payload(self, event, payload) -> tuple[str, list]:
115
+ if isinstance(event, str):
116
+ if payload is None:
117
+ args: list = []
118
+ elif isinstance(payload, (list, tuple)):
119
+ args = list(payload)
120
+ else:
121
+ args = [payload]
122
+ return event, args
123
+
124
+ return self._event_key(event), [event]
125
+
126
+ async def _call_listener(self, listener: Callable, args: list):
127
+ handler = self._resolve_listener(listener)
128
+ result = handler(*args)
129
+ if inspect.isawaitable(result):
130
+ result = await result
131
+ return result
132
+
133
+ def _resolve_listener(self, listener: Callable) -> Callable:
134
+ if inspect.isclass(listener):
135
+ return self._make(listener).handle
136
+ return listener
137
+
138
+ def _make(self, cls):
139
+ if self._container is not None:
140
+ return self._container.resolve(cls)
141
+ return cls()
@@ -0,0 +1,79 @@
1
+ """A recording fake dispatcher used by ``Event.fake()`` in tests.
2
+
3
+ Faked events are captured instead of dispatched to their listeners; any event
4
+ not in the fake list is forwarded to the real dispatcher. The recorded events
5
+ can then be asserted against.
6
+ """
7
+
8
+ from typing import TYPE_CHECKING, Callable
9
+
10
+ if TYPE_CHECKING:
11
+ from .dispatcher import Dispatcher
12
+
13
+
14
+ class EventFake:
15
+ def __init__(self, dispatcher: "Dispatcher", events_to_fake=None):
16
+ self._dispatcher = dispatcher
17
+ self._events_to_fake = self._normalize(events_to_fake)
18
+ self._dispatched: dict[str, list] = {}
19
+
20
+ async def dispatch(self, event, payload=None, halt: bool = False):
21
+ name, args = self._dispatcher._parse_event_payload(event, payload)
22
+
23
+ if self._should_fake(name):
24
+ recorded = args if isinstance(event, str) else event
25
+ self._dispatched.setdefault(name, []).append(recorded)
26
+ return None if halt else []
27
+
28
+ return await self._dispatcher.dispatch(event, payload, halt)
29
+
30
+ async def until(self, event, payload=None):
31
+ return await self.dispatch(event, payload, halt=True)
32
+
33
+ def listen(self, events, listener: Callable | None = None):
34
+ return self._dispatcher.listen(events, listener)
35
+
36
+ def has_listeners(self, event) -> bool:
37
+ return self._dispatcher.has_listeners(event)
38
+
39
+ def forget(self, event) -> None:
40
+ self._dispatcher.forget(event)
41
+
42
+ def flush(self) -> None:
43
+ self._dispatcher.flush()
44
+
45
+ def dispatched(self, event, callback: Callable | None = None) -> list:
46
+ """Return recorded dispatches for an event, optionally filtered."""
47
+ records = self._dispatched.get(self._dispatcher._event_key(event), [])
48
+ if callback is None:
49
+ return list(records)
50
+ return [record for record in records if callback(record)]
51
+
52
+ def assert_dispatched(self, event, callback: Callable | None = None) -> list:
53
+ records = self.dispatched(event, callback)
54
+ assert records, f"The expected event [{self._dispatcher._event_key(event)}] was not dispatched."
55
+ return records
56
+
57
+ def assert_dispatched_times(self, event, times: int = 1) -> None:
58
+ count = len(self.dispatched(event))
59
+ assert count == times, (
60
+ f"The expected event [{self._dispatcher._event_key(event)}] was dispatched {count} "
61
+ f"time(s) instead of {times} time(s)."
62
+ )
63
+
64
+ def assert_not_dispatched(self, event, callback: Callable | None = None) -> None:
65
+ count = len(self.dispatched(event, callback))
66
+ assert count == 0, f"The unexpected event [{self._dispatcher._event_key(event)}] was dispatched."
67
+
68
+ def assert_nothing_dispatched(self) -> None:
69
+ total = sum(len(records) for records in self._dispatched.values())
70
+ assert total == 0, f"{total} unexpected event(s) were dispatched."
71
+
72
+ def _normalize(self, events) -> list[str]:
73
+ if events is None:
74
+ return []
75
+ items = events if isinstance(events, (list, tuple)) else [events]
76
+ return [self._dispatcher._event_key(event) for event in items]
77
+
78
+ def _should_fake(self, name: str) -> bool:
79
+ return not self._events_to_fake or name in self._events_to_fake
@@ -0,0 +1,19 @@
1
+ """Global ``event()`` helper mirroring Laravel's event helper."""
2
+
3
+ from typing import cast
4
+
5
+ from .dispatcher import Dispatcher
6
+
7
+
8
+ def event(event, payload=None, halt: bool = False):
9
+ """Dispatch an event through the container's dispatcher.
10
+
11
+ Returns the awaitable produced by ``Dispatcher.dispatch`` — callers should
12
+ ``await`` it::
13
+
14
+ await event(OrderShipped(order))
15
+ """
16
+ from ..application import app
17
+
18
+ dispatcher = cast(Dispatcher, app().make("events"))
19
+ return dispatcher.dispatch(event, payload, halt)
@@ -0,0 +1,16 @@
1
+ """Optional base class for class-based listeners.
2
+
3
+ Listeners are not required to extend this — any callable, or any class exposing
4
+ a ``handle`` method, works. It exists to document the contract and to give
5
+ type checkers something to lean on. ``handle`` may be sync or async.
6
+ """
7
+
8
+ from abc import ABC, abstractmethod
9
+ from typing import Any
10
+
11
+
12
+ class Listener(ABC):
13
+ @abstractmethod
14
+ def handle(self, event: Any):
15
+ """Handle the given event."""
16
+ ...
@@ -0,0 +1,31 @@
1
+ """Service provider that registers the event dispatcher.
2
+
3
+ Subclass and define ``listen`` to map events to their listeners, mirroring
4
+ Laravel's ``EventServiceProvider``::
5
+
6
+ class AppEventServiceProvider(EventServiceProvider):
7
+ listen = {
8
+ UserRegistered: [SendWelcomeEmail, LogRegistration],
9
+ }
10
+ """
11
+
12
+ from typing import cast
13
+
14
+ from fastapi_startkit.support import Provider
15
+
16
+ from .dispatcher import Dispatcher
17
+
18
+
19
+ class EventServiceProvider(Provider):
20
+ provider_key = "events"
21
+
22
+ listen: dict = {}
23
+
24
+ def register(self) -> None:
25
+ self.app.bind("events", Dispatcher(self.app))
26
+
27
+ def boot(self) -> None:
28
+ dispatcher = cast(Dispatcher, self.app.make("events"))
29
+ for event, listeners in self.listen.items():
30
+ for listener in listeners:
31
+ dispatcher.listen(event, listener)
@@ -0,0 +1,5 @@
1
+ from .Facade import Facade
2
+
3
+
4
+ class Event(metaclass=Facade):
5
+ key = "events"
@@ -0,0 +1,41 @@
1
+ from typing import Any, Callable
2
+
3
+ from fastapi_startkit.events.fake import EventFake
4
+
5
+ class Event:
6
+ """Facade for the event dispatcher registered under the 'events' key."""
7
+
8
+ @staticmethod
9
+ def listen(events: Any, listener: Callable | None = None) -> Callable | None:
10
+ """Register a listener for one or more events (or use as a decorator)."""
11
+ ...
12
+
13
+ @staticmethod
14
+ async def dispatch(event: Any, payload: Any = None, halt: bool = False) -> Any:
15
+ """Fire an event and invoke its listeners; returns their responses."""
16
+ ...
17
+
18
+ @staticmethod
19
+ async def until(event: Any, payload: Any = None) -> Any:
20
+ """Dispatch an event, returning the first non-None listener response."""
21
+ ...
22
+
23
+ @staticmethod
24
+ def has_listeners(event: Any) -> bool:
25
+ """Return whether any listener is registered for the event."""
26
+ ...
27
+
28
+ @staticmethod
29
+ def forget(event: Any) -> None:
30
+ """Remove all listeners registered for the event."""
31
+ ...
32
+
33
+ @staticmethod
34
+ def flush() -> None:
35
+ """Remove every registered listener."""
36
+ ...
37
+
38
+ @staticmethod
39
+ def fake(events_to_fake: Any = None) -> EventFake:
40
+ """Swap the dispatcher for a recording fake and return it."""
41
+ ...
@@ -8,6 +8,7 @@ from .Session import Session
8
8
  from .View import View
9
9
  from .Gate import Gate
10
10
  from .Config import Config
11
+ from .Event import Event
11
12
  from .Loader import Loader
12
13
  from .Notification import Notification
13
14
  from .Dump import Dump
@@ -0,0 +1,15 @@
1
+ from .providers.fastapi_provider import FastAPIProvider
2
+ from .routers.router import Router
3
+ from .requests.model import RequestModel
4
+ from .config import FastAPIConfig
5
+ from .events import RequestHandled
6
+ from .middleware import RequestLifecycleMiddleware
7
+
8
+ __all__ = [
9
+ "FastAPIProvider",
10
+ "Router",
11
+ "RequestModel",
12
+ "FastAPIConfig",
13
+ "RequestHandled",
14
+ "RequestLifecycleMiddleware",
15
+ ]
@@ -0,0 +1,29 @@
1
+ """Structured events emitted by the FastAPI request lifecycle.
2
+
3
+ These ride on the framework's Laravel-style event dispatcher (see
4
+ ``fastapi_startkit.events``) — this module only defines the event payload,
5
+ it does not dispatch, log, or persist anything itself.
6
+ """
7
+
8
+ from dataclasses import dataclass
9
+
10
+
11
+ @dataclass
12
+ class RequestHandled:
13
+ """Dispatched once per HTTP request by ``RequestLifecycleMiddleware``.
14
+
15
+ Register a listener the normal way to observe it::
16
+
17
+ from fastapi_startkit.facades import Event
18
+ from fastapi_startkit.fastapi.events import RequestHandled
19
+
20
+ Event.listen(RequestHandled, lambda e: logger.info(
21
+ "%s %s -> %s (%.1fms) [%s]", e.method, e.path, e.status_code, e.duration_ms, e.request_id
22
+ ))
23
+ """
24
+
25
+ method: str
26
+ path: str
27
+ status_code: int
28
+ duration_ms: float
29
+ request_id: str
@@ -0,0 +1,54 @@
1
+ """ASGI middleware that emits a structured ``RequestHandled`` event per request.
2
+
3
+ This is dispatch-only: it fires the event through the framework's existing
4
+ Event dispatcher (task #940) and does not persist, log, or render anything
5
+ itself. Consumers — a logging listener, tests, future tooling — register
6
+ listeners the normal way via ``Event.listen(RequestHandled, ...)``.
7
+
8
+ Out of scope for this middleware (left as extension points for follow-up
9
+ work): DB query watchers, exception watchers, and any other Telescope-style
10
+ watcher, plus storage/UI for the emitted events.
11
+ """
12
+
13
+ import time
14
+ import uuid
15
+
16
+ from starlette.middleware.base import BaseHTTPMiddleware, RequestResponseEndpoint
17
+ from starlette.requests import Request
18
+ from starlette.responses import Response
19
+
20
+ from fastapi_startkit.events.helpers import event
21
+
22
+ from .events import RequestHandled
23
+
24
+ REQUEST_ID_HEADER = "X-Request-Id"
25
+
26
+
27
+ class RequestLifecycleMiddleware(BaseHTTPMiddleware):
28
+ """Dispatches ``RequestHandled`` (method, path, status, duration, request id)."""
29
+
30
+ async def dispatch(self, request: Request, call_next: RequestResponseEndpoint) -> Response:
31
+ request_id = request.headers.get(REQUEST_ID_HEADER) or str(uuid.uuid4())
32
+ request.state.request_id = request_id
33
+
34
+ started_at = time.perf_counter()
35
+ response = None
36
+ try:
37
+ response = await call_next(request)
38
+ return response
39
+ finally:
40
+ duration_ms = (time.perf_counter() - started_at) * 1000
41
+ status_code = response.status_code if response is not None else 500
42
+
43
+ if response is not None:
44
+ response.headers.setdefault(REQUEST_ID_HEADER, request_id)
45
+
46
+ await event(
47
+ RequestHandled(
48
+ method=request.method,
49
+ path=request.url.path,
50
+ status_code=status_code,
51
+ duration_ms=duration_ms,
52
+ request_id=request_id,
53
+ )
54
+ )