fastapi-startkit 0.66.0__tar.gz → 0.68.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 (426) hide show
  1. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/PKG-INFO +1 -1
  2. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/pyproject.toml +9 -1
  3. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/ai/runner.py +25 -23
  4. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/ai/testing.py +45 -41
  5. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/application.py +1 -2
  6. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/broadcasting/config.py +1 -1
  7. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/broadcasting/provider.py +59 -62
  8. fastapi_startkit-0.68.0/src/fastapi_startkit/broadcasting/reverb/channel_manager.py +21 -0
  9. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/broadcasting/reverb/connection.py +10 -3
  10. fastapi_startkit-0.68.0/src/fastapi_startkit/broadcasting/reverb/server.py +119 -0
  11. fastapi_startkit-0.68.0/src/fastapi_startkit/broadcasting/reverb/signature.py +43 -0
  12. fastapi_startkit-0.68.0/src/fastapi_startkit/cache/__init__.py +30 -0
  13. fastapi_startkit-0.68.0/src/fastapi_startkit/cache/array_store.py +62 -0
  14. fastapi_startkit-0.68.0/src/fastapi_startkit/cache/config/__init__.py +45 -0
  15. fastapi_startkit-0.68.0/src/fastapi_startkit/cache/database_store.py +94 -0
  16. fastapi_startkit-0.68.0/src/fastapi_startkit/cache/file_store.py +135 -0
  17. fastapi_startkit-0.68.0/src/fastapi_startkit/cache/lock.py +65 -0
  18. fastapi_startkit-0.68.0/src/fastapi_startkit/cache/manager.py +49 -0
  19. fastapi_startkit-0.68.0/src/fastapi_startkit/cache/memo_store.py +48 -0
  20. fastapi_startkit-0.68.0/src/fastapi_startkit/cache/migrations/2026_10_21_000000_create_caches_table.py +17 -0
  21. fastapi_startkit-0.68.0/src/fastapi_startkit/cache/provider.py +48 -0
  22. fastapi_startkit-0.68.0/src/fastapi_startkit/cache/redis_store.py +85 -0
  23. fastapi_startkit-0.68.0/src/fastapi_startkit/cache/repository.py +124 -0
  24. fastapi_startkit-0.68.0/src/fastapi_startkit/cache/store.py +29 -0
  25. fastapi_startkit-0.68.0/src/fastapi_startkit/cache/tagged_store.py +57 -0
  26. fastapi_startkit-0.68.0/src/fastapi_startkit/console/db_install_command.py +65 -0
  27. fastapi_startkit-0.68.0/src/fastapi_startkit/console/install_command.py +250 -0
  28. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/exceptions/__init__.py +2 -0
  29. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/exceptions/exceptions.py +16 -9
  30. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/exceptions/handler.py +13 -12
  31. fastapi_startkit-0.68.0/src/fastapi_startkit/facades/Cache.py +29 -0
  32. fastapi_startkit-0.68.0/src/fastapi_startkit/facades/Cache.pyi +25 -0
  33. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/facades/Vite.pyi +3 -0
  34. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/fastapi/config/fastapi.py +1 -0
  35. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/fastapi/exceptions.py +33 -0
  36. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/fastapi/providers/fastapi_provider.py +5 -2
  37. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/fastapi/routers/router.py +37 -37
  38. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/foundation/app_provider.py +2 -1
  39. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/inertia/inertia.py +49 -39
  40. fastapi_startkit-0.68.0/src/fastapi_startkit/installer/cli.py +19 -0
  41. fastapi_startkit-0.68.0/src/fastapi_startkit/installer/init_command.py +138 -0
  42. fastapi_startkit-0.68.0/src/fastapi_startkit/installer/plan.py +267 -0
  43. fastapi_startkit-0.68.0/src/fastapi_startkit/installer/prompts.py +268 -0
  44. fastapi_startkit-0.68.0/src/fastapi_startkit/installer/stubs/base/README.md.stub +10 -0
  45. fastapi_startkit-0.68.0/src/fastapi_startkit/installer/stubs/base/app.py.stub +5 -0
  46. fastapi_startkit-0.68.0/src/fastapi_startkit/installer/stubs/base/artisan.stub +7 -0
  47. fastapi_startkit-0.68.0/src/fastapi_startkit/installer/stubs/base/bootstrap.py.stub +11 -0
  48. fastapi_startkit-0.68.0/src/fastapi_startkit/installer/stubs/base/controller.py.stub +6 -0
  49. fastapi_startkit-0.68.0/src/fastapi_startkit/installer/stubs/base/fastapi.py.stub +5 -0
  50. fastapi_startkit-0.68.0/src/fastapi_startkit/installer/stubs/base/gitignore.stub +11 -0
  51. fastapi_startkit-0.68.0/src/fastapi_startkit/installer/stubs/base/logging.py.stub +5 -0
  52. fastapi_startkit-0.68.0/src/fastapi_startkit/installer/stubs/base/provider.py.stub +9 -0
  53. fastapi_startkit-0.68.0/src/fastapi_startkit/installer/stubs/base/routes.py.stub +7 -0
  54. fastapi_startkit-0.68.0/src/fastapi_startkit/installer/stubs/base/test_application.py.stub +14 -0
  55. fastapi_startkit-0.68.0/src/fastapi_startkit/installer/stubs/database/config.py.stub +11 -0
  56. fastapi_startkit-0.68.0/src/fastapi_startkit/installer/stubs/database/seeder.py.stub +6 -0
  57. fastapi_startkit-0.68.0/src/fastapi_startkit/installer/stubs/frontend/config.py.stub +5 -0
  58. fastapi_startkit-0.68.0/src/fastapi_startkit/installer/stubs/frontend/controller.py.stub +10 -0
  59. fastapi_startkit-0.68.0/src/fastapi_startkit/installer/stubs/frontend/index.html.stub +14 -0
  60. fastapi_startkit-0.68.0/src/fastapi_startkit/installer/stubs/queue/README.md.stub +12 -0
  61. fastapi_startkit-0.68.0/src/fastapi_startkit/installer/stubs/queue/command.py.stub +23 -0
  62. fastapi_startkit-0.68.0/src/fastapi_startkit/installer/stubs/queue/config.py.stub +10 -0
  63. fastapi_startkit-0.68.0/src/fastapi_startkit/installer/stubs/queue/provider.py.stub +47 -0
  64. fastapi_startkit-0.68.0/src/fastapi_startkit/installer/stubs/queue/task.py.stub +6 -0
  65. fastapi_startkit-0.68.0/src/fastapi_startkit/installer/stubs/queue/test_application.py.stub +12 -0
  66. fastapi_startkit-0.68.0/src/fastapi_startkit/installer/stubs/queue/worker.py.stub +3 -0
  67. fastapi_startkit-0.68.0/src/fastapi_startkit/installer/stubs/react/Home.tsx.stub +7 -0
  68. fastapi_startkit-0.68.0/src/fastapi_startkit/installer/stubs/react/app.tsx.stub +14 -0
  69. fastapi_startkit-0.68.0/src/fastapi_startkit/installer/stubs/react/package.json.stub +25 -0
  70. fastapi_startkit-0.68.0/src/fastapi_startkit/installer/stubs/react/vite.config.ts.stub +12 -0
  71. fastapi_startkit-0.68.0/src/fastapi_startkit/installer/stubs/vue/Home.vue.stub +7 -0
  72. fastapi_startkit-0.68.0/src/fastapi_startkit/installer/stubs/vue/app.ts.stub +13 -0
  73. fastapi_startkit-0.68.0/src/fastapi_startkit/installer/stubs/vue/package.json.stub +24 -0
  74. fastapi_startkit-0.68.0/src/fastapi_startkit/installer/stubs/vue/vite.config.ts.stub +12 -0
  75. fastapi_startkit-0.68.0/src/fastapi_startkit/installer/writer.py +13 -0
  76. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/commands/DBSeedCommand.py +22 -25
  77. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/commands/MakeModelCommand.py +8 -11
  78. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/commands/MakeObserverCommand.py +1 -1
  79. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/commands/MigrateFreshCommand.py +7 -9
  80. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/commands/MigrateRefreshCommand.py +7 -9
  81. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/commands/stubs/create_seed.stub +1 -4
  82. fastapi_startkit-0.68.0/src/fastapi_startkit/masoniteorm/commands/stubs/model.stub +5 -0
  83. fastapi_startkit-0.68.0/src/fastapi_startkit/masoniteorm/commands/stubs/observer.stub +27 -0
  84. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/connections/connection.py +7 -3
  85. fastapi_startkit-0.68.0/src/fastapi_startkit/masoniteorm/connections/postgres_connection.py +75 -0
  86. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/connections/sqlite_connection.py +13 -0
  87. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/exceptions.py +3 -2
  88. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/models/attribute.py +0 -2
  89. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/models/caster.py +18 -6
  90. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/models/model.py +23 -6
  91. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/models/observer.py +4 -5
  92. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/observers/ObservesEvents.py +14 -8
  93. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/providers/DatabaseProvider.py +4 -0
  94. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/query/grammars/BaseGrammar.py +1 -6
  95. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/relationships/BelongsToMany.py +16 -22
  96. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/schema/platforms/MSSQLPlatform.py +44 -6
  97. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/schema/platforms/PostgresPlatform.py +38 -29
  98. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/mcp/argument.py +4 -4
  99. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/mcp/prompt.py +6 -13
  100. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/mcp/protocol.py +12 -12
  101. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/mcp/request.py +3 -3
  102. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/mcp/resource.py +4 -4
  103. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/mcp/response.py +2 -2
  104. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/mcp/server.py +5 -7
  105. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/mcp/tool.py +7 -14
  106. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/process/process.py +24 -23
  107. fastapi_startkit-0.68.0/src/fastapi_startkit/py.typed +0 -0
  108. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/skills/stubs/.ai/fastapi-startkit/fastapi/SKILL.md +4 -4
  109. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/skills/stubs/.ai/fastapi-startkit/inertia/SKILL.md +9 -5
  110. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/storage/drivers/local.py +8 -6
  111. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/storage/drivers/s3.py +9 -7
  112. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/storage/helper.py +7 -0
  113. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/storage/storage.py +7 -0
  114. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/vite/__init__.py +2 -0
  115. fastapi_startkit-0.68.0/src/fastapi_startkit/vite/middleware.py +25 -0
  116. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/vite/providers/provider.py +7 -0
  117. fastapi_startkit-0.68.0/src/fastapi_startkit/vite/stubs/resources/css/app.css +1 -0
  118. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/vite/vite.py +99 -62
  119. fastapi_startkit-0.66.0/src/fastapi_startkit/broadcasting/reverb/channel_manager.py +0 -17
  120. fastapi_startkit-0.66.0/src/fastapi_startkit/broadcasting/reverb/server.py +0 -59
  121. fastapi_startkit-0.66.0/src/fastapi_startkit/facades/Cache.py +0 -5
  122. fastapi_startkit-0.66.0/src/fastapi_startkit/masoniteorm/commands/stubs/model.stub +0 -9
  123. fastapi_startkit-0.66.0/src/fastapi_startkit/masoniteorm/commands/stubs/observer.stub +0 -101
  124. fastapi_startkit-0.66.0/src/fastapi_startkit/masoniteorm/connections/postgres_connection.py +0 -25
  125. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/README.md +0 -0
  126. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/.DS_Store +0 -0
  127. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/__init__.py +0 -0
  128. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/ai/__init__.py +0 -0
  129. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/ai/agent.py +0 -0
  130. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/ai/ai.py +0 -0
  131. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/ai/audio.py +0 -0
  132. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/ai/audio_factory.py +0 -0
  133. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/ai/config/ai.py +0 -0
  134. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/ai/config/config.py +0 -0
  135. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/ai/decorators.py +0 -0
  136. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/ai/document.py +0 -0
  137. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/ai/image.py +0 -0
  138. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/ai/image_factory.py +0 -0
  139. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/ai/judge.py +0 -0
  140. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/ai/lab.py +0 -0
  141. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/ai/pipeline.py +0 -0
  142. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/ai/providers/__init__.py +0 -0
  143. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/ai/providers/ai_provider.py +0 -0
  144. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/ai/recording.py +0 -0
  145. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/ai/state.py +0 -0
  146. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/ai/tinker.py +0 -0
  147. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/ai/types.py +0 -0
  148. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/broadcasting/__init__.py +0 -0
  149. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/broadcasting/auth.py +0 -0
  150. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/broadcasting/channels.py +0 -0
  151. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/broadcasting/drivers/__init__.py +0 -0
  152. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/broadcasting/drivers/log_driver.py +0 -0
  153. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/broadcasting/drivers/reverb_driver.py +0 -0
  154. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/broadcasting/event.py +0 -0
  155. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/broadcasting/helpers.py +0 -0
  156. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/broadcasting/manager.py +0 -0
  157. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/broadcasting/reverb/__init__.py +0 -0
  158. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/broadcasting/stubs/__init__.py +0 -0
  159. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/broadcasting/stubs/channels.py +0 -0
  160. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/carbon/__init__.py +0 -0
  161. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/carbon/carbon.py +0 -0
  162. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/config/__init__.py +0 -0
  163. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/config/app.py +0 -0
  164. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/configuration/Configuration.py +0 -0
  165. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/configuration/__init__.py +0 -0
  166. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/configuration/config.py +0 -0
  167. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/configuration/helpers.py +0 -0
  168. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/configuration/providers/ConfigurationProvider.py +0 -0
  169. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/configuration/providers/__init__.py +0 -0
  170. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/console/__init__.py +0 -0
  171. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/console/application.py +0 -0
  172. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/console/can_override_config.py +0 -0
  173. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/console/can_override_default_options.py +0 -0
  174. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/console/command.py +0 -0
  175. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/console/publish_command.py +0 -0
  176. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/container/__init__.py +0 -0
  177. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/container/container.py +0 -0
  178. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/environment/__init__.py +0 -0
  179. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/environment/environment.py +0 -0
  180. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/events/__init__.py +0 -0
  181. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/events/dispatcher.py +0 -0
  182. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/events/fake.py +0 -0
  183. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/events/helpers.py +0 -0
  184. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/events/listener.py +0 -0
  185. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/events/provider.py +0 -0
  186. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/facades/AI.py +0 -0
  187. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/facades/AI.pyi +0 -0
  188. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/facades/Config.py +0 -0
  189. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/facades/Config.pyi +0 -0
  190. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/facades/Dump.py +0 -0
  191. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/facades/Dump.pyi +0 -0
  192. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/facades/Event.py +0 -0
  193. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/facades/Event.pyi +0 -0
  194. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/facades/Facade.py +0 -0
  195. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/facades/Gate.py +0 -0
  196. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/facades/Gate.pyi +0 -0
  197. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/facades/Hash.py +0 -0
  198. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/facades/Hash.pyi +0 -0
  199. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/facades/Loader.py +0 -0
  200. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/facades/Loader.pyi +0 -0
  201. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/facades/Mail.py +0 -0
  202. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/facades/Mail.pyi +0 -0
  203. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/facades/Notification.py +0 -0
  204. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/facades/Notification.pyi +0 -0
  205. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/facades/Queue.py +0 -0
  206. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/facades/Queue.pyi +0 -0
  207. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/facades/RateLimiter.py +0 -0
  208. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/facades/RateLimiter.pyi +0 -0
  209. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/facades/Redis.py +0 -0
  210. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/facades/Redis.pyi +0 -0
  211. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/facades/Request.py +0 -0
  212. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/facades/Request.pyi +0 -0
  213. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/facades/Response.py +0 -0
  214. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/facades/Response.pyi +0 -0
  215. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/facades/Session.py +0 -0
  216. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/facades/Session.pyi +0 -0
  217. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/facades/Url.py +0 -0
  218. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/facades/Url.pyi +0 -0
  219. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/facades/View.py +0 -0
  220. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/facades/View.pyi +0 -0
  221. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/facades/Vite.py +0 -0
  222. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/facades/__init__.py +0 -0
  223. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/fastapi/__init__.py +0 -0
  224. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/fastapi/commands/__init__.py +0 -0
  225. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/fastapi/commands/serve_command.py +0 -0
  226. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/fastapi/config/__init__.py +0 -0
  227. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/fastapi/events.py +0 -0
  228. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/fastapi/middleware.py +0 -0
  229. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/fastapi/referer.py +0 -0
  230. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/fastapi/requests/model.py +0 -0
  231. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/fastapi/testing/__init__.py +0 -0
  232. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/fastapi/testing/assertable_json.py +0 -0
  233. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/fastapi/testing/test_case.py +0 -0
  234. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/fastapi/testing/test_response.py +0 -0
  235. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/inertia/__init__.py +0 -0
  236. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/inertia/constant.py +0 -0
  237. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/inertia/context.py +0 -0
  238. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/inertia/encoding.py +0 -0
  239. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/inertia/errors.py +0 -0
  240. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/inertia/middleware.py +0 -0
  241. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/inertia/props/props.py +0 -0
  242. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/inertia/props/resolver.py +0 -0
  243. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/inertia/props/scroll.py +0 -0
  244. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/inertia/provider.py +0 -0
  245. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/inertia/redirect.py +0 -0
  246. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/inertia/session.py +0 -0
  247. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/inertia/ssr.py +0 -0
  248. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/inertia/testing.py +0 -0
  249. {fastapi_startkit-0.66.0/src/fastapi_startkit/masoniteorm/config → fastapi_startkit-0.68.0/src/fastapi_startkit/installer}/__init__.py +0 -0
  250. /fastapi_startkit-0.66.0/src/fastapi_startkit/vite/stubs/resources/css/app.css → /fastapi_startkit-0.68.0/src/fastapi_startkit/installer/stubs/frontend/app.css.stub +0 -0
  251. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/jsonapi/__init__.py +0 -0
  252. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/jsonapi/response.py +0 -0
  253. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/loader/Loader.py +0 -0
  254. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/loader/__init__.py +0 -0
  255. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/logging/ChannelFactory.py +0 -0
  256. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/logging/__init__.py +0 -0
  257. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/logging/channels/BaseChannel.py +0 -0
  258. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/logging/channels/DailyChannel.py +0 -0
  259. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/logging/channels/MultiBaseChannel.py +0 -0
  260. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/logging/channels/SingleChannel.py +0 -0
  261. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/logging/channels/SlackChannel.py +0 -0
  262. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/logging/channels/StackChannel.py +0 -0
  263. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/logging/channels/SyslogChannel.py +0 -0
  264. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/logging/channels/TerminalChannel.py +0 -0
  265. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/logging/channels/__init__.py +0 -0
  266. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/logging/config/__init__.py +0 -0
  267. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/logging/config/channels.py +0 -0
  268. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/logging/config/logging.py +0 -0
  269. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/logging/drivers/BaseDriver.py +0 -0
  270. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/logging/drivers/LogSingleDriver.py +0 -0
  271. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/logging/drivers/LogSlackDriver.py +0 -0
  272. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/logging/drivers/LogSyslogDriver.py +0 -0
  273. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/logging/drivers/LogTerminalDriver.py +0 -0
  274. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/logging/drivers/__init__.py +0 -0
  275. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/logging/factory.py +0 -0
  276. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/logging/file.py +0 -0
  277. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/logging/handler.py +0 -0
  278. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/logging/listeners.py +0 -0
  279. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/logging/logger.py +0 -0
  280. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/logging/managers/LoggingManager.py +0 -0
  281. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/logging/managers/__init__.py +0 -0
  282. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/logging/providers/__init__.py +0 -0
  283. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/logging/providers/log_provider.py +0 -0
  284. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/__init__.py +0 -0
  285. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/collection/Collection.py +0 -0
  286. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/collection/__init__.py +0 -0
  287. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/commands/DBMigrateCommand.py +0 -0
  288. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/commands/MakeMigrationCommand.py +0 -0
  289. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/commands/MakeSeedCommand.py +0 -0
  290. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/commands/MigrateResetCommand.py +0 -0
  291. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/commands/MigrateRollbackCommand.py +0 -0
  292. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/commands/MigrateStatusCommand.py +0 -0
  293. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/commands/ShellCommand.py +0 -0
  294. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/commands/__init__.py +0 -0
  295. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/commands/stubs/create_migration.stub +0 -0
  296. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/commands/stubs/table_migration.stub +0 -0
  297. {fastapi_startkit-0.66.0/src/fastapi_startkit/masoniteorm/helpers → fastapi_startkit-0.68.0/src/fastapi_startkit/masoniteorm/config}/__init__.py +0 -0
  298. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/config/config.py +0 -0
  299. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/config/database.py +0 -0
  300. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/connections/factory.py +0 -0
  301. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/connections/manager.py +0 -0
  302. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/connections/manages_transactions.py +0 -0
  303. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/connections/mysql_connection.py +0 -0
  304. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/connections/transactions.py +0 -0
  305. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/expressions/__init__.py +0 -0
  306. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/expressions/expressions.py +0 -0
  307. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/facades/DB.py +0 -0
  308. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/facades/Schema.py +0 -0
  309. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/facades/__init__.py +0 -0
  310. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/factory/__init__.py +0 -0
  311. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/factory/factory.py +0 -0
  312. {fastapi_startkit-0.66.0/src/fastapi_startkit/masoniteorm/query → fastapi_startkit-0.68.0/src/fastapi_startkit/masoniteorm/helpers}/__init__.py +0 -0
  313. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/helpers/misc.py +0 -0
  314. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/migrations/Migration.py +0 -0
  315. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/migrations/Migrator.py +0 -0
  316. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/migrations/__init__.py +0 -0
  317. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/models/MigrationModel.py +0 -0
  318. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/models/__init__.py +0 -0
  319. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/models/builder.py +0 -0
  320. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/models/fields.py +0 -0
  321. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/models/pivot.py +0 -0
  322. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/models/registry.py +0 -0
  323. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/models/relationship.py +0 -0
  324. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/observers/__init__.py +0 -0
  325. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/pagination/BasePaginator.py +0 -0
  326. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/pagination/LengthAwarePaginator.py +0 -0
  327. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/pagination/SimplePaginator.py +0 -0
  328. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/pagination/__init__.py +0 -0
  329. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/providers/__init__.py +0 -0
  330. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/query/EagerLoadMixin.py +0 -0
  331. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/query/EagerRelation.py +0 -0
  332. {fastapi_startkit-0.66.0/src/fastapi_startkit/mcp/providers → fastapi_startkit-0.68.0/src/fastapi_startkit/masoniteorm/query}/__init__.py +0 -0
  333. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/query/grammars/MSSQLGrammar.py +0 -0
  334. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/query/grammars/MySQLGrammar.py +0 -0
  335. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/query/grammars/PostgresGrammar.py +0 -0
  336. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/query/grammars/SQLiteGrammar.py +0 -0
  337. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/query/grammars/__init__.py +0 -0
  338. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/query/processors/MSSQLPostProcessor.py +0 -0
  339. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/query/processors/MySQLPostProcessor.py +0 -0
  340. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/query/processors/PostgresPostProcessor.py +0 -0
  341. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/query/processors/SQLitePostProcessor.py +0 -0
  342. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/query/processors/__init__.py +0 -0
  343. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/query/support.py +0 -0
  344. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/relationships/BaseRelationship.py +0 -0
  345. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/relationships/BelongsTo.py +0 -0
  346. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/relationships/HasMany.py +0 -0
  347. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/relationships/HasManyThrough.py +0 -0
  348. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/relationships/HasOne.py +0 -0
  349. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/relationships/HasOneThrough.py +0 -0
  350. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/relationships/MorphMany.py +0 -0
  351. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/relationships/MorphOne.py +0 -0
  352. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/relationships/MorphTo.py +0 -0
  353. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/relationships/MorphToMany.py +0 -0
  354. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/relationships/__init__.py +0 -0
  355. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/schema/Blueprint.py +0 -0
  356. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/schema/Column.py +0 -0
  357. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/schema/ColumnDiff.py +0 -0
  358. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/schema/Constraint.py +0 -0
  359. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/schema/ForeignKeyConstraint.py +0 -0
  360. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/schema/Index.py +0 -0
  361. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/schema/Table.py +0 -0
  362. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/schema/TableDiff.py +0 -0
  363. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/schema/__init__.py +0 -0
  364. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/schema/platforms/MySQLPlatform.py +0 -0
  365. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/schema/platforms/Platform.py +0 -0
  366. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/schema/platforms/SQLitePlatform.py +0 -0
  367. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/schema/platforms/__init__.py +0 -0
  368. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/schema/schema.py +0 -0
  369. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/seeders/Seeder.py +0 -0
  370. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/seeders/__init__.py +0 -0
  371. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/stubs/create-migration.html +0 -0
  372. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/stubs/table-migration.html +0 -0
  373. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/testing/__init__.py +0 -0
  374. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/masoniteorm/testing/transaction.py +0 -0
  375. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/mcp/__init__.py +0 -0
  376. /fastapi_startkit-0.66.0/src/fastapi_startkit/py.typed → /fastapi_startkit-0.68.0/src/fastapi_startkit/mcp/providers/__init__.py +0 -0
  377. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/mcp/providers/mcp_provider.py +0 -0
  378. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/process/__init__.py +0 -0
  379. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/process/exception.py +0 -0
  380. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/process/fake.py +0 -0
  381. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/process/result.py +0 -0
  382. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/redis/__init__.py +0 -0
  383. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/redis/config.py +0 -0
  384. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/redis/connection.py +0 -0
  385. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/redis/connector.py +0 -0
  386. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/redis/manager.py +0 -0
  387. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/redis/prefix.py +0 -0
  388. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/redis/provider.py +0 -0
  389. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/skills/__init__.py +0 -0
  390. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/skills/adapters/__init__.py +0 -0
  391. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/skills/adapters/base.py +0 -0
  392. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/skills/adapters/claude.py +0 -0
  393. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/skills/adapters/gemini.py +0 -0
  394. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/skills/commands/__init__.py +0 -0
  395. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/skills/commands/skills.py +0 -0
  396. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/skills/parser.py +0 -0
  397. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/skills/provider.py +0 -0
  398. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/skills/registry.py +0 -0
  399. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/skills/stubs/.ai/fastapi-startkit/database/SKILL.md +0 -0
  400. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/storage/__init__.py +0 -0
  401. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/storage/config/__init__.py +0 -0
  402. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/storage/config/storage.py +0 -0
  403. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/storage/data/mime.types +0 -0
  404. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/storage/drivers/__init__.py +0 -0
  405. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/storage/drivers/fake.py +0 -0
  406. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/storage/file.py +0 -0
  407. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/storage/filestream.py +0 -0
  408. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/storage/providers/provider.py +0 -0
  409. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/support/__init__.py +0 -0
  410. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/support/collection.py +0 -0
  411. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/support/config.py +0 -0
  412. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/support/dataclass.py +0 -0
  413. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/support/providers/__init__.py +0 -0
  414. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/support/providers/provider.py +0 -0
  415. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/support/string.py +0 -0
  416. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/support/structures.py +0 -0
  417. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/support/uri.py +0 -0
  418. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/testing/__init__.py +0 -0
  419. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/testing/test_case.py +0 -0
  420. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/vite/config/vite.py +0 -0
  421. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/vite/exceptions.py +0 -0
  422. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/vite/stubs/package.json +0 -0
  423. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/vite/stubs/resources/js/app.ts +0 -0
  424. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/vite/stubs/resources/templates/index.html +0 -0
  425. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/vite/stubs/tsconfig.json +0 -0
  426. {fastapi_startkit-0.66.0 → fastapi_startkit-0.68.0}/src/fastapi_startkit/vite/stubs/vite.config.ts +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: fastapi-startkit
