browserbase 1.6.0__tar.gz → 1.8.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 (140) hide show
  1. {browserbase-1.6.0 → browserbase-1.8.0}/.gitignore +1 -0
  2. browserbase-1.8.0/.release-please-manifest.json +3 -0
  3. {browserbase-1.6.0 → browserbase-1.8.0}/CHANGELOG.md +44 -0
  4. {browserbase-1.6.0 → browserbase-1.8.0}/CONTRIBUTING.md +1 -1
  5. {browserbase-1.6.0 → browserbase-1.8.0}/PKG-INFO +2 -2
  6. {browserbase-1.6.0 → browserbase-1.8.0}/api.md +12 -0
  7. {browserbase-1.6.0 → browserbase-1.8.0}/pyproject.toml +2 -2
  8. {browserbase-1.6.0 → browserbase-1.8.0}/src/browserbase/_client.py +38 -1
  9. {browserbase-1.6.0 → browserbase-1.8.0}/src/browserbase/_compat.py +9 -2
  10. {browserbase-1.6.0 → browserbase-1.8.0}/src/browserbase/_qs.py +4 -1
  11. {browserbase-1.6.0 → browserbase-1.8.0}/src/browserbase/_utils/__init__.py +1 -0
  12. browserbase-1.8.0/src/browserbase/_utils/_path.py +127 -0
  13. {browserbase-1.6.0 → browserbase-1.8.0}/src/browserbase/_version.py +1 -1
  14. {browserbase-1.6.0 → browserbase-1.8.0}/src/browserbase/resources/__init__.py +14 -0
  15. {browserbase-1.6.0 → browserbase-1.8.0}/src/browserbase/resources/contexts.py +7 -7
  16. {browserbase-1.6.0 → browserbase-1.8.0}/src/browserbase/resources/extensions.py +5 -5
  17. {browserbase-1.6.0 → browserbase-1.8.0}/src/browserbase/resources/projects.py +5 -4
  18. browserbase-1.8.0/src/browserbase/resources/search.py +185 -0
  19. {browserbase-1.6.0 → browserbase-1.8.0}/src/browserbase/resources/sessions/downloads.py +3 -2
  20. {browserbase-1.6.0 → browserbase-1.8.0}/src/browserbase/resources/sessions/logs.py +3 -2
  21. {browserbase-1.6.0 → browserbase-1.8.0}/src/browserbase/resources/sessions/recording.py +3 -2
  22. {browserbase-1.6.0 → browserbase-1.8.0}/src/browserbase/resources/sessions/sessions.py +7 -7
  23. {browserbase-1.6.0 → browserbase-1.8.0}/src/browserbase/resources/sessions/uploads.py +3 -3
  24. {browserbase-1.6.0 → browserbase-1.8.0}/src/browserbase/types/__init__.py +2 -0
  25. {browserbase-1.6.0 → browserbase-1.8.0}/src/browserbase/types/fetch_api_create_response.py +0 -2
  26. browserbase-1.8.0/src/browserbase/types/search_web_params.py +17 -0
  27. browserbase-1.8.0/src/browserbase/types/search_web_response.py +44 -0
  28. {browserbase-1.6.0 → browserbase-1.8.0}/src/browserbase/types/session_create_params.py +3 -0
  29. browserbase-1.8.0/tests/api_resources/test_search.py +102 -0
  30. {browserbase-1.6.0 → browserbase-1.8.0}/tests/api_resources/test_sessions.py +2 -0
  31. browserbase-1.8.0/tests/test_utils/test_path.py +89 -0
  32. browserbase-1.6.0/.release-please-manifest.json +0 -3
  33. {browserbase-1.6.0 → browserbase-1.8.0}/LICENSE +0 -0
  34. {browserbase-1.6.0 → browserbase-1.8.0}/MIGRATION.md +0 -0
  35. {browserbase-1.6.0 → browserbase-1.8.0}/README.md +0 -0
  36. {browserbase-1.6.0 → browserbase-1.8.0}/SECURITY.md +0 -0
  37. {browserbase-1.6.0 → browserbase-1.8.0}/bin/check-release-environment +0 -0
  38. {browserbase-1.6.0 → browserbase-1.8.0}/bin/publish-pypi +0 -0
  39. {browserbase-1.6.0 → browserbase-1.8.0}/examples/.keep +0 -0
  40. {browserbase-1.6.0 → browserbase-1.8.0}/examples/__init__.py +0 -0
  41. {browserbase-1.6.0 → browserbase-1.8.0}/examples/e2e/README.md +0 -0
  42. {browserbase-1.6.0 → browserbase-1.8.0}/examples/e2e/__init__.py +0 -0
  43. {browserbase-1.6.0 → browserbase-1.8.0}/examples/e2e/test_playwright.py +0 -0
  44. {browserbase-1.6.0 → browserbase-1.8.0}/examples/e2e/test_selenium.py +0 -0
  45. {browserbase-1.6.0 → browserbase-1.8.0}/examples/packages/extensions/.gitignore +0 -0
  46. {browserbase-1.6.0 → browserbase-1.8.0}/examples/packages/extensions/browserbase-test/hello.html +0 -0
  47. {browserbase-1.6.0 → browserbase-1.8.0}/examples/packages/extensions/browserbase-test/images/logo.png +0 -0
  48. {browserbase-1.6.0 → browserbase-1.8.0}/examples/packages/extensions/browserbase-test/manifest.json +0 -0
  49. {browserbase-1.6.0 → browserbase-1.8.0}/examples/packages/extensions/browserbase-test/scripts/content.js +0 -0
  50. {browserbase-1.6.0 → browserbase-1.8.0}/examples/packages/logo.png +0 -0
  51. {browserbase-1.6.0 → browserbase-1.8.0}/examples/playwright_basic.py +0 -0
  52. {browserbase-1.6.0 → browserbase-1.8.0}/examples/playwright_captcha.py +0 -0
  53. {browserbase-1.6.0 → browserbase-1.8.0}/examples/playwright_contexts.py +0 -0
  54. {browserbase-1.6.0 → browserbase-1.8.0}/examples/playwright_downloads.py +0 -0
  55. {browserbase-1.6.0 → browserbase-1.8.0}/examples/playwright_extensions.py +0 -0
  56. {browserbase-1.6.0 → browserbase-1.8.0}/examples/playwright_proxy.py +0 -0
  57. {browserbase-1.6.0 → browserbase-1.8.0}/examples/playwright_upload.py +0 -0
  58. {browserbase-1.6.0 → browserbase-1.8.0}/examples/selenium_basic.py +0 -0
  59. {browserbase-1.6.0 → browserbase-1.8.0}/noxfile.py +0 -0
  60. {browserbase-1.6.0 → browserbase-1.8.0}/release-please-config.json +0 -0
  61. {browserbase-1.6.0 → browserbase-1.8.0}/requirements-dev.lock +0 -0
  62. {browserbase-1.6.0 → browserbase-1.8.0}/requirements.lock +0 -0
  63. {browserbase-1.6.0 → browserbase-1.8.0}/src/browserbase/__init__.py +0 -0
  64. {browserbase-1.6.0 → browserbase-1.8.0}/src/browserbase/_base_client.py +0 -0
  65. {browserbase-1.6.0 → browserbase-1.8.0}/src/browserbase/_constants.py +0 -0
  66. {browserbase-1.6.0 → browserbase-1.8.0}/src/browserbase/_exceptions.py +0 -0
  67. {browserbase-1.6.0 → browserbase-1.8.0}/src/browserbase/_files.py +0 -0
  68. {browserbase-1.6.0 → browserbase-1.8.0}/src/browserbase/_models.py +0 -0
  69. {browserbase-1.6.0 → browserbase-1.8.0}/src/browserbase/_resource.py +0 -0
  70. {browserbase-1.6.0 → browserbase-1.8.0}/src/browserbase/_response.py +0 -0
  71. {browserbase-1.6.0 → browserbase-1.8.0}/src/browserbase/_streaming.py +0 -0
  72. {browserbase-1.6.0 → browserbase-1.8.0}/src/browserbase/_types.py +0 -0
  73. {browserbase-1.6.0 → browserbase-1.8.0}/src/browserbase/_utils/_compat.py +0 -0
  74. {browserbase-1.6.0 → browserbase-1.8.0}/src/browserbase/_utils/_datetime_parse.py +0 -0
  75. {browserbase-1.6.0 → browserbase-1.8.0}/src/browserbase/_utils/_json.py +0 -0
  76. {browserbase-1.6.0 → browserbase-1.8.0}/src/browserbase/_utils/_logs.py +0 -0
  77. {browserbase-1.6.0 → browserbase-1.8.0}/src/browserbase/_utils/_proxy.py +0 -0
  78. {browserbase-1.6.0 → browserbase-1.8.0}/src/browserbase/_utils/_reflection.py +0 -0
  79. {browserbase-1.6.0 → browserbase-1.8.0}/src/browserbase/_utils/_resources_proxy.py +0 -0
  80. {browserbase-1.6.0 → browserbase-1.8.0}/src/browserbase/_utils/_streams.py +0 -0
  81. {browserbase-1.6.0 → browserbase-1.8.0}/src/browserbase/_utils/_sync.py +0 -0
  82. {browserbase-1.6.0 → browserbase-1.8.0}/src/browserbase/_utils/_transform.py +0 -0
  83. {browserbase-1.6.0 → browserbase-1.8.0}/src/browserbase/_utils/_typing.py +0 -0
  84. {browserbase-1.6.0 → browserbase-1.8.0}/src/browserbase/_utils/_utils.py +0 -0
  85. {browserbase-1.6.0 → browserbase-1.8.0}/src/browserbase/lib/.keep +0 -0
  86. {browserbase-1.6.0 → browserbase-1.8.0}/src/browserbase/py.typed +0 -0
  87. {browserbase-1.6.0 → browserbase-1.8.0}/src/browserbase/resources/fetch_api.py +0 -0
  88. {browserbase-1.6.0 → browserbase-1.8.0}/src/browserbase/resources/sessions/__init__.py +0 -0
  89. {browserbase-1.6.0 → browserbase-1.8.0}/src/browserbase/types/context.py +0 -0
  90. {browserbase-1.6.0 → browserbase-1.8.0}/src/browserbase/types/context_create_params.py +0 -0
  91. {browserbase-1.6.0 → browserbase-1.8.0}/src/browserbase/types/context_create_response.py +0 -0
  92. {browserbase-1.6.0 → browserbase-1.8.0}/src/browserbase/types/context_update_response.py +0 -0
  93. {browserbase-1.6.0 → browserbase-1.8.0}/src/browserbase/types/extension.py +0 -0
  94. {browserbase-1.6.0 → browserbase-1.8.0}/src/browserbase/types/extension_create_params.py +0 -0
  95. {browserbase-1.6.0 → browserbase-1.8.0}/src/browserbase/types/fetch_api_create_params.py +0 -0
  96. {browserbase-1.6.0 → browserbase-1.8.0}/src/browserbase/types/project.py +0 -0
  97. {browserbase-1.6.0 → browserbase-1.8.0}/src/browserbase/types/project_list_response.py +0 -0
  98. {browserbase-1.6.0 → browserbase-1.8.0}/src/browserbase/types/project_usage.py +0 -0
  99. {browserbase-1.6.0 → browserbase-1.8.0}/src/browserbase/types/session.py +0 -0
  100. {browserbase-1.6.0 → browserbase-1.8.0}/src/browserbase/types/session_create_response.py +0 -0
  101. {browserbase-1.6.0 → browserbase-1.8.0}/src/browserbase/types/session_list_params.py +0 -0
  102. {browserbase-1.6.0 → browserbase-1.8.0}/src/browserbase/types/session_list_response.py +0 -0
  103. {browserbase-1.6.0 → browserbase-1.8.0}/src/browserbase/types/session_live_urls.py +0 -0
  104. {browserbase-1.6.0 → browserbase-1.8.0}/src/browserbase/types/session_retrieve_response.py +0 -0
  105. {browserbase-1.6.0 → browserbase-1.8.0}/src/browserbase/types/session_update_params.py +0 -0
  106. {browserbase-1.6.0 → browserbase-1.8.0}/src/browserbase/types/sessions/__init__.py +0 -0
  107. {browserbase-1.6.0 → browserbase-1.8.0}/src/browserbase/types/sessions/log_list_response.py +0 -0
  108. {browserbase-1.6.0 → browserbase-1.8.0}/src/browserbase/types/sessions/recording_retrieve_response.py +0 -0
  109. {browserbase-1.6.0 → browserbase-1.8.0}/src/browserbase/types/sessions/session_log.py +0 -0
  110. {browserbase-1.6.0 → browserbase-1.8.0}/src/browserbase/types/sessions/session_recording.py +0 -0
  111. {browserbase-1.6.0 → browserbase-1.8.0}/src/browserbase/types/sessions/upload_create_params.py +0 -0
  112. {browserbase-1.6.0 → browserbase-1.8.0}/src/browserbase/types/sessions/upload_create_response.py +0 -0
  113. {browserbase-1.6.0 → browserbase-1.8.0}/tests/__init__.py +0 -0
  114. {browserbase-1.6.0 → browserbase-1.8.0}/tests/api_resources/__init__.py +0 -0
  115. {browserbase-1.6.0 → browserbase-1.8.0}/tests/api_resources/sessions/__init__.py +0 -0
  116. {browserbase-1.6.0 → browserbase-1.8.0}/tests/api_resources/sessions/test_downloads.py +0 -0
  117. {browserbase-1.6.0 → browserbase-1.8.0}/tests/api_resources/sessions/test_logs.py +0 -0
  118. {browserbase-1.6.0 → browserbase-1.8.0}/tests/api_resources/sessions/test_recording.py +0 -0
  119. {browserbase-1.6.0 → browserbase-1.8.0}/tests/api_resources/sessions/test_uploads.py +0 -0
  120. {browserbase-1.6.0 → browserbase-1.8.0}/tests/api_resources/test_contexts.py +0 -0
  121. {browserbase-1.6.0 → browserbase-1.8.0}/tests/api_resources/test_extensions.py +0 -0
  122. {browserbase-1.6.0 → browserbase-1.8.0}/tests/api_resources/test_fetch_api.py +0 -0
  123. {browserbase-1.6.0 → browserbase-1.8.0}/tests/api_resources/test_projects.py +0 -0
  124. {browserbase-1.6.0 → browserbase-1.8.0}/tests/conftest.py +0 -0
  125. {browserbase-1.6.0 → browserbase-1.8.0}/tests/sample_file.txt +0 -0
  126. {browserbase-1.6.0 → browserbase-1.8.0}/tests/test_client.py +0 -0
  127. {browserbase-1.6.0 → browserbase-1.8.0}/tests/test_deepcopy.py +0 -0
  128. {browserbase-1.6.0 → browserbase-1.8.0}/tests/test_extract_files.py +0 -0
  129. {browserbase-1.6.0 → browserbase-1.8.0}/tests/test_files.py +0 -0
  130. {browserbase-1.6.0 → browserbase-1.8.0}/tests/test_models.py +0 -0
  131. {browserbase-1.6.0 → browserbase-1.8.0}/tests/test_qs.py +0 -0
  132. {browserbase-1.6.0 → browserbase-1.8.0}/tests/test_required_args.py +0 -0
  133. {browserbase-1.6.0 → browserbase-1.8.0}/tests/test_response.py +0 -0
  134. {browserbase-1.6.0 → browserbase-1.8.0}/tests/test_streaming.py +0 -0
  135. {browserbase-1.6.0 → browserbase-1.8.0}/tests/test_transform.py +0 -0
  136. {browserbase-1.6.0 → browserbase-1.8.0}/tests/test_utils/test_datetime_parse.py +0 -0
  137. {browserbase-1.6.0 → browserbase-1.8.0}/tests/test_utils/test_json.py +0 -0
  138. {browserbase-1.6.0 → browserbase-1.8.0}/tests/test_utils/test_proxy.py +0 -0
  139. {browserbase-1.6.0 → browserbase-1.8.0}/tests/test_utils/test_typing.py +0 -0
  140. {browserbase-1.6.0 → browserbase-1.8.0}/tests/utils.py +0 -0
