wavexis 2.0.0__tar.gz → 2.0.2__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 (197) hide show
  1. {wavexis-2.0.0 → wavexis-2.0.2}/CHANGELOG.md +22 -0
  2. {wavexis-2.0.0 → wavexis-2.0.2}/PKG-INFO +1 -1
  3. {wavexis-2.0.0 → wavexis-2.0.2}/pyproject.toml +1 -1
  4. {wavexis-2.0.0 → wavexis-2.0.2}/tests/unit/test_manager.py +2 -0
  5. {wavexis-2.0.0 → wavexis-2.0.2}/tests/unit/test_serve.py +10 -10
  6. {wavexis-2.0.0 → wavexis-2.0.2}/wavexis/__init__.py +1 -1
  7. {wavexis-2.0.0 → wavexis-2.0.2}/wavexis/auth.py +46 -0
  8. {wavexis-2.0.0 → wavexis-2.0.2}/wavexis/backend/manager.py +20 -0
  9. {wavexis-2.0.0 → wavexis-2.0.2}/wavexis/cli/app.py +84 -61
  10. {wavexis-2.0.0 → wavexis-2.0.2}/wavexis/serve.py +7 -28
  11. {wavexis-2.0.0 → wavexis-2.0.2}/.dockerignore +0 -0
  12. {wavexis-2.0.0 → wavexis-2.0.2}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  13. {wavexis-2.0.0 → wavexis-2.0.2}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  14. {wavexis-2.0.0 → wavexis-2.0.2}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  15. {wavexis-2.0.0 → wavexis-2.0.2}/.github/workflows/ci.yml +0 -0
  16. {wavexis-2.0.0 → wavexis-2.0.2}/.github/workflows/docs.yml +0 -0
  17. {wavexis-2.0.0 → wavexis-2.0.2}/.github/workflows/release.yml +0 -0
  18. {wavexis-2.0.0 → wavexis-2.0.2}/.gitignore +0 -0
  19. {wavexis-2.0.0 → wavexis-2.0.2}/CODE_OF_CONDUCT.md +0 -0
  20. {wavexis-2.0.0 → wavexis-2.0.2}/CONTRIBUTING.md +0 -0
  21. {wavexis-2.0.0 → wavexis-2.0.2}/Dockerfile +0 -0
  22. {wavexis-2.0.0 → wavexis-2.0.2}/LICENSE +0 -0
  23. {wavexis-2.0.0 → wavexis-2.0.2}/README.md +0 -0
  24. {wavexis-2.0.0 → wavexis-2.0.2}/SECURITY.md +0 -0
  25. {wavexis-2.0.0 → wavexis-2.0.2}/docs/api/actions.md +0 -0
  26. {wavexis-2.0.0 → wavexis-2.0.2}/docs/api/backends.md +0 -0
  27. {wavexis-2.0.0 → wavexis-2.0.2}/docs/api/cli.md +0 -0
  28. {wavexis-2.0.0 → wavexis-2.0.2}/docs/api/config.md +0 -0
  29. {wavexis-2.0.0 → wavexis-2.0.2}/docs/api/exceptions.md +0 -0
  30. {wavexis-2.0.0 → wavexis-2.0.2}/docs/api/multi.md +0 -0
  31. {wavexis-2.0.0 → wavexis-2.0.2}/docs/api/plugins.md +0 -0
  32. {wavexis-2.0.0 → wavexis-2.0.2}/docs/api/serve.md +0 -0
  33. {wavexis-2.0.0 → wavexis-2.0.2}/docs/cookbook/auth.md +0 -0
  34. {wavexis-2.0.0 → wavexis-2.0.2}/docs/cookbook/ci-cd.md +0 -0
  35. {wavexis-2.0.0 → wavexis-2.0.2}/docs/cookbook/css.md +0 -0
  36. {wavexis-2.0.0 → wavexis-2.0.2}/docs/cookbook/debug.md +0 -0
  37. {wavexis-2.0.0 → wavexis-2.0.2}/docs/cookbook/record-replay.md +0 -0
  38. {wavexis-2.0.0 → wavexis-2.0.2}/docs/cookbook/scraping.md +0 -0
  39. {wavexis-2.0.0 → wavexis-2.0.2}/docs/cookbook/screenshots.md +0 -0
  40. {wavexis-2.0.0 → wavexis-2.0.2}/docs/cookbook/serve-mode.md +0 -0
  41. {wavexis-2.0.0 → wavexis-2.0.2}/docs/guide/assert.md +0 -0
  42. {wavexis-2.0.0 → wavexis-2.0.2}/docs/guide/backends.md +0 -0
  43. {wavexis-2.0.0 → wavexis-2.0.2}/docs/guide/commands.md +0 -0
  44. {wavexis-2.0.0 → wavexis-2.0.2}/docs/guide/init.md +0 -0
  45. {wavexis-2.0.0 → wavexis-2.0.2}/docs/guide/installation.md +0 -0
  46. {wavexis-2.0.0 → wavexis-2.0.2}/docs/guide/multi.md +0 -0
  47. {wavexis-2.0.0 → wavexis-2.0.2}/docs/guide/perf.md +0 -0
  48. {wavexis-2.0.0 → wavexis-2.0.2}/docs/guide/plugins.md +0 -0
  49. {wavexis-2.0.0 → wavexis-2.0.2}/docs/guide/quickstart.md +0 -0
  50. {wavexis-2.0.0 → wavexis-2.0.2}/docs/guide/raw.md +0 -0
  51. {wavexis-2.0.0 → wavexis-2.0.2}/docs/guide/repl.md +0 -0
  52. {wavexis-2.0.0 → wavexis-2.0.2}/docs/guide/troubleshooting.md +0 -0
  53. {wavexis-2.0.0 → wavexis-2.0.2}/docs/index.md +0 -0
  54. {wavexis-2.0.0 → wavexis-2.0.2}/mkdocs.yml +0 -0
  55. {wavexis-2.0.0 → wavexis-2.0.2}/stubs/bidiwave/__init__.pyi +0 -0
  56. {wavexis-2.0.0 → wavexis-2.0.2}/stubs/cdpwave/__init__.pyi +0 -0
  57. {wavexis-2.0.0 → wavexis-2.0.2}/tests/__init__.py +0 -0
  58. {wavexis-2.0.0 → wavexis-2.0.2}/tests/conftest.py +0 -0
  59. {wavexis-2.0.0 → wavexis-2.0.2}/tests/integration/__init__.py +0 -0
  60. {wavexis-2.0.0 → wavexis-2.0.2}/tests/integration/test_a11y.py +0 -0
  61. {wavexis-2.0.0 → wavexis-2.0.2}/tests/integration/test_animation.py +0 -0
  62. {wavexis-2.0.0 → wavexis-2.0.2}/tests/integration/test_backend_selection.py +0 -0
  63. {wavexis-2.0.0 → wavexis-2.0.2}/tests/integration/test_browser.py +0 -0
  64. {wavexis-2.0.0 → wavexis-2.0.2}/tests/integration/test_console.py +0 -0
  65. {wavexis-2.0.0 → wavexis-2.0.2}/tests/integration/test_css.py +0 -0
  66. {wavexis-2.0.0 → wavexis-2.0.2}/tests/integration/test_debug.py +0 -0
  67. {wavexis-2.0.0 → wavexis-2.0.2}/tests/integration/test_dialog.py +0 -0
  68. {wavexis-2.0.0 → wavexis-2.0.2}/tests/integration/test_dom.py +0 -0
  69. {wavexis-2.0.0 → wavexis-2.0.2}/tests/integration/test_dom_snapshot.py +0 -0
  70. {wavexis-2.0.0 → wavexis-2.0.2}/tests/integration/test_emulation.py +0 -0
  71. {wavexis-2.0.0 → wavexis-2.0.2}/tests/integration/test_emulation_advanced.py +0 -0
  72. {wavexis-2.0.0 → wavexis-2.0.2}/tests/integration/test_eval.py +0 -0
  73. {wavexis-2.0.0 → wavexis-2.0.2}/tests/integration/test_har.py +0 -0
  74. {wavexis-2.0.0 → wavexis-2.0.2}/tests/integration/test_input.py +0 -0
  75. {wavexis-2.0.0 → wavexis-2.0.2}/tests/integration/test_media.py +0 -0
  76. {wavexis-2.0.0 → wavexis-2.0.2}/tests/integration/test_multi.py +0 -0
  77. {wavexis-2.0.0 → wavexis-2.0.2}/tests/integration/test_navigate.py +0 -0
  78. {wavexis-2.0.0 → wavexis-2.0.2}/tests/integration/test_network.py +0 -0
  79. {wavexis-2.0.0 → wavexis-2.0.2}/tests/integration/test_network_advanced.py +0 -0
  80. {wavexis-2.0.0 → wavexis-2.0.2}/tests/integration/test_overlay.py +0 -0
  81. {wavexis-2.0.0 → wavexis-2.0.2}/tests/integration/test_pdf.py +0 -0
  82. {wavexis-2.0.0 → wavexis-2.0.2}/tests/integration/test_perf.py +0 -0
  83. {wavexis-2.0.0 → wavexis-2.0.2}/tests/integration/test_permissions.py +0 -0
  84. {wavexis-2.0.0 → wavexis-2.0.2}/tests/integration/test_raw.py +0 -0
  85. {wavexis-2.0.0 → wavexis-2.0.2}/tests/integration/test_record.py +0 -0
  86. {wavexis-2.0.0 → wavexis-2.0.2}/tests/integration/test_scrape.py +0 -0
  87. {wavexis-2.0.0 → wavexis-2.0.2}/tests/integration/test_screenshot.py +0 -0
  88. {wavexis-2.0.0 → wavexis-2.0.2}/tests/integration/test_security.py +0 -0
  89. {wavexis-2.0.0 → wavexis-2.0.2}/tests/integration/test_serve.py +0 -0
  90. {wavexis-2.0.0 → wavexis-2.0.2}/tests/integration/test_service_worker.py +0 -0
  91. {wavexis-2.0.0 → wavexis-2.0.2}/tests/integration/test_storage.py +0 -0
  92. {wavexis-2.0.0 → wavexis-2.0.2}/tests/integration/test_tabs.py +0 -0
  93. {wavexis-2.0.0 → wavexis-2.0.2}/tests/integration/test_webaudio.py +0 -0
  94. {wavexis-2.0.0 → wavexis-2.0.2}/tests/integration/test_webauthn.py +0 -0
  95. {wavexis-2.0.0 → wavexis-2.0.2}/tests/unit/__init__.py +0 -0
  96. {wavexis-2.0.0 → wavexis-2.0.2}/tests/unit/test_abstract_backend_phase5.py +0 -0
  97. {wavexis-2.0.0 → wavexis-2.0.2}/tests/unit/test_actions.py +0 -0
  98. {wavexis-2.0.0 → wavexis-2.0.2}/tests/unit/test_actions_phase5.py +0 -0
  99. {wavexis-2.0.0 → wavexis-2.0.2}/tests/unit/test_animation_action.py +0 -0
  100. {wavexis-2.0.0 → wavexis-2.0.2}/tests/unit/test_assert_multi.py +0 -0
  101. {wavexis-2.0.0 → wavexis-2.0.2}/tests/unit/test_auth.py +0 -0
  102. {wavexis-2.0.0 → wavexis-2.0.2}/tests/unit/test_backend_manager.py +0 -0
  103. {wavexis-2.0.0 → wavexis-2.0.2}/tests/unit/test_bidi_backend.py +0 -0
  104. {wavexis-2.0.0 → wavexis-2.0.2}/tests/unit/test_bidi_phase5.py +0 -0
  105. {wavexis-2.0.0 → wavexis-2.0.2}/tests/unit/test_bluetooth_action.py +0 -0
  106. {wavexis-2.0.0 → wavexis-2.0.2}/tests/unit/test_cast_action.py +0 -0
  107. {wavexis-2.0.0 → wavexis-2.0.2}/tests/unit/test_cli_phase5.py +0 -0
  108. {wavexis-2.0.0 → wavexis-2.0.2}/tests/unit/test_config.py +0 -0
  109. {wavexis-2.0.0 → wavexis-2.0.2}/tests/unit/test_config_phase5.py +0 -0
  110. {wavexis-2.0.0 → wavexis-2.0.2}/tests/unit/test_cookies_headers_actions.py +0 -0
  111. {wavexis-2.0.0 → wavexis-2.0.2}/tests/unit/test_css_action.py +0 -0
  112. {wavexis-2.0.0 → wavexis-2.0.2}/tests/unit/test_debug_action.py +0 -0
  113. {wavexis-2.0.0 → wavexis-2.0.2}/tests/unit/test_dom_snapshot_action.py +0 -0
  114. {wavexis-2.0.0 → wavexis-2.0.2}/tests/unit/test_download_screencast.py +0 -0
  115. {wavexis-2.0.0 → wavexis-2.0.2}/tests/unit/test_emulation_action.py +0 -0
  116. {wavexis-2.0.0 → wavexis-2.0.2}/tests/unit/test_error_handling.py +0 -0
  117. {wavexis-2.0.0 → wavexis-2.0.2}/tests/unit/test_exceptions.py +0 -0
  118. {wavexis-2.0.0 → wavexis-2.0.2}/tests/unit/test_format_record.py +0 -0
  119. {wavexis-2.0.0 → wavexis-2.0.2}/tests/unit/test_global_options.py +0 -0
  120. {wavexis-2.0.0 → wavexis-2.0.2}/tests/unit/test_init.py +0 -0
  121. {wavexis-2.0.0 → wavexis-2.0.2}/tests/unit/test_input_action.py +0 -0
  122. {wavexis-2.0.0 → wavexis-2.0.2}/tests/unit/test_interactions_crawl.py +0 -0
  123. {wavexis-2.0.0 → wavexis-2.0.2}/tests/unit/test_media_action.py +0 -0
  124. {wavexis-2.0.0 → wavexis-2.0.2}/tests/unit/test_multi.py +0 -0
  125. {wavexis-2.0.0 → wavexis-2.0.2}/tests/unit/test_multi_improvements.py +0 -0
  126. {wavexis-2.0.0 → wavexis-2.0.2}/tests/unit/test_new_features.py +0 -0
  127. {wavexis-2.0.0 → wavexis-2.0.2}/tests/unit/test_output.py +0 -0
  128. {wavexis-2.0.0 → wavexis-2.0.2}/tests/unit/test_overlay_action.py +0 -0
  129. {wavexis-2.0.0 → wavexis-2.0.2}/tests/unit/test_perf_action.py +0 -0
  130. {wavexis-2.0.0 → wavexis-2.0.2}/tests/unit/test_perf_console.py +0 -0
  131. {wavexis-2.0.0 → wavexis-2.0.2}/tests/unit/test_plugins.py +0 -0
  132. {wavexis-2.0.0 → wavexis-2.0.2}/tests/unit/test_raw.py +0 -0
  133. {wavexis-2.0.0 → wavexis-2.0.2}/tests/unit/test_record.py +0 -0
  134. {wavexis-2.0.0 → wavexis-2.0.2}/tests/unit/test_repl.py +0 -0
  135. {wavexis-2.0.0 → wavexis-2.0.2}/tests/unit/test_service_worker_action.py +0 -0
  136. {wavexis-2.0.0 → wavexis-2.0.2}/tests/unit/test_storage_action.py +0 -0
  137. {wavexis-2.0.0 → wavexis-2.0.2}/tests/unit/test_webaudio_action.py +0 -0
  138. {wavexis-2.0.0 → wavexis-2.0.2}/tests/unit/test_webauthn_action.py +0 -0
  139. {wavexis-2.0.0 → wavexis-2.0.2}/wavexis/__main__.py +0 -0
  140. {wavexis-2.0.0 → wavexis-2.0.2}/wavexis/actions/__init__.py +0 -0
  141. {wavexis-2.0.0 → wavexis-2.0.2}/wavexis/actions/accessibility.py +0 -0
  142. {wavexis-2.0.0 → wavexis-2.0.2}/wavexis/actions/animation.py +0 -0
  143. {wavexis-2.0.0 → wavexis-2.0.2}/wavexis/actions/base.py +0 -0
  144. {wavexis-2.0.0 → wavexis-2.0.2}/wavexis/actions/bluetooth.py +0 -0
  145. {wavexis-2.0.0 → wavexis-2.0.2}/wavexis/actions/browser.py +0 -0
  146. {wavexis-2.0.0 → wavexis-2.0.2}/wavexis/actions/cast.py +0 -0
  147. {wavexis-2.0.0 → wavexis-2.0.2}/wavexis/actions/console.py +0 -0
  148. {wavexis-2.0.0 → wavexis-2.0.2}/wavexis/actions/cookies.py +0 -0
  149. {wavexis-2.0.0 → wavexis-2.0.2}/wavexis/actions/crawl.py +0 -0
  150. {wavexis-2.0.0 → wavexis-2.0.2}/wavexis/actions/css.py +0 -0
  151. {wavexis-2.0.0 → wavexis-2.0.2}/wavexis/actions/debug.py +0 -0
  152. {wavexis-2.0.0 → wavexis-2.0.2}/wavexis/actions/dialog.py +0 -0
  153. {wavexis-2.0.0 → wavexis-2.0.2}/wavexis/actions/dom.py +0 -0
  154. {wavexis-2.0.0 → wavexis-2.0.2}/wavexis/actions/dom_snapshot.py +0 -0
  155. {wavexis-2.0.0 → wavexis-2.0.2}/wavexis/actions/download.py +0 -0
  156. {wavexis-2.0.0 → wavexis-2.0.2}/wavexis/actions/emulation.py +0 -0
  157. {wavexis-2.0.0 → wavexis-2.0.2}/wavexis/actions/eval.py +0 -0
  158. {wavexis-2.0.0 → wavexis-2.0.2}/wavexis/actions/extract.py +0 -0
  159. {wavexis-2.0.0 → wavexis-2.0.2}/wavexis/actions/form.py +0 -0
  160. {wavexis-2.0.0 → wavexis-2.0.2}/wavexis/actions/har.py +0 -0
  161. {wavexis-2.0.0 → wavexis-2.0.2}/wavexis/actions/headers.py +0 -0
  162. {wavexis-2.0.0 → wavexis-2.0.2}/wavexis/actions/input.py +0 -0
  163. {wavexis-2.0.0 → wavexis-2.0.2}/wavexis/actions/lighthouse.py +0 -0
  164. {wavexis-2.0.0 → wavexis-2.0.2}/wavexis/actions/media.py +0 -0
  165. {wavexis-2.0.0 → wavexis-2.0.2}/wavexis/actions/multi.py +0 -0
  166. {wavexis-2.0.0 → wavexis-2.0.2}/wavexis/actions/navigate.py +0 -0
  167. {wavexis-2.0.0 → wavexis-2.0.2}/wavexis/actions/network.py +0 -0
  168. {wavexis-2.0.0 → wavexis-2.0.2}/wavexis/actions/overlay.py +0 -0
  169. {wavexis-2.0.0 → wavexis-2.0.2}/wavexis/actions/pdf.py +0 -0
  170. {wavexis-2.0.0 → wavexis-2.0.2}/wavexis/actions/performance.py +0 -0
  171. {wavexis-2.0.0 → wavexis-2.0.2}/wavexis/actions/permissions.py +0 -0
  172. {wavexis-2.0.0 → wavexis-2.0.2}/wavexis/actions/record.py +0 -0
  173. {wavexis-2.0.0 → wavexis-2.0.2}/wavexis/actions/scrape.py +0 -0
  174. {wavexis-2.0.0 → wavexis-2.0.2}/wavexis/actions/screencast.py +0 -0
  175. {wavexis-2.0.0 → wavexis-2.0.2}/wavexis/actions/screenshot.py +0 -0
  176. {wavexis-2.0.0 → wavexis-2.0.2}/wavexis/actions/security.py +0 -0
  177. {wavexis-2.0.0 → wavexis-2.0.2}/wavexis/actions/service_worker.py +0 -0
  178. {wavexis-2.0.0 → wavexis-2.0.2}/wavexis/actions/session.py +0 -0
  179. {wavexis-2.0.0 → wavexis-2.0.2}/wavexis/actions/storage.py +0 -0
  180. {wavexis-2.0.0 → wavexis-2.0.2}/wavexis/actions/tabs.py +0 -0
  181. {wavexis-2.0.0 → wavexis-2.0.2}/wavexis/actions/wait.py +0 -0
  182. {wavexis-2.0.0 → wavexis-2.0.2}/wavexis/actions/webaudio.py +0 -0
  183. {wavexis-2.0.0 → wavexis-2.0.2}/wavexis/actions/webauthn.py +0 -0
  184. {wavexis-2.0.0 → wavexis-2.0.2}/wavexis/actions/websocket.py +0 -0
  185. {wavexis-2.0.0 → wavexis-2.0.2}/wavexis/backend/__init__.py +0 -0
  186. {wavexis-2.0.0 → wavexis-2.0.2}/wavexis/backend/base.py +0 -0
  187. {wavexis-2.0.0 → wavexis-2.0.2}/wavexis/backend/bidi.py +0 -0
  188. {wavexis-2.0.0 → wavexis-2.0.2}/wavexis/backend/cdp.py +0 -0
  189. {wavexis-2.0.0 → wavexis-2.0.2}/wavexis/cli/__init__.py +0 -0
  190. {wavexis-2.0.0 → wavexis-2.0.2}/wavexis/config.py +0 -0
  191. {wavexis-2.0.0 → wavexis-2.0.2}/wavexis/exceptions.py +0 -0
  192. {wavexis-2.0.0 → wavexis-2.0.2}/wavexis/init.py +0 -0
  193. {wavexis-2.0.0 → wavexis-2.0.2}/wavexis/multi.py +0 -0
  194. {wavexis-2.0.0 → wavexis-2.0.2}/wavexis/output.py +0 -0
  195. {wavexis-2.0.0 → wavexis-2.0.2}/wavexis/plugins.py +0 -0
  196. {wavexis-2.0.0 → wavexis-2.0.2}/wavexis/record.py +0 -0
  197. {wavexis-2.0.0 → wavexis-2.0.2}/wavexis/repl.py +0 -0
