kernel 0.59.0__tar.gz → 0.61.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- kernel-0.61.0/.release-please-manifest.json +3 -0
- {kernel-0.59.0 → kernel-0.61.0}/CHANGELOG.md +24 -0
- {kernel-0.59.0 → kernel-0.61.0}/PKG-INFO +1 -1
- kernel-0.61.0/examples/browser_telemetry.py +32 -0
- {kernel-0.59.0 → kernel-0.61.0}/pyproject.toml +1 -1
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/_streaming.py +6 -1
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/_version.py +1 -1
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/lib/browser_routing/routing.py +1 -1
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/resources/api_keys.py +27 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/resources/browser_pools.py +12 -12
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/resources/browsers/replays.py +10 -0
- kernel-0.61.0/src/kernel/types/api_key_list_params.py +27 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/browser_pool_update_params.py +8 -8
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/browsers/replay_start_params.py +6 -0
- {kernel-0.59.0 → kernel-0.61.0}/tests/api_resources/browsers/test_replays.py +2 -0
- {kernel-0.59.0 → kernel-0.61.0}/tests/api_resources/test_api_keys.py +6 -0
- {kernel-0.59.0 → kernel-0.61.0}/tests/api_resources/test_browser_pools.py +2 -10
- {kernel-0.59.0 → kernel-0.61.0}/tests/test_browser_routing.py +23 -1
- {kernel-0.59.0 → kernel-0.61.0}/tests/test_streaming.py +26 -0
- kernel-0.59.0/.release-please-manifest.json +0 -3
- kernel-0.59.0/src/kernel/types/api_key_list_params.py +0 -15
- {kernel-0.59.0 → kernel-0.61.0}/.gitignore +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/CONTRIBUTING.md +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/LICENSE +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/README.md +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/SECURITY.md +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/api.md +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/bin/check-release-environment +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/bin/publish-pypi +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/examples/.keep +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/examples/browser_routing.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/noxfile.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/release-please-config.json +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/requirements-dev.lock +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/requirements.lock +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/__init__.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/_base_client.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/_client.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/_compat.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/_constants.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/_exceptions.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/_files.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/_models.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/_qs.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/_resource.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/_response.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/_types.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/_utils/__init__.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/_utils/_compat.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/_utils/_datetime_parse.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/_utils/_json.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/_utils/_logs.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/_utils/_path.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/_utils/_proxy.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/_utils/_reflection.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/_utils/_resources_proxy.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/_utils/_streams.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/_utils/_sync.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/_utils/_transform.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/_utils/_typing.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/_utils/_utils.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/app_framework.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/lib/.keep +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/lib/browser_routing/__init__.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/lib/browser_routing/raw_http.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/lib/browser_routing/util.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/pagination.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/py.typed +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/resources/__init__.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/resources/apps.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/resources/auth/__init__.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/resources/auth/auth.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/resources/auth/connections.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/resources/browsers/__init__.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/resources/browsers/browsers.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/resources/browsers/computer.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/resources/browsers/fs/__init__.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/resources/browsers/fs/fs.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/resources/browsers/fs/watch.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/resources/browsers/logs.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/resources/browsers/playwright.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/resources/browsers/process.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/resources/browsers/telemetry.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/resources/credential_providers.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/resources/credentials.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/resources/deployments.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/resources/extensions.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/resources/invocations.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/resources/profiles.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/resources/projects/__init__.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/resources/projects/limits.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/resources/projects/projects.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/resources/proxies.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/__init__.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/api_key.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/api_key_create_params.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/api_key_update_params.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/app_list_params.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/app_list_response.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/auth/__init__.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/auth/connection_create_params.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/auth/connection_follow_response.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/auth/connection_list_params.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/auth/connection_login_params.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/auth/connection_submit_params.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/auth/connection_update_params.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/auth/login_response.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/auth/managed_auth.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/auth/submit_fields_response.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/browser_create_params.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/browser_create_response.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/browser_curl_params.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/browser_curl_response.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/browser_list_params.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/browser_list_response.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/browser_load_extensions_params.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/browser_pool.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/browser_pool_acquire_params.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/browser_pool_acquire_response.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/browser_pool_create_params.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/browser_pool_delete_params.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/browser_pool_list_response.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/browser_pool_ref.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/browser_pool_release_params.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/browser_retrieve_params.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/browser_retrieve_response.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/browser_update_params.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/browser_update_response.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/browser_usage.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/browsers/__init__.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/browsers/browser_call_stack.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/browsers/browser_console_error_event.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/browsers/browser_console_log_event.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/browsers/browser_event_context.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/browsers/browser_event_source.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/browsers/browser_http_headers.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/browsers/browser_interaction_click_event.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/browsers/browser_interaction_key_event.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/browsers/browser_interaction_scroll_settled_event.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/browsers/browser_monitor_disconnected_event.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/browsers/browser_monitor_init_failed_event.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/browsers/browser_monitor_reconnect_failed_event.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/browsers/browser_monitor_reconnected_event.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/browsers/browser_monitor_screenshot_event.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/browsers/browser_network_idle_event.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/browsers/browser_network_loading_failed_event.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/browsers/browser_network_request_event.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/browsers/browser_network_response_event.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/browsers/browser_page_dom_content_loaded_event.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/browsers/browser_page_layout_settled_event.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/browsers/browser_page_layout_shift_event.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/browsers/browser_page_lcp_event.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/browsers/browser_page_load_event.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/browsers/browser_page_navigation_event.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/browsers/browser_page_navigation_settled_event.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/browsers/browser_page_tab_opened_event.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/browsers/browser_telemetry_categories_config.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/browsers/browser_telemetry_categories_config_param.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/browsers/browser_telemetry_category_config.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/browsers/browser_telemetry_category_config_param.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/browsers/browser_telemetry_config.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/browsers/browser_telemetry_event.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/browsers/computer_batch_params.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/browsers/computer_capture_screenshot_params.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/browsers/computer_click_mouse_params.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/browsers/computer_drag_mouse_params.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/browsers/computer_get_mouse_position_response.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/browsers/computer_move_mouse_params.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/browsers/computer_press_key_params.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/browsers/computer_read_clipboard_response.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/browsers/computer_scroll_params.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/browsers/computer_set_cursor_visibility_params.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/browsers/computer_set_cursor_visibility_response.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/browsers/computer_type_text_params.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/browsers/computer_write_clipboard_params.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/browsers/f_create_directory_params.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/browsers/f_delete_directory_params.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/browsers/f_delete_file_params.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/browsers/f_download_dir_zip_params.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/browsers/f_file_info_params.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/browsers/f_file_info_response.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/browsers/f_list_files_params.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/browsers/f_list_files_response.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/browsers/f_move_params.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/browsers/f_read_file_params.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/browsers/f_set_file_permissions_params.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/browsers/f_upload_params.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/browsers/f_upload_zip_params.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/browsers/f_write_file_params.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/browsers/fs/__init__.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/browsers/fs/watch_events_response.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/browsers/fs/watch_start_params.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/browsers/fs/watch_start_response.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/browsers/log_stream_params.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/browsers/playwright_execute_params.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/browsers/playwright_execute_response.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/browsers/process_exec_params.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/browsers/process_exec_response.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/browsers/process_kill_params.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/browsers/process_kill_response.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/browsers/process_resize_params.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/browsers/process_resize_response.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/browsers/process_spawn_params.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/browsers/process_spawn_response.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/browsers/process_status_response.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/browsers/process_stdin_params.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/browsers/process_stdin_response.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/browsers/process_stdout_stream_response.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/browsers/replay_list_response.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/browsers/replay_start_response.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/browsers/telemetry_stream_response.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/created_api_key.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/credential.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/credential_create_params.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/credential_list_params.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/credential_provider.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/credential_provider_create_params.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/credential_provider_item.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/credential_provider_list_items_response.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/credential_provider_list_response.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/credential_provider_test_result.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/credential_provider_update_params.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/credential_totp_code_response.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/credential_update_params.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/deployment_create_params.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/deployment_create_response.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/deployment_follow_params.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/deployment_follow_response.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/deployment_list_params.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/deployment_list_response.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/deployment_retrieve_response.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/deployment_state_event.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/extension_download_from_chrome_store_params.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/extension_list_response.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/extension_upload_params.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/extension_upload_response.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/invocation_create_params.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/invocation_create_response.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/invocation_follow_params.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/invocation_follow_response.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/invocation_list_browsers_response.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/invocation_list_params.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/invocation_list_response.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/invocation_retrieve_response.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/invocation_state_event.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/invocation_update_params.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/invocation_update_response.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/profile.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/profile_create_params.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/profile_list_params.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/project.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/project_create_params.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/project_list_params.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/project_update_params.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/projects/__init__.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/projects/limit_update_params.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/projects/project_limits.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/proxy_check_params.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/proxy_check_response.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/proxy_create_params.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/proxy_create_response.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/proxy_list_response.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/proxy_retrieve_response.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/shared/__init__.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/shared/app_action.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/shared/browser_extension.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/shared/browser_profile.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/shared/browser_viewport.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/shared/error_detail.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/shared/error_event.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/shared/error_model.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/shared/heartbeat_event.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/shared/log_event.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/shared_params/__init__.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/shared_params/browser_extension.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/shared_params/browser_profile.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/src/kernel/types/shared_params/browser_viewport.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/tests/__init__.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/tests/api_resources/__init__.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/tests/api_resources/auth/__init__.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/tests/api_resources/auth/test_connections.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/tests/api_resources/browsers/__init__.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/tests/api_resources/browsers/fs/__init__.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/tests/api_resources/browsers/fs/test_watch.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/tests/api_resources/browsers/test_computer.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/tests/api_resources/browsers/test_fs.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/tests/api_resources/browsers/test_logs.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/tests/api_resources/browsers/test_playwright.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/tests/api_resources/browsers/test_process.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/tests/api_resources/browsers/test_telemetry.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/tests/api_resources/projects/__init__.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/tests/api_resources/projects/test_limits.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/tests/api_resources/test_apps.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/tests/api_resources/test_browsers.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/tests/api_resources/test_credential_providers.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/tests/api_resources/test_credentials.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/tests/api_resources/test_deployments.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/tests/api_resources/test_extensions.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/tests/api_resources/test_invocations.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/tests/api_resources/test_profiles.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/tests/api_resources/test_projects.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/tests/api_resources/test_proxies.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/tests/conftest.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/tests/sample_file.txt +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/tests/test_client.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/tests/test_extract_files.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/tests/test_files.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/tests/test_models.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/tests/test_qs.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/tests/test_required_args.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/tests/test_response.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/tests/test_transform.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/tests/test_utils/test_datetime_parse.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/tests/test_utils/test_json.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/tests/test_utils/test_path.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/tests/test_utils/test_proxy.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/tests/test_utils/test_typing.py +0 -0
- {kernel-0.59.0 → kernel-0.61.0}/tests/utils.py +0 -0
|
@@ -1,5 +1,29 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.61.0 (2026-06-03)
|
|
4
|
+
|
|
5
|
+
Full Changelog: [v0.60.0...v0.61.0](https://github.com/kernel/kernel-python-sdk/compare/v0.60.0...v0.61.0)
|
|
6
|
+
|
|
7
|
+
### Features
|
|
8
|
+
|
|
9
|
+
* Add record_audio option to browser replay recording API ([7d357c2](https://github.com/kernel/kernel-python-sdk/commit/7d357c27c32315ba3a7fcaddac0f6563aab91849))
|
|
10
|
+
|
|
11
|
+
## 0.60.0 (2026-06-03)
|
|
12
|
+
|
|
13
|
+
Full Changelog: [v0.59.0...v0.60.0](https://github.com/kernel/kernel-python-sdk/compare/v0.59.0...v0.60.0)
|
|
14
|
+
|
|
15
|
+
### Features
|
|
16
|
+
|
|
17
|
+
* Add API-backed API key management endpoints ([55bd31e](https://github.com/kernel/kernel-python-sdk/commit/55bd31edfed74f3bc4b08f83e07448e2e53378b0))
|
|
18
|
+
* **examples:** add browser-telemetry example ([4c29993](https://github.com/kernel/kernel-python-sdk/commit/4c29993cdda50fcde19ee7bf696a268cd8b0eb0b))
|
|
19
|
+
* Fix browser pool update schema ([903fe13](https://github.com/kernel/kernel-python-sdk/commit/903fe13b84242acea9c27bc451c16fb5cd58e40c))
|
|
20
|
+
* route browser telemetry directly to the VM by default ([cb50725](https://github.com/kernel/kernel-python-sdk/commit/cb5072516416627ffde7198900484c46dda5b9dc))
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
### Bug Fixes
|
|
24
|
+
|
|
25
|
+
* **streaming:** don't dispatch empty SSE keepalive comment frames ([a0ee2b2](https://github.com/kernel/kernel-python-sdk/commit/a0ee2b2653c581839be11bb29be5b68166e80658))
|
|
26
|
+
|
|
3
27
|
## 0.59.0 (2026-06-03)
|
|
4
28
|
|
|
5
29
|
Full Changelog: [v0.58.0...v0.59.0](https://github.com/kernel/kernel-python-sdk/compare/v0.58.0...v0.59.0)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: kernel
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.61.0
|
|
4
4
|
Summary: The official Python library for the kernel API
|
|
5
5
|
Project-URL: Homepage, https://github.com/kernel/kernel-python-sdk
|
|
6
6
|
Project-URL: Repository, https://github.com/kernel/kernel-python-sdk
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"""Example: stream live browser telemetry events from a session."""
|
|
2
|
+
|
|
3
|
+
from kernel import Kernel
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def main() -> None:
|
|
7
|
+
client = Kernel()
|
|
8
|
+
|
|
9
|
+
# Enable telemetry capture when creating the browser.
|
|
10
|
+
browser = client.browsers.create(telemetry={"enabled": True})
|
|
11
|
+
|
|
12
|
+
try:
|
|
13
|
+
# Telemetry is a default direct-to-VM routing subresource, so the stream
|
|
14
|
+
# connects straight to the browser VM automatically.
|
|
15
|
+
stream = client.browsers.telemetry.stream(browser.session_id)
|
|
16
|
+
|
|
17
|
+
# Make a few browser activity calls to generate events. The "api" telemetry
|
|
18
|
+
# category emits an event per VM API call, so events arrive within ~1s.
|
|
19
|
+
for _ in range(3):
|
|
20
|
+
client.browsers.curl(browser.session_id, url="https://example.com", method="GET")
|
|
21
|
+
|
|
22
|
+
# Print a few events, then stop so we don't wait on the 15s keepalive.
|
|
23
|
+
for count, message in enumerate(stream, start=1):
|
|
24
|
+
print(message.seq, message.event.type)
|
|
25
|
+
if count >= 3:
|
|
26
|
+
break
|
|
27
|
+
finally:
|
|
28
|
+
client.browsers.delete_by_id(browser.session_id)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
if __name__ == "__main__":
|
|
32
|
+
main()
|
|
@@ -251,7 +251,12 @@ class SSEDecoder:
|
|
|
251
251
|
# See: https://html.spec.whatwg.org/multipage/server-sent-events.html#event-stream-interpretation # noqa: E501
|
|
252
252
|
|
|
253
253
|
if not line:
|
|
254
|
-
|
|
254
|
+
# Whether to dispatch depends only on what was set in the *current* block. last_event_id
|
|
255
|
+
# is sticky across events (per the SSE spec, it is intentionally not reset below), so it
|
|
256
|
+
# must not be part of this check -- otherwise, once any event carries an id, every
|
|
257
|
+
# subsequent comment-only block (e.g. a ``:\n\n`` keepalive) would dispatch an empty
|
|
258
|
+
# event, which then fails to JSON-decode in the typed Stream wrapper.
|
|
259
|
+
if not self._event and not self._data and self._retry is None:
|
|
255
260
|
return None
|
|
256
261
|
|
|
257
262
|
sse = ServerSentEvent(
|
|
@@ -41,7 +41,7 @@ _BROWSER_POOL_RELEASE_PATH = re.compile(r"^/(?:v\d+/)?browser_pools/[^/]+/releas
|
|
|
41
41
|
def browser_routing_config_from_env() -> BrowserRoutingConfig:
|
|
42
42
|
raw = os.environ.get("KERNEL_BROWSER_ROUTING_SUBRESOURCES")
|
|
43
43
|
if raw is None:
|
|
44
|
-
return BrowserRoutingConfig(subresources=("curl",))
|
|
44
|
+
return BrowserRoutingConfig(subresources=("curl", "telemetry"))
|
|
45
45
|
if raw.strip() == "":
|
|
46
46
|
return BrowserRoutingConfig()
|
|
47
47
|
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
5
|
from typing import Optional
|
|
6
|
+
from typing_extensions import Literal
|
|
6
7
|
|
|
7
8
|
import httpx
|
|
8
9
|
|
|
@@ -171,6 +172,9 @@ class APIKeysResource(SyncAPIResource):
|
|
|
171
172
|
*,
|
|
172
173
|
limit: int | Omit = omit,
|
|
173
174
|
offset: int | Omit = omit,
|
|
175
|
+
query: str | Omit = omit,
|
|
176
|
+
sort_by: Literal["created_at", "name", "expires_at"] | Omit = omit,
|
|
177
|
+
sort_direction: Literal["asc", "desc"] | Omit = omit,
|
|
174
178
|
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
|
|
175
179
|
# The extra values given here take precedence over values defined on the client or passed to this method.
|
|
176
180
|
extra_headers: Headers | None = None,
|
|
@@ -187,6 +191,13 @@ class APIKeysResource(SyncAPIResource):
|
|
|
187
191
|
|
|
188
192
|
offset: Number of results to skip
|
|
189
193
|
|
|
194
|
+
query: Case-insensitive substring match against API key name, creator, and project. API
|
|
195
|
+
key identifiers and masked keys match by exact value or prefix.
|
|
196
|
+
|
|
197
|
+
sort_by: Field to sort API keys by.
|
|
198
|
+
|
|
199
|
+
sort_direction: Sort direction for API keys.
|
|
200
|
+
|
|
190
201
|
extra_headers: Send extra headers
|
|
191
202
|
|
|
192
203
|
extra_query: Add additional query parameters to the request
|
|
@@ -207,6 +218,9 @@ class APIKeysResource(SyncAPIResource):
|
|
|
207
218
|
{
|
|
208
219
|
"limit": limit,
|
|
209
220
|
"offset": offset,
|
|
221
|
+
"query": query,
|
|
222
|
+
"sort_by": sort_by,
|
|
223
|
+
"sort_direction": sort_direction,
|
|
210
224
|
},
|
|
211
225
|
api_key_list_params.APIKeyListParams,
|
|
212
226
|
),
|
|
@@ -395,6 +409,9 @@ class AsyncAPIKeysResource(AsyncAPIResource):
|
|
|
395
409
|
*,
|
|
396
410
|
limit: int | Omit = omit,
|
|
397
411
|
offset: int | Omit = omit,
|
|
412
|
+
query: str | Omit = omit,
|
|
413
|
+
sort_by: Literal["created_at", "name", "expires_at"] | Omit = omit,
|
|
414
|
+
sort_direction: Literal["asc", "desc"] | Omit = omit,
|
|
398
415
|
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
|
|
399
416
|
# The extra values given here take precedence over values defined on the client or passed to this method.
|
|
400
417
|
extra_headers: Headers | None = None,
|
|
@@ -411,6 +428,13 @@ class AsyncAPIKeysResource(AsyncAPIResource):
|
|
|
411
428
|
|
|
412
429
|
offset: Number of results to skip
|
|
413
430
|
|
|
431
|
+
query: Case-insensitive substring match against API key name, creator, and project. API
|
|
432
|
+
key identifiers and masked keys match by exact value or prefix.
|
|
433
|
+
|
|
434
|
+
sort_by: Field to sort API keys by.
|
|
435
|
+
|
|
436
|
+
sort_direction: Sort direction for API keys.
|
|
437
|
+
|
|
414
438
|
extra_headers: Send extra headers
|
|
415
439
|
|
|
416
440
|
extra_query: Add additional query parameters to the request
|
|
@@ -431,6 +455,9 @@ class AsyncAPIKeysResource(AsyncAPIResource):
|
|
|
431
455
|
{
|
|
432
456
|
"limit": limit,
|
|
433
457
|
"offset": offset,
|
|
458
|
+
"query": query,
|
|
459
|
+
"sort_by": sort_by,
|
|
460
|
+
"sort_direction": sort_direction,
|
|
434
461
|
},
|
|
435
462
|
api_key_list_params.APIKeyListParams,
|
|
436
463
|
),
|
|
@@ -206,7 +206,6 @@ class BrowserPoolsResource(SyncAPIResource):
|
|
|
206
206
|
self,
|
|
207
207
|
id_or_name: str,
|
|
208
208
|
*,
|
|
209
|
-
size: int,
|
|
210
209
|
chrome_policy: Dict[str, object] | Omit = omit,
|
|
211
210
|
discard_all_idle: bool | Omit = omit,
|
|
212
211
|
extensions: Iterable[BrowserExtension] | Omit = omit,
|
|
@@ -216,6 +215,7 @@ class BrowserPoolsResource(SyncAPIResource):
|
|
|
216
215
|
name: str | Omit = omit,
|
|
217
216
|
profile: BrowserProfile | Omit = omit,
|
|
218
217
|
proxy_id: str | Omit = omit,
|
|
218
|
+
size: int | Omit = omit,
|
|
219
219
|
start_url: str | Omit = omit,
|
|
220
220
|
stealth: bool | Omit = omit,
|
|
221
221
|
timeout_seconds: int | Omit = omit,
|
|
@@ -231,10 +231,6 @@ class BrowserPoolsResource(SyncAPIResource):
|
|
|
231
231
|
Updates the configuration used to create browsers in the pool.
|
|
232
232
|
|
|
233
233
|
Args:
|
|
234
|
-
size: Number of browsers to maintain in the pool. The maximum size is determined by
|
|
235
|
-
your organization's pooled sessions limit (the sum of all pool sizes cannot
|
|
236
|
-
exceed your limit).
|
|
237
|
-
|
|
238
234
|
chrome_policy: Custom Chrome enterprise policy overrides applied to all browsers in this pool.
|
|
239
235
|
Keys are Chrome enterprise policy names; values must match their expected types.
|
|
240
236
|
Blocked: kernel-managed policies (extensions, proxy, CDP/automation). See
|
|
@@ -261,6 +257,10 @@ class BrowserPoolsResource(SyncAPIResource):
|
|
|
261
257
|
proxy_id: Optional proxy to associate to the browser session. Must reference a proxy
|
|
262
258
|
belonging to the caller's org.
|
|
263
259
|
|
|
260
|
+
size: Number of browsers to maintain in the pool. The maximum size is determined by
|
|
261
|
+
your organization's pooled sessions limit (the sum of all pool sizes cannot
|
|
262
|
+
exceed your limit).
|
|
263
|
+
|
|
264
264
|
start_url: Optional URL to navigate to when a new browser is warmed into the pool.
|
|
265
265
|
Best-effort: failures to navigate do not fail pool fill. Only applied to
|
|
266
266
|
newly-warmed browsers; browsers reused via release/acquire keep whatever URL the
|
|
@@ -300,7 +300,6 @@ class BrowserPoolsResource(SyncAPIResource):
|
|
|
300
300
|
path_template("/browser_pools/{id_or_name}", id_or_name=id_or_name),
|
|
301
301
|
body=maybe_transform(
|
|
302
302
|
{
|
|
303
|
-
"size": size,
|
|
304
303
|
"chrome_policy": chrome_policy,
|
|
305
304
|
"discard_all_idle": discard_all_idle,
|
|
306
305
|
"extensions": extensions,
|
|
@@ -310,6 +309,7 @@ class BrowserPoolsResource(SyncAPIResource):
|
|
|
310
309
|
"name": name,
|
|
311
310
|
"profile": profile,
|
|
312
311
|
"proxy_id": proxy_id,
|
|
312
|
+
"size": size,
|
|
313
313
|
"start_url": start_url,
|
|
314
314
|
"stealth": stealth,
|
|
315
315
|
"timeout_seconds": timeout_seconds,
|
|
@@ -684,7 +684,6 @@ class AsyncBrowserPoolsResource(AsyncAPIResource):
|
|
|
684
684
|
self,
|
|
685
685
|
id_or_name: str,
|
|
686
686
|
*,
|
|
687
|
-
size: int,
|
|
688
687
|
chrome_policy: Dict[str, object] | Omit = omit,
|
|
689
688
|
discard_all_idle: bool | Omit = omit,
|
|
690
689
|
extensions: Iterable[BrowserExtension] | Omit = omit,
|
|
@@ -694,6 +693,7 @@ class AsyncBrowserPoolsResource(AsyncAPIResource):
|
|
|
694
693
|
name: str | Omit = omit,
|
|
695
694
|
profile: BrowserProfile | Omit = omit,
|
|
696
695
|
proxy_id: str | Omit = omit,
|
|
696
|
+
size: int | Omit = omit,
|
|
697
697
|
start_url: str | Omit = omit,
|
|
698
698
|
stealth: bool | Omit = omit,
|
|
699
699
|
timeout_seconds: int | Omit = omit,
|
|
@@ -709,10 +709,6 @@ class AsyncBrowserPoolsResource(AsyncAPIResource):
|
|
|
709
709
|
Updates the configuration used to create browsers in the pool.
|
|
710
710
|
|
|
711
711
|
Args:
|
|
712
|
-
size: Number of browsers to maintain in the pool. The maximum size is determined by
|
|
713
|
-
your organization's pooled sessions limit (the sum of all pool sizes cannot
|
|
714
|
-
exceed your limit).
|
|
715
|
-
|
|
716
712
|
chrome_policy: Custom Chrome enterprise policy overrides applied to all browsers in this pool.
|
|
717
713
|
Keys are Chrome enterprise policy names; values must match their expected types.
|
|
718
714
|
Blocked: kernel-managed policies (extensions, proxy, CDP/automation). See
|
|
@@ -739,6 +735,10 @@ class AsyncBrowserPoolsResource(AsyncAPIResource):
|
|
|
739
735
|
proxy_id: Optional proxy to associate to the browser session. Must reference a proxy
|
|
740
736
|
belonging to the caller's org.
|
|
741
737
|
|
|
738
|
+
size: Number of browsers to maintain in the pool. The maximum size is determined by
|
|
739
|
+
your organization's pooled sessions limit (the sum of all pool sizes cannot
|
|
740
|
+
exceed your limit).
|
|
741
|
+
|
|
742
742
|
start_url: Optional URL to navigate to when a new browser is warmed into the pool.
|
|
743
743
|
Best-effort: failures to navigate do not fail pool fill. Only applied to
|
|
744
744
|
newly-warmed browsers; browsers reused via release/acquire keep whatever URL the
|
|
@@ -778,7 +778,6 @@ class AsyncBrowserPoolsResource(AsyncAPIResource):
|
|
|
778
778
|
path_template("/browser_pools/{id_or_name}", id_or_name=id_or_name),
|
|
779
779
|
body=await async_maybe_transform(
|
|
780
780
|
{
|
|
781
|
-
"size": size,
|
|
782
781
|
"chrome_policy": chrome_policy,
|
|
783
782
|
"discard_all_idle": discard_all_idle,
|
|
784
783
|
"extensions": extensions,
|
|
@@ -788,6 +787,7 @@ class AsyncBrowserPoolsResource(AsyncAPIResource):
|
|
|
788
787
|
"name": name,
|
|
789
788
|
"profile": profile,
|
|
790
789
|
"proxy_id": proxy_id,
|
|
790
|
+
"size": size,
|
|
791
791
|
"start_url": start_url,
|
|
792
792
|
"stealth": stealth,
|
|
793
793
|
"timeout_seconds": timeout_seconds,
|
|
@@ -128,6 +128,7 @@ class ReplaysResource(SyncAPIResource):
|
|
|
128
128
|
*,
|
|
129
129
|
framerate: int | Omit = omit,
|
|
130
130
|
max_duration_in_seconds: int | Omit = omit,
|
|
131
|
+
record_audio: bool | Omit = omit,
|
|
131
132
|
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
|
|
132
133
|
# The extra values given here take precedence over values defined on the client or passed to this method.
|
|
133
134
|
extra_headers: Headers | None = None,
|
|
@@ -144,6 +145,9 @@ class ReplaysResource(SyncAPIResource):
|
|
|
144
145
|
|
|
145
146
|
max_duration_in_seconds: Maximum recording duration in seconds.
|
|
146
147
|
|
|
148
|
+
record_audio: Record audio in addition to video. When false (the default), the recording is
|
|
149
|
+
video-only.
|
|
150
|
+
|
|
147
151
|
extra_headers: Send extra headers
|
|
148
152
|
|
|
149
153
|
extra_query: Add additional query parameters to the request
|
|
@@ -160,6 +164,7 @@ class ReplaysResource(SyncAPIResource):
|
|
|
160
164
|
{
|
|
161
165
|
"framerate": framerate,
|
|
162
166
|
"max_duration_in_seconds": max_duration_in_seconds,
|
|
167
|
+
"record_audio": record_audio,
|
|
163
168
|
},
|
|
164
169
|
replay_start_params.ReplayStartParams,
|
|
165
170
|
),
|
|
@@ -305,6 +310,7 @@ class AsyncReplaysResource(AsyncAPIResource):
|
|
|
305
310
|
*,
|
|
306
311
|
framerate: int | Omit = omit,
|
|
307
312
|
max_duration_in_seconds: int | Omit = omit,
|
|
313
|
+
record_audio: bool | Omit = omit,
|
|
308
314
|
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
|
|
309
315
|
# The extra values given here take precedence over values defined on the client or passed to this method.
|
|
310
316
|
extra_headers: Headers | None = None,
|
|
@@ -321,6 +327,9 @@ class AsyncReplaysResource(AsyncAPIResource):
|
|
|
321
327
|
|
|
322
328
|
max_duration_in_seconds: Maximum recording duration in seconds.
|
|
323
329
|
|
|
330
|
+
record_audio: Record audio in addition to video. When false (the default), the recording is
|
|
331
|
+
video-only.
|
|
332
|
+
|
|
324
333
|
extra_headers: Send extra headers
|
|
325
334
|
|
|
326
335
|
extra_query: Add additional query parameters to the request
|
|
@@ -337,6 +346,7 @@ class AsyncReplaysResource(AsyncAPIResource):
|
|
|
337
346
|
{
|
|
338
347
|
"framerate": framerate,
|
|
339
348
|
"max_duration_in_seconds": max_duration_in_seconds,
|
|
349
|
+
"record_audio": record_audio,
|
|
340
350
|
},
|
|
341
351
|
replay_start_params.ReplayStartParams,
|
|
342
352
|
),
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing_extensions import Literal, TypedDict
|
|
6
|
+
|
|
7
|
+
__all__ = ["APIKeyListParams"]
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class APIKeyListParams(TypedDict, total=False):
|
|
11
|
+
limit: int
|
|
12
|
+
"""Maximum number of results to return"""
|
|
13
|
+
|
|
14
|
+
offset: int
|
|
15
|
+
"""Number of results to skip"""
|
|
16
|
+
|
|
17
|
+
query: str
|
|
18
|
+
"""Case-insensitive substring match against API key name, creator, and project.
|
|
19
|
+
|
|
20
|
+
API key identifiers and masked keys match by exact value or prefix.
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
sort_by: Literal["created_at", "name", "expires_at"]
|
|
24
|
+
"""Field to sort API keys by."""
|
|
25
|
+
|
|
26
|
+
sort_direction: Literal["asc", "desc"]
|
|
27
|
+
"""Sort direction for API keys."""
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
5
|
from typing import Dict, Iterable
|
|
6
|
-
from typing_extensions import
|
|
6
|
+
from typing_extensions import TypedDict
|
|
7
7
|
|
|
8
8
|
from .shared_params.browser_profile import BrowserProfile
|
|
9
9
|
from .shared_params.browser_viewport import BrowserViewport
|
|
@@ -13,13 +13,6 @@ __all__ = ["BrowserPoolUpdateParams"]
|
|
|
13
13
|
|
|
14
14
|
|
|
15
15
|
class BrowserPoolUpdateParams(TypedDict, total=False):
|
|
16
|
-
size: Required[int]
|
|
17
|
-
"""Number of browsers to maintain in the pool.
|
|
18
|
-
|
|
19
|
-
The maximum size is determined by your organization's pooled sessions limit (the
|
|
20
|
-
sum of all pool sizes cannot exceed your limit).
|
|
21
|
-
"""
|
|
22
|
-
|
|
23
16
|
chrome_policy: Dict[str, object]
|
|
24
17
|
"""Custom Chrome enterprise policy overrides applied to all browsers in this pool.
|
|
25
18
|
|
|
@@ -68,6 +61,13 @@ class BrowserPoolUpdateParams(TypedDict, total=False):
|
|
|
68
61
|
Must reference a proxy belonging to the caller's org.
|
|
69
62
|
"""
|
|
70
63
|
|
|
64
|
+
size: int
|
|
65
|
+
"""Number of browsers to maintain in the pool.
|
|
66
|
+
|
|
67
|
+
The maximum size is determined by your organization's pooled sessions limit (the
|
|
68
|
+
sum of all pool sizes cannot exceed your limit).
|
|
69
|
+
"""
|
|
70
|
+
|
|
71
71
|
start_url: str
|
|
72
72
|
"""Optional URL to navigate to when a new browser is warmed into the pool.
|
|
73
73
|
|
|
@@ -16,3 +16,9 @@ class ReplayStartParams(TypedDict, total=False):
|
|
|
16
16
|
|
|
17
17
|
max_duration_in_seconds: int
|
|
18
18
|
"""Maximum recording duration in seconds."""
|
|
19
|
+
|
|
20
|
+
record_audio: bool
|
|
21
|
+
"""Record audio in addition to video.
|
|
22
|
+
|
|
23
|
+
When false (the default), the recording is video-only.
|
|
24
|
+
"""
|
|
@@ -142,6 +142,7 @@ class TestReplays:
|
|
|
142
142
|
id="id",
|
|
143
143
|
framerate=1,
|
|
144
144
|
max_duration_in_seconds=1,
|
|
145
|
+
record_audio=True,
|
|
145
146
|
)
|
|
146
147
|
assert_matches_type(ReplayStartResponse, replay, path=["response"])
|
|
147
148
|
|
|
@@ -354,6 +355,7 @@ class TestAsyncReplays:
|
|
|
354
355
|
id="id",
|
|
355
356
|
framerate=1,
|
|
356
357
|
max_duration_in_seconds=1,
|
|
358
|
+
record_audio=True,
|
|
357
359
|
)
|
|
358
360
|
assert_matches_type(ReplayStartResponse, replay, path=["response"])
|
|
359
361
|
|
|
@@ -162,6 +162,9 @@ class TestAPIKeys:
|
|
|
162
162
|
api_key = client.api_keys.list(
|
|
163
163
|
limit=100,
|
|
164
164
|
offset=0,
|
|
165
|
+
query="query",
|
|
166
|
+
sort_by="created_at",
|
|
167
|
+
sort_direction="asc",
|
|
165
168
|
)
|
|
166
169
|
assert_matches_type(SyncOffsetPagination[APIKey], api_key, path=["response"])
|
|
167
170
|
|
|
@@ -379,6 +382,9 @@ class TestAsyncAPIKeys:
|
|
|
379
382
|
api_key = await async_client.api_keys.list(
|
|
380
383
|
limit=100,
|
|
381
384
|
offset=0,
|
|
385
|
+
query="query",
|
|
386
|
+
sort_by="created_at",
|
|
387
|
+
sort_direction="asc",
|
|
382
388
|
)
|
|
383
389
|
assert_matches_type(AsyncOffsetPagination[APIKey], api_key, path=["response"])
|
|
384
390
|
|
|
@@ -135,7 +135,6 @@ class TestBrowserPools:
|
|
|
135
135
|
def test_method_update(self, client: Kernel) -> None:
|
|
136
136
|
browser_pool = client.browser_pools.update(
|
|
137
137
|
id_or_name="id_or_name",
|
|
138
|
-
size=10,
|
|
139
138
|
)
|
|
140
139
|
assert_matches_type(BrowserPool, browser_pool, path=["response"])
|
|
141
140
|
|
|
@@ -144,7 +143,6 @@ class TestBrowserPools:
|
|
|
144
143
|
def test_method_update_with_all_params(self, client: Kernel) -> None:
|
|
145
144
|
browser_pool = client.browser_pools.update(
|
|
146
145
|
id_or_name="id_or_name",
|
|
147
|
-
size=10,
|
|
148
146
|
chrome_policy={"foo": "bar"},
|
|
149
147
|
discard_all_idle=False,
|
|
150
148
|
extensions=[
|
|
@@ -163,6 +161,7 @@ class TestBrowserPools:
|
|
|
163
161
|
"save_changes": True,
|
|
164
162
|
},
|
|
165
163
|
proxy_id="proxy_id",
|
|
164
|
+
size=10,
|
|
166
165
|
start_url="https://example.com",
|
|
167
166
|
stealth=True,
|
|
168
167
|
timeout_seconds=60,
|
|
@@ -179,7 +178,6 @@ class TestBrowserPools:
|
|
|
179
178
|
def test_raw_response_update(self, client: Kernel) -> None:
|
|
180
179
|
response = client.browser_pools.with_raw_response.update(
|
|
181
180
|
id_or_name="id_or_name",
|
|
182
|
-
size=10,
|
|
183
181
|
)
|
|
184
182
|
|
|
185
183
|
assert response.is_closed is True
|
|
@@ -192,7 +190,6 @@ class TestBrowserPools:
|
|
|
192
190
|
def test_streaming_response_update(self, client: Kernel) -> None:
|
|
193
191
|
with client.browser_pools.with_streaming_response.update(
|
|
194
192
|
id_or_name="id_or_name",
|
|
195
|
-
size=10,
|
|
196
193
|
) as response:
|
|
197
194
|
assert not response.is_closed
|
|
198
195
|
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
|
|
@@ -208,7 +205,6 @@ class TestBrowserPools:
|
|
|
208
205
|
with pytest.raises(ValueError, match=r"Expected a non-empty value for `id_or_name` but received ''"):
|
|
209
206
|
client.browser_pools.with_raw_response.update(
|
|
210
207
|
id_or_name="",
|
|
211
|
-
size=10,
|
|
212
208
|
)
|
|
213
209
|
|
|
214
210
|
@pytest.mark.skip(reason="Mock server tests are disabled")
|
|
@@ -559,7 +555,6 @@ class TestAsyncBrowserPools:
|
|
|
559
555
|
async def test_method_update(self, async_client: AsyncKernel) -> None:
|
|
560
556
|
browser_pool = await async_client.browser_pools.update(
|
|
561
557
|
id_or_name="id_or_name",
|
|
562
|
-
size=10,
|
|
563
558
|
)
|
|
564
559
|
assert_matches_type(BrowserPool, browser_pool, path=["response"])
|
|
565
560
|
|
|
@@ -568,7 +563,6 @@ class TestAsyncBrowserPools:
|
|
|
568
563
|
async def test_method_update_with_all_params(self, async_client: AsyncKernel) -> None:
|
|
569
564
|
browser_pool = await async_client.browser_pools.update(
|
|
570
565
|
id_or_name="id_or_name",
|
|
571
|
-
size=10,
|
|
572
566
|
chrome_policy={"foo": "bar"},
|
|
573
567
|
discard_all_idle=False,
|
|
574
568
|
extensions=[
|
|
@@ -587,6 +581,7 @@ class TestAsyncBrowserPools:
|
|
|
587
581
|
"save_changes": True,
|
|
588
582
|
},
|
|
589
583
|
proxy_id="proxy_id",
|
|
584
|
+
size=10,
|
|
590
585
|
start_url="https://example.com",
|
|
591
586
|
stealth=True,
|
|
592
587
|
timeout_seconds=60,
|
|
@@ -603,7 +598,6 @@ class TestAsyncBrowserPools:
|
|
|
603
598
|
async def test_raw_response_update(self, async_client: AsyncKernel) -> None:
|
|
604
599
|
response = await async_client.browser_pools.with_raw_response.update(
|
|
605
600
|
id_or_name="id_or_name",
|
|
606
|
-
size=10,
|
|
607
601
|
)
|
|
608
602
|
|
|
609
603
|
assert response.is_closed is True
|
|
@@ -616,7 +610,6 @@ class TestAsyncBrowserPools:
|
|
|
616
610
|
async def test_streaming_response_update(self, async_client: AsyncKernel) -> None:
|
|
617
611
|
async with async_client.browser_pools.with_streaming_response.update(
|
|
618
612
|
id_or_name="id_or_name",
|
|
619
|
-
size=10,
|
|
620
613
|
) as response:
|
|
621
614
|
assert not response.is_closed
|
|
622
615
|
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
|
|
@@ -632,7 +625,6 @@ class TestAsyncBrowserPools:
|
|
|
632
625
|
with pytest.raises(ValueError, match=r"Expected a non-empty value for `id_or_name` but received ''"):
|
|
633
626
|
await async_client.browser_pools.with_raw_response.update(
|
|
634
627
|
id_or_name="",
|
|
635
|
-
size=10,
|
|
636
628
|
)
|
|
637
629
|
|
|
638
630
|
@pytest.mark.skip(reason="Mock server tests are disabled")
|
|
@@ -97,6 +97,28 @@ def test_browser_request_uses_curl_raw() -> None:
|
|
|
97
97
|
assert request.url.params.get("jwt") == "token-abc"
|
|
98
98
|
|
|
99
99
|
|
|
100
|
+
@respx.mock
|
|
101
|
+
def test_telemetry_stream_routes_directly_to_vm(monkeypatch: pytest.MonkeyPatch) -> None:
|
|
102
|
+
monkeypatch.setenv("KERNEL_BROWSER_ROUTING_SUBRESOURCES", "telemetry")
|
|
103
|
+
route = respx.get("http://browser-session.test/browser/kernel/telemetry/stream").mock(
|
|
104
|
+
return_value=httpx.Response(
|
|
105
|
+
200,
|
|
106
|
+
headers={"content-type": "text/event-stream"},
|
|
107
|
+
content=b'id: 1\ndata: {"category":"api"}\n\n',
|
|
108
|
+
)
|
|
109
|
+
)
|
|
110
|
+
with Kernel(base_url=base_url, api_key=api_key, _strict_response_validation=True) as client:
|
|
111
|
+
_cache_browser(client)
|
|
112
|
+
stream = client.browsers.telemetry.stream("sess-1")
|
|
113
|
+
stream.close()
|
|
114
|
+
|
|
115
|
+
assert route.called
|
|
116
|
+
request = cast(httpx.Request, cast(Any, route.calls[0]).request)
|
|
117
|
+
assert request.url.path == "/browser/kernel/telemetry/stream"
|
|
118
|
+
assert request.url.params.get("jwt") == "token-abc"
|
|
119
|
+
assert request.headers.get("Authorization") is None
|
|
120
|
+
|
|
121
|
+
|
|
100
122
|
@respx.mock
|
|
101
123
|
def test_browser_request_params_cannot_override_target_url_or_jwt() -> None:
|
|
102
124
|
route = respx.get("http://browser-session.test/browser/kernel/curl/raw").mock(
|
|
@@ -315,7 +337,7 @@ def test_browser_route_from_browser_requires_base_url_and_jwt() -> None:
|
|
|
315
337
|
|
|
316
338
|
def test_browser_routing_config_from_env_defaults_to_curl(monkeypatch: pytest.MonkeyPatch) -> None:
|
|
317
339
|
monkeypatch.delenv("KERNEL_BROWSER_ROUTING_SUBRESOURCES", raising=False)
|
|
318
|
-
assert browser_routing_config_from_env().subresources == ("curl",)
|
|
340
|
+
assert browser_routing_config_from_env().subresources == ("curl", "telemetry")
|
|
319
341
|
|
|
320
342
|
|
|
321
343
|
def test_browser_routing_config_from_env_empty_string_disables_routing(monkeypatch: pytest.MonkeyPatch) -> None:
|
|
@@ -26,6 +26,32 @@ async def test_basic(sync: bool, client: Kernel, async_client: AsyncKernel) -> N
|
|
|
26
26
|
await assert_empty_iter(iterator)
|
|
27
27
|
|
|
28
28
|
|
|
29
|
+
@pytest.mark.asyncio
|
|
30
|
+
@pytest.mark.parametrize("sync", [True, False], ids=["sync", "async"])
|
|
31
|
+
async def test_keepalive_comment_after_event_with_id(sync: bool, client: Kernel, async_client: AsyncKernel) -> None:
|
|
32
|
+
# A ``:`` comment frame (the server's SSE keepalive) that arrives after an event which set an
|
|
33
|
+
# id must be ignored, not dispatched as an empty event. last_event_id is sticky, so this is a
|
|
34
|
+
# regression guard against it leaking an undecodable empty frame into the typed stream.
|
|
35
|
+
def body() -> Iterator[bytes]:
|
|
36
|
+
yield b"id: 1\n"
|
|
37
|
+
yield b'data: {"foo":true}\n'
|
|
38
|
+
yield b"\n"
|
|
39
|
+
yield b":\n"
|
|
40
|
+
yield b"\n"
|
|
41
|
+
yield b'data: {"bar":false}\n'
|
|
42
|
+
yield b"\n"
|
|
43
|
+
|
|
44
|
+
iterator = make_event_iterator(content=body(), sync=sync, client=client, async_client=async_client)
|
|
45
|
+
|
|
46
|
+
sse = await iter_next(iterator)
|
|
47
|
+
assert sse.json() == {"foo": True}
|
|
48
|
+
|
|
49
|
+
sse = await iter_next(iterator)
|
|
50
|
+
assert sse.json() == {"bar": False}
|
|
51
|
+
|
|
52
|
+
await assert_empty_iter(iterator)
|
|
53
|
+
|
|
54
|
+
|
|
29
55
|
@pytest.mark.asyncio
|
|
30
56
|
@pytest.mark.parametrize("sync", [True, False], ids=["sync", "async"])
|
|
31
57
|
async def test_data_missing_event(sync: bool, client: Kernel, async_client: AsyncKernel) -> None:
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
|
|
2
|
-
|
|
3
|
-
from __future__ import annotations
|
|
4
|
-
|
|
5
|
-
from typing_extensions import TypedDict
|
|
6
|
-
|
|
7
|
-
__all__ = ["APIKeyListParams"]
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
class APIKeyListParams(TypedDict, total=False):
|
|
11
|
-
limit: int
|
|
12
|
-
"""Maximum number of results to return"""
|
|
13
|
-
|
|
14
|
-
offset: int
|
|
15
|
-
"""Number of results to skip"""
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|