mountaineer 0.20.0.dev1__tar.gz → 0.20.0.dev2__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 (216) hide show
  1. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/Cargo.lock +1 -1
  2. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/Cargo.toml +1 -1
  3. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/PKG-INFO +1 -1
  4. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/crates/lib/vite/assets/entrypoints.mjs +5 -5
  5. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/crates/lib/vite/assets/vite.config.mjs +15 -12
  6. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/crates/lib/vite/src/lib.rs +10 -17
  7. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/pyproject.toml +1 -1
  8. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/src/cli/development/mod.rs +6 -6
  9. mountaineer-0.20.0.dev2/src/cli/development/proxy.rs +148 -0
  10. mountaineer-0.20.0.dev1/src/cli/development/proxy.rs +0 -69
  11. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/.determystic/tests/fixtures_at_top.determystic +0 -0
  12. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/.determystic/tests/future_annotations.determystic +0 -0
  13. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/.determystic/tests/inline-simple-helpers.determystic +0 -0
  14. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/.determystic/validations/fixtures_at_top.determystic +0 -0
  15. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/.determystic/validations/future_annotations.determystic +0 -0
  16. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/.determystic/validations/inline-simple-helpers.determystic +0 -0
  17. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/.git-blame-ignore-revs +0 -0
  18. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/.gitattributes +0 -0
  19. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/.github/actions/setup-python-rust/action.yml +0 -0
  20. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/.github/pyproject.toml +0 -0
  21. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/.github/scripts/__init__.py +0 -0
  22. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/.github/scripts/update_version.py +0 -0
  23. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/.github/uv.lock +0 -0
  24. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/.github/workflows/test.yml +0 -0
  25. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/.gitignore +0 -0
  26. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/AGENTS.md +0 -0
  27. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/Dockerfile +0 -0
  28. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/LICENSE +0 -0
  29. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/Makefile +0 -0
  30. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/README.md +0 -0
  31. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/benchmarking/README.md +0 -0
  32. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/benchmarking/benchmarking/__init__.py +0 -0
  33. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/benchmarking/benchmarking/simple_render.py +0 -0
  34. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/benchmarking/pyproject.toml +0 -0
  35. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/benchmarking/uv.lock +0 -0
  36. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/crates/lib/file-monitor/Cargo.toml +0 -0
  37. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/crates/lib/file-monitor/src/lib.rs +0 -0
  38. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/crates/lib/hot-reload-discover/Cargo.toml +0 -0
  39. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/crates/lib/hot-reload-discover/assets/discover_imports.py +0 -0
  40. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/crates/lib/hot-reload-discover/src/lib.rs +0 -0
  41. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/crates/lib/hot-reload-fork/Cargo.toml +0 -0
  42. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/crates/lib/hot-reload-fork/assets/fork_parent.py +0 -0
  43. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/crates/lib/hot-reload-fork/assets/import_safety_probe.py +0 -0
  44. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/crates/lib/hot-reload-fork/src/lib.rs +0 -0
  45. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/crates/lib/hot-reload-pool/Cargo.toml +0 -0
  46. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/crates/lib/hot-reload-pool/assets/warm_worker.py +0 -0
  47. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/crates/lib/hot-reload-pool/src/lib.rs +0 -0
  48. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/crates/lib/ssr/Cargo.toml +0 -0
  49. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/crates/lib/ssr/src/error.rs +0 -0
  50. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/crates/lib/ssr/src/lib.rs +0 -0
  51. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/crates/lib/ssr/src/renderer.rs +0 -0
  52. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/crates/lib/ssr/src/timeout.rs +0 -0
  53. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/crates/lib/terminal/Cargo.toml +0 -0
  54. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/crates/lib/terminal/src/lib.rs +0 -0
  55. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/crates/lib/vite/Cargo.toml +0 -0
  56. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/crates/lib/vite/assets/use-client.mjs +0 -0
  57. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/create_mountaineer_app/README.md +0 -0
  58. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/create_mountaineer_app/create_mountaineer_app/__init__.py +0 -0
  59. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/create_mountaineer_app/create_mountaineer_app/builder.py +0 -0
  60. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/create_mountaineer_app/create_mountaineer_app/cli.py +0 -0
  61. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/create_mountaineer_app/create_mountaineer_app/enums.py +0 -0
  62. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/create_mountaineer_app/create_mountaineer_app/environments/__init__.py +0 -0
  63. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/create_mountaineer_app/create_mountaineer_app/environments/base.py +0 -0
  64. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/create_mountaineer_app/create_mountaineer_app/environments/uv.py +0 -0
  65. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/create_mountaineer_app/create_mountaineer_app/environments/venv.py +0 -0
  66. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/create_mountaineer_app/create_mountaineer_app/external.py +0 -0
  67. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/create_mountaineer_app/create_mountaineer_app/generation.py +0 -0
  68. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/create_mountaineer_app/create_mountaineer_app/io.py +0 -0
  69. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/create_mountaineer_app/create_mountaineer_app/templates/.zed/settings.json +0 -0
  70. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/create_mountaineer_app/create_mountaineer_app/templates/__init__.py +0 -0
  71. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/create_mountaineer_app/create_mountaineer_app/templates/editor_configs/vim/.vimrc +0 -0
  72. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/create_mountaineer_app/create_mountaineer_app/templates/editor_configs/vscode/.vscode/settings.json +0 -0
  73. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/create_mountaineer_app/create_mountaineer_app/templates/project/.dockerignore +0 -0
  74. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/create_mountaineer_app/create_mountaineer_app/templates/project/.env +0 -0
  75. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/create_mountaineer_app/create_mountaineer_app/templates/project/.gitignore +0 -0
  76. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/create_mountaineer_app/create_mountaineer_app/templates/project/AGENTS.md +0 -0
  77. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/create_mountaineer_app/create_mountaineer_app/templates/project/CLAUDE.md +0 -0
  78. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/create_mountaineer_app/create_mountaineer_app/templates/project/Dockerfile +0 -0
  79. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/create_mountaineer_app/create_mountaineer_app/templates/project/Dockerfile.local +0 -0
  80. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/create_mountaineer_app/create_mountaineer_app/templates/project/README.md +0 -0
  81. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/create_mountaineer_app/create_mountaineer_app/templates/project/[project_name]/__init__.py +0 -0
  82. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/create_mountaineer_app/create_mountaineer_app/templates/project/[project_name]/app.py +0 -0
  83. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/create_mountaineer_app/create_mountaineer_app/templates/project/[project_name]/cli.py +0 -0
  84. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/create_mountaineer_app/create_mountaineer_app/templates/project/[project_name]/config.py +0 -0
  85. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/create_mountaineer_app/create_mountaineer_app/templates/project/[project_name]/controllers/__init__.py +0 -0
  86. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/create_mountaineer_app/create_mountaineer_app/templates/project/[project_name]/controllers/detail.py +0 -0
  87. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/create_mountaineer_app/create_mountaineer_app/templates/project/[project_name]/controllers/home.py +0 -0
  88. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/create_mountaineer_app/create_mountaineer_app/templates/project/[project_name]/database_setup.py +0 -0
  89. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/create_mountaineer_app/create_mountaineer_app/templates/project/[project_name]/main.py +0 -0
  90. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/create_mountaineer_app/create_mountaineer_app/templates/project/[project_name]/models/__init__.py +0 -0
  91. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/create_mountaineer_app/create_mountaineer_app/templates/project/[project_name]/models/detail.py +0 -0
  92. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/create_mountaineer_app/create_mountaineer_app/templates/project/[project_name]/views/__init__.py +0 -0
  93. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/create_mountaineer_app/create_mountaineer_app/templates/project/[project_name]/views/app/_common/database-setup-page.tsx +0 -0
  94. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/create_mountaineer_app/create_mountaineer_app/templates/project/[project_name]/views/app/_common/field-guide.tsx +0 -0
  95. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/create_mountaineer_app/create_mountaineer_app/templates/project/[project_name]/views/app/detail/page.tsx +0 -0
  96. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/create_mountaineer_app/create_mountaineer_app/templates/project/[project_name]/views/app/home/page.tsx +0 -0
  97. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/create_mountaineer_app/create_mountaineer_app/templates/project/[project_name]/views/app/main.css +0 -0
  98. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/create_mountaineer_app/create_mountaineer_app/templates/project/[project_name]/views/package.json +0 -0
  99. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/create_mountaineer_app/create_mountaineer_app/templates/project/[project_name]/views/postcss.config.mjs +0 -0
  100. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/create_mountaineer_app/create_mountaineer_app/templates/project/[project_name]/views/tsconfig.json +0 -0
  101. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/create_mountaineer_app/create_mountaineer_app/templates/project/bootstrap.sql +0 -0
  102. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/create_mountaineer_app/create_mountaineer_app/templates/project/docker-compose.yml +0 -0
  103. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/create_mountaineer_app/create_mountaineer_app/templates/project/pyproject.toml.jinja +0 -0
  104. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/create_mountaineer_app/create_mountaineer_app/ui.py +0 -0
  105. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/create_mountaineer_app/pyproject.toml +0 -0
  106. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/create_mountaineer_app/uv.lock +0 -0
  107. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/docker-compose.test.yml +0 -0
  108. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/docs/api/actions/page.mdx +0 -0
  109. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/docs/api/api_exception/page.mdx +0 -0
  110. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/docs/api/cli/page.mdx +0 -0
  111. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/docs/api/client_builder/page.mdx +0 -0
  112. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/docs/api/config/page.mdx +0 -0
  113. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/docs/api/controllers/page.mdx +0 -0
  114. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/docs/api/core_dependencies/page.mdx +0 -0
  115. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/docs/api/development/page.mdx +0 -0
  116. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/docs/api/logging/page.mdx +0 -0
  117. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/docs/guides/actions/page.mdx +0 -0
  118. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/docs/guides/cma/page.mdx +0 -0
  119. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/docs/guides/deploy/page.mdx +0 -0
  120. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/docs/guides/errors/page.mdx +0 -0
  121. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/docs/guides/links/page.mdx +0 -0
  122. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/docs/guides/metadata/page.mdx +0 -0
  123. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/docs/guides/philosophy/page.mdx +0 -0
  124. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/docs/guides/plugins/auth/page.mdx +0 -0
  125. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/docs/guides/plugins/billing/page.mdx +0 -0
  126. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/docs/guides/plugins/cloud/page.mdx +0 -0
  127. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/docs/guides/plugins/page.mdx +0 -0
  128. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/docs/guides/postcss/page.mdx +0 -0
  129. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/docs/guides/quickstart/page.mdx +0 -0
  130. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/docs/guides/static/page.mdx +0 -0
  131. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/docs/guides/structure/page.mdx +0 -0
  132. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/docs/guides/tests/page.mdx +0 -0
  133. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/docs/guides/views/layout-organization/page.mdx +0 -0
  134. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/docs/guides/views/page.mdx +0 -0
  135. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/media/header.png +0 -0
  136. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/mountaineer/__init__.py +0 -0
  137. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/mountaineer/actions/__init__.py +0 -0
  138. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/mountaineer/actions/fields.py +0 -0
  139. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/mountaineer/actions/passthrough_dec.py +0 -0
  140. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/mountaineer/actions/sideeffect_dec.py +0 -0
  141. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/mountaineer/annotation_helpers.py +0 -0
  142. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/mountaineer/app.py +0 -0
  143. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/mountaineer/cache.py +0 -0
  144. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/mountaineer/cli.py +0 -0
  145. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/mountaineer/client_builder/aliases.py +0 -0
  146. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/mountaineer/client_builder/builder.py +0 -0
  147. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/mountaineer/client_builder/manifest.py +0 -0
  148. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/mountaineer/client_builder/parser.py +0 -0
  149. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/mountaineer/client_builder/types.py +0 -0
  150. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/mountaineer/compat.py +0 -0
  151. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/mountaineer/config.py +0 -0
  152. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/mountaineer/console.py +0 -0
  153. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/mountaineer/constants.py +0 -0
  154. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/mountaineer/controller.py +0 -0
  155. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/mountaineer/controller_layout.py +0 -0
  156. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/mountaineer/cropper.py +0 -0
  157. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/mountaineer/dependencies/__init__.py +0 -0
  158. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/mountaineer/dependencies/base.py +0 -0
  159. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/mountaineer/dependencies/core/__init__.py +0 -0
  160. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/mountaineer/dependencies/core/core.py +0 -0
  161. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/mountaineer/development/__init__.py +0 -0
  162. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/mountaineer/development/isolation.py +0 -0
  163. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/mountaineer/development/packages.py +0 -0
  164. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/mountaineer/exceptions.py +0 -0
  165. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/mountaineer/frontend.py +0 -0
  166. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/mountaineer/generics.py +0 -0
  167. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/mountaineer/graph/__init__.py +0 -0
  168. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/mountaineer/graph/app_graph.py +0 -0
  169. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/mountaineer/io.py +0 -0
  170. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/mountaineer/logging.py +0 -0
  171. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/mountaineer/paths.py +0 -0
  172. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/mountaineer/plugin.py +0 -0
  173. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/mountaineer/py.typed +0 -0
  174. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/mountaineer/render.py +0 -0
  175. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/mountaineer/runtime.py +0 -0
  176. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/mountaineer/runtime_cli.py +0 -0
  177. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/mountaineer/source_maps.py +0 -0
  178. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/mountaineer/ssr.py +0 -0
  179. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/mountaineer/static/__init__.py +0 -0
  180. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/mountaineer/static/api.ts +0 -0
  181. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/mountaineer/static/harness/jest.config.js +0 -0
  182. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/mountaineer/static/harness/package-lock.json +0 -0
  183. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/mountaineer/static/harness/package.json +0 -0
  184. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/mountaineer/static/harness/tsconfig.json +0 -0
  185. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/mountaineer/static/live_reload.ts +0 -0
  186. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/mountaineer/static/ssr_polyfills.js +0 -0
  187. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/mountaineer/test_utilities.py +0 -0
  188. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/src/benches/fixtures/complex_sourcemap_mapping.txt +0 -0
  189. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/src/benches/fixtures/home_controller_ssr_with_react.js +0 -0
  190. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/src/benches/fixtures/ssr_polyfill_archive.js +0 -0
  191. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/src/benches/lexers_benchmark.rs +0 -0
  192. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/src/benches/source_map_benchmark.rs +0 -0
  193. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/src/benches/ssr_benchmark.rs +0 -0
  194. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/src/cli/config.rs +0 -0
  195. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/src/cli/development/hot_reload.rs +0 -0
  196. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/src/cli/migration/frontend_imports.rs +0 -0
  197. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/src/cli/migration/mod.rs +0 -0
  198. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/src/cli/mod.rs +0 -0
  199. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/src/cli/output.rs +0 -0
  200. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/src/cli/production.rs +0 -0
  201. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/src/cli/watch.rs +0 -0
  202. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/src/client_builder/manifest.rs +0 -0
  203. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/src/client_builder/mod.rs +0 -0
  204. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/src/client_builder/output.rs +0 -0
  205. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/src/client_builder/typescript/actions.rs +0 -0
  206. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/src/client_builder/typescript/controllers.rs +0 -0
  207. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/src/client_builder/typescript/links.rs +0 -0
  208. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/src/client_builder/typescript/mod.rs +0 -0
  209. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/src/client_builder/typescript/schema.rs +0 -0
  210. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/src/client_builder/typescript/support.rs +0 -0
  211. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/src/client_builder/typescript/use_server.rs +0 -0
  212. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/src/lexers.rs +0 -0
  213. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/src/lib.rs +0 -0
  214. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/src/logging.rs +0 -0
  215. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/src/source_map.rs +0 -0
  216. {mountaineer-0.20.0.dev1 → mountaineer-0.20.0.dev2}/uv.lock +0 -0