@@ -2,6 +2,28 @@
2
2
 
3
3
  All notable changes to wavexis are documented in this file.
4
4
 
5
+ ## v2.0.2 — 2026-07-06
6
+
7
+ ### Changed
8
+
9
+ - Removed redundant `import json as _json` in `webauthn` and `raw` commands — uses top-level `json` import
10
+ - Consolidated `_write_perf_output` into `_write_json_output` — eliminates duplicate function
11
+ - Replaced inline JSON output in `raw` command with `_write_json_output` call
12
+
13
+ ### Refactored
14
+
15
+ - Extracted `apply_auth_context` to `wavexis/auth.py` — eliminates duplication between `serve.py` `handle_auth` and `cli/app.py` `auth` command
16
+ - Removed unused `_basic_auth` helper from `cli/app.py`
17
+
18
+ ## v2.0.1 — 2026-07-06
19
+
20
+ ### Fixed
21
+
22
+ - `serve.py` `/version` endpoint now returns the correct package version instead of hardcoded `1.11.2`
23
+ - `BackendManager` is now cached as a singleton via `get_manager()` — avoids re-discovering entry points on every call
24
+ - Added missing `return` after `_handle_error(e)` in 66 CLI command paths — prevents `NameError` and unintended output after errors
25
+ - `FakeBackend` in `test_manager.py` now implements `set_files` abstract method
26
+
5
27
  ## v2.0.0 — 2026-07-06
