hyperbrowser 1.7.0__tar.gz → 1.8.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/PKG-INFO +37 -1
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/README.md +36 -0
- hyperbrowser-1.8.0/hyperbrowser/build_context.py +8 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/client/managers/async_manager/sandbox.py +6 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/client/managers/sandboxes/image_build.py +197 -43
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/client/managers/sync_manager/sandbox.py +6 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/models/sandbox.py +1 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/pyproject.toml +1 -1
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/LICENSE +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/__init__.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/client/_request.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/client/async_client.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/client/base.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/client/managers/async_manager/agents/__init__.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/client/managers/async_manager/agents/browser_use.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/client/managers/async_manager/agents/claude_computer_use.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/client/managers/async_manager/agents/cua.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/client/managers/async_manager/agents/gemini_computer_use.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/client/managers/async_manager/agents/grok_computer_use.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/client/managers/async_manager/agents/hyper_agent.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/client/managers/async_manager/agents/jev_computer_use.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/client/managers/async_manager/agents/meta_computer_use.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/client/managers/async_manager/computer_action.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/client/managers/async_manager/crawl.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/client/managers/async_manager/extension.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/client/managers/async_manager/extract.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/client/managers/async_manager/profile.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/client/managers/async_manager/sandboxes/__init__.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/client/managers/async_manager/sandboxes/sandbox_files.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/client/managers/async_manager/sandboxes/sandbox_processes.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/client/managers/async_manager/sandboxes/sandbox_terminal.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/client/managers/async_manager/sandboxes/sandbox_transport.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/client/managers/async_manager/scrape.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/client/managers/async_manager/session.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/client/managers/async_manager/team.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/client/managers/async_manager/volume.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/client/managers/async_manager/web/__init__.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/client/managers/async_manager/web/batch_fetch.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/client/managers/async_manager/web/crawl.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/client/managers/sandboxes/__init__.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/client/managers/sandboxes/dockerfile_analysis.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/client/managers/sandboxes/dockerignore.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/client/managers/sandboxes/process_output.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/client/managers/sandboxes/shared.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/client/managers/sync_manager/agents/__init__.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/client/managers/sync_manager/agents/browser_use.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/client/managers/sync_manager/agents/claude_computer_use.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/client/managers/sync_manager/agents/cua.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/client/managers/sync_manager/agents/gemini_computer_use.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/client/managers/sync_manager/agents/grok_computer_use.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/client/managers/sync_manager/agents/hyper_agent.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/client/managers/sync_manager/agents/jev_computer_use.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/client/managers/sync_manager/agents/meta_computer_use.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/client/managers/sync_manager/computer_action.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/client/managers/sync_manager/crawl.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/client/managers/sync_manager/extension.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/client/managers/sync_manager/extract.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/client/managers/sync_manager/profile.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/client/managers/sync_manager/sandboxes/__init__.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/client/managers/sync_manager/sandboxes/sandbox_files.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/client/managers/sync_manager/sandboxes/sandbox_processes.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/client/managers/sync_manager/sandboxes/sandbox_terminal.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/client/managers/sync_manager/sandboxes/sandbox_transport.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/client/managers/sync_manager/scrape.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/client/managers/sync_manager/session.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/client/managers/sync_manager/team.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/client/managers/sync_manager/volume.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/client/managers/sync_manager/web/__init__.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/client/managers/sync_manager/web/batch_fetch.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/client/managers/sync_manager/web/crawl.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/client/sync.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/config.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/exceptions.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/models/__init__.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/models/_parsers.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/models/agents/browser_use.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/models/agents/claude_computer_use.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/models/agents/cua.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/models/agents/gemini_computer_use.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/models/agents/grok_computer_use.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/models/agents/hyper_agent.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/models/agents/jev_computer_use.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/models/agents/meta_computer_use.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/models/computer_action.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/models/consts.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/models/crawl.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/models/extension.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/models/extract.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/models/profile.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/models/scrape.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/models/session.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/models/team.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/models/volume.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/models/web/batch_fetch.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/models/web/branding.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/models/web/common.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/models/web/crawl.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/models/web/fetch.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/models/web/search.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/py.typed +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/sandbox_common.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/tools/__init__.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/tools/anthropic.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/tools/openai.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/tools/schema.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/transport/async_transport.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/transport/base.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/transport/sync.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/types/__init__.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/types/_json.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/types/agents.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/types/computer_action.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/types/crawl.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/types/extension.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/types/extract.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/types/profile.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/types/sandbox.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/types/scrape.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/types/session.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/types/volume.py +0 -0
- {hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/types/web.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: hyperbrowser
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.8.0
|
|
4
4
|
Summary: Python SDK for hyperbrowser
|
|
5
5
|
License: MIT
|
|
6
6
|
License-File: LICENSE
|
|
@@ -380,6 +380,42 @@ for event in connection.events():
|
|
|
380
380
|
print(event)
|
|
381
381
|
```
|
|
382
382
|
|
|
383
|
+
### Cache remote Dockerfile builds
|
|
384
|
+
|
|
385
|
+
Use the public context fingerprint when deriving a cache name. It uses the same
|
|
386
|
+
Dockerfile source selection and `.dockerignore` rules as remote packaging,
|
|
387
|
+
including file contents, modes, paths, and symlinks. It ignores timestamps and
|
|
388
|
+
does not compress or stage the context on disk.
|
|
389
|
+
|
|
390
|
+
```python
|
|
391
|
+
from hyperbrowser.build_context import docker_build_context_fingerprint
|
|
392
|
+
|
|
393
|
+
fingerprint = docker_build_context_fingerprint("./app")
|
|
394
|
+
# Include build options such as platform and image_init in your cache key too.
|
|
395
|
+
image_name = f"app-{fingerprint[:32]}"
|
|
396
|
+
build = client.sandboxes.build_image_from_dockerfile(
|
|
397
|
+
context_path="./app",
|
|
398
|
+
image_name=image_name,
|
|
399
|
+
expected_context_fingerprint=fingerprint,
|
|
400
|
+
)
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
If the archived inputs differ from the fingerprint, the SDK raises
|
|
404
|
+
`DockerBuildContextChangedError` before creating or uploading a build. Compute a
|
|
405
|
+
fresh fingerprint and repeat the lookup/build operation. Use the same `dockerfile`
|
|
406
|
+
and `force_full_context` selection when fingerprinting and building (the latter
|
|
407
|
+
is named `remote_full_context` on the build method). The expected fingerprint is
|
|
408
|
+
supported only for remote builds.
|
|
409
|
+
|
|
410
|
+
Fingerprinting streams included files and performs blocking I/O. Async callers
|
|
411
|
+
should use `await asyncio.to_thread(docker_build_context_fingerprint, "./app")`
|
|
412
|
+
(Python 3.9+) or an executor. It does not resolve mutable base-image tags or
|
|
413
|
+
network resources fetched by a Dockerfile; rebuild explicitly when those change.
|
|
414
|
+
|
|
415
|
+
Image listings distinguish `ready` from `uploaded`: a completed team image can
|
|
416
|
+
be ready to launch before its durability backup is uploaded. `ready` is `None`
|
|
417
|
+
when talking to an older server. Keep the returned image ID to pin that revision.
|
|
418
|
+
|
|
383
419
|
## License
|
|
384
420
|
|
|
385
421
|
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
|
@@ -352,6 +352,42 @@ for event in connection.events():
|
|
|
352
352
|
print(event)
|
|
353
353
|
```
|
|
354
354
|
|
|
355
|
+
### Cache remote Dockerfile builds
|
|
356
|
+
|
|
357
|
+
Use the public context fingerprint when deriving a cache name. It uses the same
|
|
358
|
+
Dockerfile source selection and `.dockerignore` rules as remote packaging,
|
|
359
|
+
including file contents, modes, paths, and symlinks. It ignores timestamps and
|
|
360
|
+
does not compress or stage the context on disk.
|
|
361
|
+
|
|
362
|
+
```python
|
|
363
|
+
from hyperbrowser.build_context import docker_build_context_fingerprint
|
|
364
|
+
|
|
365
|
+
fingerprint = docker_build_context_fingerprint("./app")
|
|
366
|
+
# Include build options such as platform and image_init in your cache key too.
|
|
367
|
+
image_name = f"app-{fingerprint[:32]}"
|
|
368
|
+
build = client.sandboxes.build_image_from_dockerfile(
|
|
369
|
+
context_path="./app",
|
|
370
|
+
image_name=image_name,
|
|
371
|
+
expected_context_fingerprint=fingerprint,
|
|
372
|
+
)
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
If the archived inputs differ from the fingerprint, the SDK raises
|
|
376
|
+
`DockerBuildContextChangedError` before creating or uploading a build. Compute a
|
|
377
|
+
fresh fingerprint and repeat the lookup/build operation. Use the same `dockerfile`
|
|
378
|
+
and `force_full_context` selection when fingerprinting and building (the latter
|
|
379
|
+
is named `remote_full_context` on the build method). The expected fingerprint is
|
|
380
|
+
supported only for remote builds.
|
|
381
|
+
|
|
382
|
+
Fingerprinting streams included files and performs blocking I/O. Async callers
|
|
383
|
+
should use `await asyncio.to_thread(docker_build_context_fingerprint, "./app")`
|
|
384
|
+
(Python 3.9+) or an executor. It does not resolve mutable base-image tags or
|
|
385
|
+
network resources fetched by a Dockerfile; rebuild explicitly when those change.
|
|
386
|
+
|
|
387
|
+
Image listings distinguish `ready` from `uploaded`: a completed team image can
|
|
388
|
+
be ready to launch before its durability backup is uploaded. `ready` is `None`
|
|
389
|
+
when talking to an older server. Keep the returned image ID to pin that revision.
|
|
390
|
+
|
|
355
391
|
## License
|
|
356
392
|
|
|
357
393
|
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"""Public helpers for identifying inputs to remote Dockerfile builds."""
|
|
2
|
+
|
|
3
|
+
from .client.managers.sandboxes.image_build import (
|
|
4
|
+
DockerBuildContextChangedError,
|
|
5
|
+
docker_build_context_fingerprint,
|
|
6
|
+
)
|
|
7
|
+
|
|
8
|
+
__all__ = ["DockerBuildContextChangedError", "docker_build_context_fingerprint"]
|
{hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/client/managers/async_manager/sandbox.py
RENAMED
|
@@ -725,6 +725,7 @@ class SandboxManager:
|
|
|
725
725
|
dockerfile,
|
|
726
726
|
platform: str,
|
|
727
727
|
remote_full_context: bool,
|
|
728
|
+
expected_context_fingerprint: Optional[str],
|
|
728
729
|
image_init: Optional[Union[SandboxImageInitDict, SandboxImageInit]],
|
|
729
730
|
image_config_user: Optional[str],
|
|
730
731
|
builder_cpus: Optional[int],
|
|
@@ -741,6 +742,7 @@ class SandboxManager:
|
|
|
741
742
|
context_path,
|
|
742
743
|
dockerfile=dockerfile,
|
|
743
744
|
force_full_context=remote_full_context,
|
|
745
|
+
expected_context_fingerprint=expected_context_fingerprint,
|
|
744
746
|
temp_dir=temp_dir,
|
|
745
747
|
)
|
|
746
748
|
build_id = None
|
|
@@ -803,6 +805,7 @@ class SandboxManager:
|
|
|
803
805
|
dockerfile="Dockerfile",
|
|
804
806
|
remote: bool = True,
|
|
805
807
|
remote_full_context: bool = False,
|
|
808
|
+
expected_context_fingerprint: Optional[str] = None,
|
|
806
809
|
docker_tag: Optional[str] = None,
|
|
807
810
|
platform: str = IMAGE_BUILD_SOURCE_PLATFORM,
|
|
808
811
|
build_args: Optional[Dict[str, str]] = None,
|
|
@@ -829,6 +832,7 @@ class SandboxManager:
|
|
|
829
832
|
dockerfile=dockerfile,
|
|
830
833
|
platform=platform,
|
|
831
834
|
remote_full_context=remote_full_context,
|
|
835
|
+
expected_context_fingerprint=expected_context_fingerprint,
|
|
832
836
|
image_init=image_init,
|
|
833
837
|
image_config_user=image_config_user,
|
|
834
838
|
builder_cpus=builder_cpus,
|
|
@@ -840,6 +844,8 @@ class SandboxManager:
|
|
|
840
844
|
temp_dir=temp_dir,
|
|
841
845
|
upload_timeout=upload_timeout,
|
|
842
846
|
)
|
|
847
|
+
if expected_context_fingerprint is not None:
|
|
848
|
+
raise ValueError("expected_context_fingerprint requires remote=True")
|
|
843
849
|
tag = docker_tag or make_temp_docker_tag()
|
|
844
850
|
remove_tag = docker_tag is None
|
|
845
851
|
try:
|
{hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/client/managers/sandboxes/image_build.py
RENAMED
|
@@ -7,6 +7,7 @@ import os
|
|
|
7
7
|
import posixpath
|
|
8
8
|
import re
|
|
9
9
|
import shutil
|
|
10
|
+
import stat
|
|
10
11
|
import subprocess
|
|
11
12
|
import tarfile
|
|
12
13
|
import tempfile
|
|
@@ -25,6 +26,7 @@ from typing import (
|
|
|
25
26
|
Sequence,
|
|
26
27
|
Set,
|
|
27
28
|
Tuple,
|
|
29
|
+
Union,
|
|
28
30
|
)
|
|
29
31
|
|
|
30
32
|
import httpx
|
|
@@ -99,6 +101,7 @@ class PackagedDockerBuildContext:
|
|
|
99
101
|
manifest: SandboxBuildContextManifest
|
|
100
102
|
bundles: Dict[str, DockerImageBuildArtifact]
|
|
101
103
|
workspace: str
|
|
104
|
+
fingerprint: str
|
|
102
105
|
|
|
103
106
|
def cleanup(self) -> None:
|
|
104
107
|
shutil.rmtree(self.workspace, ignore_errors=True)
|
|
@@ -155,6 +158,85 @@ class _HashingCountingWriter:
|
|
|
155
158
|
return self._fileobj.flush()
|
|
156
159
|
|
|
157
160
|
|
|
161
|
+
class _ContextHashingReader:
|
|
162
|
+
def __init__(self, source, hasher):
|
|
163
|
+
self._source = source
|
|
164
|
+
self._hasher = hasher
|
|
165
|
+
|
|
166
|
+
def read(self, size):
|
|
167
|
+
data = self._source.read(size)
|
|
168
|
+
self._hasher.update(data)
|
|
169
|
+
return data
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
class DockerBuildContextChangedError(ValueError):
|
|
173
|
+
"""The packaged context no longer matches the caller's cache fingerprint."""
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
@dataclass
|
|
177
|
+
class _DockerBuildContextSelection:
|
|
178
|
+
root: Path
|
|
179
|
+
dockerfile: str
|
|
180
|
+
mode: Literal["sparse", "full"]
|
|
181
|
+
fallback_reason: Optional[str]
|
|
182
|
+
entry_groups: List[Set[str]]
|
|
183
|
+
|
|
184
|
+
def fingerprint(self, bundle_hashes: Sequence[str]) -> str:
|
|
185
|
+
# Hash entry metadata and contents, not transport encoding: cache
|
|
186
|
+
# identity must not depend on tar headers or a compression library.
|
|
187
|
+
identity = {
|
|
188
|
+
"version": 1,
|
|
189
|
+
"dockerfile": self.dockerfile,
|
|
190
|
+
"contextMode": self.mode,
|
|
191
|
+
"bundles": sorted(set(bundle_hashes)),
|
|
192
|
+
}
|
|
193
|
+
return hashlib.sha256(
|
|
194
|
+
json.dumps(identity, sort_keys=True, separators=(",", ":")).encode()
|
|
195
|
+
).hexdigest()
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
def docker_build_context_fingerprint(
|
|
199
|
+
context_path: Union[str, Path],
|
|
200
|
+
*,
|
|
201
|
+
dockerfile: str = "Dockerfile",
|
|
202
|
+
force_full_context: bool = False,
|
|
203
|
+
) -> str:
|
|
204
|
+
"""Fingerprint the effective remote context without compressing or staging it.
|
|
205
|
+
|
|
206
|
+
Uses the same Dockerfile source selection, ignore rules, and normalized tar
|
|
207
|
+
entries as remote packaging. Reads file contents with bounded memory. This
|
|
208
|
+
is blocking I/O; async callers should run it in an executor. Pass the result
|
|
209
|
+
as ``expected_context_fingerprint`` when building to detect context changes.
|
|
210
|
+
Build options outside the context (e.g. platform or image_init) must also be
|
|
211
|
+
included in the caller's cache key. Mutable base tags and network resources
|
|
212
|
+
are not resolved by this fingerprint.
|
|
213
|
+
"""
|
|
214
|
+
selection = _select_docker_build_context(
|
|
215
|
+
context_path, dockerfile=dockerfile, force_full_context=force_full_context
|
|
216
|
+
)
|
|
217
|
+
hashes = []
|
|
218
|
+
for entries in selection.entry_groups:
|
|
219
|
+
hasher = hashlib.sha256()
|
|
220
|
+
for relative in sorted(entries):
|
|
221
|
+
info = _context_entry_info(selection.root, relative)
|
|
222
|
+
if info is None:
|
|
223
|
+
continue
|
|
224
|
+
_hash_context_entry_metadata(hasher, info)
|
|
225
|
+
if info.isfile():
|
|
226
|
+
with open(selection.root / relative, "rb") as source:
|
|
227
|
+
reader = _ContextHashingReader(source, hasher)
|
|
228
|
+
remaining = info.size
|
|
229
|
+
while remaining:
|
|
230
|
+
data = reader.read(min(64 * 1024, remaining))
|
|
231
|
+
if not data:
|
|
232
|
+
raise OSError(
|
|
233
|
+
f'build context file "{relative}" was truncated'
|
|
234
|
+
)
|
|
235
|
+
remaining -= len(data)
|
|
236
|
+
hashes.append(hasher.hexdigest())
|
|
237
|
+
return selection.fingerprint(hashes)
|
|
238
|
+
|
|
239
|
+
|
|
158
240
|
def build_docker_image_from_dockerfile(
|
|
159
241
|
*,
|
|
160
242
|
context_path,
|
|
@@ -188,13 +270,12 @@ def build_docker_image_from_dockerfile(
|
|
|
188
270
|
_run_command(args)
|
|
189
271
|
|
|
190
272
|
|
|
191
|
-
def
|
|
273
|
+
def _select_docker_build_context(
|
|
192
274
|
context_path,
|
|
193
275
|
*,
|
|
194
276
|
dockerfile="Dockerfile",
|
|
195
277
|
force_full_context: bool = False,
|
|
196
|
-
|
|
197
|
-
) -> PackagedDockerBuildContext:
|
|
278
|
+
) -> _DockerBuildContextSelection:
|
|
198
279
|
context_root = Path(context_path).expanduser().resolve(strict=True)
|
|
199
280
|
if not context_root.is_dir():
|
|
200
281
|
raise ValueError("Docker build context must be a directory")
|
|
@@ -288,28 +369,59 @@ def package_docker_build_context_manifest(
|
|
|
288
369
|
]
|
|
289
370
|
|
|
290
371
|
entry_groups = _remove_subsumed_entry_groups(entry_groups)
|
|
372
|
+
return _DockerBuildContextSelection(
|
|
373
|
+
context_root, dockerfile_relative, context_mode, fallback_reason, entry_groups
|
|
374
|
+
)
|
|
375
|
+
|
|
376
|
+
|
|
377
|
+
def package_docker_build_context_manifest(
|
|
378
|
+
context_path,
|
|
379
|
+
*,
|
|
380
|
+
dockerfile="Dockerfile",
|
|
381
|
+
force_full_context: bool = False,
|
|
382
|
+
temp_dir: Optional[str] = None,
|
|
383
|
+
expected_context_fingerprint: Optional[str] = None,
|
|
384
|
+
) -> PackagedDockerBuildContext:
|
|
385
|
+
if expected_context_fingerprint is not None and not _SHA256_PATTERN.fullmatch(
|
|
386
|
+
expected_context_fingerprint
|
|
387
|
+
):
|
|
388
|
+
raise ValueError("expected_context_fingerprint must be a SHA-256 hex digest")
|
|
389
|
+
selection = _select_docker_build_context(
|
|
390
|
+
context_path, dockerfile=dockerfile, force_full_context=force_full_context
|
|
391
|
+
)
|
|
291
392
|
workspace = tempfile.mkdtemp(prefix="hb-docker-context-", dir=temp_dir)
|
|
292
393
|
try:
|
|
293
394
|
bundles = {}
|
|
294
395
|
descriptors = []
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
396
|
+
bundle_hashes = []
|
|
397
|
+
for index, entries in enumerate(selection.entry_groups):
|
|
398
|
+
artifact, descriptor, bundle_hash = _package_context_bundle(
|
|
399
|
+
selection.root,
|
|
298
400
|
sorted(entries),
|
|
299
401
|
workspace,
|
|
300
402
|
index,
|
|
301
403
|
)
|
|
404
|
+
bundle_hashes.append(bundle_hash)
|
|
302
405
|
if descriptor.sha256 in bundles:
|
|
303
406
|
artifact.cleanup()
|
|
304
407
|
continue
|
|
305
408
|
bundles[descriptor.sha256] = artifact
|
|
306
409
|
descriptors.append(descriptor)
|
|
307
410
|
descriptors.sort(key=lambda item: item.sha256)
|
|
411
|
+
fingerprint = selection.fingerprint(bundle_hashes)
|
|
412
|
+
if (
|
|
413
|
+
expected_context_fingerprint is not None
|
|
414
|
+
and fingerprint != expected_context_fingerprint
|
|
415
|
+
):
|
|
416
|
+
raise DockerBuildContextChangedError(
|
|
417
|
+
"Docker build context changed after its cache fingerprint was "
|
|
418
|
+
"computed. Retry the build with a fresh fingerprint."
|
|
419
|
+
)
|
|
308
420
|
manifest = SandboxBuildContextManifest(
|
|
309
421
|
version=1,
|
|
310
|
-
dockerfile_path=
|
|
311
|
-
context_mode=
|
|
312
|
-
fallback_reason=fallback_reason or None,
|
|
422
|
+
dockerfile_path=selection.dockerfile,
|
|
423
|
+
context_mode=selection.mode,
|
|
424
|
+
fallback_reason=selection.fallback_reason or None,
|
|
313
425
|
bundles=descriptors,
|
|
314
426
|
)
|
|
315
427
|
manifest_bytes = _canonical_model_json(manifest)
|
|
@@ -324,6 +436,7 @@ def package_docker_build_context_manifest(
|
|
|
324
436
|
manifest=manifest,
|
|
325
437
|
bundles=bundles,
|
|
326
438
|
workspace=workspace,
|
|
439
|
+
fingerprint=fingerprint,
|
|
327
440
|
)
|
|
328
441
|
except Exception:
|
|
329
442
|
shutil.rmtree(workspace, ignore_errors=True)
|
|
@@ -1192,11 +1305,10 @@ def _package_context_bundle(
|
|
|
1192
1305
|
entries: Sequence[str],
|
|
1193
1306
|
workspace: str,
|
|
1194
1307
|
index: int,
|
|
1195
|
-
) -> Tuple[DockerImageBuildArtifact, SandboxBuildContextBundle]:
|
|
1308
|
+
) -> Tuple[DockerImageBuildArtifact, SandboxBuildContextBundle, str]:
|
|
1196
1309
|
bundle_path = os.path.join(workspace, f"bundle-{index:04d}.tar.gz")
|
|
1197
1310
|
hasher = hashlib.sha256()
|
|
1198
|
-
|
|
1199
|
-
entry_count = 0
|
|
1311
|
+
context_hasher = hashlib.sha256()
|
|
1200
1312
|
with open(bundle_path, "wb") as destination:
|
|
1201
1313
|
writer = _HashingCountingWriter(destination, hasher)
|
|
1202
1314
|
with gzip.GzipFile(
|
|
@@ -1206,36 +1318,12 @@ def _package_context_bundle(
|
|
|
1206
1318
|
compresslevel=1,
|
|
1207
1319
|
mtime=0,
|
|
1208
1320
|
) as compressed:
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
_validate_archive_relative_path(relative)
|
|
1216
|
-
absolute = context_root / relative
|
|
1217
|
-
info = archive.gettarinfo(str(absolute), arcname=relative)
|
|
1218
|
-
if not (info.isfile() or info.isdir() or info.issym()):
|
|
1219
|
-
continue
|
|
1220
|
-
info.uid = 0
|
|
1221
|
-
info.gid = 0
|
|
1222
|
-
info.uname = ""
|
|
1223
|
-
info.gname = ""
|
|
1224
|
-
info.mtime = 0
|
|
1225
|
-
info.pax_headers = {}
|
|
1226
|
-
if info.isdir() and not info.name.endswith("/"):
|
|
1227
|
-
info.name += "/"
|
|
1228
|
-
if info.issym() and not info.linkname:
|
|
1229
|
-
raise ValueError(
|
|
1230
|
-
f'build context symlink "{relative}" has an invalid target'
|
|
1231
|
-
)
|
|
1232
|
-
if info.isfile():
|
|
1233
|
-
with open(absolute, "rb") as source:
|
|
1234
|
-
archive.addfile(info, source)
|
|
1235
|
-
uncompressed_size += info.size
|
|
1236
|
-
else:
|
|
1237
|
-
archive.addfile(info)
|
|
1238
|
-
entry_count += 1
|
|
1321
|
+
uncompressed_size, entry_count = _write_context_archive(
|
|
1322
|
+
context_root,
|
|
1323
|
+
entries,
|
|
1324
|
+
compressed,
|
|
1325
|
+
context_hasher,
|
|
1326
|
+
)
|
|
1239
1327
|
size_bytes = os.path.getsize(bundle_path)
|
|
1240
1328
|
sha256_hex = hasher.hexdigest()
|
|
1241
1329
|
artifact = DockerImageBuildArtifact(
|
|
@@ -1250,7 +1338,73 @@ def _package_context_bundle(
|
|
|
1250
1338
|
uncompressed_size_bytes=uncompressed_size,
|
|
1251
1339
|
entry_count=entry_count,
|
|
1252
1340
|
)
|
|
1253
|
-
return artifact, descriptor
|
|
1341
|
+
return artifact, descriptor, context_hasher.hexdigest()
|
|
1342
|
+
|
|
1343
|
+
|
|
1344
|
+
def _context_entry_info(context_root: Path, relative: str) -> Optional[tarfile.TarInfo]:
|
|
1345
|
+
_validate_archive_relative_path(relative)
|
|
1346
|
+
absolute = context_root / relative
|
|
1347
|
+
metadata = absolute.lstat()
|
|
1348
|
+
# Construct normalized metadata directly. gettarinfo() resolves owner names
|
|
1349
|
+
# that we discard and converts repeated host inodes to hard-link entries.
|
|
1350
|
+
# Every regular path must instead be present with its own contents; preserve
|
|
1351
|
+
# symlinks without following them.
|
|
1352
|
+
info = tarfile.TarInfo(relative)
|
|
1353
|
+
info.mode = stat.S_IMODE(metadata.st_mode)
|
|
1354
|
+
if stat.S_ISREG(metadata.st_mode):
|
|
1355
|
+
info.type = tarfile.REGTYPE
|
|
1356
|
+
info.size = metadata.st_size
|
|
1357
|
+
elif stat.S_ISDIR(metadata.st_mode):
|
|
1358
|
+
info.type = tarfile.DIRTYPE
|
|
1359
|
+
info.name += "/"
|
|
1360
|
+
elif stat.S_ISLNK(metadata.st_mode):
|
|
1361
|
+
info.type = tarfile.SYMTYPE
|
|
1362
|
+
info.linkname = os.readlink(absolute)
|
|
1363
|
+
if not info.linkname:
|
|
1364
|
+
raise ValueError(
|
|
1365
|
+
f'build context symlink "{relative}" has an invalid target'
|
|
1366
|
+
)
|
|
1367
|
+
else:
|
|
1368
|
+
return None
|
|
1369
|
+
return info
|
|
1370
|
+
|
|
1371
|
+
|
|
1372
|
+
def _hash_context_entry_metadata(hasher, info: tarfile.TarInfo) -> None:
|
|
1373
|
+
metadata = json.dumps(
|
|
1374
|
+
[
|
|
1375
|
+
info.name.rstrip("/") if info.isdir() else info.name,
|
|
1376
|
+
"file" if info.isfile() else "directory" if info.isdir() else "symlink",
|
|
1377
|
+
info.mode,
|
|
1378
|
+
info.size,
|
|
1379
|
+
info.linkname,
|
|
1380
|
+
],
|
|
1381
|
+
separators=(",", ":"),
|
|
1382
|
+
).encode()
|
|
1383
|
+
hasher.update(len(metadata).to_bytes(8, "big"))
|
|
1384
|
+
hasher.update(metadata)
|
|
1385
|
+
|
|
1386
|
+
|
|
1387
|
+
def _write_context_archive(
|
|
1388
|
+
context_root: Path, entries: Sequence[str], destination, hasher
|
|
1389
|
+
):
|
|
1390
|
+
uncompressed_size = 0
|
|
1391
|
+
entry_count = 0
|
|
1392
|
+
with tarfile.open(
|
|
1393
|
+
fileobj=destination, mode="w", format=tarfile.PAX_FORMAT
|
|
1394
|
+
) as archive:
|
|
1395
|
+
for relative in entries:
|
|
1396
|
+
info = _context_entry_info(context_root, relative)
|
|
1397
|
+
if info is None:
|
|
1398
|
+
continue
|
|
1399
|
+
_hash_context_entry_metadata(hasher, info)
|
|
1400
|
+
if info.isfile():
|
|
1401
|
+
with open(context_root / relative, "rb") as source:
|
|
1402
|
+
archive.addfile(info, _ContextHashingReader(source, hasher))
|
|
1403
|
+
uncompressed_size += info.size
|
|
1404
|
+
else:
|
|
1405
|
+
archive.addfile(info)
|
|
1406
|
+
entry_count += 1
|
|
1407
|
+
return uncompressed_size, entry_count
|
|
1254
1408
|
|
|
1255
1409
|
|
|
1256
1410
|
def _normalize_docker_save_entry_name(raw: str) -> str:
|
{hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/client/managers/sync_manager/sandbox.py
RENAMED
|
@@ -711,6 +711,7 @@ class SandboxManager:
|
|
|
711
711
|
dockerfile,
|
|
712
712
|
platform: str,
|
|
713
713
|
remote_full_context: bool,
|
|
714
|
+
expected_context_fingerprint: Optional[str],
|
|
714
715
|
image_init: Optional[Union[SandboxImageInitDict, SandboxImageInit]],
|
|
715
716
|
image_config_user: Optional[str],
|
|
716
717
|
builder_cpus: Optional[int],
|
|
@@ -726,6 +727,7 @@ class SandboxManager:
|
|
|
726
727
|
context_path,
|
|
727
728
|
dockerfile=dockerfile,
|
|
728
729
|
force_full_context=remote_full_context,
|
|
730
|
+
expected_context_fingerprint=expected_context_fingerprint,
|
|
729
731
|
temp_dir=temp_dir,
|
|
730
732
|
)
|
|
731
733
|
build_id = None
|
|
@@ -787,6 +789,7 @@ class SandboxManager:
|
|
|
787
789
|
dockerfile="Dockerfile",
|
|
788
790
|
remote: bool = True,
|
|
789
791
|
remote_full_context: bool = False,
|
|
792
|
+
expected_context_fingerprint: Optional[str] = None,
|
|
790
793
|
docker_tag: Optional[str] = None,
|
|
791
794
|
platform: str = IMAGE_BUILD_SOURCE_PLATFORM,
|
|
792
795
|
build_args: Optional[Dict[str, str]] = None,
|
|
@@ -813,6 +816,7 @@ class SandboxManager:
|
|
|
813
816
|
dockerfile=dockerfile,
|
|
814
817
|
platform=platform,
|
|
815
818
|
remote_full_context=remote_full_context,
|
|
819
|
+
expected_context_fingerprint=expected_context_fingerprint,
|
|
816
820
|
image_init=image_init,
|
|
817
821
|
image_config_user=image_config_user,
|
|
818
822
|
builder_cpus=builder_cpus,
|
|
@@ -824,6 +828,8 @@ class SandboxManager:
|
|
|
824
828
|
temp_dir=temp_dir,
|
|
825
829
|
upload_timeout=upload_timeout,
|
|
826
830
|
)
|
|
831
|
+
if expected_context_fingerprint is not None:
|
|
832
|
+
raise ValueError("expected_context_fingerprint requires remote=True")
|
|
827
833
|
tag = docker_tag or make_temp_docker_tag()
|
|
828
834
|
remove_tag = docker_tag is None
|
|
829
835
|
try:
|
|
@@ -306,6 +306,7 @@ class SandboxImageSummary(SandboxBaseModel):
|
|
|
306
306
|
source: Optional[str] = None
|
|
307
307
|
image_init: Optional[SandboxImageInit] = Field(default=None, alias="imageInit")
|
|
308
308
|
uploaded: bool
|
|
309
|
+
ready: Optional[bool] = None
|
|
309
310
|
created_at: datetime = Field(alias="createdAt")
|
|
310
311
|
updated_at: datetime = Field(alias="updatedAt")
|
|
311
312
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/client/managers/async_manager/agents/cua.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/client/managers/async_manager/crawl.py
RENAMED
|
File without changes
|
{hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/client/managers/async_manager/extension.py
RENAMED
|
File without changes
|
{hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/client/managers/async_manager/extract.py
RENAMED
|
File without changes
|
{hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/client/managers/async_manager/profile.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/client/managers/async_manager/scrape.py
RENAMED
|
File without changes
|
{hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/client/managers/async_manager/session.py
RENAMED
|
File without changes
|
{hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/client/managers/async_manager/team.py
RENAMED
|
File without changes
|
{hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/client/managers/async_manager/volume.py
RENAMED
|
File without changes
|
{hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/client/managers/async_manager/web/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/client/managers/async_manager/web/crawl.py
RENAMED
|
File without changes
|
{hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/client/managers/sandboxes/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/client/managers/sandboxes/dockerignore.py
RENAMED
|
File without changes
|
{hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/client/managers/sandboxes/process_output.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/client/managers/sync_manager/agents/cua.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/client/managers/sync_manager/crawl.py
RENAMED
|
File without changes
|
{hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/client/managers/sync_manager/extension.py
RENAMED
|
File without changes
|
{hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/client/managers/sync_manager/extract.py
RENAMED
|
File without changes
|
{hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/client/managers/sync_manager/profile.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/client/managers/sync_manager/scrape.py
RENAMED
|
File without changes
|
{hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/client/managers/sync_manager/session.py
RENAMED
|
File without changes
|
|
File without changes
|
{hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/client/managers/sync_manager/volume.py
RENAMED
|
File without changes
|
{hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/client/managers/sync_manager/web/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{hyperbrowser-1.7.0 → hyperbrowser-1.8.0}/hyperbrowser/client/managers/sync_manager/web/crawl.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|