@@ -724,7 +724,7 @@ dependencies = [
724
724
 
725
725
  [[package]]
726
726
  name = "mountaineer"
727
- version = "0.20.0-dev1"
727
+ version = "0.20.0-dev2"
728
728
  dependencies = [
729
729
  "clap",
730
730
  "console",
@@ -19,7 +19,7 @@ resolver = "2"
19
19
 
20
20
  [package]
21
21
  name = "mountaineer"
22
- version = "0.20.0-dev1"
22
+ version = "0.20.0-dev2"
23
23
  edition = "2021"
24
24
  readme = "README.md"
25
25
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mountaineer
3
- Version: 0.20.0.dev1
3
+ Version: 0.20.0.dev2
4
4
  Requires-Dist: pydantic>=2.5.3,<3.0.0
5
5
  Requires-Dist: fastapi>=0.114.1,<1.0.0
6
6
  Requires-Dist: inflection>=0.5.1,<1.0.0
@@ -35,18 +35,18 @@ export function mountaineerEntrypoints(entrypoints, target) {
35
35
  };
36
36
  }
37
37
 
38
- export function developmentClientSource(views, styles) {
38
+ export function developmentClientSource(views, styles, base) {
39
39
  return `
40
- import "/@vite/client";
41
- import RefreshRuntime from "/@react-refresh";
40
+ import "${base}@vite/client";
41
+ import RefreshRuntime from "${base}@react-refresh";
42
42
  RefreshRuntime.injectIntoGlobalHook(window);
43
43
  window.$RefreshReg$ = () => {};
44
44
  window.$RefreshSig$ = () => (type) => type;
45
45
  window.__vite_plugin_react_preamble_installed__ = true;
46
46
  await Promise.all(${JSON.stringify(styles)}.map((source) => import(source)));
47
- const ReactModule = await import("/@id/react");
47
+ const ReactModule = await import("${base}@id/react");
48
48
  const React = ReactModule.default ?? ReactModule;
49
- const ReactDOMModule = await import("/@id/react-dom/client");
49
+ const ReactDOMModule = await import("${base}@id/react-dom/client");
50
50
  const { hydrateRoot } = ReactDOMModule.default ?? ReactDOMModule;
51
51
  const components = await Promise.all(
52
52
  ${JSON.stringify(views)}.map((source) => import(source)),
@@ -29,6 +29,7 @@ const react = (
29
29
 
30
30
  const development =
31
31
  mountaineer.mode === "development" ? mountaineer : undefined;
32
+ const developmentBase = development?.base;
32
33
  const clientBuild =
33
34
  mountaineer.mode === "build_client" ? mountaineer : undefined;
34
35
  const ssrBuild = mountaineer.mode === "build_ssr" ? mountaineer : undefined;
@@ -49,7 +50,7 @@ const styleEntries = Object.fromEntries(
49
50
  export default defineConfig({
50
51
  root: mountaineer.frontend_root,
51
52
  appType: "custom",
52
- base: "./",
53
+ base: developmentBase ?? "./",
53
54
  clearScreen: false,
54
55
  resolve: {
55
56
  alias: [
@@ -89,7 +90,7 @@ export default defineConfig({
89
90
  name: "mountaineer:development",
90
91
  configureServer(server) {
91
92
  server.middlewares.use(
92
- "/@mountaineer/client",
93
+ `${developmentBase}@mountaineer/client`,
93
94
  (request, response) => {
94
95
  const params = new URL(
95
96
  request.url ?? "",
@@ -97,10 +98,16 @@ export default defineConfig({
97
98
  ).searchParams;
98
99
  const views = params
99
100
  .getAll("view")
100
- .map((view) => `/@fs/${view.replaceAll("\\", "/")}`);
101
+ .map(
102
+ (view) =>
103
+ `${developmentBase}@fs/${view.replaceAll("\\", "/")}`,
104
+ );
101
105
  const styles = params
102
106
  .getAll("style")
103
- .map((style) => `/@fs/${style.replaceAll("\\", "/")}`);
107
+ .map(
108
+ (style) =>
109
+ `${developmentBase}@fs/${style.replaceAll("\\", "/")}`,
110
+ );
104
111
  if (views.length === 0) {
105
112
  response.statusCode = 400;
106
113
  response.end("Missing Mountaineer view");
@@ -108,7 +115,9 @@ export default defineConfig({
108
115
  }
109
116
 
110
117
  response.setHeader("Content-Type", "text/javascript");
111
- response.end(developmentClientSource(views, styles));
118
+ response.end(
119
+ developmentClientSource(views, styles, developmentBase),
120
+ );
112
121
  },
113
122
  );
114
123
 
@@ -130,15 +139,9 @@ export default defineConfig({
130
139
  ],
131
140
  server: development
132
141
  ? {
133
- host: development.host,
142
+ host: "127.0.0.1",
134
143
  port: development.port,
135
144
  strictPort: true,
136
- cors: true,
137
- origin: `http://${development.public_host}:${development.port}`,
138
- hmr: {
139
- host: development.public_host,
140
- port: development.port,
141
- },
142
145
  watch: {
143
146
  ignored: ["**/.mountaineer/**", "**/.mountaineer-vite/**"],
144
147
  },
@@ -59,8 +59,8 @@ pub struct DevelopmentConfig {
59
59
  /// Root directory containing the application's frontend source.
60
60
  pub frontend_root: PathBuf,
61
61
 
62
- /// Host interface Vite should listen on.
63
- pub host: String,
62
+ /// Browser-visible path prefix routed to Vite by the public development server.
63
+ pub base: String,
64
64
  }
65
65
 
66
66
  /// One named Mountaineer page and its ordered layout hierarchy.
@@ -145,7 +145,7 @@ pub struct StyleBuildConfig {
145
145
  pub struct DevelopmentServer {
146
146
  child: Child,
147
147
  _directory: TempDir,
148
- origin: String,
148
+ address: SocketAddr,
149
149
  backend_signal: PathBuf,
150
150
  }
151
151
 
@@ -157,11 +157,7 @@ impl DevelopmentServer {
157
157
  let javascript_runtime = javascript_runtime().await?;
158
158
  let directory = tempfile::tempdir()?;
159
159
  let port = reserve_loopback_port()?;
160
- let public_host = match config.host.as_str() {
161
- "0.0.0.0" | "::" => "127.0.0.1",
162
- host => host,
163
- };
164
- let origin = format!("http://{public_host}:{port}");
160
+ let address = SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), port);
165
161
  let backend_signal = directory.path().join("backend-generation");
166
162
  fs::write(&backend_signal, b"1")?;
167
163
  write_config(
@@ -170,8 +166,7 @@ impl DevelopmentServer {
170
166
  frontend_root: &frontend_root,
171
167
  toolchain_package_json: toolchain_root.join("package.json"),
172
168
  mode: Mode::Development {
173
- host: &config.host,
174
- public_host,
169
+ base: &config.base,
175
170
  port,
176
171
  backend_signal: &backend_signal,
177
172
  },
@@ -189,7 +184,6 @@ impl DevelopmentServer {
189
184
  .stderr(Stdio::inherit())
190
185
  .kill_on_drop(true)
191
186
  .spawn()?;
192
- let address = SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), port);
193
187
  let ready = tokio::select! {
194
188
  result = wait_until_ready(address, Duration::from_secs(15)) => result,
195
189
  status = child.wait() => {
@@ -208,14 +202,14 @@ impl DevelopmentServer {
208
202
  Ok(Self {
209
203
  child,
210
204
  _directory: directory,
211
- origin,
205
+ address,
212
206
  backend_signal,
213
207
  })
214
208
  }
215
209
 
216
- /// Browser-visible origin of the running Vite server.
217
- pub fn origin(&self) -> &str {
218
- &self.origin
210
+ /// Loopback address of the running Vite server.
211
+ pub fn address(&self) -> SocketAddr {
212
+ self.address
219
213
  }
220
214
 
221
215
  /// Invalidates Vite's backend-dependent modules and reloads connected browsers.
@@ -381,8 +375,7 @@ struct Config<'a> {
381
375
  #[serde(tag = "mode", rename_all = "snake_case")]
382
376
  enum Mode<'a> {
383
377
  Development {
384
- host: &'a str,
385
- public_host: &'a str,
378
+ base: &'a str,
386
379
  port: u16,
387
380
  backend_signal: &'a Path,
388
381
  },
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "mountaineer"
3
- version = "0.20.0.dev1"
3
+ version = "0.20.0.dev2"
4
4
  description = "Mountaineer is a batteries-included webapp framework for Python."
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.10,<3.15"
@@ -3,7 +3,7 @@ mod proxy;
3
3
 
4
4
  use self::{
5
5
  hot_reload::{discover_imports, ActiveWorker, PythonHotReload},
6
- proxy::{reserve_loopback_port, serve_proxy, wait_until_ready},
6
+ proxy::{reserve_loopback_port, serve_proxy, wait_until_ready, VITE_PROXY_PREFIX},
7
7
  };
8
8
  use super::{
9
9
  config::{write_payload, LaunchConfig, RuntimeMode, ServerConfig},
@@ -65,7 +65,7 @@ pub(super) async fn run(args: &[String], python: String) -> Result<()> {
65
65
  let payload_dir = tempfile::tempdir()?;
66
66
  let mut vite = ViteDevServer::spawn(ViteConfig {
67
67
  frontend_root: config.frontend_root.clone(),
68
- host: config.host.clone(),
68
+ base: VITE_PROXY_PREFIX.to_string(),
69
69
  })
70
70
  .await?;
71
71
  let mut generation = 1;
@@ -77,7 +77,7 @@ pub(super) async fn run(args: &[String], python: String) -> Result<()> {
77
77
  &payload_dir,
78
78
  &mut hot_reload,
79
79
  generation,
80
- vite.origin(),
80
+ VITE_PROXY_PREFIX.trim_end_matches('/'),
81
81
  true,
82
82
  )
83
83
  .await?;
@@ -90,7 +90,7 @@ pub(super) async fn run(args: &[String], python: String) -> Result<()> {
90
90
  debounce: Duration::from_millis(debounce_ms),
91
91
  })?;
92
92
 
93
- let mut proxy_task = tokio::spawn(serve_proxy(listener, active_target.clone()));
93
+ let mut proxy_task = tokio::spawn(serve_proxy(listener, active_target.clone(), vite.address()));
94
94
  finish_startup_spinner();
95
95
  status(
96
96
  Tone::Accent,
@@ -166,7 +166,7 @@ pub(super) async fn run(args: &[String], python: String) -> Result<()> {
166
166
  &payload_dir,
167
167
  &mut hot_reload,
168
168
  generation,
169
- vite.origin(),
169
+ VITE_PROXY_PREFIX.trim_end_matches('/'),
170
170
  refresh_imports,
171
171
  ).await {
172
172
  Ok((candidate, target)) => {
@@ -219,7 +219,7 @@ pub(super) async fn run(args: &[String], python: String) -> Result<()> {
219
219
  &payload_dir,
220
220
  &mut candidate_strategy,
221
221
  generation,
222
- vite.origin(),
222
+ VITE_PROXY_PREFIX.trim_end_matches('/'),
223
223
  true,
224
224
  ).await {
225
225
  Ok((candidate, target)) => {
@@ -0,0 +1,148 @@
1
+ use crate::cli::{
2
+ invalid,
3
+ output::{status, Tone},
4
+ Result,
5
+ };
6
+ use std::{
7
+ net::{Ipv4Addr, SocketAddr},
8
+ sync::Arc,
9
+ time::Duration,
10
+ };
11
+ use tokio::{
12
+ io::{copy_bidirectional, AsyncReadExt, AsyncWriteExt},
13
+ net::{TcpListener, TcpStream},
14
+ sync::RwLock,
15
+ time::{sleep, Instant},
16
+ };
17
+
18
+ pub(super) const VITE_PROXY_PREFIX: &str = "/__mountaineer__/";
19
+
20
+ pub(super) async fn wait_until_ready(address: SocketAddr, wait: Duration) -> Result<()> {
21
+ let deadline = Instant::now() + wait;
22
+ loop {
23
+ if TcpStream::connect(address).await.is_ok() {
24
+ return Ok(());
25
+ }
26
+ if Instant::now() >= deadline {
27
+ return Err(invalid(format!(
28
+ "timed out waiting for backend at {address}"
29
+ )));
30
+ }
31
+ sleep(Duration::from_millis(50)).await;
32
+ }
33
+ }
34
+
35
+ pub(super) async fn serve_proxy(
36
+ listener: TcpListener,
37
+ active_target: Arc<RwLock<Option<SocketAddr>>>,
38
+ vite_target: SocketAddr,
39
+ ) -> Result<()> {
40
+ loop {
41
+ let (inbound, _) = listener.accept().await?;
42
+ let active_target = active_target.clone();
43
+ tokio::spawn(async move {
44
+ if let Err(error) = proxy_connection(inbound, active_target, vite_target).await {
45
+ status(
46
+ Tone::Warning,
47
+ "Warning",
48
+ format!("development proxy connection failed: {error}"),
49
+ );
50
+ }
51
+ });
52
+ }
53
+ }
54
+
55
+ async fn proxy_connection(
56
+ mut inbound: TcpStream,
57
+ active_target: Arc<RwLock<Option<SocketAddr>>>,
58
+ vite_target: SocketAddr,
59
+ ) -> std::io::Result<()> {
60
+ let mut request = Vec::with_capacity(1024);
61
+ let mut chunk = [0_u8; 1024];
62
+ while !request.windows(4).any(|window| window == b"\r\n\r\n") && request.len() < 65536 {
63
+ let read = inbound.read(&mut chunk).await?;
64
+ if read == 0 {
65
+ return Ok(());
66
+ }
67
+ request.extend_from_slice(&chunk[..read]);
68
+ }
69
+
70
+ let vite_request = is_vite_request(&request);
71
+ let target = if vite_request {
72
+ Some(vite_target)
73
+ } else {
74
+ *active_target.read().await
75
+ };
76
+ let Some(target) = target else {
77
+ inbound
78
+ .write_all(
79
+ b"HTTP/1.1 503 Service Unavailable\r\nContent-Length: 23\r\n\r\nBackend is starting up.",
80
+ )
81
+ .await?;
82
+ return Ok(());
83
+ };
84
+
85
+ let mut outbound = TcpStream::connect(target).await?;
86
+ if vite_request {
87
+ rewrite_host(&mut request, vite_target);
88
+ }
89
+ if !is_websocket_upgrade(&request) {
90
+ close_after_response(&mut request);
91
+ }
92
+ outbound.write_all(&request).await?;
93
+ copy_bidirectional(&mut inbound, &mut outbound).await?;
94
+ Ok(())
95
+ }
96
+
97
+ fn rewrite_host(request: &mut Vec<u8>, host: SocketAddr) {
98
+ let Some(host_start) = request
99
+ .windows(b"\r\nhost:".len())
100
+ .position(|window| window.eq_ignore_ascii_case(b"\r\nhost:"))
101
+ .map(|position| position + 2)
102
+ else {
103
+ return;
104
+ };
105
+ let Some(host_end) = request[host_start..]
106
+ .windows(2)
107
+ .position(|window| window == b"\r\n")
108
+ .map(|position| host_start + position)
109
+ else {
110
+ return;
111
+ };
112
+ request.splice(host_start..host_end, format!("Host: {host}").bytes());
113
+ }
114
+
115
+ fn is_websocket_upgrade(request: &[u8]) -> bool {
116
+ std::str::from_utf8(request)
117
+ .is_ok_and(|request| request.to_ascii_lowercase().contains("upgrade: websocket"))
118
+ }
119
+
120
+ fn close_after_response(request: &mut Vec<u8>) {
121
+ if let Some(headers_end) = request.windows(4).position(|window| window == b"\r\n\r\n") {
122
+ request.splice(
123
+ headers_end..headers_end,
124
+ b"\r\nConnection: close".iter().copied(),
125
+ );
126
+ }
127
+ }
128
+
129
+ fn is_vite_request(request: &[u8]) -> bool {
130
+ let Some(line_end) = request.iter().position(|byte| *byte == b'\n') else {
131
+ return false;
132
+ };
133
+ let Ok(request_line) = std::str::from_utf8(&request[..line_end]) else {
134
+ return false;
135
+ };
136
+ request_line
137
+ .split_ascii_whitespace()
138
+ .nth(1)
139
+ .is_some_and(|path| path.starts_with(VITE_PROXY_PREFIX))
140
+ }
141
+
142
+ pub(super) fn reserve_loopback_port() -> Result<u16> {
143
+ // ponytail: a short bind/drop race is acceptable; pass an open socket to
144
+ // Python if real-world collisions make this observable.
145
+ Ok(std::net::TcpListener::bind((Ipv4Addr::LOCALHOST, 0))?
146
+ .local_addr()?
147
+ .port())
148
+ }
@@ -1,69 +0,0 @@
1
- use crate::cli::{
2
- invalid,
3
- output::{status, Tone},
4
- Result,
5
- };
6
- use std::{
7
- net::{Ipv4Addr, SocketAddr},
8
- sync::Arc,
9
- time::Duration,
10
- };
11
- use tokio::{
12
- io::{copy_bidirectional, AsyncWriteExt},
13
- net::{TcpListener, TcpStream},
14
- sync::RwLock,
15
- time::{sleep, Instant},
16
- };
17
-
18
- pub(super) async fn wait_until_ready(address: SocketAddr, wait: Duration) -> Result<()> {
19
- let deadline = Instant::now() + wait;
20
- loop {
21
- if TcpStream::connect(address).await.is_ok() {
22
- return Ok(());
23
- }
24
- if Instant::now() >= deadline {
25
- return Err(invalid(format!(
26
- "timed out waiting for backend at {address}"
27
- )));
28
- }
29
- sleep(Duration::from_millis(50)).await;
30
- }
31
- }
32
-
33
- pub(super) async fn serve_proxy(
34
- listener: TcpListener,
35
- active_target: Arc<RwLock<Option<SocketAddr>>>,
36
- ) -> Result<()> {
37
- loop {
38
- let (mut inbound, _) = listener.accept().await?;
39
- let target = *active_target.read().await;
40
- tokio::spawn(async move {
41
- let Some(target) = target else {
42
- let _ = inbound
43
- .write_all(
44
- b"HTTP/1.1 503 Service Unavailable\r\nContent-Length: 23\r\n\r\nBackend is starting up.",
45
- )
46
- .await;
47
- return;
48
- };
49
- match TcpStream::connect(target).await {
50
- Ok(mut outbound) => {
51
- let _ = copy_bidirectional(&mut inbound, &mut outbound).await;
52
- }
53
- Err(error) => status(
54
- Tone::Warning,
55
- "Warning",
56
- format!("backend proxy connection failed: {error}"),
57
- ),
58
- }
59
- });
60
- }
61
- }
62
-
63
- pub(super) fn reserve_loopback_port() -> Result<u16> {
64
- // ponytail: a short bind/drop race is acceptable; pass an open socket to
65
- // Python if real-world collisions make this observable.
66
- Ok(std::net::TcpListener::bind((Ipv4Addr::LOCALHOST, 0))?
67
- .local_addr()?
68
- .port())
69
- }