6
28
 
7
29
  ### Changed
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: wavexis
3
- Version: 2.0.0
3
+ Version: 2.0.2
4
4
  Summary: Browser automation CLI — wraps cdpwave and bidiwave, no Node.js, no Chromium download
5
5
  Project-URL: Homepage, https://github.com/MathiasPaulenko/wavexis
6
6
  Project-URL: Repository, https://github.com/MathiasPaulenko/wavexis
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "wavexis"
7
- version = "2.0.0"
7
+ version = "2.0.2"
8
8
  description = "Browser automation CLI — wraps cdpwave and bidiwave, no Node.js, no Chromium download"
9
9
  readme = "README.md"
10
10
  license = { text = "MIT" }
@@ -260,6 +260,8 @@ class FakeBackend(AbstractBackend):
260
260
  """Bluetooth emulate."""
261
261
  async def bluetooth_stop(self):
262
262
  """Bluetooth stop."""
263
+ async def set_files(self, selector, files):
264
+ """Set files."""
263
265
 
264
266
 
265
267
  class TestBackendManager:
@@ -162,7 +162,7 @@ class TestServeHandlerMocks:
162
162
  server = TestServer(app)
163
163
  client = TestClient(server)
164
164
  await client.start_server()
165
- with patch("wavexis.serve.BackendManager.select", return_value=mock_backend):
165
+ with patch("wavexis.backend.manager.BackendManager.select", return_value=mock_backend):
166
166
  resp = await client.post(
167
167
  "/screenshot",
168
168
  json={"url": "https://example.com"},
@@ -186,7 +186,7 @@ class TestServeHandlerMocks:
186
186
  server = TestServer(app)
187
187
  client = TestClient(server)
188
188
  await client.start_server()
189
- with patch("wavexis.serve.BackendManager.select", return_value=mock_backend):
189
+ with patch("wavexis.backend.manager.BackendManager.select", return_value=mock_backend):
190
190
  resp = await client.post(
191
191
  "/pdf",
192
192
  json={"url": "https://example.com"},
@@ -210,7 +210,7 @@ class TestServeHandlerMocks:
210
210
  server = TestServer(app)
211
211
  client = TestClient(server)
212
212
  await client.start_server()
213
- with patch("wavexis.serve.BackendManager.select", return_value=mock_backend):
213
+ with patch("wavexis.backend.manager.BackendManager.select", return_value=mock_backend):
214
214
  resp = await client.post(
215
215
  "/eval",
216
216
  json={"url": "https://example.com", "expression": "1+1"},
@@ -233,7 +233,7 @@ class TestServeHandlerMocks:
233
233
  server = TestServer(app)
234
234
  client = TestClient(server)
235
235
  await client.start_server()
236
- with patch("wavexis.serve.BackendManager.select", return_value=mock_backend):
236
+ with patch("wavexis.backend.manager.BackendManager.select", return_value=mock_backend):
237
237
  resp = await client.post(
238
238
  "/perf/metrics",
239
239
  json={"url": "https://example.com"},
@@ -256,7 +256,7 @@ class TestServeHandlerMocks:
256
256
  server = TestServer(app)
257
257
  client = TestClient(server)
258
258
  await client.start_server()
259
- with patch("wavexis.serve.BackendManager.select", return_value=mock_backend):
259
+ with patch("wavexis.backend.manager.BackendManager.select", return_value=mock_backend):
260
260
  resp = await client.post(
261
261
  "/perf/trace",
262
262
  json={"url": "https://example.com", "duration_ms": 1000},
@@ -279,7 +279,7 @@ class TestServeHandlerMocks:
279
279
  server = TestServer(app)
280
280
  client = TestClient(server)
281
281
  await client.start_server()
282
- with patch("wavexis.serve.BackendManager.select", return_value=mock_backend):
282
+ with patch("wavexis.backend.manager.BackendManager.select", return_value=mock_backend):
283
283
  resp = await client.post(
284
284
  "/navigate",
285
285
  json={"url": "https://example.com"},
@@ -302,7 +302,7 @@ class TestServeHandlerMocks:
302
302
  server = TestServer(app)
303
303
  client = TestClient(server)
304
304
  await client.start_server()
305
- with patch("wavexis.serve.BackendManager.select", return_value=mock_backend):
305
+ with patch("wavexis.backend.manager.BackendManager.select", return_value=mock_backend):
306
306
  resp = await client.post(
307
307
  "/cookies/get",
308
308
  json={"url": "https://example.com"},
@@ -325,7 +325,7 @@ class TestServeHandlerMocks:
325
325
  server = TestServer(app)
326
326
  client = TestClient(server)
327
327
  await client.start_server()
328
- with patch("wavexis.serve.BackendManager.select", return_value=mock_backend):
328
+ with patch("wavexis.backend.manager.BackendManager.select", return_value=mock_backend):
329
329
  resp = await client.post(
330
330
  "/cookies/set",
331
331
  json={
@@ -353,7 +353,7 @@ class TestServeHandlerMocks:
353
353
  server = TestServer(app)
354
354
  client = TestClient(server)
355
355
  await client.start_server()
356
- with patch("wavexis.serve.BackendManager.select", return_value=mock_backend):
356
+ with patch("wavexis.backend.manager.BackendManager.select", return_value=mock_backend):
357
357
  ws = await client.ws_connect("/ws")
358
358
  await ws.send_json({
359
359
  "url": "https://example.com",
@@ -383,7 +383,7 @@ class TestServeHandlerMocks:
383
383
  server = TestServer(app)
384
384
  client = TestClient(server)
385
385
  await client.start_server()
386
- with patch("wavexis.serve.BackendManager.select", return_value=mock_backend):
386
+ with patch("wavexis.backend.manager.BackendManager.select", return_value=mock_backend):
387
387
  ws = await client.ws_connect("/ws")
388
388
  await ws.send_json({
389
389
  "url": "https://example.com",
@@ -1,3 +1,3 @@
1
1
  """wavexis — CLI de automatización de navegador."""
2
2
 
3
- __version__ = "2.0.0"
3
+ __version__ = "2.0.2"
@@ -2,9 +2,15 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
+ import base64
5
6
  import json
6
7
  from dataclasses import dataclass, field
7
8
  from pathlib import Path
9
+ from typing import TYPE_CHECKING
10
+
11
+ if TYPE_CHECKING:
12
+ from wavexis.backend.base import AbstractBackend
13
+ from wavexis.config import WaitStrategy
8
14
 
9
15
 
10
16
  @dataclass
@@ -84,3 +90,43 @@ def load_headers(path: str | Path) -> dict[str, str]:
84
90
  return data["headers"]
85
91
  return data
86
92
  return {}
93
+
94
+
95
+ async def apply_auth_context(
96
+ backend: AbstractBackend,
97
+ ctx: AuthContext,
98
+ url: str,
99
+ wait: WaitStrategy | None = None,
100
+ ) -> None:
101
+ """Apply auth context to a backend and navigate to a URL.
102
+
103
+ Sets headers, basic auth, navigates, sets cookies, and re-navigates.
104
+
105
+ Args:
106
+ backend: The browser backend to apply auth to.
107
+ ctx: The auth context with cookies, headers, and credentials.
108
+ url: The URL to navigate to.
109
+ wait: Wait strategy for navigation. Defaults to "load".
110
+ """
111
+ from wavexis.config import CookieParams, WaitStrategy
112
+
113
+ if wait is None:
114
+ wait = WaitStrategy(strategy="load")
115
+
116
+ if ctx.headers:
117
+ await backend.set_headers(ctx.headers)
118
+ if ctx.username and ctx.password:
119
+ cred = base64.b64encode(
120
+ f"{ctx.username}:{ctx.password}".encode()
121
+ ).decode()
122
+ await backend.set_headers({"Authorization": f"Basic {cred}"})
123
+ await backend.navigate(url, wait)
124
+ for cookie in ctx.cookies:
125
+ cp = CookieParams(
126
+ name=cookie.get("name", ""),
127
+ value=cookie.get("value", ""),
128
+ domain=cookie.get("domain", ""),
129
+ path=cookie.get("path", "/"),
130
+ )
131
+ await backend.set_cookie(cp)
132
+ await backend.navigate(url, wait)
@@ -5,6 +5,26 @@ from __future__ import annotations
5
5
  from wavexis.backend.base import AbstractBackend
6
6
  from wavexis.exceptions import BackendNotAvailableError, BackendNotSupportedError
7
7
 
8
+ _manager: BackendManager | None = None
9
+
10
+
11
+ def get_manager() -> BackendManager:
12
+ """Return the singleton BackendManager instance.
13
+
14
+ Returns:
15
+ The shared BackendManager, created on first call.
16
+ """
17
+ global _manager
18
+ if _manager is None:
19
+ _manager = BackendManager()
20
+ return _manager
21
+
22
+
23
+ def reset_manager() -> None:
24
+ """Reset the singleton manager (useful for tests)."""
25
+ global _manager
26
+ _manager = None
27
+
8
28
 
9
29
  class BackendManager:
10
30
  """Manages backend availability, selection, and registration.