@@ -1,4 +1,5 @@
1
1
  .prism.log
2
+ .stdy.log
2
3
  _dev
3
4
 
4
5
  __pycache__
@@ -0,0 +1,3 @@
1
+ {
2
+ ".": "1.8.0"
3
+ }
@@ -1,5 +1,49 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.8.0 (2026-04-06)
4
+
5
+ Full Changelog: [v1.7.0...v1.8.0](https://github.com/browserbase/sdk-python/compare/v1.7.0...v1.8.0)
6
+
7
+ ### Features
8
+
9
+ * [CORE-000][apps/api] Add verified to SDK ([1579bf9](https://github.com/browserbase/sdk-python/commit/1579bf91b323f565abc7bdf54a131cd3e8e2f4d9))
10
+ * **internal:** implement indices array format for query and form serialization ([17a85d5](https://github.com/browserbase/sdk-python/commit/17a85d54d36f45acf242d066b13c49e90b4a2777))
11
+ * Update search docs by removing description from typebox schemas ([7913112](https://github.com/browserbase/sdk-python/commit/7913112d697666bf4381119f5962c284bd91b410))
12
+
13
+
14
+ ### Bug Fixes
15
+
16
+ * **deps:** bump minimum typing-extensions version ([962e72a](https://github.com/browserbase/sdk-python/commit/962e72a121f27a603f92311917426c9aee84d805))
17
+ * **pydantic:** do not pass `by_alias` unless set ([3e6a912](https://github.com/browserbase/sdk-python/commit/3e6a912dc0a117c2deb229bb5230d2294de3b129))
18
+ * sanitize endpoint path params ([8a63eb5](https://github.com/browserbase/sdk-python/commit/8a63eb5e275eb25849f22cf210d42487e8283078))
19
+
20
+
21
+ ### Chores
22
+
23
+ * **ci:** skip lint on metadata-only changes ([80a6a3c](https://github.com/browserbase/sdk-python/commit/80a6a3c61b73be9c2f99fbdd20b2e47e9024fec5))
24
+ * **internal:** tweak CI branches ([9901c59](https://github.com/browserbase/sdk-python/commit/9901c595fa68e1ab213ac22eb06aeebc722edb03))
25
+ * **internal:** update gitignore ([2e3ba9b](https://github.com/browserbase/sdk-python/commit/2e3ba9b833a663b2b355b2b4a4f4d698de731e5e))
26
+ * **tests:** bump steady to v0.19.4 ([f81180d](https://github.com/browserbase/sdk-python/commit/f81180d7502d612aaaab8665740f2cc133da1e80))
27
+ * **tests:** bump steady to v0.19.5 ([10d0b70](https://github.com/browserbase/sdk-python/commit/10d0b70f04059ff66f199b9512ffb4ab11699262))
28
+ * **tests:** bump steady to v0.19.6 ([f9d4f90](https://github.com/browserbase/sdk-python/commit/f9d4f900ca05f245a5ac91b26df8e8a4520ec1d3))
29
+ * **tests:** bump steady to v0.19.7 ([27c797d](https://github.com/browserbase/sdk-python/commit/27c797da65010f04a0cd3d2f42cfef5d6eeb8105))
30
+ * **tests:** bump steady to v0.20.1 ([17f2e35](https://github.com/browserbase/sdk-python/commit/17f2e357b8c9f09c34eec9a3f7a055b3f9c72d14))
31
+ * **tests:** bump steady to v0.20.2 ([85ef397](https://github.com/browserbase/sdk-python/commit/85ef397598b8856217510a081fa5ebecc94819d3))
32
+
33
+
34
+ ### Refactors
35
+
36
+ * **tests:** switch from prism to steady ([39217ea](https://github.com/browserbase/sdk-python/commit/39217ea5ffd68b03900a6272378a3b3a8d5efc4a))
37
+
38
+ ## 1.7.0 (2026-03-16)
39
+
40
+ Full Changelog: [v1.6.0...v1.7.0](https://github.com/browserbase/sdk-python/compare/v1.6.0...v1.7.0)
41
+
42
+ ### Features
43
+
44
+ * [CORE-1796][apps/api] Update Node.js SDK ([ecafbb5](https://github.com/browserbase/sdk-python/commit/ecafbb511dbe9be78e84f4e1d34e1feefa1fce8e))
45
+ * [GRO-000] docs: Add guide + docs for search api ([55e2d0d](https://github.com/browserbase/sdk-python/commit/55e2d0db2f31b2ca390eaa6855f22de1f1688a88))
46
+
3
47
  ## 1.6.0 (2026-03-11)
4
48
 
5
49
  Full Changelog: [v1.5.0...v1.6.0](https://github.com/browserbase/sdk-python/compare/v1.5.0...v1.6.0)
@@ -85,7 +85,7 @@ $ pip install ./path-to-wheel-file.whl
85
85
 
86
86
  ## Running tests
87
87
 
88
- Most tests require you to [set up a mock server](https://github.com/stoplightio/prism) against the OpenAPI spec to run the tests.
88
+ Most tests require you to [set up a mock server](https://github.com/dgellow/steady) against the OpenAPI spec to run the tests.
89
89
 
90
90
  ```sh
91
91
  $ ./scripts/mock
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: browserbase
3
- Version: 1.6.0
3
+ Version: 1.8.0
4
4
  Summary: The official Python library for the Browserbase API
5
5
  Project-URL: Homepage, https://github.com/browserbase/sdk-python
6
6
  Project-URL: Repository, https://github.com/browserbase/sdk-python
@@ -27,7 +27,7 @@ Requires-Dist: distro<2,>=1.7.0
27
27
  Requires-Dist: httpx<1,>=0.23.0
28
28
  Requires-Dist: pydantic<3,>=1.9.0
29
29
  Requires-Dist: sniffio
30
- Requires-Dist: typing-extensions<5,>=4.10
30
+ Requires-Dist: typing-extensions<5,>=4.14
31
31
  Provides-Extra: aiohttp
32
32
  Requires-Dist: aiohttp; extra == 'aiohttp'
33
33
  Requires-Dist: httpx-aiohttp>=0.1.9; extra == 'aiohttp'
@@ -53,6 +53,18 @@ Methods:
53
53
  - <code title="get /v1/projects">client.projects.<a href="./src/browserbase/resources/projects.py">list</a>() -> <a href="./src/browserbase/types/project_list_response.py">ProjectListResponse</a></code>
54
54
  - <code title="get /v1/projects/{id}/usage">client.projects.<a href="./src/browserbase/resources/projects.py">usage</a>(id) -> <a href="./src/browserbase/types/project_usage.py">ProjectUsage</a></code>
55
55
 
56
+ # Search
57
+
58
+ Types:
59
+
60
+ ```python
61
+ from browserbase.types import SearchWebResponse
62
+ ```
63
+
64
+ Methods:
65
+
66
+ - <code title="post /v1/search">client.search.<a href="./src/browserbase/resources/search.py">web</a>(\*\*<a href="src/browserbase/types/search_web_params.py">params</a>) -> <a href="./src/browserbase/types/search_web_response.py">SearchWebResponse</a></code>
67
+
56
68
  # Sessions
57
69
 
58
70
  Types:
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "browserbase"
3
- version = "1.6.0"
3
+ version = "1.8.0"
4
4
  description = "The official Python library for the Browserbase API"
5
5
  dynamic = ["readme"]
6
6
  license = "Apache-2.0"
@@ -11,7 +11,7 @@ authors = [
11
11
  dependencies = [
12
12
  "httpx>=0.23.0, <1",
13
13
  "pydantic>=1.9.0, <3",
14
- "typing-extensions>=4.10, <5",
14
+ "typing-extensions>=4.14, <5",
15
15
  "anyio>=3.5.0, <5",
16
16
  "distro>=1.7.0, <2",
17
17
  "sniffio",
@@ -31,7 +31,8 @@ from ._base_client import (
31
31
  )
32
32
 
33
33
  if TYPE_CHECKING:
34
- from .resources import contexts, projects, sessions, fetch_api, extensions
34
+ from .resources import search, contexts, projects, sessions, fetch_api, extensions
35
+ from .resources.search import SearchResource, AsyncSearchResource
35
36
  from .resources.contexts import ContextsResource, AsyncContextsResource
36
37
  from .resources.projects import ProjectsResource, AsyncProjectsResource
37
38
  from .resources.fetch_api import FetchAPIResource, AsyncFetchAPIResource
@@ -129,6 +130,12 @@ class Browserbase(SyncAPIClient):
129
130
 
130
131
  return ProjectsResource(self)
131
132
 
133
+ @cached_property
134
+ def search(self) -> SearchResource:
135
+ from .resources.search import SearchResource
136
+
137
+ return SearchResource(self)
138
+
132
139
  @cached_property
133
140
  def sessions(self) -> SessionsResource:
134
141
  from .resources.sessions import SessionsResource
@@ -327,6 +334,12 @@ class AsyncBrowserbase(AsyncAPIClient):
327
334
 
328
335
  return AsyncProjectsResource(self)
329
336
 
337
+ @cached_property
338
+ def search(self) -> AsyncSearchResource:
339
+ from .resources.search import AsyncSearchResource
340
+
341
+ return AsyncSearchResource(self)
342
+
330
343
  @cached_property
331
344
  def sessions(self) -> AsyncSessionsResource:
332
345
  from .resources.sessions import AsyncSessionsResource
@@ -476,6 +489,12 @@ class BrowserbaseWithRawResponse:
476
489
 
477
490
  return ProjectsResourceWithRawResponse(self._client.projects)
478
491
 
492
+ @cached_property
493
+ def search(self) -> search.SearchResourceWithRawResponse:
494
+ from .resources.search import SearchResourceWithRawResponse
495
+
496
+ return SearchResourceWithRawResponse(self._client.search)
497
+
479
498
  @cached_property
480
499
  def sessions(self) -> sessions.SessionsResourceWithRawResponse:
481
500
  from .resources.sessions import SessionsResourceWithRawResponse
@@ -513,6 +532,12 @@ class AsyncBrowserbaseWithRawResponse:
513
532
 
514
533
  return AsyncProjectsResourceWithRawResponse(self._client.projects)
515
534
 
535
+ @cached_property
536
+ def search(self) -> search.AsyncSearchResourceWithRawResponse:
537
+ from .resources.search import AsyncSearchResourceWithRawResponse
538
+
539
+ return AsyncSearchResourceWithRawResponse(self._client.search)
540
+
516
541
  @cached_property
517
542
  def sessions(self) -> sessions.AsyncSessionsResourceWithRawResponse:
518
543
  from .resources.sessions import AsyncSessionsResourceWithRawResponse
@@ -550,6 +575,12 @@ class BrowserbaseWithStreamedResponse:
550
575
 
551
576
  return ProjectsResourceWithStreamingResponse(self._client.projects)
552
577
 
578
+ @cached_property
579
+ def search(self) -> search.SearchResourceWithStreamingResponse:
580
+ from .resources.search import SearchResourceWithStreamingResponse
581
+
582
+ return SearchResourceWithStreamingResponse(self._client.search)
583
+
553
584
  @cached_property
554
585
  def sessions(self) -> sessions.SessionsResourceWithStreamingResponse:
555
586
  from .resources.sessions import SessionsResourceWithStreamingResponse
@@ -587,6 +618,12 @@ class AsyncBrowserbaseWithStreamedResponse:
587
618
 
588
619
  return AsyncProjectsResourceWithStreamingResponse(self._client.projects)
589
620
 
621
+ @cached_property
622
+ def search(self) -> search.AsyncSearchResourceWithStreamingResponse:
623
+ from .resources.search import AsyncSearchResourceWithStreamingResponse
624
+
625
+ return AsyncSearchResourceWithStreamingResponse(self._client.search)
626
+
590
627
  @cached_property
591
628
  def sessions(self) -> sessions.AsyncSessionsResourceWithStreamingResponse:
592
629
  from .resources.sessions import AsyncSessionsResourceWithStreamingResponse
@@ -2,7 +2,7 @@ from __future__ import annotations
2
2
 
3
3
  from typing import TYPE_CHECKING, Any, Union, Generic, TypeVar, Callable, cast, overload
4
4
  from datetime import date, datetime
5
- from typing_extensions import Self, Literal
5
+ from typing_extensions import Self, Literal, TypedDict
6
6
 
7
7
  import pydantic
8
8
  from pydantic.fields import FieldInfo
@@ -131,6 +131,10 @@ def model_json(model: pydantic.BaseModel, *, indent: int | None = None) -> str:
131
131
  return model.model_dump_json(indent=indent)
132
132
 
133
133
 
134
+ class _ModelDumpKwargs(TypedDict, total=False):
135
+ by_alias: bool
136
+
137
+
134
138
  def model_dump(
135
139
  model: pydantic.BaseModel,
136
140
  *,
@@ -142,6 +146,9 @@ def model_dump(
142
146
  by_alias: bool | None = None,
143
147
  ) -> dict[str, Any]:
144
148
  if (not PYDANTIC_V1) or hasattr(model, "model_dump"):
149
+ kwargs: _ModelDumpKwargs = {}
150
+ if by_alias is not None:
151
+ kwargs["by_alias"] = by_alias
145
152
  return model.model_dump(
146
153
  mode=mode,
147
154
  exclude=exclude,
@@ -149,7 +156,7 @@ def model_dump(
149
156
  exclude_defaults=exclude_defaults,
150
157
  # warnings are not supported in Pydantic v1
151
158
  warnings=True if PYDANTIC_V1 else warnings,
152
- by_alias=by_alias,
159
+ **kwargs,
153
160
  )
154
161
  return cast(
155
162
  "dict[str, Any]",
@@ -101,7 +101,10 @@ class Querystring:
101
101
  items.extend(self._stringify_item(key, item, opts))
102
102
  return items
103
103
  elif array_format == "indices":
104
- raise NotImplementedError("The array indices format is not supported yet")
104
+ items = []
105
+ for i, item in enumerate(value):
106
+ items.extend(self._stringify_item(f"{key}[{i}]", item, opts))
107
+ return items
105
108
  elif array_format == "brackets":
106
109
  items = []
107
110
  key = key + "[]"
@@ -1,3 +1,4 @@
1
+ from ._path import path_template as path_template
1
2
  from ._sync import asyncify as asyncify
2
3
  from ._proxy import LazyProxy as LazyProxy
3
4
  from ._utils import (
@@ -0,0 +1,127 @@
1
+ from __future__ import annotations
2
+
3
+ import re
4
+ from typing import (
5
+ Any,
6
+ Mapping,
7
+ Callable,
8
+ )
9
+ from urllib.parse import quote
10
+
11
+ # Matches '.' or '..' where each dot is either literal or percent-encoded (%2e / %2E).
12
+ _DOT_SEGMENT_RE = re.compile(r"^(?:\.|%2[eE]){1,2}$")
13
+
14
+ _PLACEHOLDER_RE = re.compile(r"\{(\w+)\}")
15
+
16
+
17
+ def _quote_path_segment_part(value: str) -> str:
18
+ """Percent-encode `value` for use in a URI path segment.
19
+
20
+ Considers characters not in `pchar` set from RFC 3986 §3.3 to be unsafe.
21
+ https://datatracker.ietf.org/doc/html/rfc3986#section-3.3
22
+ """
23
+ # quote() already treats unreserved characters (letters, digits, and -._~)
24
+ # as safe, so we only need to add sub-delims, ':', and '@'.
25
+ # Notably, unlike the default `safe` for quote(), / is unsafe and must be quoted.
26
+ return quote(value, safe="!$&'()*+,;=:@")
27
+
28
+
29
+ def _quote_query_part(value: str) -> str:
30
+ """Percent-encode `value` for use in a URI query string.
31
+
32
+ Considers &, = and characters not in `query` set from RFC 3986 §3.4 to be unsafe.
33
+ https://datatracker.ietf.org/doc/html/rfc3986#section-3.4
34
+ """
35
+ return quote(value, safe="!$'()*+,;:@/?")
36
+
37
+
38
+ def _quote_fragment_part(value: str) -> str:
39
+ """Percent-encode `value` for use in a URI fragment.
40
+
41
+ Considers characters not in `fragment` set from RFC 3986 §3.5 to be unsafe.
42
+ https://datatracker.ietf.org/doc/html/rfc3986#section-3.5
43
+ """
44
+ return quote(value, safe="!$&'()*+,;=:@/?")
45
+
46
+
47
+ def _interpolate(
48
+ template: str,
49
+ values: Mapping[str, Any],
50
+ quoter: Callable[[str], str],
51
+ ) -> str:
52
+ """Replace {name} placeholders in `template`, quoting each value with `quoter`.
53
+
54
+ Placeholder names are looked up in `values`.
55
+
56
+ Raises:
57
+ KeyError: If a placeholder is not found in `values`.
58
+ """
59
+ # re.split with a capturing group returns alternating
60
+ # [text, name, text, name, ..., text] elements.
61
+ parts = _PLACEHOLDER_RE.split(template)
62
+
63
+ for i in range(1, len(parts), 2):
64
+ name = parts[i]
65
+ if name not in values:
66
+ raise KeyError(f"a value for placeholder {{{name}}} was not provided")
67
+ val = values[name]
68
+ if val is None:
69
+ parts[i] = "null"
70
+ elif isinstance(val, bool):
71
+ parts[i] = "true" if val else "false"
72
+ else:
73
+ parts[i] = quoter(str(values[name]))
74
+
75
+ return "".join(parts)
76
+
77
+
78
+ def path_template(template: str, /, **kwargs: Any) -> str:
79
+ """Interpolate {name} placeholders in `template` from keyword arguments.
80
+
81
+ Args:
82
+ template: The template string containing {name} placeholders.
83
+ **kwargs: Keyword arguments to interpolate into the template.
84
+
85
+ Returns:
86
+ The template with placeholders interpolated and percent-encoded.
87
+
88
+ Safe characters for percent-encoding are dependent on the URI component.
89
+ Placeholders in path and fragment portions are percent-encoded where the `segment`
90
+ and `fragment` sets from RFC 3986 respectively are considered safe.
91
+ Placeholders in the query portion are percent-encoded where the `query` set from
92
+ RFC 3986 §3.3 is considered safe except for = and & characters.
93
+
94
+ Raises:
95
+ KeyError: If a placeholder is not found in `kwargs`.
96
+ ValueError: If resulting path contains /./ or /../ segments (including percent-encoded dot-segments).
97
+ """
98
+ # Split the template into path, query, and fragment portions.
99
+ fragment_template: str | None = None
100
+ query_template: str | None = None
101
+
102
+ rest = template
103
+ if "#" in rest:
104
+ rest, fragment_template = rest.split("#", 1)
105
+ if "?" in rest:
106
+ rest, query_template = rest.split("?", 1)
107
+ path_template = rest
108
+
109
+ # Interpolate each portion with the appropriate quoting rules.
110
+ path_result = _interpolate(path_template, kwargs, _quote_path_segment_part)
111
+
112
+ # Reject dot-segments (. and ..) in the final assembled path. The check
113
+ # runs after interpolation so that adjacent placeholders or a mix of static
114
+ # text and placeholders that together form a dot-segment are caught.
115
+ # Also reject percent-encoded dot-segments to protect against incorrectly
116
+ # implemented normalization in servers/proxies.
117
+ for segment in path_result.split("/"):
118
+ if _DOT_SEGMENT_RE.match(segment):
119
+ raise ValueError(f"Constructed path {path_result!r} contains dot-segment {segment!r} which is not allowed")
120
+
121
+ result = path_result
122
+ if query_template is not None:
123
+ result += "?" + _interpolate(query_template, kwargs, _quote_query_part)
124
+ if fragment_template is not None:
125
+ result += "#" + _interpolate(fragment_template, kwargs, _quote_fragment_part)
126
+
127
+ return result
@@ -1,4 +1,4 @@
1
1
  # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
2
2
 
3
3
  __title__ = "browserbase"
4
- __version__ = "1.6.0" # x-release-please-version
4
+ __version__ = "1.8.0" # x-release-please-version
@@ -1,5 +1,13 @@
1
1
  # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
2
2
 
3
+ from .search import (
4
+ SearchResource,
5
+ AsyncSearchResource,
6
+ SearchResourceWithRawResponse,
7
+ AsyncSearchResourceWithRawResponse,
8
+ SearchResourceWithStreamingResponse,
9
+ AsyncSearchResourceWithStreamingResponse,
10
+ )
3
11
  from .contexts import (
4
12
  ContextsResource,
5
13
  AsyncContextsResource,
@@ -66,6 +74,12 @@ __all__ = [
66
74
  "AsyncProjectsResourceWithRawResponse",
67
75
  "ProjectsResourceWithStreamingResponse",
68
76
  "AsyncProjectsResourceWithStreamingResponse",
77
+ "SearchResource",
78
+ "AsyncSearchResource",
79
+ "SearchResourceWithRawResponse",
80
+ "AsyncSearchResourceWithRawResponse",
81
+ "SearchResourceWithStreamingResponse",
82
+ "AsyncSearchResourceWithStreamingResponse",
69
83
  "SessionsResource",
70
84
  "AsyncSessionsResource",
71
85
  "SessionsResourceWithRawResponse",
@@ -6,7 +6,7 @@ import httpx
6
6
 
7
7
  from ..types import context_create_params
8
8
  from .._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given
9
- from .._utils import maybe_transform, async_maybe_transform
9
+ from .._utils import path_template, maybe_transform, async_maybe_transform
10
10
  from .._compat import cached_property
11
11
  from .._resource import SyncAPIResource, AsyncAPIResource
12
12
  from .._response import (
@@ -106,7 +106,7 @@ class ContextsResource(SyncAPIResource):
106
106
  if not id:
107
107
  raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
108
108
  return self._get(
109
- f"/v1/contexts/{id}",
109
+ path_template("/v1/contexts/{id}", id=id),
110
110
  options=make_request_options(
111
111
  extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
112
112
  ),
@@ -139,7 +139,7 @@ class ContextsResource(SyncAPIResource):
139
139
  if not id:
140
140
  raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
141
141
  return self._put(
142
- f"/v1/contexts/{id}",
142
+ path_template("/v1/contexts/{id}", id=id),
143
143
  options=make_request_options(
144
144
  extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
145
145
  ),
@@ -173,7 +173,7 @@ class ContextsResource(SyncAPIResource):
173
173
  raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
174
174
  extra_headers = {"Accept": "*/*", **(extra_headers or {})}
175
175
  return self._delete(
176
- f"/v1/contexts/{id}",
176
+ path_template("/v1/contexts/{id}", id=id),
177
177
  options=make_request_options(
178
178
  extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
179
179
  ),
@@ -264,7 +264,7 @@ class AsyncContextsResource(AsyncAPIResource):
264
264
  if not id:
265
265
  raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
266
266
  return await self._get(
267
- f"/v1/contexts/{id}",
267
+ path_template("/v1/contexts/{id}", id=id),
268
268
  options=make_request_options(
269
269
  extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
270
270
  ),
@@ -297,7 +297,7 @@ class AsyncContextsResource(AsyncAPIResource):
297
297
  if not id:
298
298
  raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
299
299
  return await self._put(
300
- f"/v1/contexts/{id}",
300
+ path_template("/v1/contexts/{id}", id=id),
301
301
  options=make_request_options(
302
302
  extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
303
303
  ),
@@ -331,7 +331,7 @@ class AsyncContextsResource(AsyncAPIResource):
331
331
  raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
332
332
  extra_headers = {"Accept": "*/*", **(extra_headers or {})}
333
333
  return await self._delete(
334
- f"/v1/contexts/{id}",
334
+ path_template("/v1/contexts/{id}", id=id),
335
335
  options=make_request_options(
336
336
  extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
337
337
  ),
@@ -8,7 +8,7 @@ import httpx
8
8
 
9
9
  from ..types import extension_create_params
10
10
  from .._types import Body, Query, Headers, NoneType, NotGiven, FileTypes, not_given
11
- from .._utils import extract_files, maybe_transform, deepcopy_minimal, async_maybe_transform
11
+ from .._utils import extract_files, path_template, maybe_transform, deepcopy_minimal, async_maybe_transform
12
12
  from .._compat import cached_property
13
13
  from .._resource import SyncAPIResource, AsyncAPIResource
14
14
  from .._response import (
@@ -108,7 +108,7 @@ class ExtensionsResource(SyncAPIResource):
108
108
  if not id:
109
109
  raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
110
110
  return self._get(
111
- f"/v1/extensions/{id}",
111
+ path_template("/v1/extensions/{id}", id=id),
112
112
  options=make_request_options(
113
113
  extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
114
114
  ),
@@ -142,7 +142,7 @@ class ExtensionsResource(SyncAPIResource):
142
142
  raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
143
143
  extra_headers = {"Accept": "*/*", **(extra_headers or {})}
144
144
  return self._delete(
145
- f"/v1/extensions/{id}",
145
+ path_template("/v1/extensions/{id}", id=id),
146
146
  options=make_request_options(
147
147
  extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
148
148
  ),
@@ -235,7 +235,7 @@ class AsyncExtensionsResource(AsyncAPIResource):
235
235
  if not id:
236
236
  raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
237
237
  return await self._get(
238
- f"/v1/extensions/{id}",
238
+ path_template("/v1/extensions/{id}", id=id),
239
239
  options=make_request_options(
240
240
  extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
241
241
  ),
@@ -269,7 +269,7 @@ class AsyncExtensionsResource(AsyncAPIResource):
269
269
  raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
270
270
  extra_headers = {"Accept": "*/*", **(extra_headers or {})}
271
271
  return await self._delete(
272
- f"/v1/extensions/{id}",
272
+ path_template("/v1/extensions/{id}", id=id),
273
273
  options=make_request_options(
274
274
  extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
275
275
  ),
@@ -5,6 +5,7 @@ from __future__ import annotations
5
5
  import httpx
6
6
 
7
7
  from .._types import Body, Query, Headers, NotGiven, not_given
8
+ from .._utils import path_template
8
9
  from .._compat import cached_property
9
10
  from .._resource import SyncAPIResource, AsyncAPIResource
10
11
  from .._response import (
@@ -67,7 +68,7 @@ class ProjectsResource(SyncAPIResource):
67
68
  if not id:
68
69
  raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
69
70
  return self._get(
70
- f"/v1/projects/{id}",
71
+ path_template("/v1/projects/{id}", id=id),
71
72
  options=make_request_options(
72
73
  extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
73
74
  ),
@@ -119,7 +120,7 @@ class ProjectsResource(SyncAPIResource):
119
120
  if not id:
120
121
  raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
121
122
  return self._get(
122
- f"/v1/projects/{id}/usage",
123
+ path_template("/v1/projects/{id}/usage", id=id),
123
124
  options=make_request_options(
124
125
  extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
125
126
  ),
@@ -173,7 +174,7 @@ class AsyncProjectsResource(AsyncAPIResource):
173
174
  if not id:
174
175
  raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
175
176
  return await self._get(
176
- f"/v1/projects/{id}",
177
+ path_template("/v1/projects/{id}", id=id),
177
178
  options=make_request_options(
178
179
  extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
179
180
  ),
@@ -225,7 +226,7 @@ class AsyncProjectsResource(AsyncAPIResource):
225
226
  if not id:
226
227
  raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
227
228
  return await self._get(
228
- f"/v1/projects/{id}/usage",
229
+ path_template("/v1/projects/{id}/usage", id=id),
229
230
  options=make_request_options(
230
231
  extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
231
232
  ),