bytekit-sdk 0.3.2__tar.gz → 0.3.5__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 (275) hide show
  1. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/.gitignore +8 -0
  2. bytekit_sdk-0.3.5/CHANGELOG.md +321 -0
  3. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/PKG-INFO +77 -12
  4. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/README.md +76 -11
  5. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/pyproject.toml +32 -2
  6. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/api/account/get_account.py +16 -12
  7. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/api/bulk/create_bulk.py +105 -2
  8. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/api/bulk/delete_bulk.py +3 -5
  9. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/api/bulk/get_bulk.py +3 -5
  10. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/api/bulk/list_bulk_screenshots.py +51 -5
  11. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/api/fetch/get_fetch.py +32 -29
  12. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/api/fetch/post_fetch.py +17 -2
  13. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/api/fetch_bulk/create_fetch_bulk.py +45 -2
  14. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/api/fetch_bulk/get_fetch_bulk.py +47 -5
  15. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/api/monitors/create_monitor.py +13 -2
  16. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/api/monitors/delete_monitor.py +3 -5
  17. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/api/monitors/get_monitor.py +3 -5
  18. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/api/monitors/list_monitor_captures.py +12 -14
  19. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/api/monitors/list_monitors.py +19 -20
  20. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/api/monitors/update_monitor.py +3 -5
  21. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/api/scrape/create_scrape.py +1 -2
  22. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/api/scrape/get_scrape.py +3 -5
  23. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/api/scrape_bulk/create_scrape_bulk.py +1 -2
  24. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/api/scrape_bulk/get_scrape_bulk.py +3 -5
  25. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/api/screenshots/create_screenshot.py +53 -22
  26. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/api/screenshots/get_screenshot.py +3 -5
  27. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/api/search/create_search.py +1 -2
  28. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/api/sitemap/create_sitemap.py +17 -2
  29. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/api/sitemap/get_sitemap.py +7 -5
  30. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/api/usage/get_usage.py +1 -2
  31. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/api/usage/get_usage_by_endpoint.py +1 -2
  32. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/api/usage/get_usage_daily.py +1 -2
  33. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/api/webhooks/list_webhook_deliveries.py +10 -11
  34. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/api/webhooks/retry_webhook_delivery.py +23 -5
  35. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/client.py +129 -18
  36. bytekit_sdk-0.3.5/src/bytekit/errors.py +216 -0
  37. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/__init__.py +22 -6
  38. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/create_bulk_body.py +16 -20
  39. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/create_bulk_body_defaults.py +27 -52
  40. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/create_bulk_body_items_item.py +4 -24
  41. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/create_bulk_response_202.py +21 -8
  42. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/create_fetch_bulk_body.py +6 -6
  43. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/create_fetch_bulk_body_defaults.py +4 -4
  44. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/create_fetch_bulk_body_urls_item_type_1.py +1 -20
  45. bytekit_sdk-0.3.5/src/bytekit/models/create_fetch_bulk_response_202.py +179 -0
  46. bytekit_sdk-0.3.5/src/bytekit/models/create_fetch_bulk_response_202_status.py +10 -0
  47. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/create_scrape_bulk_body_defaults.py +7 -8
  48. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/create_scrape_bulk_body_items_item.py +7 -12
  49. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/create_scrape_bulk_response_202.py +21 -8
  50. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/create_search_body.py +5 -10
  51. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/create_search_response_200_results_item.py +6 -5
  52. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/delete_bulk_response_200.py +17 -8
  53. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/get_bulk_response_200.py +17 -8
  54. bytekit_sdk-0.3.5/src/bytekit/models/get_fetch_bulk_response_200.py +201 -0
  55. bytekit_sdk-0.3.5/src/bytekit/models/get_fetch_bulk_response_200_items_item.py +217 -0
  56. bytekit_sdk-0.3.5/src/bytekit/models/get_fetch_bulk_response_200_items_item_status.py +12 -0
  57. bytekit_sdk-0.3.5/src/bytekit/models/get_fetch_bulk_response_200_status.py +10 -0
  58. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/get_scrape_bulk_response_200.py +17 -8
  59. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/get_usage_response_200.py +2 -2
  60. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/get_usage_response_200_plan_type.py +0 -1
  61. bytekit_sdk-0.3.5/src/bytekit/models/list_bulk_screenshots_response_200.py +100 -0
  62. bytekit_sdk-0.3.5/src/bytekit/models/list_bulk_screenshots_response_200_items_item.py +352 -0
  63. bytekit_sdk-0.3.5/src/bytekit/models/list_bulk_screenshots_response_200_items_item_status.py +12 -0
  64. bytekit_sdk-0.3.5/src/bytekit/models/list_bulk_screenshots_response_200_items_item_type.py +10 -0
  65. bytekit_sdk-0.3.2/CHANGELOG.md +0 -89
  66. bytekit_sdk-0.3.2/src/bytekit/errors.py +0 -106
  67. bytekit_sdk-0.3.2/src/bytekit/models/create_fetch_bulk_body_metadata.py +0 -44
  68. bytekit_sdk-0.3.2/src/bytekit/models/create_fetch_bulk_response_202.py +0 -44
  69. bytekit_sdk-0.3.2/src/bytekit/models/create_scrape_bulk_body_items_item_metadata.py +0 -44
  70. bytekit_sdk-0.3.2/src/bytekit/models/get_fetch_bulk_response_200.py +0 -44
  71. bytekit_sdk-0.3.2/src/bytekit/models/list_bulk_screenshots_response_200.py +0 -44
  72. bytekit_sdk-0.3.2/tests/__init__.py +0 -0
  73. bytekit_sdk-0.3.2/tests/conftest.py +0 -97
  74. bytekit_sdk-0.3.2/tests/fixtures/unpatched_client.py.snapshot +0 -365
  75. bytekit_sdk-0.3.2/tests/fixtures/unpatched_create_scrape.py.snapshot +0 -197
  76. bytekit_sdk-0.3.2/tests/fixtures/unpatched_delete_monitor.py.snapshot +0 -155
  77. bytekit_sdk-0.3.2/tests/fixtures/unpatched_errors.py.snapshot +0 -16
  78. bytekit_sdk-0.3.2/tests/fixtures/unpatched_get_fetch.py.snapshot +0 -254
  79. bytekit_sdk-0.3.2/tests/test_bulk_delete.py +0 -33
  80. bytekit_sdk-0.3.2/tests/test_client.py +0 -121
  81. bytekit_sdk-0.3.2/tests/test_client_defaults.py +0 -122
  82. bytekit_sdk-0.3.2/tests/test_deactivated_resources.py +0 -108
  83. bytekit_sdk-0.3.2/tests/test_generate_docs.py +0 -285
  84. bytekit_sdk-0.3.2/tests/test_models.py +0 -178
  85. bytekit_sdk-0.3.2/tests/test_no_materialized_defaults.py +0 -31
  86. bytekit_sdk-0.3.2/tests/test_op_error_paths.py +0 -360
  87. bytekit_sdk-0.3.2/tests/test_package_identity.py +0 -24
  88. bytekit_sdk-0.3.2/tests/test_patch_functions.py +0 -308
  89. bytekit_sdk-0.3.2/tests/test_prune_stale_api.py +0 -753
  90. bytekit_sdk-0.3.2/tests/test_publish_metadata.py +0 -179
  91. bytekit_sdk-0.3.2/tests/test_readme_examples.py +0 -127
  92. bytekit_sdk-0.3.2/tests/test_regen_durability.py +0 -170
  93. bytekit_sdk-0.3.2/tests/test_removed_surface.py +0 -50
  94. bytekit_sdk-0.3.2/tests/test_scrape_markdown_opts.py +0 -157
  95. bytekit_sdk-0.3.2/tests/test_scrape_scored_formats.py +0 -135
  96. bytekit_sdk-0.3.2/tests/test_sdist_contents.py +0 -182
  97. bytekit_sdk-0.3.2/tests/test_search.py +0 -209
  98. bytekit_sdk-0.3.2/tests/test_search_errors.py +0 -97
  99. bytekit_sdk-0.3.2/tests/test_spec_field_parity.py +0 -106
  100. bytekit_sdk-0.3.2/tests/test_typed_search_surface.py +0 -181
  101. bytekit_sdk-0.3.2/tests/test_usage.py +0 -80
  102. bytekit_sdk-0.3.2/tests/test_version.py +0 -110
  103. bytekit_sdk-0.3.2/tests/test_webhook_deliveries.py +0 -59
  104. bytekit_sdk-0.3.2/tests/test_wheel_contents.py +0 -109
  105. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/LICENSE +0 -0
  106. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/__init__.py +0 -0
  107. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/api/__init__.py +0 -0
  108. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/api/account/__init__.py +0 -0
  109. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/api/bulk/__init__.py +0 -0
  110. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/api/fetch/__init__.py +0 -0
  111. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/api/fetch_bulk/__init__.py +0 -0
  112. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/api/monitors/__init__.py +0 -0
  113. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/api/scrape/__init__.py +0 -0
  114. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/api/scrape_bulk/__init__.py +0 -0
  115. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/api/screenshots/__init__.py +0 -0
  116. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/api/search/__init__.py +0 -0
  117. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/api/sitemap/__init__.py +0 -0
  118. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/api/usage/__init__.py +0 -0
  119. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/api/webhooks/__init__.py +0 -0
  120. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/account_bearer_response.py +0 -0
  121. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/account_bearer_response_api_key.py +0 -0
  122. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/account_bearer_response_api_key_environment.py +0 -0
  123. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/account_bearer_response_auto_topup.py +0 -0
  124. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/account_bearer_response_plan.py +0 -0
  125. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/account_bearer_response_subscription.py +0 -0
  126. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/account_bearer_response_subscription_plan.py +0 -0
  127. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/account_bearer_response_subscription_status.py +0 -0
  128. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/account_session_response.py +0 -0
  129. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/account_session_response_notifications.py +0 -0
  130. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/account_session_response_plan.py +0 -0
  131. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/bandwidth_balance.py +0 -0
  132. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/capture_response.py +0 -0
  133. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/capture_response_outcome.py +0 -0
  134. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/clip.py +0 -0
  135. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/cookie.py +0 -0
  136. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/create_bulk_body_defaults_device.py +0 -0
  137. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/create_bulk_body_defaults_device_scale_factor_type_1.py +0 -0
  138. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/create_bulk_body_defaults_device_scale_factor_type_2_type_1.py +0 -0
  139. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/create_bulk_body_defaults_device_scale_factor_type_3_type_1.py +0 -0
  140. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/create_bulk_body_defaults_formats_item.py +0 -0
  141. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/create_bulk_body_defaults_type.py +0 -0
  142. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/create_bulk_body_defaults_viewport_type_0.py +0 -0
  143. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/create_bulk_body_defaults_wait_until.py +0 -0
  144. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/create_bulk_body_items_item_device.py +0 -0
  145. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/create_bulk_body_items_item_formats_item.py +0 -0
  146. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/create_bulk_body_items_item_scenario.py +0 -0
  147. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/create_bulk_body_items_item_type.py +0 -0
  148. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/create_bulk_body_items_item_viewport_type_0.py +0 -0
  149. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/create_bulk_body_items_item_wait_until.py +0 -0
  150. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/create_bulk_response_202_status.py +0 -0
  151. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/create_fetch_bulk_body_defaults_format.py +0 -0
  152. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/create_fetch_bulk_body_urls_item_type_1_format.py +0 -0
  153. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/create_scrape_bulk_body.py +0 -0
  154. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/create_scrape_bulk_body_custom.py +0 -0
  155. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/create_scrape_bulk_body_defaults_formats_item.py +0 -0
  156. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/create_scrape_bulk_body_defaults_headers.py +0 -0
  157. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/create_scrape_bulk_body_items_item_custom.py +0 -0
  158. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/create_scrape_bulk_body_items_item_formats_item.py +0 -0
  159. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/create_scrape_bulk_body_items_item_headers.py +0 -0
  160. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/create_scrape_bulk_response_202_status.py +0 -0
  161. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/create_search_body_date_range.py +0 -0
  162. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/create_search_body_type.py +0 -0
  163. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/create_search_response_200.py +0 -0
  164. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/create_search_response_200_results_item_image.py +0 -0
  165. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/create_search_response_502.py +0 -0
  166. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/create_search_response_502_error.py +0 -0
  167. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/credit_balance.py +0 -0
  168. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/delete_bulk_response_200_status.py +0 -0
  169. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/error.py +0 -0
  170. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/error_error.py +0 -0
  171. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/error_status.py +0 -0
  172. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/fetch_request.py +0 -0
  173. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/fetch_request_cache_ttl_type_1.py +0 -0
  174. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/fetch_request_custom.py +0 -0
  175. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/fetch_request_format.py +0 -0
  176. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/fetch_request_markdown_images.py +0 -0
  177. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/fetch_request_markdown_links.py +0 -0
  178. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/fetch_request_markdown_mode.py +0 -0
  179. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/get_bulk_response_200_status.py +0 -0
  180. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/get_fetch_cache_ttl_type_1.py +0 -0
  181. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/get_fetch_format.py +0 -0
  182. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/get_scrape_bulk_response_200_status.py +0 -0
  183. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/get_usage_by_endpoint_response_200.py +0 -0
  184. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/get_usage_by_endpoint_response_200_rows_item.py +0 -0
  185. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/get_usage_by_endpoint_response_200_rows_item_endpoint.py +0 -0
  186. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/get_usage_by_endpoint_response_200_totals.py +0 -0
  187. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/get_usage_daily_response_200.py +0 -0
  188. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/get_usage_daily_response_200_data_item.py +0 -0
  189. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/list_monitor_captures_response_200.py +0 -0
  190. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/list_monitors_response_200.py +0 -0
  191. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/list_monitors_status.py +0 -0
  192. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/list_webhook_deliveries_response_200.py +0 -0
  193. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/list_webhook_deliveries_status.py +0 -0
  194. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/metadata.py +0 -0
  195. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/monitor_create_request.py +0 -0
  196. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/monitor_create_request_interval_type.py +0 -0
  197. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/monitor_create_request_notify_on.py +0 -0
  198. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/monitor_create_request_options.py +0 -0
  199. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/monitor_create_request_scrape_options.py +0 -0
  200. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/monitor_create_request_type.py +0 -0
  201. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/monitor_create_request_webhook_headers.py +0 -0
  202. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/monitor_create_response.py +0 -0
  203. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/monitor_response.py +0 -0
  204. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/monitor_response_interval_type.py +0 -0
  205. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/monitor_response_metadata_type_0.py +0 -0
  206. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/monitor_response_status.py +0 -0
  207. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/monitor_response_type.py +0 -0
  208. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/monitor_response_webhook_headers_type_0.py +0 -0
  209. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/monitor_update_request.py +0 -0
  210. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/monitor_update_request_interval_type.py +0 -0
  211. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/monitor_update_request_notify_on.py +0 -0
  212. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/monitor_update_request_options.py +0 -0
  213. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/monitor_update_request_scrape_options.py +0 -0
  214. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/monitor_update_request_status.py +0 -0
  215. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/monitor_update_request_webhook_headers.py +0 -0
  216. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/scrape_error_envelope.py +0 -0
  217. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/scrape_error_envelope_error.py +0 -0
  218. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/scrape_error_envelope_error_code.py +0 -0
  219. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/scrape_error_envelope_schema_version.py +0 -0
  220. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/scrape_error_envelope_status.py +0 -0
  221. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/scrape_formats.py +0 -0
  222. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/scrape_markdown_tokens.py +0 -0
  223. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/scrape_metadata.py +0 -0
  224. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/scrape_queued_envelope.py +0 -0
  225. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/scrape_queued_envelope_schema_version.py +0 -0
  226. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/scrape_queued_envelope_status.py +0 -0
  227. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/scrape_request.py +0 -0
  228. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/scrape_request_cache_ttl_type_1.py +0 -0
  229. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/scrape_request_custom.py +0 -0
  230. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/scrape_request_events_item.py +0 -0
  231. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/scrape_request_formats_item.py +0 -0
  232. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/scrape_request_headers.py +0 -0
  233. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/scrape_request_markdown_images.py +0 -0
  234. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/scrape_request_markdown_links.py +0 -0
  235. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/scrape_request_markdown_mode.py +0 -0
  236. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/scrape_request_token_encoding.py +0 -0
  237. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/scrape_request_x_internal_scrape_path.py +0 -0
  238. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/scrape_scored_image.py +0 -0
  239. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/scrape_scored_link.py +0 -0
  240. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/scrape_stats.py +0 -0
  241. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/scrape_success_envelope.py +0 -0
  242. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/scrape_success_envelope_cache.py +0 -0
  243. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/scrape_success_envelope_custom.py +0 -0
  244. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/scrape_success_envelope_schema_version.py +0 -0
  245. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/scrape_success_envelope_status.py +0 -0
  246. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/scrape_table.py +0 -0
  247. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/scrape_table_kind.py +0 -0
  248. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/scrape_warning.py +0 -0
  249. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/scrape_warning_code.py +0 -0
  250. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/screenshot_request.py +0 -0
  251. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/screenshot_request_device.py +0 -0
  252. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/screenshot_request_device_scale_factor_type_1.py +0 -0
  253. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/screenshot_request_device_scale_factor_type_2_type_1.py +0 -0
  254. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/screenshot_request_device_scale_factor_type_3_type_1.py +0 -0
  255. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/screenshot_request_format.py +0 -0
  256. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/screenshot_request_headers.py +0 -0
  257. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/screenshot_request_wait_until.py +0 -0
  258. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/screenshot_response.py +0 -0
  259. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/screenshot_response_status.py +0 -0
  260. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/sitemap_request.py +0 -0
  261. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/sitemap_request_process_type_0.py +0 -0
  262. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/sitemap_request_process_type_0_options.py +0 -0
  263. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/sitemap_request_strategy.py +0 -0
  264. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/sitemap_response.py +0 -0
  265. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/sitemap_response_cache.py +0 -0
  266. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/sitemap_response_metadata_type_0.py +0 -0
  267. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/sitemap_response_process_type_0.py +0 -0
  268. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/sitemap_response_sources_type_0.py +0 -0
  269. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/sitemap_response_status.py +0 -0
  270. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/viewport.py +0 -0
  271. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/webhook_delivery_response.py +0 -0
  272. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/webhook_delivery_response_event_type.py +0 -0
  273. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/models/webhook_delivery_response_status.py +0 -0
  274. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/py.typed +0 -0
  275. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.5}/src/bytekit/types.py +0 -0