3
- Version: 0.66.0
3
+ Version: 0.68.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
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "fastapi-startkit"
3
- version = "0.66.0"
3
+ version = "0.68.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
5
  readme = "README.md"
6
6
  keywords = [
@@ -49,6 +49,9 @@ dependencies = [
49
49
  "typing-extensions>=4.12.0",
50
50
  ]
51
51
 
52
+ [project.scripts]
53
+ fastapi-startkit = "fastapi_startkit.installer.cli:main"
54
+
52
55
  [project.urls]
53
56
  Homepage = "https://fastapi-startkit.github.io"
54
57
  Documentation = "https://fastapi-startkit.github.io"
@@ -99,6 +102,8 @@ redis = [
99
102
 
100
103
  [dependency-groups]
101
104
  dev = [
105
+ "taskiq>=0.11,<1",
106
+ "taskiq-redis>=1,<2",
102
107
  "dumpdie>=1.5.0",
103
108
  "pytest>=9.0.3",
104
109
  "pytest-asyncio>=1.3.0",
@@ -144,6 +149,9 @@ exclude = [
144
149
  ]
145
150
  typeCheckingMode = "standard"
146
151
  pythonVersion = "3.12"
152
+ deprecateTypingAliases = true
153
+ reportDeprecated = "warning"
154
+ reportMissingTypeArgument = "warning"
147
155
 
148
156
  [tool.pytest.ini_options]
149
157
  asyncio_mode = "auto"
@@ -24,7 +24,7 @@ def _as_text(content: Any) -> str:
24
24
  return content if isinstance(content, str) else str(content)
25
25
 
26
26
 
27
- def _stream_event(event: str, name: str, run_id: str, data: dict) -> dict:
27
+ def _stream_event(event: str, name: str, run_id: str, data: dict[str, Any]) -> dict[str, Any]:
28
28
  """A StandardStreamEvent dict, the shape LangChain's astream_events yields."""
29
29
  return {"event": event, "name": name, "run_id": run_id, "tags": [], "metadata": {}, "parent_ids": [], "data": data}
30
30
 
@@ -35,17 +35,17 @@ class BaseRunner(ABC):
35
35
  self._reset_capture()
36
36
  # Populated by stream() so the record-and-replay harness can persist the
37
37
  # same structured turn a buffered prompt() produces.
38
- self.last_response: dict | None = None
38
+ self.last_response: dict[str, Any] | None = None
39
39
 
40
40
  def _reset_capture(self) -> None:
41
41
  """Clear the per-turn interaction captured across the model/tool calls."""
42
- self._transcript: list[dict] = []
43
- self._tool_events: list[dict] = []
44
- self._requested_tool_calls: list[dict] = []
45
- self._usage: dict = {}
42
+ self._transcript: list[dict[str, Any]] = []
43
+ self._tool_events: list[dict[str, Any]] = []
44
+ self._requested_tool_calls: list[ToolCall] = []
45
+ self._usage: dict[str, int] = {}
46
46
 
47
47
  @staticmethod
48
- def _usage_from_message(message: Any) -> dict:
48
+ def _usage_from_message(message: Any) -> dict[str, int]:
49
49
  meta = getattr(message, "usage_metadata", None)
50
50
  if not meta:
51
51
  return {}
@@ -120,9 +120,9 @@ class BaseRunner(ABC):
120
120
  )
121
121
  return messages
122
122
 
123
- async def _build_messages(self, message: str, attachments: list[Document] | None = None) -> list[dict]:
123
+ async def _build_messages(self, message: str, attachments: list[Document] | None = None) -> list[dict[str, Any]]:
124
124
  agent = self.agent
125
- messages: list[dict] = []
125
+ messages: list[dict[str, Any]] = []
126
126
 
127
127
  instruction = agent.instructions()
128
128
  if instruction:
@@ -146,12 +146,12 @@ class BaseRunner(ABC):
146
146
 
147
147
  return messages
148
148
 
149
- def _build_model(self, model: str | None = None, provider_options: dict | None = None) -> Any:
149
+ def _build_model(self, model: str | None = None, provider_options: dict[str, Any] | None = None) -> Any:
150
150
  from .ai import Ai # noqa: PLC0415
151
151
 
152
152
  return Ai().get_model_for(self.agent, model, provider_options)
153
153
 
154
- def _apply_schema(self, state: dict) -> dict:
154
+ def _apply_schema(self, state: dict[str, Any]) -> dict[str, Any]:
155
155
  from . import state as agent_state # noqa: PLC0415
156
156
 
157
157
  schema = self.agent.schema()
@@ -176,8 +176,8 @@ class BaseRunner(ABC):
176
176
  *,
177
177
  model: str | None = None,
178
178
  attachments: list[Document] | None = None,
179
- provider_options: dict | None = None,
180
- ) -> dict: ...
179
+ provider_options: dict[str, Any] | None = None,
180
+ ) -> dict[str, Any]: ...
181
181
 
