vercel-runtime 0.5.6__tar.gz → 0.7.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 (162) hide show
  1. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/PKG-INFO +1 -1
  2. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/pyproject.toml +1 -1
  3. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/crons.py +50 -4
  4. vercel_runtime-0.7.0/src/vercel_runtime/dev.py +421 -0
  5. vercel_runtime-0.7.0/src/vercel_runtime/resolver.py +92 -0
  6. vercel_runtime-0.7.0/src/vercel_runtime/routing.py +177 -0
  7. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/vc_init.py +45 -182
  8. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/workers.py +41 -1
  9. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/__init__.py +0 -0
  10. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/__init__.py +0 -0
  11. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/click/LICENSE.txt +0 -0
  12. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/click/__init__.py +0 -0
  13. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/click/_compat.py +0 -0
  14. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/click/_termui_impl.py +0 -0
  15. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/click/_textwrap.py +0 -0
  16. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/click/_winconsole.py +0 -0
  17. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/click/core.py +0 -0
  18. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/click/decorators.py +0 -0
  19. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/click/exceptions.py +0 -0
  20. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/click/formatting.py +0 -0
  21. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/click/globals.py +0 -0
  22. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/click/parser.py +0 -0
  23. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/click/py.typed +0 -0
  24. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/click/shell_completion.py +0 -0
  25. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/click/termui.py +0 -0
  26. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/click/testing.py +0 -0
  27. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/click/types.py +0 -0
  28. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/click/utils.py +0 -0
  29. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/colorama/LICENSE.txt +0 -0
  30. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/colorama/__init__.py +0 -0
  31. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/colorama/ansi.py +0 -0
  32. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/colorama/ansitowin32.py +0 -0
  33. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/colorama/initialise.py +0 -0
  34. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/colorama/win32.py +0 -0
  35. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/colorama/winterm.py +0 -0
  36. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/colorama.pyi +0 -0
  37. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/h11/LICENSE.txt +0 -0
  38. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/h11/__init__.py +0 -0
  39. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/h11/_abnf.py +0 -0
  40. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/h11/_connection.py +0 -0
  41. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/h11/_events.py +0 -0
  42. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/h11/_headers.py +0 -0
  43. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/h11/_readers.py +0 -0
  44. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/h11/_receivebuffer.py +0 -0
  45. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/h11/_state.py +0 -0
  46. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/h11/_util.py +0 -0
  47. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/h11/_version.py +0 -0
  48. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/h11/_writers.py +0 -0
  49. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/h11/py.typed +0 -0
  50. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/markupsafe/LICENSE.txt +0 -0
  51. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/markupsafe/__init__.py +0 -0
  52. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/markupsafe/_native.py +0 -0
  53. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/markupsafe/_speedups.c +0 -0
  54. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/markupsafe/_speedups.pyi +0 -0
  55. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/markupsafe/py.typed +0 -0
  56. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/uvicorn/LICENSE.md +0 -0
  57. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/uvicorn/__init__.py +0 -0
  58. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/uvicorn/__main__.py +0 -0
  59. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/uvicorn/_compat.py +0 -0
  60. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/uvicorn/_subprocess.py +0 -0
  61. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/uvicorn/_types.py +0 -0
  62. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/uvicorn/config.py +0 -0
  63. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/uvicorn/importer.py +0 -0
  64. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/uvicorn/lifespan/__init__.py +0 -0
  65. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/uvicorn/lifespan/off.py +0 -0
  66. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/uvicorn/lifespan/on.py +0 -0
  67. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/uvicorn/logging.py +0 -0
  68. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/uvicorn/loops/__init__.py +0 -0
  69. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/uvicorn/loops/asyncio.py +0 -0
  70. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/uvicorn/loops/auto.py +0 -0
  71. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/uvicorn/loops/uvloop.py +0 -0
  72. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/uvicorn/main.py +0 -0
  73. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/uvicorn/middleware/__init__.py +0 -0
  74. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/uvicorn/middleware/asgi2.py +0 -0
  75. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/uvicorn/middleware/message_logger.py +0 -0
  76. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/uvicorn/middleware/proxy_headers.py +0 -0
  77. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/uvicorn/middleware/wsgi.py +0 -0
  78. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/uvicorn/protocols/__init__.py +0 -0
  79. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/uvicorn/protocols/http/__init__.py +0 -0
  80. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/uvicorn/protocols/http/auto.py +0 -0
  81. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/uvicorn/protocols/http/flow_control.py +0 -0
  82. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/uvicorn/protocols/http/h11_impl.py +0 -0
  83. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/uvicorn/protocols/http/httptools_impl.py +0 -0
  84. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/uvicorn/protocols/utils.py +0 -0
  85. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/uvicorn/protocols/websockets/__init__.py +0 -0
  86. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/uvicorn/protocols/websockets/auto.py +0 -0
  87. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/uvicorn/protocols/websockets/websockets_impl.py +0 -0
  88. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/uvicorn/protocols/websockets/websockets_sansio_impl.py +0 -0
  89. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/uvicorn/protocols/websockets/wsproto_impl.py +0 -0
  90. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/uvicorn/py.typed +0 -0
  91. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/uvicorn/server.py +0 -0
  92. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/uvicorn/supervisors/__init__.py +0 -0
  93. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/uvicorn/supervisors/basereload.py +0 -0
  94. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/uvicorn/supervisors/multiprocess.py +0 -0
  95. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/uvicorn/supervisors/statreload.py +0 -0
  96. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/uvicorn/supervisors/watchfilesreload.py +0 -0
  97. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/uvicorn/workers.py +0 -0
  98. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/vendor.txt +0 -0
  99. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/werkzeug/ICON_LICENSE.md +0 -0
  100. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/werkzeug/LICENSE.txt +0 -0
  101. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/werkzeug/__init__.py +0 -0
  102. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/werkzeug/_internal.py +0 -0
  103. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/werkzeug/_reloader.py +0 -0
  104. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/werkzeug/datastructures/__init__.py +0 -0
  105. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/werkzeug/datastructures/accept.py +0 -0
  106. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/werkzeug/datastructures/auth.py +0 -0
  107. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/werkzeug/datastructures/cache_control.py +0 -0
  108. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/werkzeug/datastructures/csp.py +0 -0
  109. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/werkzeug/datastructures/etag.py +0 -0
  110. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/werkzeug/datastructures/file_storage.py +0 -0
  111. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/werkzeug/datastructures/headers.py +0 -0
  112. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/werkzeug/datastructures/mixins.py +0 -0
  113. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/werkzeug/datastructures/range.py +0 -0
  114. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/werkzeug/datastructures/structures.py +0 -0
  115. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/werkzeug/debug/__init__.py +0 -0
  116. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/werkzeug/debug/console.py +0 -0
  117. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/werkzeug/debug/repr.py +0 -0
  118. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/werkzeug/debug/shared/ICON_LICENSE.md +0 -0
  119. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/werkzeug/debug/shared/console.png +0 -0
  120. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/werkzeug/debug/shared/debugger.js +0 -0
  121. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/werkzeug/debug/shared/less.png +0 -0
  122. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/werkzeug/debug/shared/more.png +0 -0
  123. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/werkzeug/debug/shared/style.css +0 -0
  124. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/werkzeug/debug/tbtools.py +0 -0
  125. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/werkzeug/exceptions.py +0 -0
  126. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/werkzeug/formparser.py +0 -0
  127. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/werkzeug/http.py +0 -0
  128. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/werkzeug/local.py +0 -0
  129. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/werkzeug/middleware/__init__.py +0 -0
  130. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/werkzeug/middleware/dispatcher.py +0 -0
  131. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/werkzeug/middleware/http_proxy.py +0 -0
  132. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/werkzeug/middleware/lint.py +0 -0
  133. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/werkzeug/middleware/profiler.py +0 -0
  134. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/werkzeug/middleware/proxy_fix.py +0 -0
  135. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/werkzeug/middleware/shared_data.py +0 -0
  136. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/werkzeug/py.typed +0 -0
  137. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/werkzeug/routing/__init__.py +0 -0
  138. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/werkzeug/routing/converters.py +0 -0
  139. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/werkzeug/routing/exceptions.py +0 -0
  140. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/werkzeug/routing/map.py +0 -0
  141. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/werkzeug/routing/matcher.py +0 -0
  142. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/werkzeug/routing/rules.py +0 -0
  143. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/werkzeug/sansio/__init__.py +0 -0
  144. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/werkzeug/sansio/http.py +0 -0
  145. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/werkzeug/sansio/multipart.py +0 -0
  146. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/werkzeug/sansio/request.py +0 -0
  147. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/werkzeug/sansio/response.py +0 -0
  148. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/werkzeug/sansio/utils.py +0 -0
  149. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/werkzeug/security.py +0 -0
  150. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/werkzeug/serving.py +0 -0
  151. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/werkzeug/test.py +0 -0
  152. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/werkzeug/testapp.py +0 -0
  153. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/werkzeug/urls.py +0 -0
  154. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/werkzeug/user_agent.py +0 -0
  155. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/werkzeug/utils.py +0 -0
  156. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/werkzeug/wrappers/__init__.py +0 -0
  157. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/werkzeug/wrappers/request.py +0 -0
  158. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/werkzeug/wrappers/response.py +0 -0
  159. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/_vendor/werkzeug/wsgi.py +0 -0
  160. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/asgi.py +0 -0
  161. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/headers.py +0 -0
  162. {vercel_runtime-0.5.6 → vercel_runtime-0.7.0}/src/vercel_runtime/utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: vercel-runtime