@@ -47,6 +47,14 @@ packages/http-fetcher/server
47
47
  packages/http-fetcher/browserforge-bench
48
48
  __pycache__/
49
49
  *.pyc
50
+ # ruff's incremental cache. Written by the openapi-python-client post-hooks INSIDE the
51
+ # generated output dir (packages/sdk-python/src/bytekit/.ruff_cache/). ruff already drops a
52
+ # self-ignoring `.gitignore` containing `*` in there, which is exactly why the directory went
53
+ # unnoticed for so long — `git status` never mentions it. This entry is belt-and-braces so the
54
+ # by-product is ignored even if ruff stops self-ignoring. The reproducibility gate
55
+ # (ci/scripts/check-sdk-python-regen.sh) excludes it from BOTH of its diffs: cache entry names
56
+ # are hashes of the absolute path, so two clean-room generates differ by construction.
57
+ .ruff_cache/
50
58
  # Generated artifact — reproduced via `pnpm --filter @rapidcrawl/sdk-python generate`
51
59
  packages/sdk-python/filtered-openapi.yaml
52
60
  # NOTE: the MCP server's generated docs JSON (see packages/mcp-server/src) is intentionally
@@ -0,0 +1,321 @@
1
+ # Changelog
2
+
3
+ All notable changes to the ByteKit Python SDK are documented here.
4
+ PyPI distribution: `bytekit-sdk`. Import name: `bytekit`.
5
+
6
+ ## 0.3.5
7
+
8
+ ### Breaking
9
+
10
+ - **`AuthenticatedClient` takes no positional arguments.** `token`, `prefix` and
11
+ `auth_header_name` are now keyword-only, joining `base_url`, `timeout`,
12
+ `raise_on_unexpected_status` and the rest — so `AuthenticatedClient(...)` accepts keywords
13
+ only. Before 0.3.0 the first positional argument was `base_url`, which made
14
+ `AuthenticatedClient("https://api-stg.bytekit.com", "sk_live_…")` a documented call. When
15
+ 0.3.0 made `base_url` a defaulted keyword argument, that call stopped meaning what it said
16
+ and started **binding the URL to `token` and the API key to `prefix`** — sending
17
+ `Authorization: sk_live_… https://api-stg.bytekit.com` to the _default_ host,
18
+ `https://api.bytekit.com`, with nothing raised and nothing warned. It now raises
19
+ `TypeError`. Migration is mechanical:
20
+ `AuthenticatedClient(base_url="https://api-stg.bytekit.com", token="sk_live_…")`. Keyword
21
+ construction — the form the README, the docs site and every example already use — is
22
+ entirely unchanged, including `prefix=`/`auth_header_name=` overrides and the
23
+ `with_headers`/`with_cookies`/`with_timeout` helpers. The unauthenticated `Client` was
24
+ already keyword-only and is unaffected.
25
+
26
+ ### Fixed
27
+
28
+ - **A schema-drifted response body no longer crashes with a bare `KeyError`.** A generated
29
+ model's `from_dict` trusts the `required` keys the OpenAPI spec declared when the client
30
+ was generated, so a server that renamed, dropped or retyped a field leaked the generator's
31
+ own internal exception straight to the caller — `KeyError: 'schema_version'` from
32
+ `create_scrape`, `KeyError: 'period_start'` from `get_usage`, `KeyError: 'data'` from
33
+ `list_monitors`, plus `TypeError`/`ValueError` for non-object and nested-drift bodies. It
34
+ happened on a **documented** status (a `200`/`202`), in **both** raise modes, and no row of
35
+ the documented error table covered it, so a caller who handled that table faithfully still
36
+ had no branch for it. Schema drift now takes exactly the same two arms as a non-JSON body:
37
+ `errors.UnexpectedStatus` (carrying `.status_code` and the raw `.content`, with the
38
+ original parse failure attached as `__cause__`) in the default mode, and `None` under
39
+ `raise_on_unexpected_status=False`. Deliberately **no new exception type** — a new class
40
+ would be one every existing `except errors.UnexpectedStatus` silently fails to catch, i.e.
41
+ the same untyped crash in a different costume. Bodies that match the documented schema
42
+ parse exactly as before, and a genuinely optional key that is absent still yields `UNSET`.
43
+ - **`client.search()` never returns a silent `None`.** Its 200 body is parsed through the
44
+ same shared guard the generated operations use, which honors
45
+ `raise_on_unexpected_status` — so an opt-out client got `None` handed back from a non-JSON
46
+ 200 or a schema-drifted one, contradicting both the method's non-`Optional` return
47
+ annotation and its own docstring. `search()` now raises `errors.UnexpectedStatus` in
48
+ **both** raise modes. `raise_on_unexpected_status` configures the generated two-tier
49
+ contract, whose signatures are `Optional[...]`; `search()` was never part of it — it
50
+ already raises on documented error statuses that the generated `create_search` returns as
51
+ a typed `Error` model. A well-formed 200 still returns the parsed
52
+ `CreateSearchResponse200` in either mode.
53
+ - **A non-IANA HTTP status no longer crashes every operation with a bare `ValueError`.**
54
+ Each generated operation built its `Response` with
55
+ `status_code=HTTPStatus(response.status_code)` evaluated _before_ the response was
56
+ parsed, so any status outside Python's `http.HTTPStatus` — Cloudflare's `520`–`530`
57
+ family, nginx's `499` — raised `ValueError: 520 is not a valid HTTPStatus` from inside
58
+ the SDK. This happened in **both** raise modes: the default
59
+ `raise_on_unexpected_status=True` never got to raise its `errors.UnexpectedStatus`, and
60
+ `raise_on_unexpected_status=False`, which promises `None`, raised the `ValueError` too.
61
+ `api.bytekit.com` is served through Cloudflare, so this was exactly the edge/CDN failure
62
+ class the typed-error contract exists for. All 29 operations now behave as documented:
63
+ `errors.UnexpectedStatus` (carrying `.status_code` and the raw `.content`) in the default
64
+ mode, a `Response` with `.parsed is None` in the opt-out mode. The hand-written
65
+ `client.search()` wrapper was never affected and is unchanged.
66
+
67
+ ### Changed
68
+
69
+ - **`Response.status_code` is a plain `int` for a status `http.HTTPStatus` does not know.**
70
+ This is the contract decision behind the fix above, recorded here because it is the one
71
+ observable difference in the typed surface. Concretely:
72
+ - Every status the stdlib enum **does** know — documented by the API or not, `200` as
73
+ much as `503` — still comes back as a real `http.HTTPStatus` member, so
74
+ `response.status_code.phrase`, `.name`, and identity comparisons such as
75
+ `response.status_code is HTTPStatus.OK` keep working exactly as before.
76
+ - A status the enum does **not** know (`499`, `520`, `521`, `522`, `530`, …) comes back
77
+ as the plain `int` the wire carried. `int` comparisons (`response.status_code == 520`,
78
+ `>= 500`) work; enum-only attributes (`.phrase`, `.name`) do not exist on it. The
79
+ alternatives were rejected deliberately: a synthetic `IntEnum` member would invent a
80
+ `.phrase`/`.name` no registry backs, and raising before the `Response` is constructed
81
+ is the bug itself — it is precisely what `raise_on_unexpected_status=False` promises
82
+ not to do.
83
+ - The **declared** annotation on `Response.status_code` is unchanged (`HTTPStatus`), so
84
+ this release adds no type errors to existing consumer code; widening it to
85
+ `Union[HTTPStatus, int]` would make `.phrase`/`.name` a type error on _every_ response,
86
+ including the IANA ones, which is a far larger break than the residual it would close.
87
+ Reach for `.phrase`/`.name` only after an `isinstance(..., HTTPStatus)` check if you
88
+ handle edge statuses off a non-raising client.
89
+
90
+ In the default (raising) mode this is largely invisible: a non-IANA status raises
91
+ `errors.UnexpectedStatus` before any `Response` is returned, and
92
+ `UnexpectedStatus.status_code` has always been a plain `int`.
93
+
94
+ ### Documentation
95
+
96
+ - The "Error handling" example in the README now requests `formats=[…MARKDOWN]` explicitly.
97
+ Run literally, its success arm printed `<bytekit.types.Unset object at 0x…>`: the snippet
98
+ built `ScrapeRequest(url=...)` with no `formats`, so the server applied its `raw_html`
99
+ default and `result.formats.markdown` was legitimately unset. The same class of defect
100
+ 0.3.3 fixed in the quick start, in the block directly beneath it. The README's error table
101
+ gains the schema-drift row, a note that `search()` is outside the two-tier contract, and a
102
+ migration note for the keyword-only constructor.
103
+
104
+ ## 0.3.4
105
+
106
+ ### Breaking
107
+
108
+ - **`CreateBulkBody`, `CreateBulkBodyDefaults`, `CreateBulkBodyItemsItem`, and
109
+ `CreateFetchBulkBodyUrlsItemType1` lost their additional-properties mapping API.**
110
+ `docs/api/openapi.yaml`'s `/v1/bulk` request schema declares `additionalProperties: false`
111
+ on the top-level body, `items[]`, and `defaults` (issue #2641), and `/v1/fetch/bulk`'s
112
+ per-item override schema inside `urls[]` declares the same (issue #2648), matching the
113
+ gateway's own `.strict()` validators. The code generator responds to
114
+ `additionalProperties: false` by omitting the catch-all mapping it otherwise attaches to
115
+ every generated model, so these four models no longer expose `additional_properties`, the
116
+ `additional_keys` property, `__getitem__`, `__setitem__`, `__delitem__`, or `__contains__`.
117
+ Code that did `body["some_key"] = value`, `"some_key" in body`, or read
118
+ `body.additional_keys` on any of these four models will now raise
119
+ `AttributeError`/`TypeError` instead. Use the model's declared `attrs` fields directly
120
+ instead (e.g. `CreateBulkBodyItemsItem(url=..., type=...)`,
121
+ `CreateFetchBulkBodyUrlsItemType1(url=..., format_=...)`); the server itself now rejects
122
+ unrecognized keys on these endpoints with `422 validation_error`, so the removed escape
123
+ hatch could never have reached the API successfully anyway. This is scoped to the four
124
+ `create_bulk_body*` / `create_fetch_bulk_body_urls_item_type_1` models — no other generated
125
+ model is affected.
126
+
127
+ - If you are upgrading from 0.3.2 or earlier, note that **0.3.3 also carried a breaking model
128
+ removal** that went undocumented at the time — see the "Breaking" entry under 0.3.3 below
129
+ (`CreateFetchBulkBodyMetadata` and `CreateScrapeBulkBodyItemsItemMetadata`).
130
+
131
+ ## 0.3.3 [NEVER PUBLISHED]
132
+
133
+ > **Never published to PyPI.** This version was cut in-tree but no `bytekit-sdk` 0.3.3 artifact
134
+ > exists — `pip install bytekit-sdk==0.3.3` fails. Everything below shipped to users in **0.3.4**,
135
+ > which is the first published release containing it. Reconciled by issue #2680; the
136
+ > `release-drift` CI gate now blocks a new phantom heading from being introduced.
137
+
138
+ ### Breaking
139
+
140
+ - **`CreateFetchBulkBodyMetadata` and `CreateScrapeBulkBodyItemsItemMetadata` were removed;
141
+ both fields now use the shared `Metadata` model.** This landed with the default-stripping
142
+ traversal fix listed under "Fixed" below (issue #2592) and was not recorded at the time.
143
+ Once server defaults stopped being materialized into the request-direction schemas, the two
144
+ per-body `metadata` objects became structurally identical to the shared `Metadata`
145
+ component, and the code generator emits one model per distinct schema — so
146
+ `bytekit.models.create_fetch_bulk_body_metadata` and
147
+ `bytekit.models.create_scrape_bulk_body_items_item_metadata` no longer exist and importing
148
+ either raises `ModuleNotFoundError`. `CreateFetchBulkBody.metadata` and
149
+ `CreateScrapeBulkBodyItemsItem.metadata` are now typed `Union[Unset, Metadata]`. The wire
150
+ format is **unchanged** — the same JSON object is sent either way — so the migration is
151
+ purely at the import site: `from bytekit.models.metadata import Metadata`, then
152
+ `Metadata(...)` (or `Metadata.from_dict({...})`) wherever you constructed one of the two
153
+ removed classes.
154
+
155
+ ### Security
156
+
157
+ - **Path parameters are now percent-encoded.** All 13 operations that interpolate an id into
158
+ their URL (`get_scrape`, `get_screenshot`, `get_bulk`, `delete_bulk`,
159
+ `list_bulk_screenshots`, `get_scrape_bulk`, `get_fetch_bulk`, `get_monitor`,
160
+ `update_monitor`, `delete_monitor`, `list_monitor_captures`, `get_sitemap`,
161
+ `retry_webhook_delivery`) previously interpolated the value raw, so an id containing `/`,
162
+ `?`, `#` or traversal segments could retarget the request to a **different path on the same
163
+ authenticated host** — e.g. a `DELETE /v1/bulk/{id}` becoming a delete against another
164
+ resource. Values are now encoded with `quote(str(value), safe="")`. This is **not** a
165
+ breaking change for any id the API issues: hex and `sc_`/`ss_`/`mon_`/`sm_`/`bulk_`-prefixed
166
+ ids contain no reserved characters, so the resulting URL is byte-identical to before.
167
+ No id-format validation was added — the client does not reject id shapes.
168
+
169
+ ### Fixed
170
+
171
+ - **Reusing one client across several `asyncio.run(...)` calls no longer raises
172
+ `RuntimeError: Event loop is closed`.** An `httpx.AsyncClient`'s connection pool belongs to
173
+ the event loop that created it, and the SDK cached its internal async client
174
+ unconditionally. It now tracks which loop that client was built on and transparently
175
+ rebuilds it when the running loop changes, re-applying `base_url`, headers, timeout,
176
+ `httpx_args` and authentication. Behavior is unchanged when no loop is running, and a client
177
+ you supply via `set_async_httpx_client(...)` is **never** rebuilt or closed — it stays yours
178
+ to manage. See the README's new "Clients and event loops" section.
179
+ - **The README quick start now prints markdown instead of an `Unset` placeholder.** It
180
+ requested no `formats`, so the server applied its `raw_html` default and
181
+ `result.formats.markdown` was legitimately unset. It now asks for
182
+ `formats=[ScrapeRequestFormatsItem.MARKDOWN]` — note `formats` takes enum members, not plain
183
+ strings.
184
+ - **`client.search(type="images")` no longer crashes with a bare `KeyError: 'snippet'`.**
185
+ The OpenAPI spec's search result-item schema declared `snippet` as `required` while its
186
+ own description said the key is omitted for `images` results — a self-contradiction the
187
+ code generator trusted literally, so `CreateSearchResponse200ResultsItem.from_dict`
188
+ unconditionally did `d.pop("snippet")`. `snippet` (like `date`) is now `Union[Unset, str]`,
189
+ matching the real gateway behavior (`web`/`news` results still always carry `snippet`;
190
+ `images` results omit it entirely) — fixed at the spec level (`docs/api/openapi.yaml`) and
191
+ regenerated, not patched in the generated model. (Issue #2579.)
192
+ - **Server defaults are no longer materialized into request wire bodies/query strings
193
+ for inline request bodies and `$ref`'d parameters.** `scripts/filter-spec.ts`'s
194
+ default-stripping traversal previously only followed `$ref`'d request-body component
195
+ schemas, so `ScrapeRequest`/`FetchRequest` were clean but every other request-direction
196
+ shape kept baking in server defaults: `/v1/search`'s fully-inline body (`type`,
197
+ `limit`, `country`, `language`, `date_range`), all three bulk endpoints' bodies and
198
+ their nested `Defaults`/`ItemsItem` models, and `$ref`'d query parameters
199
+ (`GET /v1/fetch`'s `country`/`timeout_ms`/`cache_ttl`, `list_monitors`'
200
+ `limit`/`status`, `list_webhook_deliveries`'/`list_monitor_captures`' `limit`,
201
+ `create_screenshot`'s `async`). The traversal now walks inline request bodies AND
202
+ parameters (both operation-level and shared path-item-level, `$ref`'d or inline)
203
+ before generation, so an omitted optional field always serializes to nothing and
204
+ the server's own default applies — caller-supplied values are unaffected and still
205
+ serialize exactly as given (issue #2592).
206
+ - `tests/test_no_materialized_defaults.py` rewritten to enumerate every
207
+ request-direction model and operation parameter programmatically (walking the
208
+ generated `bytekit.api`/`bytekit.models` trees) instead of sampling two known-clean
209
+ models, so a newly introduced leaker is caught automatically.
210
+
211
+ ### Changed
212
+
213
+ - **The source distribution no longer ships `tests/`.** The bundled suite could not be
214
+ collected from an unpacked sdist: 12 of its 27 modules require the repository's codegen
215
+ scripts or the canonical OpenAPI spec, neither of which belongs in a published
216
+ distribution, and three of them build distributions of the package itself. Nothing
217
+ importable was removed — the **wheel is unchanged**, `py.typed` included, so
218
+ `pip install bytekit-sdk` is unaffected.
219
+
220
+ ### Internal
221
+
222
+ - CI now proves the committed client is reproducible from the canonical OpenAPI spec, and that
223
+ the generation chain is deterministic (generating twice yields byte-identical output). This
224
+ closes the gap where a spec change could land with a TypeScript-only regeneration and leave
225
+ the Python client silently stranded on an older spec.
226
+ - `ruff` is now pinned to an exact version alongside the code generator. The generator runs
227
+ `ruff` over everything it emits, so it — not the generator alone — determines the committed
228
+ bytes; the generator itself accepts any `ruff<0.13`, which meant a fresh install could
229
+ reformat the whole tree. Bumping the pin is a deliberate, reviewed reformat.
230
+ - The PEP 561 `py.typed` marker is now emitted by the post-generation injector rather than
231
+ hand-maintained inside the generated tree (the generator omits it under `--meta none`).
232
+
233
+ ## 0.3.2
234
+
235
+ ### Added
236
+
237
+ - **`bytekit.__version__`** reports the installed distribution version, resolved at import
238
+ time from `importlib.metadata` (so it can never drift from `pyproject.toml`'s
239
+ `[project].version`). When the package is imported from a source tree with no installed
240
+ distribution it reads `0.0.0.dev0` rather than raising. The dead version override in
241
+ `sdk-python-config.yaml` — inert under `--meta none` and contradicting the real
242
+ version — has been removed, leaving one authoritative version.
243
+
244
+ ### Fixed
245
+
246
+ - **`AuthenticatedClient.search()` is now visible to type checkers.** It was attached to the
247
+ class after creation, so despite the package shipping a `py.typed` marker, `mypy` and
248
+ `pyright` reported `"AuthenticatedClient" has no attribute "search"`. It is now declared as a
249
+ real method in the class body that delegates to the same implementation: **runtime behavior,
250
+ arguments, return type and raised errors are unchanged** — only the static surface is fixed.
251
+
252
+ ## 0.3.1 [NEVER PUBLISHED]
253
+
254
+ > **Never published to PyPI.** This version was cut in-tree but no `bytekit-sdk` 0.3.1 artifact
255
+ > exists — `pip install bytekit-sdk==0.3.1` fails. Everything below shipped to users in **0.3.2**,
256
+ > which is the first published release containing it. Reconciled by issue #2680; the
257
+ > `release-drift` CI gate now blocks a new phantom heading from being introduced.
258
+
259
+ ### Fixed
260
+
261
+ - **The "never a bare `json.JSONDecodeError`" guarantee is now package-wide across all
262
+ generated operations**, not only the `AuthenticatedClient.search()` wrapper. Every
263
+ generated operation previously called `response.json()` unconditionally on a
264
+ DOCUMENTED status, so a `500`/`502` serving an HTML load-balancer page raised a bare
265
+ `json.JSONDecodeError` from inside the SDK. All operations now parse documented
266
+ statuses through a shared guard: a non-JSON body raises the typed
267
+ `errors.UnexpectedStatus` (or returns `None` when
268
+ `raise_on_unexpected_status=False`), carrying the status code and the raw body.
269
+ - **`errors.UnexpectedStatus.code` / `.message` are now populated for generated
270
+ operations too**, from the documented `Error` envelope — previously they were always
271
+ `None` outside `search()`. A string-valued `error` (the masked search-provider `502`)
272
+ still never enriches, so the upstream provider's identity is never surfaced.
273
+ - Behavior on JSON bodies is unchanged: JSON success bodies still parse into their typed
274
+ success models, documented JSON error bodies are still **returned** as typed `Error`
275
+ models rather than raised, and `raise_on_unexpected_status` semantics are untouched.
276
+ The documented non-JSON success paths — `get_fetch`/`post_fetch`'s raw-text `200` and
277
+ `delete_monitor`'s empty `204` — are likewise unaffected.
278
+ - **README error documentation corrected.** The quick-start example wrapped a call in
279
+ `try/except UnexpectedStatus` and then read `response.formats.markdown`, but a
280
+ documented `4xx` _returns_ a typed `Error` model without raising — so the documented
281
+ example failed with `AttributeError: 'Error' object has no attribute 'formats'`. The
282
+ README now documents the real two-tier contract, and the snippet is executed by
283
+ `tests/test_readme_examples.py` so it cannot silently drift again.
284
+
285
+ ### Documentation
286
+
287
+ - Removed the contributor-only `Publishing`, `Regenerating`, and `Development` sections
288
+ from the published README (the PyPI long description) — they described internal CI
289
+ mechanics and a monorepo-contributor workflow that do not belong on a public package
290
+ index. The regeneration/development knowledge is preserved in-repo in
291
+ `packages/sdk-python/CLAUDE.md` (not shipped in the distribution).
292
+ - Added a `## License` section and a `LICENSE` file, matching the npm sibling packages.
293
+
294
+ ## 0.3.0
295
+
296
+ ### Breaking
297
+
298
+ - **PyPI distribution renamed `bytekit` -> `bytekit-sdk`.** PyPI administratively
299
+ denylists the bare name `bytekit`, so the package installs as
300
+ `pip install bytekit-sdk`. The **import name is unchanged** — `import bytekit`
301
+ still works, and no module path moved. Nothing was ever published under the old
302
+ distribution name, so there is no migration for existing installs.
303
+ - **`raise_on_unexpected_status` now defaults to `True`.** Undocumented response
304
+ statuses now raise `errors.UnexpectedStatus` instead of silently returning `None`.
305
+ Callers that relied on the old `None`-return behavior must pass
306
+ `raise_on_unexpected_status=False` explicitly to opt out.
307
+ - **`base_url` is now a keyword-only argument.** It gained a default
308
+ (`https://api.bytekit.com`), and to satisfy attrs field ordering it became
309
+ keyword-only. Any caller passing `base_url` positionally must switch to the
310
+ `base_url=` keyword form. (`base_url=` was already the documented usage.)
311
+
312
+ ### Added
313
+
314
+ - `AuthenticatedClient(token=...)` now works out of the box against production:
315
+ `base_url` defaults to `https://api.bytekit.com`.
316
+ - Finite default request timeout of `120s` (`httpx.Timeout(120.0)`) — requests no
317
+ longer hang indefinitely. Override with `timeout=`.
318
+ - `errors.UnexpectedStatus` now carries optional `.code` / `.message` attributes.
319
+ The `AuthenticatedClient.search()` wrapper populates them from the documented
320
+ `Error` envelope, and safely raises a typed error (never a bare
321
+ `json.JSONDecodeError`) on a non-JSON documented-status body such as an HTML 502.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: bytekit-sdk
3
- Version: 0.3.2
3
+ Version: 0.3.5
4
4
  Summary: Official Python SDK for the ByteKit API
5
5
  Project-URL: Homepage, https://bytekit.com
6
6
  Project-URL: Repository, https://github.com/Hunt-Labs-Inc/ByteKit
@@ -46,16 +46,24 @@ The installed version is available as `bytekit.__version__`.
46
46
  from bytekit import AuthenticatedClient
47
47
  from bytekit.api.scrape import create_scrape
48
48
  from bytekit.models.scrape_request import ScrapeRequest
49
+ from bytekit.models.scrape_request_formats_item import ScrapeRequestFormatsItem
49
50
  from bytekit.models.scrape_success_envelope import ScrapeSuccessEnvelope
50
51
 
51
52
  # base_url defaults to https://api.bytekit.com, so only the token is required.
52
53
  client = AuthenticatedClient(token="sk_live_your_api_key_here")
53
54
 
54
- result = create_scrape.sync(client=client, body=ScrapeRequest(url="https://example.com"))
55
+ result = create_scrape.sync(
56
+ client=client,
57
+ body=ScrapeRequest(
58
+ url="https://example.com",
59
+ # Ask for markdown explicitly. `formats` is a list of enum members, not plain
60
+ # strings. Omit it and the server returns raw HTML instead, leaving
61
+ # `formats.markdown` unset.
62
+ formats=[ScrapeRequestFormatsItem.MARKDOWN],
63
+ ),
64
+ )
55
65
 
56
66
  if isinstance(result, ScrapeSuccessEnvelope):
57
- # formats.markdown is str | Unset — only set when "markdown" was among the
58
- # requested formats.
59
67
  print(result.formats.markdown)
60
68
  ```
61
69
 
@@ -64,13 +72,22 @@ See [Error handling](#error-handling) for what `result` can be when the request
64
72
  ### Error handling
65
73
 
66
74
  The SDK has a **two-tier** error contract. Both tiers are safe: an operation never raises
67
- a bare `json.JSONDecodeError`, even when a server returns an HTML error page.
68
-
69
- | Situation | What you get |
70
- | --------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
71
- | A status the OpenAPI spec **documents** for that operation (e.g. a `422` or `500` on `create_scrape`), with a JSON body | The typed `Error` model is **returned**, not raised. Check with `isinstance(result, Error)` and read `result.error.code` / `result.error.message`. |
72
- | An **undocumented** status, or a **non-JSON body on a documented status** (HTML error page, load-balancer text, empty body) | `errors.UnexpectedStatus` is **raised**, carrying `.status_code` and the raw `.content`. When the body is the documented `Error` envelope, `.code` / `.message` are populated too. |
73
- | Either of the above, with `raise_on_unexpected_status=False` | Nothing is raised; the operation returns `None`. |
75
+ a bare `json.JSONDecodeError` or a bare `KeyError`, even when a server returns an HTML error
76
+ page or a payload whose shape has drifted from the spec.
77
+
78
+ | Situation | What you get |
79
+ | ----------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
80
+ | A status the OpenAPI spec **documents** for that operation (e.g. a `422` or `500` on `create_scrape`), with a JSON body of the documented shape | The typed `Error` model is **returned**, not raised. Check with `isinstance(result, Error)` and read `result.error.code` / `result.error.message`. |
81
+ | An **undocumented** status, or a **non-JSON body on a documented status** (HTML error page, load-balancer text, empty body) | `errors.UnexpectedStatus` is **raised**, carrying `.status_code` and the raw `.content`. When the body is the documented `Error` envelope, `.code` / `.message` are populated too. |
82
+ | A **documented status whose JSON body does not match the documented schema** — a field the server renamed, dropped or retyped | `errors.UnexpectedStatus` is **raised**, same shape as the row above. The underlying parse failure (e.g. `KeyError: 'schema_version'`) is attached as `__cause__` for diagnosis. |
83
+ | Any of the above, with `raise_on_unexpected_status=False` | Nothing is raised; the operation returns `None`. |
84
+
85
+ The table describes the **generated operations** (`create_scrape.sync`, `get_usage.sync`, …),
86
+ whose return types are `Optional[...]` accordingly. The hand-written
87
+ `AuthenticatedClient.search(...)` convenience method is deliberately outside it: it returns a
88
+ non-`Optional` `CreateSearchResponse200` and raises `errors.UnexpectedStatus` on anything else
89
+ — including documented error statuses, and including a malformed `200` — **in both raise
90
+ modes**. `raise_on_unexpected_status` does not apply to it.
74
91
 
75
92
  ```python
76
93
  from bytekit import AuthenticatedClient
@@ -78,12 +95,21 @@ from bytekit.api.scrape import create_scrape
78
95
  from bytekit.errors import UnexpectedStatus
79
96
  from bytekit.models.error import Error
80
97
  from bytekit.models.scrape_request import ScrapeRequest
98
+ from bytekit.models.scrape_request_formats_item import ScrapeRequestFormatsItem
81
99
  from bytekit.models.scrape_success_envelope import ScrapeSuccessEnvelope
82
100
 
83
101
  client = AuthenticatedClient(token="sk_live_your_api_key_here")
84
102
 
85
103
  try:
86
- result = create_scrape.sync(client=client, body=ScrapeRequest(url="https://example.com"))
104
+ result = create_scrape.sync(
105
+ client=client,
106
+ body=ScrapeRequest(
107
+ url="https://example.com",
108
+ # Ask for markdown explicitly — omit `formats` and the server returns raw HTML,
109
+ # leaving `formats.markdown` unset.
110
+ formats=[ScrapeRequestFormatsItem.MARKDOWN],
111
+ ),
112
+ )
87
113
  except UnexpectedStatus as err:
88
114
  # Undocumented status, or a non-JSON body on a documented one. Never a JSONDecodeError.
89
115
  print(f"request failed with status {err.status_code}: {err.code} {err.message}")
@@ -110,6 +136,22 @@ The client ships with production-ready defaults so `AuthenticatedClient(token=..
110
136
 
111
137
  Explicit constructor arguments always win over these defaults (explicit arg > default).
112
138
 
139
+ #### Every constructor argument is keyword-only
140
+
141
+ `AuthenticatedClient` accepts **no positional arguments**. `token`, `base_url`, `prefix`,
142
+ `auth_header_name` and the rest are all passed by name:
143
+
144
+ ```python
145
+ client = AuthenticatedClient(base_url="https://api.bytekit.com", token="sk_live_your_api_key_here")
146
+ ```
147
+
148
+ **Migrating from a pre-0.3.0 positional call.** `base_url` used to be the first positional
149
+ argument, so `AuthenticatedClient("https://…", "sk_live_…")` was a documented call. Once
150
+ `base_url` became a defaulted keyword argument, that same call silently bound the **URL to
151
+ `token`** and the **API key to `prefix`** — producing an `Authorization: sk_live_… https://…`
152
+ header sent to the _default_ host, i.e. a wrong credential against production with nothing
153
+ raised. Since 0.3.5 it raises `TypeError` instead. Add the keywords; nothing else changes.
154
+
113
155
  ## Async usage
114
156
 
115
157
  ```python
@@ -127,6 +169,29 @@ async def main():
127
169
  asyncio.run(main())
128
170
  ```
129
171
 
172
+ ### Clients and event loops
173
+
174
+ An `httpx.AsyncClient` — and therefore its connection pool — belongs to the event loop that
175
+ created it. The recommended shape is a context manager, which scopes the client to exactly one
176
+ loop:
177
+
178
+ ```python
179
+ async def main():
180
+ async with AuthenticatedClient(token="sk_live_your_api_key_here") as client:
181
+ ...
182
+ ```
183
+
184
+ Two rules cover everything else:
185
+
186
+ - **A client the SDK builds for you is rebuilt automatically.** If you reuse one client across
187
+ several `asyncio.run(...)` calls, the SDK notices the running loop has changed and transparently
188
+ replaces its internal `AsyncClient`. Your `base_url`, headers, timeout, `httpx_args` and
189
+ authentication are all re-applied, so this is invisible apart from a new connection. Calling
190
+ `get_async_httpx_client()` outside any running loop returns the cached client unchanged.
191
+ - **A client you pass to `set_async_httpx_client(...)` is yours.** The SDK never rebuilds or
192
+ closes it, so a client you supply must be created and used on the same loop — that is the one
193
+ case where crossing loops is still your responsibility.
194
+
130
195
  ## Available operations
131
196
 
132
197
  | Module | Method | Description |
@@ -20,16 +20,24 @@ The installed version is available as `bytekit.__version__`.
20
20
  from bytekit import AuthenticatedClient
21
21
  from bytekit.api.scrape import create_scrape
22
22
  from bytekit.models.scrape_request import ScrapeRequest
23
+ from bytekit.models.scrape_request_formats_item import ScrapeRequestFormatsItem
23
24
  from bytekit.models.scrape_success_envelope import ScrapeSuccessEnvelope
24
25
 
25
26
  # base_url defaults to https://api.bytekit.com, so only the token is required.
26
27
  client = AuthenticatedClient(token="sk_live_your_api_key_here")
27
28
 
28
- result = create_scrape.sync(client=client, body=ScrapeRequest(url="https://example.com"))
29
+ result = create_scrape.sync(
30
+ client=client,
31
+ body=ScrapeRequest(
32
+ url="https://example.com",
33
+ # Ask for markdown explicitly. `formats` is a list of enum members, not plain
34
+ # strings. Omit it and the server returns raw HTML instead, leaving
35
+ # `formats.markdown` unset.
36
+ formats=[ScrapeRequestFormatsItem.MARKDOWN],
37
+ ),
38
+ )
29
39
 
30
40
  if isinstance(result, ScrapeSuccessEnvelope):
31
- # formats.markdown is str | Unset — only set when "markdown" was among the
32
- # requested formats.
33
41
  print(result.formats.markdown)
34
42
  ```
35
43
 
@@ -38,13 +46,22 @@ See [Error handling](#error-handling) for what `result` can be when the request
38
46
  ### Error handling
39
47
 
40
48
  The SDK has a **two-tier** error contract. Both tiers are safe: an operation never raises
41
- a bare `json.JSONDecodeError`, even when a server returns an HTML error page.
42
-
43
- | Situation | What you get |
44
- | --------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
45
- | A status the OpenAPI spec **documents** for that operation (e.g. a `422` or `500` on `create_scrape`), with a JSON body | The typed `Error` model is **returned**, not raised. Check with `isinstance(result, Error)` and read `result.error.code` / `result.error.message`. |
46
- | An **undocumented** status, or a **non-JSON body on a documented status** (HTML error page, load-balancer text, empty body) | `errors.UnexpectedStatus` is **raised**, carrying `.status_code` and the raw `.content`. When the body is the documented `Error` envelope, `.code` / `.message` are populated too. |
47
- | Either of the above, with `raise_on_unexpected_status=False` | Nothing is raised; the operation returns `None`. |
49
+ a bare `json.JSONDecodeError` or a bare `KeyError`, even when a server returns an HTML error
50
+ page or a payload whose shape has drifted from the spec.
51
+
52
+ | Situation | What you get |
53
+ | ----------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
54
+ | A status the OpenAPI spec **documents** for that operation (e.g. a `422` or `500` on `create_scrape`), with a JSON body of the documented shape | The typed `Error` model is **returned**, not raised. Check with `isinstance(result, Error)` and read `result.error.code` / `result.error.message`. |
55
+ | An **undocumented** status, or a **non-JSON body on a documented status** (HTML error page, load-balancer text, empty body) | `errors.UnexpectedStatus` is **raised**, carrying `.status_code` and the raw `.content`. When the body is the documented `Error` envelope, `.code` / `.message` are populated too. |
56
+ | A **documented status whose JSON body does not match the documented schema** — a field the server renamed, dropped or retyped | `errors.UnexpectedStatus` is **raised**, same shape as the row above. The underlying parse failure (e.g. `KeyError: 'schema_version'`) is attached as `__cause__` for diagnosis. |
57
+ | Any of the above, with `raise_on_unexpected_status=False` | Nothing is raised; the operation returns `None`. |
58
+
59
+ The table describes the **generated operations** (`create_scrape.sync`, `get_usage.sync`, …),
60
+ whose return types are `Optional[...]` accordingly. The hand-written
61
+ `AuthenticatedClient.search(...)` convenience method is deliberately outside it: it returns a
62
+ non-`Optional` `CreateSearchResponse200` and raises `errors.UnexpectedStatus` on anything else
63
+ — including documented error statuses, and including a malformed `200` — **in both raise
64
+ modes**. `raise_on_unexpected_status` does not apply to it.
48
65
 
49
66
  ```python
50
67
  from bytekit import AuthenticatedClient
@@ -52,12 +69,21 @@ from bytekit.api.scrape import create_scrape
52
69
  from bytekit.errors import UnexpectedStatus
53
70
  from bytekit.models.error import Error
54
71
  from bytekit.models.scrape_request import ScrapeRequest
72
+ from bytekit.models.scrape_request_formats_item import ScrapeRequestFormatsItem
55
73
  from bytekit.models.scrape_success_envelope import ScrapeSuccessEnvelope
56
74
 
57
75
  client = AuthenticatedClient(token="sk_live_your_api_key_here")
58
76
 
59
77
  try:
60
- result = create_scrape.sync(client=client, body=ScrapeRequest(url="https://example.com"))
78
+ result = create_scrape.sync(
79
+ client=client,
80
+ body=ScrapeRequest(
81
+ url="https://example.com",
82
+ # Ask for markdown explicitly — omit `formats` and the server returns raw HTML,
83
+ # leaving `formats.markdown` unset.
84
+ formats=[ScrapeRequestFormatsItem.MARKDOWN],
85
+ ),
86
+ )
61
87
  except UnexpectedStatus as err:
62
88
  # Undocumented status, or a non-JSON body on a documented one. Never a JSONDecodeError.
63
89
  print(f"request failed with status {err.status_code}: {err.code} {err.message}")
@@ -84,6 +110,22 @@ The client ships with production-ready defaults so `AuthenticatedClient(token=..
84
110
 
85
111
  Explicit constructor arguments always win over these defaults (explicit arg > default).
86
112
 
113
+ #### Every constructor argument is keyword-only
114
+
115
+ `AuthenticatedClient` accepts **no positional arguments**. `token`, `base_url`, `prefix`,
116
+ `auth_header_name` and the rest are all passed by name:
117
+
118
+ ```python
119
+ client = AuthenticatedClient(base_url="https://api.bytekit.com", token="sk_live_your_api_key_here")
120
+ ```
121
+
122
+ **Migrating from a pre-0.3.0 positional call.** `base_url` used to be the first positional
123
+ argument, so `AuthenticatedClient("https://…", "sk_live_…")` was a documented call. Once
124
+ `base_url` became a defaulted keyword argument, that same call silently bound the **URL to
125
+ `token`** and the **API key to `prefix`** — producing an `Authorization: sk_live_… https://…`
126
+ header sent to the _default_ host, i.e. a wrong credential against production with nothing
127
+ raised. Since 0.3.5 it raises `TypeError` instead. Add the keywords; nothing else changes.
128
+
87
129
  ## Async usage
88
130
 
89
131
  ```python
@@ -101,6 +143,29 @@ async def main():
101
143
  asyncio.run(main())
102
144
  ```
103
145
 
146
+ ### Clients and event loops
147
+
148
+ An `httpx.AsyncClient` — and therefore its connection pool — belongs to the event loop that
149
+ created it. The recommended shape is a context manager, which scopes the client to exactly one
150
+ loop:
151
+
152
+ ```python
153
+ async def main():
154
+ async with AuthenticatedClient(token="sk_live_your_api_key_here") as client:
155
+ ...
156
+ ```
157
+
158
+ Two rules cover everything else:
159
+
160
+ - **A client the SDK builds for you is rebuilt automatically.** If you reuse one client across
161
+ several `asyncio.run(...)` calls, the SDK notices the running loop has changed and transparently
162
+ replaces its internal `AsyncClient`. Your `base_url`, headers, timeout, `httpx_args` and
163
+ authentication are all re-applied, so this is invisible apart from a new connection. Calling
164
+ `get_async_httpx_client()` outside any running loop returns the cached client unchanged.
165
+ - **A client you pass to `set_async_httpx_client(...)` is yours.** The SDK never rebuilds or
166
+ closes it, so a client you supply must be created and used on the same loop — that is the one
167
+ case where crossing loops is still your responsibility.
168
+
104
169
  ## Available operations
105
170
 
106
171
  | Module | Method | Description |