182
182
  @abstractmethod
183
183
  def stream(
@@ -185,8 +185,8 @@ class BaseRunner(ABC):
185
185
  message: str,
186
186
  *,
187
187
  model: str | None = None,
188
- provider_options: dict | None = None,
189
- ) -> AsyncIterator[dict]: ...
188
+ provider_options: dict[str, Any] | None = None,
189
+ ) -> AsyncIterator[dict[str, Any]]: ...
190
190
 
191
191
 
192
192
  class Runner(BaseRunner):
@@ -196,19 +196,19 @@ class Runner(BaseRunner):
196
196
  *,
197
197
  model: str | None = None,
198
198
  attachments: list[Document] | None = None,
199
- provider_options: dict | None = None,
200
- ) -> dict:
199
+ provider_options: dict[str, Any] | None = None,
200
+ ) -> dict[str, Any]:
201
201
  self._reset_capture()
202
202
  messages = await self._build_messages(message, attachments)
203
203
  model = self._build_model(model, provider_options)
204
204
 
205
205
  parsed = await self._run_pipeline(model, messages)
206
- state: dict = {"messages": self._turn_messages(message)}
206
+ state: dict[str, Any] = {"messages": self._turn_messages(message)}
207
207
  if parsed is not None:
208
208
  state["structured_response"] = parsed