3
- Version: 0.5.6
3
+ Version: 0.7.0
4
4
  License-Expression: Apache-2.0
5
5
  License-File: src/vercel_runtime/_vendor/__init__.py
6
6
  License-File: src/vercel_runtime/_vendor/click/LICENSE.txt
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "vercel-runtime"
3
- version = "0.5.6"
3
+ version = "0.7.0"
4
4
  license = "Apache-2.0"
5
5
  license-files = [
6
6
  "src/vercel_runtime/_vendor/*/LICEN[CS]E*",
@@ -2,9 +2,10 @@ from __future__ import annotations
2
2
 
3
3
  import asyncio
4
4
  import hmac
5
+ import inspect
5
6
  import os
6
7
  import traceback
7
- from typing import TYPE_CHECKING, Any
8
+ from typing import TYPE_CHECKING, Any, cast
8
9
 
9
10
  from vercel_runtime.asgi import ASGI, drain_body, get_header, send_json_response
10
11
  from vercel_runtime.utils import (
@@ -13,7 +14,12 @@ from vercel_runtime.utils import (
13
14
  )
14
15
 
15
16
  if TYPE_CHECKING:
16
- from collections.abc import Awaitable, Callable
17
+ from collections.abc import Awaitable, Callable, Coroutine
18
+ from types import ModuleType
19
+
20
+ type SyncCronHandler = Callable[[], None]
21
+ type AsyncCronHandler = Callable[[], Coroutine[Any, Any, None]]
22
+ type CronHandler = SyncCronHandler | AsyncCronHandler
17
23
 
18
24
 
19
25
  def is_cron_service() -> bool:
@@ -21,7 +27,16 @@ def is_cron_service() -> bool:
21
27
  return svc_type.strip().lower() == "cron"
22
28
 
23
29
 
24
- def bootstrap_cron_service_app(module: object) -> ASGI:
30
+ def bootstrap_cron_service_app(module: ModuleType) -> ASGI:
31
+ # Check for a named handler function (module:function entrypoint)
32
+ handler_func = _resolve_handler_function(module)
33
+ if handler_func is not None:
34
+ return _make_cron_asgi_app(
35
+ handler_func,
36
+ is_async=inspect.iscoroutinefunction(handler_func),
37
+ )
38
+
39
+ # Fall back to __main__ guard execution
25
40
  entrypoint_abs = os.environ.get("__VC_HANDLER_ENTRYPOINT_ABS")
26
41
  if not entrypoint_abs:
27
42
  raise RuntimeError(
@@ -35,6 +50,34 @@ def bootstrap_cron_service_app(module: object) -> ASGI:
35
50
  'The entrypoint must define an `if __name__ == "__main__"` block.'
36
51
  )
37
52
 
53
+ return _make_cron_asgi_app(
54
+ lambda: run_entrypoint_as_main(entrypoint_abs),
55
+ is_async=False,
56
+ )
57
+
58
+
59
+ def _resolve_handler_function(module: ModuleType) -> CronHandler | None:
60
+ func_name = os.environ.get("__VC_HANDLER_FUNC_NAME")
61
+ if not func_name:
62
+ return None
63
+
64
+ func = getattr(module, func_name, None)
65
+ if func is None:
66
+ raise RuntimeError(
67
+ f'cron handler function "{func_name}" not found in module'
68
+ )
69
+
70
+ if not callable(func):
71
+ raise RuntimeError(f'cron handler "{func_name}" is not callable')
72
+
73
+ return cast("CronHandler", func)
74
+
75
+
76
+ def _make_cron_asgi_app(
77
+ run_job: CronHandler,
78
+ *,
79
+ is_async: bool,
80
+ ) -> ASGI:
38
81
  async def app(
39
82
  scope: dict[str, Any],
40
83
  receive: Callable[[], Awaitable[dict[str, Any]]],
@@ -75,7 +118,10 @@ def bootstrap_cron_service_app(module: object) -> ASGI:
75
118
  await drain_body(receive)
76
119
 
77
120
  try:
78
- await asyncio.to_thread(run_entrypoint_as_main, entrypoint_abs)
121
+ if is_async:
122
+ await cast("AsyncCronHandler", run_job)()
123
+ else:
124
+ await asyncio.to_thread(cast("SyncCronHandler", run_job))
79
125
  except Exception:
80
126
  traceback.print_exc()
81
127
  await send_json_response(send, 500, {"error": "internal"})
@@ -0,0 +1,421 @@
1
+ from __future__ import annotations
2
+
3
+ import logging
4
+ import logging.config
5
+ import mimetypes
6
+ import os
7
+ import sys
8
+ from typing import TYPE_CHECKING, Any, cast
9
+
10
+ from vercel_runtime._vendor import uvicorn as vendored_uvicorn
11
+ from vercel_runtime._vendor.uvicorn.config import (
12
+ LOGGING_CONFIG as UVICORN_LOGGING_CONFIG,
13
+ )
14
+ from vercel_runtime._vendor.werkzeug.serving import run_simple
15
+ from vercel_runtime.resolver import detect_app_type, import_module, resolve_app
16
+ from vercel_runtime.routing import (
17
+ apply_service_route_prefix_to_asgi_scope,
18
+ strip_service_route_prefix,
19
+ )
20
+
21
+ if TYPE_CHECKING:
22
+ from collections.abc import Awaitable, Callable
23
+ from wsgiref.types import WSGIApplication
24
+
25
+ from vercel_runtime.asgi import ASGI
26
+
27
+ _NO_COLOR = "NO_COLOR" in os.environ
28
+
29
+ _log = logging.getLogger("vercel.dev")
30
+
31
+
32
+ # Used to split DEBUG-WARNING -> stdout and ERROR-CRITICAL -> stderr
33
+ class _MaxLevelFilter(logging.Filter):
34
+ def __init__(self, max_level: int) -> None:
35
+ super().__init__()
36
+ self.max_level = max_level
37
+
38
+ def filter(self, record: logging.LogRecord) -> bool:
39
+ return record.levelno <= self.max_level
40
+
41
+
42
+ def _build_log_config(
43
+ loggers: dict[str, Any],
44
+ _filter_ref: object | None = None,
45
+ ) -> dict[str, Any]:
46
+ if _filter_ref is None:
47
+ _filter_ref = "vercel_runtime.dev._MaxLevelFilter"
48
+
49
+ return {
50
+ "version": 1,
51
+ "disable_existing_loggers": False,
52
+ "filters": {
53
+ "max_warning": {
54
+ "()": _filter_ref,
55
+ "max_level": logging.WARNING,
56
+ }
57
+ },
58
+ "handlers": {
59
+ "stdout": {
60
+ "class": "logging.StreamHandler",
61
+ "stream": "ext://sys.stdout",
62
+ "filters": ["max_warning"],
63
+ },
64
+ "stderr": {
65
+ "class": "logging.StreamHandler",
66
+ "stream": "ext://sys.stderr",
67
+ "level": "ERROR",
68
+ },
69
+ },
70
+ "loggers": loggers,
71
+ "root": {
72
+ "handlers": ["stdout", "stderr"],
73
+ "level": "INFO",
74
+ },
75
+ }
76
+
77
+
78
+ def _setup_server_log_routing(logger_name: str | None = None) -> None:
79
+ loggers: dict[str, Any] = {}
80
+
81
+ if logger_name:
82
+ loggers[logger_name] = {
83
+ "handlers": ["stdout", "stderr"],
84
+ "level": "INFO",
85
+ "propagate": False,
86
+ }
87
+
88
+ logging.config.dictConfig(
89
+ _build_log_config(
90
+ loggers=loggers,
91
+ _filter_ref=_MaxLevelFilter,
92
+ ),
93
+ )
94
+
95
+
96
+ def _build_uvicorn_log_config(
97
+ default_fmt: dict[str, Any] | None = None,
98
+ access_fmt: dict[str, Any] | None = None,
99
+ ) -> dict[str, Any]:
100
+ uvicorn_fmts: dict[str, Any] = UVICORN_LOGGING_CONFIG["formatters"]
101
+
102
+ cfg = _build_log_config(
103
+ loggers={
104
+ "uvicorn": {
105
+ "handlers": ["stdout", "stderr"],
106
+ "level": "INFO",
107
+ "propagate": False,
108
+ },
109
+ "uvicorn.error": {"level": "INFO"},
110
+ "uvicorn.access": {
111
+ "handlers": ["access"],
112
+ "level": "INFO",
113
+ "propagate": False,
114
+ },
115
+ },
116
+ )
117
+
118
+ if default_fmt is None:
119
+ default_fmt = {
120
+ **uvicorn_fmts["default"],
121
+ "use_colors": not _NO_COLOR,
122
+ }
123
+
124
+ if access_fmt is None:
125
+ access_fmt = {
126
+ **uvicorn_fmts["access"],
127
+ "use_colors": not _NO_COLOR,
128
+ }
129
+
130
+ cfg["formatters"] = {"default": default_fmt, "access": access_fmt}
131
+ cfg["handlers"]["stdout"]["formatter"] = "default"
132
+ cfg["handlers"]["stderr"]["formatter"] = "default"
133
+ cfg["handlers"]["access"] = {
134
+ "class": "logging.StreamHandler",
135
+ "stream": "ext://sys.stdout",
136
+ "formatter": "access",
137
+ }
138
+
139
+ return cfg
140
+
141
+
142
+ def _patch_fastapi_cli_log_config() -> None:
143
+ try:
144
+ import fastapi_cli.cli as _fcli_cli # type: ignore[import-not-found] # noqa: PLC0415 # pyright: ignore[reportMissingImports]
145
+ import fastapi_cli.utils.cli as _fcli # type: ignore[import-not-found] # noqa: PLC0415 # pyright: ignore[reportMissingImports]
146
+
147
+ orig_get_config = cast(
148
+ "Callable[[], dict[str, Any]]",
149
+ _fcli.get_uvicorn_log_config, # pyright: ignore[reportUnknownMemberType]
150
+ )
151
+
152
+ # we want to ensure that attr exists
153
+ # because we're going to patch it as well
154
+ _fcli_cli.get_uvicorn_log_config # noqa: B018 # pyright: ignore[reportUnknownMemberType]
155
+ except (ImportError, AttributeError):
156
+ return
157
+
158
+ def _get_routed_config() -> dict[str, Any]:
159
+ orig = orig_get_config()
160
+ return _build_uvicorn_log_config(
161
+ default_fmt={
162
+ "()": "fastapi_cli.utils.cli.CustomFormatter",
163
+ "fmt": orig["formatters"]["default"].get(
164
+ "fmt", "%(levelprefix)s %(message)s"
165
+ ),
166
+ "use_colors": orig["formatters"]["default"].get("use_colors"),
167
+ },
168
+ access_fmt={
169
+ "()": "fastapi_cli.utils.cli.CustomFormatter",
170
+ "fmt": orig["formatters"]["access"].get(
171
+ "fmt",
172
+ "%(levelprefix)s %(client_addr)s - "
173
+ "'%(request_line)s' %(status_code)s",
174
+ ),
175
+ },
176
+ )
177
+
178
+ _fcli.get_uvicorn_log_config = _get_routed_config
179
+ _fcli_cli.get_uvicorn_log_config = _get_routed_config
180
+
181
+
182
+ PUBLIC_DIR = "public"
183
+
184
+
185
+ def _build_static_asgi_app() -> ASGI | None:
186
+ static_files_cls: type[Any] | None = None
187
+ try:
188
+ from fastapi.staticfiles import ( # type: ignore[import-not-found] # noqa: PLC0415 # pyright: ignore[reportMissingImports]
189
+ StaticFiles, # pyright: ignore[reportUnknownVariableType]
190
+ )
191
+
192
+ static_files_cls = StaticFiles # pyright: ignore[reportUnknownVariableType]
193
+ except Exception:
194
+ try:
195
+ from starlette.staticfiles import ( # type: ignore[import-not-found] # noqa: PLC0415 # pyright: ignore[reportMissingImports]
196
+ StaticFiles, # pyright: ignore[reportUnknownVariableType]
197
+ )
198
+
199
+ static_files_cls = StaticFiles # pyright: ignore[reportUnknownVariableType]
200
+ except Exception:
201
+ return None
202
+
203
+ if static_files_cls is not None:
204
+ try:
205
+ try:
206
+ return cast(
207
+ "ASGI",
208
+ static_files_cls(directory=PUBLIC_DIR, check_dir=False),
209
+ )
210
+ except TypeError:
211
+ return cast("ASGI", static_files_cls(directory=PUBLIC_DIR))
212
+ except Exception:
213
+ return None
214
+
215
+ return None
216
+
217
+
218
+ def _is_safe_file(base_dir: str, target: str) -> bool:
219
+ try:
220
+ base = os.path.realpath(base_dir)
221
+ tgt = os.path.realpath(target)
222
+ return (
223
+ tgt == base or tgt.startswith(base + os.sep)
224
+ ) and os.path.isfile(tgt)
225
+ except Exception:
226
+ return False
227
+
228
+
229
+ def _static_wsgi_app(
230
+ environ: dict[str, Any],
231
+ start_response: Callable[..., Any],
232
+ ) -> list[bytes]:
233
+ if environ.get("REQUEST_METHOD", "GET") not in ("GET", "HEAD"):
234
+ return _not_found(start_response)
235
+
236
+ req_path = environ.get("PATH_INFO", "/") or "/"
237
+ safe = os.path.normpath(req_path).lstrip("/")
238
+ full = os.path.join(PUBLIC_DIR, safe)
239
+ if not _is_safe_file(PUBLIC_DIR, full):
240
+ return _not_found(start_response)
241
+
242
+ ctype, _ = mimetypes.guess_type(full)
243
+ headers = [("Content-Type", ctype or "application/octet-stream")]
244
+ try:
245
+ if environ.get("REQUEST_METHOD") == "HEAD":
246
+ start_response("200 OK", headers)
247
+ return []
248
+ with open(full, "rb") as f:
249
+ data = f.read()
250
+ headers.append(("Content-Length", str(len(data))))
251
+ start_response("200 OK", headers)
252
+ return [data]
253
+ except Exception:
254
+ return _not_found(start_response)
255
+
256
+
257
+ def _not_found(
258
+ start_response: Callable[..., Any],
259
+ ) -> list[bytes]:
260
+ start_response(
261
+ "404 Not Found",
262
+ [("Content-Type", "text/plain; charset=utf-8")],
263
+ )
264
+ return [b"Not Found"]
265
+
266
+
267
+ static_asgi = _build_static_asgi_app()
268
+ _asgi_user_app: ASGI | None = None
269
+ _wsgi_user_app: WSGIApplication | None = None
270
+
271
+
272
+ async def asgi_app(
273
+ scope: dict[str, Any],
274
+ receive: Callable[[], Awaitable[Any]],
275
+ send: Callable[[Any], Awaitable[None]],
276
+ ) -> None:
277
+ effective_scope = dict(scope)
278
+ apply_service_route_prefix_to_asgi_scope(effective_scope)
279
+
280
+ if static_asgi is not None and effective_scope.get("type") == "http":
281
+ req_path = effective_scope.get("path", "/") or "/"
282
+ safe = os.path.normpath(req_path).lstrip("/")
283
+ full = os.path.join(PUBLIC_DIR, safe)
284
+ try:
285
+ base = os.path.realpath(PUBLIC_DIR)
286
+ target = os.path.realpath(full)
287
+ if (
288
+ target == base or target.startswith(base + os.path.sep)
289
+ ) and os.path.isfile(target):
290
+ await static_asgi(effective_scope, receive, send)
291
+ return
292
+ except Exception:
293
+ pass
294
+
295
+ assert _asgi_user_app is not None
296
+ await _asgi_user_app(effective_scope, receive, send)
297
+
298
+
299
+ def wsgi_app(
300
+ environ: dict[str, Any],
301
+ start_response: Callable[..., Any],
302
+ ) -> Any:
303
+ path_info, matched_prefix = strip_service_route_prefix(
304
+ environ.get("PATH_INFO", "/") or "/"
305
+ )
306
+ environ["PATH_INFO"] = path_info
307
+ if matched_prefix:
308
+ script_name = environ.get("SCRIPT_NAME", "") or ""
309
+ if script_name and script_name != "/":
310
+ script_name = script_name.rstrip("/")
311
+ else:
312
+ script_name = ""
313
+ environ["SCRIPT_NAME"] = f"{script_name}{matched_prefix}"
314
+
315
+ # Try static first; if 404 then delegate to user app
316
+ captured_status = ""
317
+ captured_headers: tuple[tuple[str, str], ...] = ()
318
+ body_chunks: list[bytes] = []
319
+
320
+ def capture_start_response(
321
+ status: str,
322
+ headers: list[tuple[str, str]],
323
+ exc_info: Any = None,
324
+ ) -> Callable[[bytes], None]:
325
+ nonlocal captured_status, captured_headers
326
+ captured_status = status
327
+ captured_headers = tuple(headers)
328
+
329
+ def write(chunk: bytes) -> None:
330
+ body_chunks.append(chunk)
331
+
332
+ return write
333
+
334
+ result = _static_wsgi_app(environ, capture_start_response)
335
+ # If static handler produced 200, forward its response
336
+ if captured_status.startswith("200 "):
337
+ # Send headers and any chunks collected
338
+ writer = start_response(captured_status, list(captured_headers))
339
+ for chunk in body_chunks:
340
+ writer(chunk)
341
+ return result
342
+
343
+ # Otherwise, delegate to user's WSGI app
344
+ assert _wsgi_user_app is not None
345
+ return _wsgi_user_app(environ, start_response)
346
+
347
+
348
+ def _start_wsgi(host: str, port: int) -> None:
349
+ _setup_server_log_routing("werkzeug")
350
+ run_simple(host, port, wsgi_app, use_reloader=True, threaded=True)
351
+
352
+
353
+ def _start_asgi(host: str, port: int) -> None:
354
+ # Prefer user-installed fastapi-cli when available
355
+ try:
356
+ from fastapi_cli.cli import ( # noqa: PLC0415 # pyright: ignore[reportMissingImports]
357
+ dev as fastapi_dev, # pyright: ignore[reportUnknownVariableType]
358
+ )
359
+
360
+ _patch_fastapi_cli_log_config()
361
+ fastapi_dev(
362
+ entrypoint="vercel_runtime.dev:asgi_app",
363
+ host=host,
364
+ port=port,
365
+ reload=True,
366
+ )
367
+ sys.exit(0)
368
+ except (ImportError, AttributeError):
369
+ pass
370
+
371
+ vendored_uvicorn.run(
372
+ "vercel_runtime.dev:asgi_app",
373
+ host=host,
374
+ port=port,
375
+ use_colors=not _NO_COLOR,
376
+ reload=True,
377
+ log_config=_build_uvicorn_log_config(),
378
+ )
379
+
380
+
381
+ def _setup_apps() -> None:
382
+ global _asgi_user_app, _wsgi_user_app # noqa: PLW0603
383
+
384
+ module_name = os.environ["VERCEL_DEV_MODULE_NAME"]
385
+ entry_abs = os.environ["VERCEL_DEV_ENTRY_ABS"]
386
+
387
+ _setup_server_log_routing()
388
+
389
+ mod = import_module(module_name, entry_abs)
390
+ app_name, user_app = resolve_app(mod, module_name)
391
+ try:
392
+ result = detect_app_type(user_app, module_name, app_name)
393
+ except RuntimeError:
394
+ _log.exception("could not detect application type")
395
+ sys.exit(1)
396
+
397
+ if result[0] == "asgi":
398
+ _asgi_user_app = result[1]
399
+ else:
400
+ _wsgi_user_app = result[1]
401
+
402
+
403
+ # Setup apps at import time so that servers reloader can pick them up.
404
+ if os.environ.get("VERCEL_DEV_MODULE_NAME") and os.environ.get(
405
+ "VERCEL_DEV_ENTRY_ABS"
406
+ ):
407
+ _setup_apps()
408
+
409
+
410
+ def main() -> None:
411
+ host = "127.0.0.1"
412
+ raw_port = os.environ.get("PORT")
413
+ if not raw_port:
414
+ _log.error("PORT environment variable is required")
415
+ sys.exit(1)
416
+ port = int(raw_port)
417
+
418
+ if _wsgi_user_app is not None:
419
+ _start_wsgi(host, port)
420
+ else:
421
+ _start_asgi(host, port)
@@ -0,0 +1,92 @@
1
+ from __future__ import annotations
2
+
3
+ import inspect
4
+ import sys
5
+ from importlib import util as _importlib_util
6
+ from typing import TYPE_CHECKING, Any, Literal, cast
7
+
8
+ if TYPE_CHECKING:
9
+ from types import ModuleType
10
+ from wsgiref.types import WSGIApplication
11
+
12
+ from vercel_runtime.asgi import ASGI
13
+
14
+
15
+ # Import relative path
16
+ # https://docs.python.org/3/library/importlib.html#importing-a-source-file-directly
17
+ def import_module(name: str, path: str) -> ModuleType:
18
+ spec = _importlib_util.spec_from_file_location(name, path)
19
+ if spec is None or spec.loader is None:
20
+ msg = f'could not load module spec for "{name}" at {path}'
21
+ raise RuntimeError(msg)
22
+ mod = _importlib_util.module_from_spec(spec)
23
+ sys.modules[name] = mod
24
+ spec.loader.exec_module(mod)
25
+ return mod
26
+
27
+
28
+ def resolve_app(mod: ModuleType, module_name: str) -> tuple[str, Any]:
29
+ for app_var in ("app", "application"):
30
+ if hasattr(mod, app_var):
31
+ return app_var, getattr(mod, app_var)
32
+
33
+ raise RuntimeError(
34
+ f"Missing 'app' or 'application' in module '{module_name}': "
35
+ "define `app = ...` or `application = ...` in your entrypoint"
36
+ )
37
+
38
+
39
+ def _get_positional_param_count(obj: object) -> int | None:
40
+ try:
41
+ sig = inspect.signature(obj) # type: ignore[arg-type]
42
+ return sum(
43
+ 1
44
+ for p in sig.parameters.values()
45
+ if p.default is inspect.Parameter.empty
46
+ and p.kind
47
+ in (
48
+ inspect.Parameter.POSITIONAL_ONLY,
49
+ inspect.Parameter.POSITIONAL_OR_KEYWORD,
50
+ )
51
+ )
52
+ except (ValueError, TypeError):
53
+ return None
54
+
55
+
56
+ def detect_app_type(
57
+ app_obj: object,
58
+ module_name: str,
59
+ app_name: str,
60
+ ) -> tuple[Literal["asgi"], ASGI] | tuple[Literal["wsgi"], WSGIApplication]:
61
+ # Try .asgi attribute if it's available and is callable
62
+ asgi_attr = getattr(app_obj, "asgi", None)
63
+ if asgi_attr is not None and callable(asgi_attr):
64
+ return "asgi", cast("ASGI", asgi_attr)
65
+
66
+ # For async detection, check the object itself first
67
+ # (works for plain functions/methods).
68
+ # For class instances iscoroutinefunction(obj) is False,
69
+ # so fall back to __call__.
70
+ is_async = inspect.iscoroutinefunction(app_obj)
71
+ if not is_async and callable(app_obj):
72
+ is_async = inspect.iscoroutinefunction(
73
+ app_obj.__call__ # pyright: ignore[reportFunctionMemberAccess]
74
+ )
75
+
76
+ param_count = _get_positional_param_count(app_obj)
77
+
78
+ # that's ASGI (scope, receive, send)
79
+ if is_async and param_count == 3:
80
+ return "asgi", cast("ASGI", app_obj)
81
+
82
+ # that's WSGI (environ, start_response)
83
+ if param_count == 2:
84
+ return "wsgi", cast("WSGIApplication", app_obj)
85
+
86
+ raise RuntimeError(
87
+ f"Could not determine the application interface for "
88
+ f"'{module_name}:{app_name}'\n"
89
+ f"Expected either:\n"
90
+ f" - an ASGI app: async callable(scope, receive, send)\n"
91
+ f" - a WSGI app: callable(environ, start_response)"
92
+ )