bytekit-sdk 0.3.2__tar.gz → 0.3.4__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 (274) hide show
  1. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/.gitignore +8 -0
  2. bytekit_sdk-0.3.4/CHANGELOG.md +192 -0
  3. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/PKG-INFO +35 -4
  4. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/README.md +34 -3
  5. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/pyproject.toml +32 -2
  6. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/api/account/get_account.py +15 -10
  7. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/api/bulk/create_bulk.py +104 -0
  8. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/api/bulk/delete_bulk.py +2 -3
  9. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/api/bulk/get_bulk.py +2 -3
  10. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/api/bulk/list_bulk_screenshots.py +2 -3
  11. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/api/fetch/get_fetch.py +31 -27
  12. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/api/fetch/post_fetch.py +16 -0
  13. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/api/fetch_bulk/create_fetch_bulk.py +44 -0
  14. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/api/fetch_bulk/get_fetch_bulk.py +2 -3
  15. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/api/monitors/create_monitor.py +12 -0
  16. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/api/monitors/delete_monitor.py +2 -3
  17. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/api/monitors/get_monitor.py +2 -3
  18. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/api/monitors/list_monitor_captures.py +11 -12
  19. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/api/monitors/list_monitors.py +18 -18
  20. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/api/monitors/update_monitor.py +2 -3
  21. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/api/scrape/get_scrape.py +2 -3
  22. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/api/scrape_bulk/get_scrape_bulk.py +2 -3
  23. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/api/screenshots/create_screenshot.py +25 -9
  24. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/api/screenshots/get_screenshot.py +2 -3
  25. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/api/sitemap/create_sitemap.py +16 -0
  26. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/api/sitemap/get_sitemap.py +6 -3
  27. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/api/webhooks/list_webhook_deliveries.py +9 -9
  28. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/api/webhooks/retry_webhook_delivery.py +22 -3
  29. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/client.py +82 -0
  30. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/__init__.py +22 -6
  31. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/create_bulk_body.py +16 -20
  32. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/create_bulk_body_defaults.py +27 -52
  33. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/create_bulk_body_items_item.py +4 -24
  34. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/create_bulk_response_202.py +21 -8
  35. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/create_fetch_bulk_body.py +6 -6
  36. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/create_fetch_bulk_body_defaults.py +4 -4
  37. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/create_fetch_bulk_body_urls_item_type_1.py +1 -20
  38. bytekit_sdk-0.3.4/src/bytekit/models/create_fetch_bulk_response_202.py +179 -0
  39. bytekit_sdk-0.3.4/src/bytekit/models/create_fetch_bulk_response_202_status.py +10 -0
  40. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/create_scrape_bulk_body_defaults.py +7 -8
  41. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/create_scrape_bulk_body_items_item.py +7 -12
  42. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/create_scrape_bulk_response_202.py +21 -8
  43. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/create_search_body.py +5 -10
  44. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/create_search_response_200_results_item.py +6 -5
  45. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/delete_bulk_response_200.py +17 -8
  46. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/get_bulk_response_200.py +17 -8
  47. bytekit_sdk-0.3.4/src/bytekit/models/get_fetch_bulk_response_200.py +201 -0
  48. bytekit_sdk-0.3.4/src/bytekit/models/get_fetch_bulk_response_200_items_item.py +211 -0
  49. bytekit_sdk-0.3.4/src/bytekit/models/get_fetch_bulk_response_200_items_item_status.py +12 -0
  50. bytekit_sdk-0.3.4/src/bytekit/models/get_fetch_bulk_response_200_status.py +10 -0
  51. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/get_scrape_bulk_response_200.py +17 -8
  52. bytekit_sdk-0.3.4/src/bytekit/models/list_bulk_screenshots_response_200.py +100 -0
  53. bytekit_sdk-0.3.4/src/bytekit/models/list_bulk_screenshots_response_200_items_item.py +344 -0
  54. bytekit_sdk-0.3.4/src/bytekit/models/list_bulk_screenshots_response_200_items_item_status.py +12 -0
  55. bytekit_sdk-0.3.4/src/bytekit/models/list_bulk_screenshots_response_200_items_item_type.py +10 -0
  56. bytekit_sdk-0.3.2/CHANGELOG.md +0 -89
  57. bytekit_sdk-0.3.2/src/bytekit/models/create_fetch_bulk_body_metadata.py +0 -44
  58. bytekit_sdk-0.3.2/src/bytekit/models/create_fetch_bulk_response_202.py +0 -44
  59. bytekit_sdk-0.3.2/src/bytekit/models/create_scrape_bulk_body_items_item_metadata.py +0 -44
  60. bytekit_sdk-0.3.2/src/bytekit/models/get_fetch_bulk_response_200.py +0 -44
  61. bytekit_sdk-0.3.2/src/bytekit/models/list_bulk_screenshots_response_200.py +0 -44
  62. bytekit_sdk-0.3.2/tests/__init__.py +0 -0
  63. bytekit_sdk-0.3.2/tests/conftest.py +0 -97
  64. bytekit_sdk-0.3.2/tests/fixtures/unpatched_client.py.snapshot +0 -365
  65. bytekit_sdk-0.3.2/tests/fixtures/unpatched_create_scrape.py.snapshot +0 -197
  66. bytekit_sdk-0.3.2/tests/fixtures/unpatched_delete_monitor.py.snapshot +0 -155
  67. bytekit_sdk-0.3.2/tests/fixtures/unpatched_errors.py.snapshot +0 -16
  68. bytekit_sdk-0.3.2/tests/fixtures/unpatched_get_fetch.py.snapshot +0 -254
  69. bytekit_sdk-0.3.2/tests/test_bulk_delete.py +0 -33
  70. bytekit_sdk-0.3.2/tests/test_client.py +0 -121
  71. bytekit_sdk-0.3.2/tests/test_client_defaults.py +0 -122
  72. bytekit_sdk-0.3.2/tests/test_deactivated_resources.py +0 -108
  73. bytekit_sdk-0.3.2/tests/test_generate_docs.py +0 -285
  74. bytekit_sdk-0.3.2/tests/test_models.py +0 -178
  75. bytekit_sdk-0.3.2/tests/test_no_materialized_defaults.py +0 -31
  76. bytekit_sdk-0.3.2/tests/test_op_error_paths.py +0 -360
  77. bytekit_sdk-0.3.2/tests/test_package_identity.py +0 -24
  78. bytekit_sdk-0.3.2/tests/test_patch_functions.py +0 -308
  79. bytekit_sdk-0.3.2/tests/test_prune_stale_api.py +0 -753
  80. bytekit_sdk-0.3.2/tests/test_publish_metadata.py +0 -179
  81. bytekit_sdk-0.3.2/tests/test_readme_examples.py +0 -127
  82. bytekit_sdk-0.3.2/tests/test_regen_durability.py +0 -170
  83. bytekit_sdk-0.3.2/tests/test_removed_surface.py +0 -50
  84. bytekit_sdk-0.3.2/tests/test_scrape_markdown_opts.py +0 -157
  85. bytekit_sdk-0.3.2/tests/test_scrape_scored_formats.py +0 -135
  86. bytekit_sdk-0.3.2/tests/test_sdist_contents.py +0 -182
  87. bytekit_sdk-0.3.2/tests/test_search.py +0 -209
  88. bytekit_sdk-0.3.2/tests/test_search_errors.py +0 -97
  89. bytekit_sdk-0.3.2/tests/test_spec_field_parity.py +0 -106
  90. bytekit_sdk-0.3.2/tests/test_typed_search_surface.py +0 -181
  91. bytekit_sdk-0.3.2/tests/test_usage.py +0 -80
  92. bytekit_sdk-0.3.2/tests/test_version.py +0 -110
  93. bytekit_sdk-0.3.2/tests/test_webhook_deliveries.py +0 -59
  94. bytekit_sdk-0.3.2/tests/test_wheel_contents.py +0 -109
  95. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/LICENSE +0 -0
  96. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/__init__.py +0 -0
  97. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/api/__init__.py +0 -0
  98. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/api/account/__init__.py +0 -0
  99. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/api/bulk/__init__.py +0 -0
  100. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/api/fetch/__init__.py +0 -0
  101. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/api/fetch_bulk/__init__.py +0 -0
  102. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/api/monitors/__init__.py +0 -0
  103. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/api/scrape/__init__.py +0 -0
  104. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/api/scrape/create_scrape.py +0 -0
  105. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/api/scrape_bulk/__init__.py +0 -0
  106. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/api/scrape_bulk/create_scrape_bulk.py +0 -0
  107. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/api/screenshots/__init__.py +0 -0
  108. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/api/search/__init__.py +0 -0
  109. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/api/search/create_search.py +0 -0
  110. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/api/sitemap/__init__.py +0 -0
  111. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/api/usage/__init__.py +0 -0
  112. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/api/usage/get_usage.py +0 -0
  113. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/api/usage/get_usage_by_endpoint.py +0 -0
  114. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/api/usage/get_usage_daily.py +0 -0
  115. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/api/webhooks/__init__.py +0 -0
  116. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/errors.py +0 -0
  117. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/account_bearer_response.py +0 -0
  118. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/account_bearer_response_api_key.py +0 -0
  119. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/account_bearer_response_api_key_environment.py +0 -0
  120. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/account_bearer_response_auto_topup.py +0 -0
  121. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/account_bearer_response_plan.py +0 -0
  122. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/account_bearer_response_subscription.py +0 -0
  123. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/account_bearer_response_subscription_plan.py +0 -0
  124. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/account_bearer_response_subscription_status.py +0 -0
  125. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/account_session_response.py +0 -0
  126. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/account_session_response_notifications.py +0 -0
  127. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/account_session_response_plan.py +0 -0
  128. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/bandwidth_balance.py +0 -0
  129. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/capture_response.py +0 -0
  130. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/capture_response_outcome.py +0 -0
  131. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/clip.py +0 -0
  132. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/cookie.py +0 -0
  133. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/create_bulk_body_defaults_device.py +0 -0
  134. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/create_bulk_body_defaults_device_scale_factor_type_1.py +0 -0
  135. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/create_bulk_body_defaults_device_scale_factor_type_2_type_1.py +0 -0
  136. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/create_bulk_body_defaults_device_scale_factor_type_3_type_1.py +0 -0
  137. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/create_bulk_body_defaults_formats_item.py +0 -0
  138. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/create_bulk_body_defaults_type.py +0 -0
  139. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/create_bulk_body_defaults_viewport_type_0.py +0 -0
  140. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/create_bulk_body_defaults_wait_until.py +0 -0
  141. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/create_bulk_body_items_item_device.py +0 -0
  142. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/create_bulk_body_items_item_formats_item.py +0 -0
  143. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/create_bulk_body_items_item_scenario.py +0 -0
  144. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/create_bulk_body_items_item_type.py +0 -0
  145. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/create_bulk_body_items_item_viewport_type_0.py +0 -0
  146. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/create_bulk_body_items_item_wait_until.py +0 -0
  147. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/create_bulk_response_202_status.py +0 -0
  148. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/create_fetch_bulk_body_defaults_format.py +0 -0
  149. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/create_fetch_bulk_body_urls_item_type_1_format.py +0 -0
  150. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/create_scrape_bulk_body.py +0 -0
  151. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/create_scrape_bulk_body_custom.py +0 -0
  152. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/create_scrape_bulk_body_defaults_formats_item.py +0 -0
  153. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/create_scrape_bulk_body_defaults_headers.py +0 -0
  154. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/create_scrape_bulk_body_items_item_custom.py +0 -0
  155. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/create_scrape_bulk_body_items_item_formats_item.py +0 -0
  156. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/create_scrape_bulk_body_items_item_headers.py +0 -0
  157. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/create_scrape_bulk_response_202_status.py +0 -0
  158. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/create_search_body_date_range.py +0 -0
  159. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/create_search_body_type.py +0 -0
  160. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/create_search_response_200.py +0 -0
  161. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/create_search_response_200_results_item_image.py +0 -0
  162. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/create_search_response_502.py +0 -0
  163. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/create_search_response_502_error.py +0 -0
  164. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/credit_balance.py +0 -0
  165. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/delete_bulk_response_200_status.py +0 -0
  166. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/error.py +0 -0
  167. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/error_error.py +0 -0
  168. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/error_status.py +0 -0
  169. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/fetch_request.py +0 -0
  170. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/fetch_request_cache_ttl_type_1.py +0 -0
  171. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/fetch_request_custom.py +0 -0
  172. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/fetch_request_format.py +0 -0
  173. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/fetch_request_markdown_images.py +0 -0
  174. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/fetch_request_markdown_links.py +0 -0
  175. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/fetch_request_markdown_mode.py +0 -0
  176. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/get_bulk_response_200_status.py +0 -0
  177. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/get_fetch_cache_ttl_type_1.py +0 -0
  178. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/get_fetch_format.py +0 -0
  179. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/get_scrape_bulk_response_200_status.py +0 -0
  180. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/get_usage_by_endpoint_response_200.py +0 -0
  181. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/get_usage_by_endpoint_response_200_rows_item.py +0 -0
  182. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/get_usage_by_endpoint_response_200_rows_item_endpoint.py +0 -0
  183. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/get_usage_by_endpoint_response_200_totals.py +0 -0
  184. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/get_usage_daily_response_200.py +0 -0
  185. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/get_usage_daily_response_200_data_item.py +0 -0
  186. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/get_usage_response_200.py +0 -0
  187. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/get_usage_response_200_plan_type.py +0 -0
  188. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/list_monitor_captures_response_200.py +0 -0
  189. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/list_monitors_response_200.py +0 -0
  190. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/list_monitors_status.py +0 -0
  191. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/list_webhook_deliveries_response_200.py +0 -0
  192. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/list_webhook_deliveries_status.py +0 -0
  193. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/metadata.py +0 -0
  194. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/monitor_create_request.py +0 -0
  195. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/monitor_create_request_interval_type.py +0 -0
  196. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/monitor_create_request_notify_on.py +0 -0
  197. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/monitor_create_request_options.py +0 -0
  198. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/monitor_create_request_scrape_options.py +0 -0
  199. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/monitor_create_request_type.py +0 -0
  200. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/monitor_create_request_webhook_headers.py +0 -0
  201. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/monitor_create_response.py +0 -0
  202. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/monitor_response.py +0 -0
  203. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/monitor_response_interval_type.py +0 -0
  204. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/monitor_response_metadata_type_0.py +0 -0
  205. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/monitor_response_status.py +0 -0
  206. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/monitor_response_type.py +0 -0
  207. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/monitor_response_webhook_headers_type_0.py +0 -0
  208. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/monitor_update_request.py +0 -0
  209. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/monitor_update_request_interval_type.py +0 -0
  210. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/monitor_update_request_notify_on.py +0 -0
  211. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/monitor_update_request_options.py +0 -0
  212. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/monitor_update_request_scrape_options.py +0 -0
  213. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/monitor_update_request_status.py +0 -0
  214. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/monitor_update_request_webhook_headers.py +0 -0
  215. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/scrape_error_envelope.py +0 -0
  216. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/scrape_error_envelope_error.py +0 -0
  217. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/scrape_error_envelope_error_code.py +0 -0
  218. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/scrape_error_envelope_schema_version.py +0 -0
  219. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/scrape_error_envelope_status.py +0 -0
  220. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/scrape_formats.py +0 -0
  221. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/scrape_markdown_tokens.py +0 -0
  222. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/scrape_metadata.py +0 -0
  223. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/scrape_queued_envelope.py +0 -0
  224. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/scrape_queued_envelope_schema_version.py +0 -0
  225. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/scrape_queued_envelope_status.py +0 -0
  226. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/scrape_request.py +0 -0
  227. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/scrape_request_cache_ttl_type_1.py +0 -0
  228. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/scrape_request_custom.py +0 -0
  229. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/scrape_request_events_item.py +0 -0
  230. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/scrape_request_formats_item.py +0 -0
  231. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/scrape_request_headers.py +0 -0
  232. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/scrape_request_markdown_images.py +0 -0
  233. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/scrape_request_markdown_links.py +0 -0
  234. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/scrape_request_markdown_mode.py +0 -0
  235. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/scrape_request_token_encoding.py +0 -0
  236. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/scrape_request_x_internal_scrape_path.py +0 -0
  237. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/scrape_scored_image.py +0 -0
  238. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/scrape_scored_link.py +0 -0
  239. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/scrape_stats.py +0 -0
  240. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/scrape_success_envelope.py +0 -0
  241. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/scrape_success_envelope_cache.py +0 -0
  242. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/scrape_success_envelope_custom.py +0 -0
  243. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/scrape_success_envelope_schema_version.py +0 -0
  244. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/scrape_success_envelope_status.py +0 -0
  245. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/scrape_table.py +0 -0
  246. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/scrape_table_kind.py +0 -0
  247. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/scrape_warning.py +0 -0
  248. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/scrape_warning_code.py +0 -0
  249. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/screenshot_request.py +0 -0
  250. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/screenshot_request_device.py +0 -0
  251. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/screenshot_request_device_scale_factor_type_1.py +0 -0
  252. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/screenshot_request_device_scale_factor_type_2_type_1.py +0 -0
  253. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/screenshot_request_device_scale_factor_type_3_type_1.py +0 -0
  254. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/screenshot_request_format.py +0 -0
  255. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/screenshot_request_headers.py +0 -0
  256. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/screenshot_request_wait_until.py +0 -0
  257. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/screenshot_response.py +0 -0
  258. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/screenshot_response_status.py +0 -0
  259. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/sitemap_request.py +0 -0
  260. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/sitemap_request_process_type_0.py +0 -0
  261. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/sitemap_request_process_type_0_options.py +0 -0
  262. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/sitemap_request_strategy.py +0 -0
  263. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/sitemap_response.py +0 -0
  264. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/sitemap_response_cache.py +0 -0
  265. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/sitemap_response_metadata_type_0.py +0 -0
  266. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/sitemap_response_process_type_0.py +0 -0
  267. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/sitemap_response_sources_type_0.py +0 -0
  268. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/sitemap_response_status.py +0 -0
  269. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/viewport.py +0 -0
  270. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/webhook_delivery_response.py +0 -0
  271. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/webhook_delivery_response_event_type.py +0 -0
  272. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/models/webhook_delivery_response_status.py +0 -0
  273. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/src/bytekit/py.typed +0 -0
  274. {bytekit_sdk-0.3.2 → bytekit_sdk-0.3.4}/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,192 @@
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.4
7
+
8
+ ### Breaking
9
+
10
+ - **`CreateBulkBody`, `CreateBulkBodyDefaults`, `CreateBulkBodyItemsItem`, and
11
+ `CreateFetchBulkBodyUrlsItemType1` lost their additional-properties mapping API.**
12
+ `docs/api/openapi.yaml`'s `/v1/bulk` request schema declares `additionalProperties: false`
13
+ on the top-level body, `items[]`, and `defaults` (issue #2641), and `/v1/fetch/bulk`'s
14
+ per-item override schema inside `urls[]` declares the same (issue #2648), matching the
15
+ gateway's own `.strict()` validators. The code generator responds to
16
+ `additionalProperties: false` by omitting the catch-all mapping it otherwise attaches to
17
+ every generated model, so these four models no longer expose `additional_properties`, the
18
+ `additional_keys` property, `__getitem__`, `__setitem__`, `__delitem__`, or `__contains__`.
19
+ Code that did `body["some_key"] = value`, `"some_key" in body`, or read
20
+ `body.additional_keys` on any of these four models will now raise
21
+ `AttributeError`/`TypeError` instead. Use the model's declared `attrs` fields directly
22
+ instead (e.g. `CreateBulkBodyItemsItem(url=..., type=...)`,
23
+ `CreateFetchBulkBodyUrlsItemType1(url=..., format_=...)`); the server itself now rejects
24
+ unrecognized keys on these endpoints with `422 validation_error`, so the removed escape
25
+ hatch could never have reached the API successfully anyway. This is scoped to the four
26
+ `create_bulk_body*` / `create_fetch_bulk_body_urls_item_type_1` models — no other generated
27
+ model is affected.
28
+
29
+ ## 0.3.3
30
+
31
+ ### Security
32
+
33
+ - **Path parameters are now percent-encoded.** All 13 operations that interpolate an id into
34
+ their URL (`get_scrape`, `get_screenshot`, `get_bulk`, `delete_bulk`,
35
+ `list_bulk_screenshots`, `get_scrape_bulk`, `get_fetch_bulk`, `get_monitor`,
36
+ `update_monitor`, `delete_monitor`, `list_monitor_captures`, `get_sitemap`,
37
+ `retry_webhook_delivery`) previously interpolated the value raw, so an id containing `/`,
38
+ `?`, `#` or traversal segments could retarget the request to a **different path on the same
39
+ authenticated host** — e.g. a `DELETE /v1/bulk/{id}` becoming a delete against another
40
+ resource. Values are now encoded with `quote(str(value), safe="")`. This is **not** a
41
+ breaking change for any id the API issues: hex and `sc_`/`ss_`/`mon_`/`sm_`/`bulk_`-prefixed
42
+ ids contain no reserved characters, so the resulting URL is byte-identical to before.
43
+ No id-format validation was added — the client does not reject id shapes.
44
+
45
+ ### Fixed
46
+
47
+ - **Reusing one client across several `asyncio.run(...)` calls no longer raises
48
+ `RuntimeError: Event loop is closed`.** An `httpx.AsyncClient`'s connection pool belongs to
49
+ the event loop that created it, and the SDK cached its internal async client
50
+ unconditionally. It now tracks which loop that client was built on and transparently
51
+ rebuilds it when the running loop changes, re-applying `base_url`, headers, timeout,
52
+ `httpx_args` and authentication. Behavior is unchanged when no loop is running, and a client
53
+ you supply via `set_async_httpx_client(...)` is **never** rebuilt or closed — it stays yours
54
+ to manage. See the README's new "Clients and event loops" section.
55
+ - **The README quick start now prints markdown instead of an `Unset` placeholder.** It
56
+ requested no `formats`, so the server applied its `raw_html` default and
57
+ `result.formats.markdown` was legitimately unset. It now asks for
58
+ `formats=[ScrapeRequestFormatsItem.MARKDOWN]` — note `formats` takes enum members, not plain
59
+ strings.
60
+ - **`client.search(type="images")` no longer crashes with a bare `KeyError: 'snippet'`.**
61
+ The OpenAPI spec's search result-item schema declared `snippet` as `required` while its
62
+ own description said the key is omitted for `images` results — a self-contradiction the
63
+ code generator trusted literally, so `CreateSearchResponse200ResultsItem.from_dict`
64
+ unconditionally did `d.pop("snippet")`. `snippet` (like `date`) is now `Union[Unset, str]`,
65
+ matching the real gateway behavior (`web`/`news` results still always carry `snippet`;
66
+ `images` results omit it entirely) — fixed at the spec level (`docs/api/openapi.yaml`) and
67
+ regenerated, not patched in the generated model. (Issue #2579.)
68
+ - **Server defaults are no longer materialized into request wire bodies/query strings
69
+ for inline request bodies and `$ref`'d parameters.** `scripts/filter-spec.ts`'s
70
+ default-stripping traversal previously only followed `$ref`'d request-body component
71
+ schemas, so `ScrapeRequest`/`FetchRequest` were clean but every other request-direction
72
+ shape kept baking in server defaults: `/v1/search`'s fully-inline body (`type`,
73
+ `limit`, `country`, `language`, `date_range`), all three bulk endpoints' bodies and
74
+ their nested `Defaults`/`ItemsItem` models, and `$ref`'d query parameters
75
+ (`GET /v1/fetch`'s `country`/`timeout_ms`/`cache_ttl`, `list_monitors`'
76
+ `limit`/`status`, `list_webhook_deliveries`'/`list_monitor_captures`' `limit`,
77
+ `create_screenshot`'s `async`). The traversal now walks inline request bodies AND
78
+ parameters (both operation-level and shared path-item-level, `$ref`'d or inline)
79
+ before generation, so an omitted optional field always serializes to nothing and
80
+ the server's own default applies — caller-supplied values are unaffected and still
81
+ serialize exactly as given (issue #2592).
82
+ - `tests/test_no_materialized_defaults.py` rewritten to enumerate every
83
+ request-direction model and operation parameter programmatically (walking the
84
+ generated `bytekit.api`/`bytekit.models` trees) instead of sampling two known-clean
85
+ models, so a newly introduced leaker is caught automatically.
86
+
87
+ ### Changed
88
+
89
+ - **The source distribution no longer ships `tests/`.** The bundled suite could not be
90
+ collected from an unpacked sdist: 12 of its 27 modules require the repository's codegen
91
+ scripts or the canonical OpenAPI spec, neither of which belongs in a published
92
+ distribution, and three of them build distributions of the package itself. Nothing
93
+ importable was removed — the **wheel is unchanged**, `py.typed` included, so
94
+ `pip install bytekit-sdk` is unaffected.
95
+
96
+ ### Internal
97
+
98
+ - CI now proves the committed client is reproducible from the canonical OpenAPI spec, and that
99
+ the generation chain is deterministic (generating twice yields byte-identical output). This
100
+ closes the gap where a spec change could land with a TypeScript-only regeneration and leave
101
+ the Python client silently stranded on an older spec.
102
+ - `ruff` is now pinned to an exact version alongside the code generator. The generator runs
103
+ `ruff` over everything it emits, so it — not the generator alone — determines the committed
104
+ bytes; the generator itself accepts any `ruff<0.13`, which meant a fresh install could
105
+ reformat the whole tree. Bumping the pin is a deliberate, reviewed reformat.
106
+ - The PEP 561 `py.typed` marker is now emitted by the post-generation injector rather than
107
+ hand-maintained inside the generated tree (the generator omits it under `--meta none`).
108
+
109
+ ## 0.3.2
110
+
111
+ ### Added
112
+
113
+ - **`bytekit.__version__`** reports the installed distribution version, resolved at import
114
+ time from `importlib.metadata` (so it can never drift from `pyproject.toml`'s
115
+ `[project].version`). When the package is imported from a source tree with no installed
116
+ distribution it reads `0.0.0.dev0` rather than raising. The dead version override in
117
+ `sdk-python-config.yaml` — inert under `--meta none` and contradicting the real
118
+ version — has been removed, leaving one authoritative version.
119
+
120
+ ### Fixed
121
+
122
+ - **`AuthenticatedClient.search()` is now visible to type checkers.** It was attached to the
123
+ class after creation, so despite the package shipping a `py.typed` marker, `mypy` and
124
+ `pyright` reported `"AuthenticatedClient" has no attribute "search"`. It is now declared as a
125
+ real method in the class body that delegates to the same implementation: **runtime behavior,
126
+ arguments, return type and raised errors are unchanged** — only the static surface is fixed.
127
+
128
+ ## 0.3.1
129
+
130
+ ### Fixed
131
+
132
+ - **The "never a bare `json.JSONDecodeError`" guarantee is now package-wide across all
133
+ generated operations**, not only the `AuthenticatedClient.search()` wrapper. Every
134
+ generated operation previously called `response.json()` unconditionally on a
135
+ DOCUMENTED status, so a `500`/`502` serving an HTML load-balancer page raised a bare
136
+ `json.JSONDecodeError` from inside the SDK. All operations now parse documented
137
+ statuses through a shared guard: a non-JSON body raises the typed
138
+ `errors.UnexpectedStatus` (or returns `None` when
139
+ `raise_on_unexpected_status=False`), carrying the status code and the raw body.
140
+ - **`errors.UnexpectedStatus.code` / `.message` are now populated for generated
141
+ operations too**, from the documented `Error` envelope — previously they were always
142
+ `None` outside `search()`. A string-valued `error` (the masked search-provider `502`)
143
+ still never enriches, so the upstream provider's identity is never surfaced.
144
+ - Behavior on JSON bodies is unchanged: JSON success bodies still parse into their typed
145
+ success models, documented JSON error bodies are still **returned** as typed `Error`
146
+ models rather than raised, and `raise_on_unexpected_status` semantics are untouched.
147
+ The documented non-JSON success paths — `get_fetch`/`post_fetch`'s raw-text `200` and
148
+ `delete_monitor`'s empty `204` — are likewise unaffected.
149
+ - **README error documentation corrected.** The quick-start example wrapped a call in
150
+ `try/except UnexpectedStatus` and then read `response.formats.markdown`, but a
151
+ documented `4xx` _returns_ a typed `Error` model without raising — so the documented
152
+ example failed with `AttributeError: 'Error' object has no attribute 'formats'`. The
153
+ README now documents the real two-tier contract, and the snippet is executed by
154
+ `tests/test_readme_examples.py` so it cannot silently drift again.
155
+
156
+ ### Documentation
157
+
158
+ - Removed the contributor-only `Publishing`, `Regenerating`, and `Development` sections
159
+ from the published README (the PyPI long description) — they described internal CI
160
+ mechanics and a monorepo-contributor workflow that do not belong on a public package
161
+ index. The regeneration/development knowledge is preserved in-repo in
162
+ `packages/sdk-python/CLAUDE.md` (not shipped in the distribution).
163
+ - Added a `## License` section and a `LICENSE` file, matching the npm sibling packages.
164
+
165
+ ## 0.3.0
166
+
167
+ ### Breaking
168
+
169
+ - **PyPI distribution renamed `bytekit` -> `bytekit-sdk`.** PyPI administratively
170
+ denylists the bare name `bytekit`, so the package installs as
171
+ `pip install bytekit-sdk`. The **import name is unchanged** — `import bytekit`
172
+ still works, and no module path moved. Nothing was ever published under the old
173
+ distribution name, so there is no migration for existing installs.
174
+ - **`raise_on_unexpected_status` now defaults to `True`.** Undocumented response
175
+ statuses now raise `errors.UnexpectedStatus` instead of silently returning `None`.
176
+ Callers that relied on the old `None`-return behavior must pass
177
+ `raise_on_unexpected_status=False` explicitly to opt out.
178
+ - **`base_url` is now a keyword-only argument.** It gained a default
179
+ (`https://api.bytekit.com`), and to satisfy attrs field ordering it became
180
+ keyword-only. Any caller passing `base_url` positionally must switch to the
181
+ `base_url=` keyword form. (`base_url=` was already the documented usage.)
182
+
183
+ ### Added
184
+
185
+ - `AuthenticatedClient(token=...)` now works out of the box against production:
186
+ `base_url` defaults to `https://api.bytekit.com`.
187
+ - Finite default request timeout of `120s` (`httpx.Timeout(120.0)`) — requests no
188
+ longer hang indefinitely. Override with `timeout=`.
189
+ - `errors.UnexpectedStatus` now carries optional `.code` / `.message` attributes.
190
+ The `AuthenticatedClient.search()` wrapper populates them from the documented
191
+ `Error` envelope, and safely raises a typed error (never a bare
192
+ `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.4
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
 
@@ -127,6 +135,29 @@ async def main():
127
135
  asyncio.run(main())
128
136
  ```
129
137
 
138
+ ### Clients and event loops
139
+
140
+ An `httpx.AsyncClient` — and therefore its connection pool — belongs to the event loop that
141
+ created it. The recommended shape is a context manager, which scopes the client to exactly one
142
+ loop:
143
+
144
+ ```python
145
+ async def main():
146
+ async with AuthenticatedClient(token="sk_live_your_api_key_here") as client:
147
+ ...
148
+ ```
149
+
150
+ Two rules cover everything else:
151
+
152
+ - **A client the SDK builds for you is rebuilt automatically.** If you reuse one client across
153
+ several `asyncio.run(...)` calls, the SDK notices the running loop has changed and transparently
154
+ replaces its internal `AsyncClient`. Your `base_url`, headers, timeout, `httpx_args` and
155
+ authentication are all re-applied, so this is invisible apart from a new connection. Calling
156
+ `get_async_httpx_client()` outside any running loop returns the cached client unchanged.
157
+ - **A client you pass to `set_async_httpx_client(...)` is yours.** The SDK never rebuilds or
158
+ closes it, so a client you supply must be created and used on the same loop — that is the one
159
+ case where crossing loops is still your responsibility.
160
+
130
161
  ## Available operations
131
162
 
132
163
  | 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
 
@@ -101,6 +109,29 @@ async def main():
101
109
  asyncio.run(main())
102
110
  ```
103
111
 
112
+ ### Clients and event loops
113
+
114
+ An `httpx.AsyncClient` — and therefore its connection pool — belongs to the event loop that
115
+ created it. The recommended shape is a context manager, which scopes the client to exactly one
116
+ loop:
117
+
118
+ ```python
119
+ async def main():
120
+ async with AuthenticatedClient(token="sk_live_your_api_key_here") as client:
121
+ ...
122
+ ```
123
+
124
+ Two rules cover everything else:
125
+
126
+ - **A client the SDK builds for you is rebuilt automatically.** If you reuse one client across
127
+ several `asyncio.run(...)` calls, the SDK notices the running loop has changed and transparently
128
+ replaces its internal `AsyncClient`. Your `base_url`, headers, timeout, `httpx_args` and
129
+ authentication are all re-applied, so this is invisible apart from a new connection. Calling
130
+ `get_async_httpx_client()` outside any running loop returns the cached client unchanged.
131
+ - **A client you pass to `set_async_httpx_client(...)` is yours.** The SDK never rebuilds or
132
+ closes it, so a client you supply must be created and used on the same loop — that is the one
133
+ case where crossing loops is still your responsibility.
134
+
104
135
  ## Available operations
105
136
 
106
137
  | Module | Method | Description |
@@ -7,7 +7,7 @@
7
7
  # `pip install bytekit-sdk` yields a working `import bytekit`. Mirrors the npm sibling
8
8
  # @hunt-labs/bytekit-sdk.
9
9
  name = "bytekit-sdk"
10
- version = "0.3.2"
10
+ version = "0.3.4"
11
11
  description = "Official Python SDK for the ByteKit API"
12
12
  readme = "README.md"
13
13
  requires-python = ">=3.10"
@@ -57,6 +57,22 @@ Documentation = "https://bytekit.com/docs"
57
57
  [dependency-groups]
58
58
  dev = [
59
59
  "openapi-python-client==0.25.3",
60
+ # THE FORMATTER IS PART OF THE CODEGEN CONTRACT (#2593). openapi-python-client's DEFAULT
61
+ # post_hooks are `ruff check . --fix --extend-select=I` and `ruff format .`, run with
62
+ # cwd = --output-path (see openapi_python_client/config.py) — and sdk-python-config.yaml
63
+ # sets no `post_hooks` override, so they apply. ruff therefore decides the BYTES of every
64
+ # emitted module, which makes pinning the generator alone insufficient.
65
+ #
66
+ # The generator's own metadata only asks for `ruff<0.13,>=0.2`, so a fresh
67
+ # `pip install openapi-python-client==0.25.3` resolves 0.12.x — nine minor versions above
68
+ # the version that actually produced the committed tree. Left unpinned, the reproducibility
69
+ # gate (ci/scripts/check-sdk-python-regen.sh) would red a CORRECT tree, and no regen would
70
+ # stably fix it. 0.3.7 is measured to reproduce all 221 committed modules byte-for-byte.
71
+ #
72
+ # Bumping this pin is a DELIBERATE, REVIEWED 221-file reformat — exactly like bumping the
73
+ # generator pin above — never an incidental upgrade. The gate reads this pin, so there is
74
+ # no second copy of the version to keep in sync.
75
+ "ruff==0.3.7",
60
76
  # Read by scripts/prune-stale-api.py (parses filtered-openapi.yaml to derive which
61
77
  # api/ group dirs the spec still produces) and by tests/conftest.py. Generation-time
62
78
  # and test-time only — never a runtime dependency of the published client.
@@ -82,9 +98,23 @@ testpaths = ["tests"]
82
98
  pythonpath = ["src"]
83
99
 
84
100
  [tool.hatch.build.targets.sdist]
101
+ # The test tree was REMOVED from this allowlist in #2593 (the pre-merge grep gate asserts the
102
+ # glob appears zero times in this file, so a reintroduction is caught even inside a comment —
103
+ # hence the prose here names it in words). The shipped suite could not collect: 12 of 27 modules need
104
+ # `scripts/` (contributor-only codegen tooling) or the canonical `docs/api/openapi.yaml` (which
105
+ # lives two directories above this package), and three of them build distributions of this
106
+ # package — incoherent from inside an unpacked sdist. Verified from the built artifact:
107
+ # `FileNotFoundError: .../scripts/inject-handwritten.py` interrupted collection.
108
+ #
109
+ # Dropped rather than made self-contained: vendoring `scripts/` + a copy of the spec into a
110
+ # public distribution would breach the same published-content boundary that keeps CLAUDE.md out.
111
+ # A test tree that cannot run is worse than none — it reads as a promise to downstream packagers
112
+ # that running it validates the install. Pinned by tests/test_sdist_excludes_tests.
113
+ #
114
+ # The WHEEL is untouched (see [tool.hatch.build.targets.wheel] above): no importable module is
115
+ # removed from what users install.
85
116
  include = [
86
117
  "src/bytekit/**",
87
- "tests/**",
88
118
  "README.md",
89
119
  "CHANGELOG.md",
90
120
  "LICENSE",
@@ -7,6 +7,7 @@ from ... import errors
7
7
  from ...client import AuthenticatedClient, Client
8
8
  from ...models.account_bearer_response import AccountBearerResponse
9
9
  from ...models.account_session_response import AccountSessionResponse
10
+ from ...models.error import Error
10
11
  from ...types import Response
11
12
 
12
13
 
@@ -21,7 +22,7 @@ def _get_kwargs() -> dict[str, Any]:
21
22
 
22
23
  def _parse_response(
23
24
  *, client: Union[AuthenticatedClient, Client], response: httpx.Response
24
- ) -> Optional[Union["AccountBearerResponse", "AccountSessionResponse"]]:
25
+ ) -> Optional[Union[Error, Union["AccountBearerResponse", "AccountSessionResponse"]]]:
25
26
  if response.status_code == 200:
26
27
 
27
28
  def _parse_response_200(
@@ -44,6 +45,10 @@ def _parse_response(
44
45
  response_200 = errors.bytekit_parse(_parse_response_200, client=client, response=response)
45
46
 
46
47
  return response_200
48
+ if response.status_code == 429:
49
+ response_429 = errors.bytekit_parse(Error.from_dict, client=client, response=response)
50
+
51
+ return response_429
47
52
  if client.raise_on_unexpected_status:
48
53
  raise errors.bytekit_unexpected(response) # BYTEKIT-OP-GUARD
49
54
  else:
@@ -52,7 +57,7 @@ def _parse_response(
52
57
 
53
58
  def _build_response(
54
59
  *, client: Union[AuthenticatedClient, Client], response: httpx.Response
55
- ) -> Response[Union["AccountBearerResponse", "AccountSessionResponse"]]:
60
+ ) -> Response[Union[Error, Union["AccountBearerResponse", "AccountSessionResponse"]]]:
56
61
  return Response(
57
62
  status_code=HTTPStatus(response.status_code),
58
63
  content=response.content,
@@ -64,7 +69,7 @@ def _build_response(
64
69
  def sync_detailed(
65
70
  *,
66
71
  client: AuthenticatedClient,
67
- ) -> Response[Union["AccountBearerResponse", "AccountSessionResponse"]]:
72
+ ) -> Response[Union[Error, Union["AccountBearerResponse", "AccountSessionResponse"]]]:
68
73
  """Get account details
69
74
 
70
75
  Returns account, plan, and current API key details, including the
@@ -75,7 +80,7 @@ def sync_detailed(
75
80
  httpx.TimeoutException: If the request takes longer than Client.timeout.
76
81
 
77
82
  Returns:
78
- Response[Union['AccountBearerResponse', 'AccountSessionResponse']]
83
+ Response[Union[Error, Union['AccountBearerResponse', 'AccountSessionResponse']]]
79
84
  """
80
85
 
81
86
  kwargs = _get_kwargs()
@@ -90,7 +95,7 @@ def sync_detailed(
90
95
  def sync(
91
96
  *,
92
97
  client: AuthenticatedClient,
93
- ) -> Optional[Union["AccountBearerResponse", "AccountSessionResponse"]]:
98
+ ) -> Optional[Union[Error, Union["AccountBearerResponse", "AccountSessionResponse"]]]:
94
99
  """Get account details
95
100
 
96
101
  Returns account, plan, and current API key details, including the
@@ -101,7 +106,7 @@ def sync(
101
106
  httpx.TimeoutException: If the request takes longer than Client.timeout.
102
107
 
103
108
  Returns:
104
- Union['AccountBearerResponse', 'AccountSessionResponse']
109
+ Union[Error, Union['AccountBearerResponse', 'AccountSessionResponse']]
105
110
  """
106
111
 
107
112
  return sync_detailed(
@@ -112,7 +117,7 @@ def sync(
112
117
  async def asyncio_detailed(
113
118
  *,
114
119
  client: AuthenticatedClient,
115
- ) -> Response[Union["AccountBearerResponse", "AccountSessionResponse"]]:
120
+ ) -> Response[Union[Error, Union["AccountBearerResponse", "AccountSessionResponse"]]]:
116
121
  """Get account details
117
122
 
118
123
  Returns account, plan, and current API key details, including the
@@ -123,7 +128,7 @@ async def asyncio_detailed(
123
128
  httpx.TimeoutException: If the request takes longer than Client.timeout.
124
129
 
125
130
  Returns:
126
- Response[Union['AccountBearerResponse', 'AccountSessionResponse']]
131
+ Response[Union[Error, Union['AccountBearerResponse', 'AccountSessionResponse']]]
127
132
  """
128
133
 
129
134
  kwargs = _get_kwargs()
@@ -136,7 +141,7 @@ async def asyncio_detailed(
136
141
  async def asyncio(
137
142
  *,
138
143
  client: AuthenticatedClient,
139
- ) -> Optional[Union["AccountBearerResponse", "AccountSessionResponse"]]:
144
+ ) -> Optional[Union[Error, Union["AccountBearerResponse", "AccountSessionResponse"]]]:
140
145
  """Get account details
141
146
 
142
147
  Returns account, plan, and current API key details, including the
@@ -147,7 +152,7 @@ async def asyncio(
147
152
  httpx.TimeoutException: If the request takes longer than Client.timeout.
148
153
 
149
154
  Returns:
150
- Union['AccountBearerResponse', 'AccountSessionResponse']
155
+ Union[Error, Union['AccountBearerResponse', 'AccountSessionResponse']]
151
156
  """
152
157
 
153
158
  return (
@@ -74,12 +74,38 @@ def sync_detailed(
74
74
  Webhook deliveries include `X-ByteKit-Event: bulk.completed` so
75
75
  receivers can dispatch on the header without parsing the body shape.
76
76
 
77
+ **Limits:** request bodies are guarded in a two-tier shape. A streamed body
78
+ with no `Content-Length` header is capped at 4 MB before your API key
79
+ is checked; a body that declares `Content-Length` is instead bounded
80
+ there by a 32 MB fail-safe (not the real limit — see below), since
81
+ that branch reads nothing until your key is verified. Once your key
82
+ is verified, a second check re-gates the body against your account's
83
+ own `max_bulk_size` (at this endpoint's richer per-item override
84
+ budget), which reaches 28.7 MB for the largest documented account. A
85
+ standard-plan account's effective ceiling is 4 MB; either tier's
86
+ overrun returns a `400` with error code `request_too_large`.
87
+
77
88
  Args:
78
89
  body (CreateBulkBody): Provide `urls` (simple list) OR `items` (per-item config), not
79
90
  both. `type` selects the capture kind per entry — only
80
91
  `screenshot` and `scrape` are accepted (`recording` is
81
92
  deactivated). Behaviour fields may be set per item or via
82
93
  `defaults`; a per-item value overrides the matching default.
94
+ This includes `type`: an entry with no `type` of its own
95
+ inherits `defaults.type`, falling back to `screenshot` only
96
+ when neither is set.
97
+
98
+ The top-level object, each `items[]` entry, and `defaults`
99
+ each reject unrecognized keys with a 422 `validation_error`
100
+ (the offending key name appears in the error's `details`
101
+ message text) rather than silently discarding them.
102
+ `items[]` and `defaults` do not share one field set:
103
+ `device_scale_factor` is accepted only under `defaults` (a
104
+ per-item value 422s), and `duration`/`scenario` are accepted
105
+ only per item (a `defaults` value 422s). `metadata` is
106
+ different from those three: it is valid both at the top
107
+ level of the body and per item, but rejected with a 422 if
108
+ placed under `defaults`. See the `422` response below.
83
109
 
84
110
  Raises:
85
111
  errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
@@ -112,12 +138,38 @@ def sync(
112
138
  Webhook deliveries include `X-ByteKit-Event: bulk.completed` so
113
139
  receivers can dispatch on the header without parsing the body shape.
114
140
 
141
+ **Limits:** request bodies are guarded in a two-tier shape. A streamed body
142
+ with no `Content-Length` header is capped at 4 MB before your API key
143
+ is checked; a body that declares `Content-Length` is instead bounded
144
+ there by a 32 MB fail-safe (not the real limit — see below), since
145
+ that branch reads nothing until your key is verified. Once your key
146
+ is verified, a second check re-gates the body against your account's
147
+ own `max_bulk_size` (at this endpoint's richer per-item override
148
+ budget), which reaches 28.7 MB for the largest documented account. A
149
+ standard-plan account's effective ceiling is 4 MB; either tier's
150
+ overrun returns a `400` with error code `request_too_large`.
151
+
115
152
  Args:
116
153
  body (CreateBulkBody): Provide `urls` (simple list) OR `items` (per-item config), not
117
154
  both. `type` selects the capture kind per entry — only
118
155
  `screenshot` and `scrape` are accepted (`recording` is
119
156
  deactivated). Behaviour fields may be set per item or via
120
157
  `defaults`; a per-item value overrides the matching default.
158
+ This includes `type`: an entry with no `type` of its own
159
+ inherits `defaults.type`, falling back to `screenshot` only
160
+ when neither is set.
161
+
162
+ The top-level object, each `items[]` entry, and `defaults`
163
+ each reject unrecognized keys with a 422 `validation_error`
164
+ (the offending key name appears in the error's `details`
165
+ message text) rather than silently discarding them.
166
+ `items[]` and `defaults` do not share one field set:
167
+ `device_scale_factor` is accepted only under `defaults` (a
168
+ per-item value 422s), and `duration`/`scenario` are accepted
169
+ only per item (a `defaults` value 422s). `metadata` is
170
+ different from those three: it is valid both at the top
171
+ level of the body and per item, but rejected with a 422 if
172
+ placed under `defaults`. See the `422` response below.
121
173
 
122
174
  Raises:
123
175
  errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
@@ -145,12 +197,38 @@ async def asyncio_detailed(
145
197
  Webhook deliveries include `X-ByteKit-Event: bulk.completed` so
146
198
  receivers can dispatch on the header without parsing the body shape.
147
199
 
200
+ **Limits:** request bodies are guarded in a two-tier shape. A streamed body
201
+ with no `Content-Length` header is capped at 4 MB before your API key
202
+ is checked; a body that declares `Content-Length` is instead bounded
203
+ there by a 32 MB fail-safe (not the real limit — see below), since
204
+ that branch reads nothing until your key is verified. Once your key
205
+ is verified, a second check re-gates the body against your account's
206
+ own `max_bulk_size` (at this endpoint's richer per-item override
207
+ budget), which reaches 28.7 MB for the largest documented account. A
208
+ standard-plan account's effective ceiling is 4 MB; either tier's
209
+ overrun returns a `400` with error code `request_too_large`.
210
+
148
211
  Args:
149
212
  body (CreateBulkBody): Provide `urls` (simple list) OR `items` (per-item config), not
150
213
  both. `type` selects the capture kind per entry — only
151
214
  `screenshot` and `scrape` are accepted (`recording` is
152
215
  deactivated). Behaviour fields may be set per item or via
153
216
  `defaults`; a per-item value overrides the matching default.
217
+ This includes `type`: an entry with no `type` of its own
218
+ inherits `defaults.type`, falling back to `screenshot` only
219
+ when neither is set.
220
+
221
+ The top-level object, each `items[]` entry, and `defaults`
222
+ each reject unrecognized keys with a 422 `validation_error`
223
+ (the offending key name appears in the error's `details`
224
+ message text) rather than silently discarding them.
225
+ `items[]` and `defaults` do not share one field set:
226
+ `device_scale_factor` is accepted only under `defaults` (a
227
+ per-item value 422s), and `duration`/`scenario` are accepted
228
+ only per item (a `defaults` value 422s). `metadata` is
229
+ different from those three: it is valid both at the top
230
+ level of the body and per item, but rejected with a 422 if
231
+ placed under `defaults`. See the `422` response below.
154
232
 
155
233
  Raises:
156
234
  errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
@@ -181,12 +259,38 @@ async def asyncio(
181
259
  Webhook deliveries include `X-ByteKit-Event: bulk.completed` so
182
260
  receivers can dispatch on the header without parsing the body shape.
183
261
 
262
+ **Limits:** request bodies are guarded in a two-tier shape. A streamed body
263
+ with no `Content-Length` header is capped at 4 MB before your API key
264
+ is checked; a body that declares `Content-Length` is instead bounded
265
+ there by a 32 MB fail-safe (not the real limit — see below), since
266
+ that branch reads nothing until your key is verified. Once your key
267
+ is verified, a second check re-gates the body against your account's
268
+ own `max_bulk_size` (at this endpoint's richer per-item override
269
+ budget), which reaches 28.7 MB for the largest documented account. A
270
+ standard-plan account's effective ceiling is 4 MB; either tier's
271
+ overrun returns a `400` with error code `request_too_large`.
272
+
184
273
  Args:
185
274
  body (CreateBulkBody): Provide `urls` (simple list) OR `items` (per-item config), not
186
275
  both. `type` selects the capture kind per entry — only
187
276
  `screenshot` and `scrape` are accepted (`recording` is
188
277
  deactivated). Behaviour fields may be set per item or via
189
278
  `defaults`; a per-item value overrides the matching default.
279
+ This includes `type`: an entry with no `type` of its own
280
+ inherits `defaults.type`, falling back to `screenshot` only
281
+ when neither is set.
282
+
283
+ The top-level object, each `items[]` entry, and `defaults`
284
+ each reject unrecognized keys with a 422 `validation_error`
285
+ (the offending key name appears in the error's `details`
286
+ message text) rather than silently discarding them.
287
+ `items[]` and `defaults` do not share one field set:
288
+ `device_scale_factor` is accepted only under `defaults` (a
289
+ per-item value 422s), and `duration`/`scenario` are accepted
290
+ only per item (a `defaults` value 422s). `metadata` is
291
+ different from those three: it is valid both at the top
292
+ level of the body and per item, but rejected with a 422 if
293
+ placed under `defaults`. See the `422` response below.
190
294
 
191
295
  Raises:
192
296
  errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.