209
209
  return self._apply_schema(state)
210
210
 
211
- async def _run_pipeline(self, chat_model: Any, messages: list) -> Any:
211
+ async def _run_pipeline(self, chat_model: Any, messages: list[dict[str, Any]]) -> Any:
212
212
  """Run the turn through the middleware pipeline; the interaction lands on
213
213
  the capture buffers. Returns the parsed structured output, if any."""
214
214
  chain = list(self.agent.middleware())
@@ -238,8 +238,8 @@ class Runner(BaseRunner):
238
238
  message: str,
239
239
  *,
240
240
  model: str | None = None,
241
- provider_options: dict | None = None,
242
- ) -> AsyncIterator[dict]:
241
+ provider_options: dict[str, Any] | None = None,
242
+ ) -> AsyncIterator[dict[str, Any]]:
243
243
  self._reset_capture()
244
244
  messages = await self._build_messages(message)
245
245
  chat_model = self._build_model(model, provider_options)
@@ -257,7 +257,7 @@ class Runner(BaseRunner):
257
257
  # record-and-replay harness can persist streamed runs identically.
258
258
  self.last_response = {"messages": self._turn_messages(message)}
259
259
 
260
- async def _invoke(self, model: Runnable[Any, BaseMessage], messages: list) -> BaseMessage:
260
+ async def _invoke(self, model: Runnable[Any, BaseMessage], messages: list[dict[str, Any]]) -> BaseMessage:
261
261
  started = time.perf_counter()
262
262
  response: AIMessage = await model.ainvoke(list(messages)) # type: ignore[assignment]
263
263
  latency_ms = (time.perf_counter() - started) * 1000
@@ -273,7 +273,9 @@ class Runner(BaseRunner):
273
273
  return response
274
274
  return (await self._run_tools(response.tool_calls))[-1]
275
275
 
276
- async def _invoke_stream(self, model: Runnable[Any, BaseMessage], messages: list) -> AsyncIterator[dict]:
276
+ async def _invoke_stream(
277
+ self, model: Runnable[Any, BaseMessage], messages: list[dict[str, Any]]
278
+ ) -> AsyncIterator[dict[str, Any]]:
277
279
  """Yield the same StandardStreamEvent dicts LangChain's astream_events
278
280
  produces: on_chat_model_(start|stream|end) for the model turn, then
279
281
  on_tool_(start|end) around each tool execution."""
@@ -7,14 +7,16 @@ import json
7
7
  import operator
8
8
  import sys
9
9
  import time
10
- from collections.abc import AsyncIterator
10
+ from collections.abc import AsyncIterator, Callable
11
11
  from pathlib import Path
12
- from typing import TYPE_CHECKING, Any, Callable
12
+ from typing import TYPE_CHECKING, Any
13
13
 
14
14
  from . import recording
15
15
  from . import state as agent_state
16
16
 
17
17
  if TYPE_CHECKING:
18
+ from langchain_core.messages import ToolCall
19
+
18
20
  from .agent import Agent
19
21
  from .document import Document
20
22
 
@@ -36,7 +38,7 @@ def _frame_text(frame: Any) -> str:
36
38
  return str(frame)
37
39
 
38
40
 
39
- def _chunk_event(text: str) -> dict:
41
+ def _chunk_event(text: str) -> dict[str, Any]:
40
42
  """A replayed on_chat_model_stream event, shaped like astream_events yields."""
41
43
  from langchain_core.messages import AIMessageChunk # noqa: PLC0415
42
44
 
@@ -51,11 +53,11 @@ def _chunk_event(text: str) -> dict:
51
53
  }
52
54
 
53
55
 
54
- def _new_token_totals() -> dict:
56
+ def _new_token_totals() -> dict[str, int]:
55
57
  return {"input": 0, "output": 0, "cache": 0, "total": 0}
56
58
 
57
59
 
58
- def _text_state(content: str, tool_calls: list | None = None) -> dict:
60
+ def _text_state(content: str, tool_calls: list[ToolCall] | None = None) -> dict[str, Any]:
59
61
  """A minimal one-message state for legacy/fallback shapes."""
60
62
  from langchain_core.messages import AIMessage # noqa: PLC0415
61
63
 
@@ -80,7 +82,7 @@ class TokenQuery:
80
82
  "!=": operator.ne,
81
83
  }
82
84
 
83
- def __init__(self, totals: dict) -> None:
85
+ def __init__(self, totals: dict[str, int]) -> None:
84
86
  self._totals = totals
85
87
  self._checks: list[tuple[str, str, float]] = []
86
88
 
@@ -101,19 +103,19 @@ class TokenQuery:
101
103
 
102
104
 
103
105
  class AgentFake:
104
- def __init__(self, agent_cls: type[Agent], responses: list) -> None:
106
+ def __init__(self, agent_cls: type[Agent], responses: list[Any]) -> None:
105
107
  self._agent_cls = agent_cls
106
108
  self._responses = list(responses)
107
109
  self._agent = agent_cls()
108
110
  self._agent.messages = self._history # type: ignore[method-assign]
109
- self._records: list[dict] = []
110
- self._last_response: dict | None = None
111
+ self._records: list[dict[str, Any]] = []
112
+ self._last_response: dict[str, Any] | None = None
111
113
  self.last_elapsed: float | None = None
112
- self._tokens: dict = _new_token_totals()
114
+ self._tokens: dict[str, int] = _new_token_totals()
113
115
  self._response_time: float = 0.0
114
116
  self._trajectory: list[str] = []
115
117
 
116
- def _history(self) -> list:
118
+ def _history(self) -> list[dict[str, Any]]:
117
119
  return self._records
118
120
 
119
121
  def _subject(self) -> Agent:
@@ -147,8 +149,8 @@ class AgentFake:
147
149
  *,
148
150
  model: str | None = None,
149
151
  attachments: list[Document] | None = None,
150
- provider_options: dict | None = None,
151
- ) -> dict:
152
+ provider_options: dict[str, Any] | None = None,
153
+ ) -> dict[str, Any]:
152
154
  start = time.monotonic()
153
155
  self._last_response = await self._agent.prompt(
154
156
  message, model=model, attachments=attachments, provider_options=provider_options
@@ -158,8 +160,8 @@ class AgentFake:
158
160
  return self._last_response
159
161
 
160
162
  async def stream(
161
- self, message: str, *, model: str | None = None, provider_options: dict | None = None
162
- ) -> AsyncIterator[dict]:
163
+ self, message: str, *, model: str | None = None, provider_options: dict[str, Any] | None = None
164
+ ) -> AsyncIterator[dict[str, Any]]:
163
165
  chunks: list[str] = []
164
166
  # Drive the runner directly so we can read the structured response it
165
167
  # captures while streaming (content + tool_calls), not just joined text.
@@ -172,14 +174,14 @@ class AgentFake:
172
174
  self._last_response = state
173
175
  self._remember(message, state)
174
176
 
175
- def _remember(self, message: str, state: dict) -> None:
177
+ def _remember(self, message: str, state: dict[str, Any]) -> None:
176
178
  self._accumulate_tokens(state)
177
179
  self._response_time += agent_state.runtime(state)
178
180
  self._trajectory.extend(tc.get("name", "") for tc in agent_state.tool_calls(state))
179
181
  self._records.append({"role": "user", "content": message})
180
182
  self._records.append({"role": "assistant", "content": agent_state.text(state)})
181
183
 
182
- def _accumulate_tokens(self, state: dict) -> None:
184
+ def _accumulate_tokens(self, state: dict[str, Any]) -> None:
183
185
  """Add a turn's token usage — read from each AI message's usage_metadata —
184
186
  to the running totals."""
185
187
  recording.accumulate_uses(agent_state.messages(state), self._tokens)
@@ -229,7 +231,7 @@ class AgentFake:
229
231
  self._trajectory = []
230
232
  return self
231
233
 
232
- def _require_response(self) -> dict:
234
+ def _require_response(self) -> dict[str, Any]:
233
235
  assert self._last_response is not None, "No prompt() call has been made yet."
234
236
  return self._last_response
235
237
 
@@ -361,10 +363,12 @@ class AgentFake:
361
363
  provider: str | None = None,
362
364
  *,
363
365
  fallbacks: tuple[str, ...] = (),
364
- ) -> dict:
366
+ ) -> dict[str, Any]:
365
367
  return await self._judge_live(model, expectation, content, provider)
366
368
 
367
- async def _judge_live(self, model: str | None, expectation: str, content: str, provider: str | None = None) -> dict:
369
+ async def _judge_live(
370
+ self, model: str | None, expectation: str, content: str, provider: str | None = None
371
+ ) -> dict[str, Any]:
368
372
  from .judge import JudgeAgent # noqa: PLC0415
369
373
 
370
374
  judge = JudgeAgent()
@@ -372,7 +376,7 @@ class AgentFake:
372
376
  judge.provider = provider
373
377
  return await judge.judge(expectation, content)
374
378
 
375
- def __call__(self, func: Callable) -> Callable:
379
+ def __call__(self, func: Callable[..., Any]) -> Callable[..., Any]:
376
380
  if inspect.iscoroutinefunction(func):
377
381
 
378
382
  @functools.wraps(func)
@@ -391,7 +395,7 @@ class AgentFake:
391
395
 
392
396
 
393
397
  class AssertToolCall:
394
- def __init__(self, data: dict) -> None:
398
+ def __init__(self, data: dict[str, Any]) -> None:
395
399
  self.name = data.get("name", "")
396
400
  self.args = data.get("args") or {}
397
401
  self.id = data.get("id")
@@ -402,19 +406,19 @@ class AssertToolCall:
402
406
 
403
407
 
404
408
  class AgentRecordFake(AgentFake):
405
- def __init__(self, real: Agent, cassette: str | None = None, messages: list | None = None) -> None:
409
+ def __init__(self, real: Agent, cassette: str | None = None, messages: list[Any] | None = None) -> None:
406
410
  self._real = real
407
411
  self.cassette: Path | None = Path(cassette) if cassette else None
408
- self._seed_messages: list = list(messages or [])
409
- self._records: list[dict] = []
412
+ self._seed_messages: list[Any] = list(messages or [])
413
+ self._records: list[dict[str, Any]] = []
410
414
  self._real.messages = self._history # type: ignore[method-assign]
411
- self._last_response: dict | None = None
415
+ self._last_response: dict[str, Any] | None = None
412
416
  self.last_elapsed: float | None = None
413
- self._tokens: dict = _new_token_totals()
417
+ self._tokens: dict[str, int] = _new_token_totals()
414
418
  self._response_time: float = 0.0
415
419
  self._trajectory: list[str] = []
416
420
 
417
- def _history(self) -> list:
421
+ def _history(self) -> list[Any]:
418
422
  return self._seed_messages + self._records
419
423
 
420
424
  def _subject(self) -> Agent:
@@ -438,22 +442,22 @@ class AgentRecordFake(AgentFake):
438
442
  )
439
443
  return hashlib.sha256(payload.encode()).hexdigest()
440
444
 
441
- def _load(self) -> tuple[Path, dict]:
445
+ def _load(self) -> tuple[Path, dict[str, Any]]:
442
446
  cassette = self.cassette
443
447
  assert cassette is not None, "AgentRecordFake has no cassette resolved"
444
448
  return cassette, (json.loads(cassette.read_text()) if cassette.exists() else {})
445
449
 
446
- def _save(self, cassette: Path, store: dict, key: str, value: Any) -> None:
450
+ def _save(self, cassette: Path, store: dict[str, Any], key: str, value: Any) -> None:
447
451
  store[key] = value
448
452
  cassette.parent.mkdir(parents=True, exist_ok=True)
449
453
  cassette.write_text(json.dumps(store, indent=2, sort_keys=True))
450
454
 
451
- def _turn(self, message: str, state: dict, chunks: list[str] | None = None) -> list[dict]:
455
+ def _turn(self, message: str, state: dict[str, Any], chunks: list[str] | None = None) -> list[dict[str, Any]]:
452
456
  """Build the ordered per-turn transcript persisted to the cassette:
453
457
  the human input followed by the turn's AI/tool messages. Streamed
454
458
  ``chunks`` are attached to the last model entry so replay can re-emit
455
459
  them."""
456
- entries: list[dict] = [recording.human(message)]
460
+ entries: list[dict[str, Any]] = [recording.human(message)]
457
461
  entries.extend(recording.entries_from_messages(agent_state.messages(state)))
458
462
  if chunks:
459
463
  for entry in reversed(entries):
@@ -463,14 +467,14 @@ class AgentRecordFake(AgentFake):
463
467
  return entries
464
468
 
465
469
  @staticmethod
466
- def _state_from_cache(value: Any) -> dict:
470
+ def _state_from_cache(value: Any) -> dict[str, Any]:
467
471
  if recording.is_transcript(value):
468
472
  return recording.to_state(value)
469
473
  if isinstance(value, dict) and "content" in value: # legacy flat shape
470
474
  return _text_state(_joined(value.get("content", "")), value.get("tool_calls") or [])
471
475
  return _text_state(_joined(value))
472
476
 
473
- def _remember_turn(self, message: str, state: dict) -> None:
477
+ def _remember_turn(self, message: str, state: dict[str, Any]) -> None:
474
478
  self._accumulate_tokens(state)
475
479
  self._response_time += agent_state.runtime(state)
476
480
  self._trajectory.extend(tc.get("name", "") for tc in agent_state.tool_calls(state))
@@ -486,8 +490,8 @@ class AgentRecordFake(AgentFake):
486
490
  *,
487
491
  model: str | None = None,
488
492
  attachments: list[Document] | None = None,
489
- provider_options: dict | None = None,
490
- ) -> dict:
493
+ provider_options: dict[str, Any] | None = None,
494
+ ) -> dict[str, Any]:
491
495
  cassette, store = self._load()
492
496
  key = self._key(message, attachments)
493
497
  start = time.monotonic()
@@ -505,8 +509,8 @@ class AgentRecordFake(AgentFake):
505
509
  return state
506
510
 
507
511
  async def stream(
508
- self, message: str, *, model: str | None = None, provider_options: dict | None = None
509
- ) -> AsyncIterator[dict]:
512
+ self, message: str, *, model: str | None = None, provider_options: dict[str, Any] | None = None
513
+ ) -> AsyncIterator[dict[str, Any]]:
510
514
  cassette, store = self._load()
511
515
  key = self._key(message, None)
512
516
  if key in store:
@@ -543,7 +547,7 @@ class AgentRecordFake(AgentFake):
543
547
  assert cassette is not None, "AgentRecordFake has no cassette resolved"
544
548
  return cassette.with_name(f"{cassette.stem}.judge{cassette.suffix}")
545
549
 
546
- def _load_judge(self) -> tuple[Path, dict]:
550
+ def _load_judge(self) -> tuple[Path, dict[str, Any]]:
547
551
  path = self._judge_cassette()
548
552
  return path, (json.loads(path.read_text()) if path.exists() else {})
549
553
 
@@ -555,7 +559,7 @@ class AgentRecordFake(AgentFake):
555
559
  provider: str | None = None,
556
560
  *,
557
561
  fallbacks: tuple[str, ...] = (),
558
- ) -> dict:
562
+ ) -> dict[str, Any]:
559
563
  path, store = self._load_judge()
560
564
  _, legacy = self._load() # verdicts recorded before the sidecar split lived here
561
565
  for candidate in (content, *fallbacks):
@@ -591,7 +595,7 @@ class AgentRecordFake(AgentFake):
591
595
  def __exit__(self, *_exc: Any) -> bool:
592
596
  return False
593
597
 
594
- def __call__(self, func: Callable) -> Callable:
598
+ def __call__(self, func: Callable[..., Any]) -> Callable[..., Any]:
595
599
  self._resolve_cassette(inspect.getfile(func), func.__qualname__)
596
600
 
597
601
  if inspect.iscoroutinefunction(func):
@@ -61,9 +61,8 @@ class Application(Container, Generic[TConfig]):
61
61
  self.resolve_environment()
62
62
  self.configure_config()
63
63
  self.configure_paths()
64
- self.register_providers()
65
-
66
64
  self._fastapi: Optional["FastAPI"] = None
65
+ self.register_providers()
67
66
  self.load_providers()
68
67
 
69
68
  def set_environment(self, env: str):
@@ -8,7 +8,7 @@ from fastapi_startkit.environment import env
8
8
  class ReverbConnectionConfig(Config):
9
9
  driver: str = "reverb"
10
10
  key: str = env("REVERB_APP_KEY", "local")
11
- secret: str = env("REVERB_APP_SECRET", "secret")
11
+ secret: str = env("REVERB_APP_SECRET", "")
12
12
  app_id: str = env("REVERB_APP_ID", "1")
13
13
  host: str = env("REVERB_HOST", "0.0.0.0")
14
14
  port: int = env("REVERB_PORT", 8080)
@@ -2,13 +2,19 @@ from __future__ import annotations
2
2
 
3
3
  import importlib
4
4
  import importlib.util
5
+ import json
5
6
  import sys
7
+ from collections.abc import Mapping
6
8
  from pathlib import Path
7
9
 
8
10
  from fastapi_startkit.support import Provider
9
11
  from .config import BroadcastingConfig
10
12
  from .manager import BroadcastManager
11
13
  from .reverb.server import ReverbServer
14
+ from .reverb.signature import is_presence, requires_auth, sign, valid_channel, valid_socket_id
15
+
16
+ UNSAFE_SECRETS = ("", "secret")
17
+ INSECURE_ENVIRONMENTS = ("local", "testing")
12
18
 
13
19
 
14
20
  class ReverbProvider(Provider):
@@ -36,7 +42,14 @@ class ReverbProvider(Provider):
36
42
  config_data = self.resolve_config(BroadcastingConfig)
37
43
  self.merge_config_from(config_data, "broadcasting")
38
44
 
39
- server = ReverbServer()
45
+ reverb = config_data.get("connections", {}).get("reverb", {})
46
+ secret = reverb.get("secret") or ""
47
+ if secret in UNSAFE_SECRETS and self.app.env not in INSECURE_ENVIRONMENTS:
48
+ raise RuntimeError(
49
+ f"REVERB_APP_SECRET must be set to a private value when APP_ENV is {self.app.env!r}; "
50
+ "private and presence channel signatures would otherwise be forgeable."
51
+ )
52
+ server = ReverbServer(key=reverb.get("key", "local"), secret=secret)
40
53
  manager = BroadcastManager(config_data, server)
41
54
 
42
55
  self.app.bind("broadcasting", manager)
@@ -81,91 +94,75 @@ class ReverbProvider(Provider):
81
94
  spec.loader.exec_module(module) # type: ignore[union-attr]
82
95
 
83
96
  def _mount_websocket(self) -> None:
84
- """Mount the Reverb WebSocket endpoint on the FastAPI application.
85
-
86
- The endpoint path is ``/app/{app_key}``, matching the Pusher protocol
87
- expected by Laravel Echo. The ``app_key`` is taken from the
88
- ``reverb.connections.reverb.key`` config value (default: ``"local"``).
89
- """
90
97
  try:
91
98
  fastapi_app = self.app.fastapi
92
99
  except RuntimeError:
93
- # FastAPI not installed or app not yet booted — skip
94
100
  return
95
101
 
96
- config = self.app.make("config").get("broadcasting") or {}
97
- connections = config.get("connections", {}) if isinstance(config, dict) else {}
98
- reverb_conn = connections.get("reverb", {}) if isinstance(connections, dict) else {}
99
- app_key = reverb_conn.get("key", "local") if isinstance(reverb_conn, dict) else "local"
100
-
101
102
  server: ReverbServer = self.app.make("reverb.server")
102
103
 
103
- from starlette.routing import WebSocketRoute
104
- from starlette.applications import Starlette
105
-
106
104
  async def ws_endpoint(websocket):
107
105
  await server.handle(websocket)
108
106
 
109
- ws_app = Starlette(routes=[WebSocketRoute(f"/app/{app_key}", ws_endpoint)])
110
- fastapi_app.mount("", ws_app)
107
+ fastapi_app.router.add_websocket_route(f"/app/{server.key}", ws_endpoint)
111
108
 
112
109
  def _mount_auth_endpoint(self) -> None:
113
- """Mount the ``/broadcasting/auth`` HTTP endpoint.
114
-
115
- The endpoint handles the Laravel Echo authentication handshake for
116
- private and presence channels. It:
117
-
118
- 1. Reads ``channel_name`` from the POST body (form or JSON).
119
- 2. Resolves the current user via the container's ``auth`` binding (if
120
- available), falling back to ``request.state.user``.
121
- 3. Calls :meth:`~.auth.ChannelAuthRegistry.authorize` with the channel
122
- name and the resolved user.
123
- 4. Returns **200** on success or **403** on denial.
124
- """
125
110
  try:
126
111
  fastapi_app = self.app.fastapi
127
112
  except RuntimeError:
128
113
  return
129
114
 
130
- from fastapi import Request
131
- from fastapi.responses import JSONResponse
115
+ from starlette.requests import Request
116
+ from starlette.responses import JSONResponse
132
117
 
133
118
  application = self.app
134
119
 
135
- @fastapi_app.post("/broadcasting/auth")
136
120
  async def broadcasting_auth(request: Request):
137
- # Resolve channel name from form data or JSON body
138
- content_type = request.headers.get("content-type", "")
139
- if "application/json" in content_type:
140
- body = await request.json()
141
- channel_name = body.get("channel_name", "")
121
+ if "application/json" in request.headers.get("content-type", ""):
122
+ try:
123
+ body = await request.json()
124
+ except ValueError:
125
+ return JSONResponse({"error": "Malformed JSON body"}, status_code=400)
142
126
  else:
143
- form = await request.form()
144
- channel_name = form.get("channel_name", "")
145
-
146
- if not isinstance(channel_name, str):
147
- return JSONResponse({"error": "channel_name must be a string"}, status_code=422)
127
+ body = await request.form()
128
+ if not isinstance(body, Mapping):
129
+ return JSONResponse({"error": "Request body must be an object"}, status_code=422)
130
+
131
+ channel_name = body.get("channel_name", "")
132
+ socket_id = body.get("socket_id", "")
133
+ if not valid_socket_id(socket_id):
134
+ return JSONResponse({"error": "socket_id is invalid"}, status_code=422)
135
+ if not valid_channel(channel_name):
136
+ return JSONResponse({"error": "channel_name is invalid"}, status_code=422)
137
+
138
+ server: ReverbServer = application.make("reverb.server")
139
+ user = self._resolve_user(application, request)
140
+ if not server.secret or not requires_auth(channel_name) or user is None:
141
+ return JSONResponse({"error": "Forbidden"}, status_code=403)
148
142
 
149
- # Resolve authenticated user.
150
- # Prefer request.state.user (set by auth middleware), then fall
151
- # back to the container's "auth" service.
152
- user = getattr(request.state, "user", None)
153
- if user is None:
154
- try:
155
- auth_service = application.make("auth")
156
- user_attr = getattr(auth_service, "user", None)
157
- if callable(user_attr):
158
- user = user_attr()
159
- else:
160
- user = user_attr
161
- except Exception:
162
- user = None
163
-
164
- # Authorise
165
143
  manager: BroadcastManager = application.make("broadcasting")
166
- allowed = await manager.channel_registry.authorize(channel_name, user)
144
+ if not await manager.channel_registry.authorize(channel_name, user):
145
+ return JSONResponse({"error": "Forbidden"}, status_code=403)
146
+
147
+ if not is_presence(channel_name):
148
+ return JSONResponse({"auth": sign(server.key, server.secret, socket_id, channel_name)})
167
149
 
168
- if not allowed:
150
+ user_id = getattr(user, "id", None)
151
+ if user_id is None:
169
152
  return JSONResponse({"error": "Forbidden"}, status_code=403)
153
+ channel_data = json.dumps({"user_id": str(user_id)})
154
+ auth = sign(server.key, server.secret, socket_id, channel_name, channel_data)
155
+ return JSONResponse({"auth": auth, "channel_data": channel_data})
170
156
 
171
- return JSONResponse({"auth": True, "channel_data": {}})
157
+ fastapi_app.router.add_route("/broadcasting/auth", broadcasting_auth, methods=["POST"])
158
+
159
+ @staticmethod
160
+ def _resolve_user(application, request):
161
+ user = getattr(request.state, "user", None)
162
+ if user is not None:
163
+ return user
164
+ try:
165
+ user_attr = getattr(application.make("auth"), "user", None)
166
+ except Exception:
167
+ return None
168
+ return user_attr() if callable(user_attr) else user_attr
@@ -0,0 +1,21 @@
1
+ class ChannelManager:
2
+ def __init__(self):
3
+ self._subscriptions: dict[str, set[str]] = {}
4
+
5
+ def subscribe(self, channel: str, socket_id: str) -> None:
6
+ self._subscriptions.setdefault(channel, set()).add(socket_id)
7
+
8
+ def unsubscribe(self, channel: str, socket_id: str) -> None:
9
+ subscribers = self._subscriptions.get(channel)
10
+ if subscribers is None:
11
+ return
12
+ subscribers.discard(socket_id)
13
+ if not subscribers:
14
+ del self._subscriptions[channel]
15
+
16
+ def remove_socket(self, socket_id: str) -> None:
17
+ for channel in list(self._subscriptions):
18
+ self.unsubscribe(channel, socket_id)
19
+
20
+ def subscribers(self, channel: str) -> set[str]:
21
+ return set(self._subscriptions.get(channel, set()))