unrealon 2.0.7__tar.gz → 2.0.9__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (139) hide show
  1. {unrealon-2.0.7/unrealon.egg-info → unrealon-2.0.9}/PKG-INFO +1 -1
  2. {unrealon-2.0.7 → unrealon-2.0.9}/pyproject.toml +1 -1
  3. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-browser/src/unrealon_browser/core/browser_manager.py +6 -0
  4. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-browser/src/unrealon_browser/managers/__init__.py +2 -0
  5. unrealon-2.0.9/unrealon-browser/src/unrealon_browser/managers/script_manager.py +314 -0
  6. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-browser/src/unrealon_browser/stealth/manager.pyc +0 -0
  7. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/config/urls.py +2 -1
  8. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/enums/__init__.py +10 -0
  9. unrealon-2.0.9/unrealon-core/src/unrealon_core/enums/events.py +98 -0
  10. unrealon-2.0.9/unrealon-core/src/unrealon_core/enums/jobs.py +32 -0
  11. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/enums/types.py +1 -0
  12. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/models/__init__.py +9 -0
  13. unrealon-2.0.9/unrealon-core/src/unrealon_core/models/authentication.py +24 -0
  14. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-driver/src/unrealon_driver/managers/browser.py +21 -1
  15. {unrealon-2.0.7 → unrealon-2.0.9/unrealon.egg-info}/PKG-INFO +1 -1
  16. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon.egg-info/SOURCES.txt +4 -0
  17. {unrealon-2.0.7 → unrealon-2.0.9}/LICENSE +0 -0
  18. {unrealon-2.0.7 → unrealon-2.0.9}/MANIFEST.in +0 -0
  19. {unrealon-2.0.7 → unrealon-2.0.9}/README.md +0 -0
  20. {unrealon-2.0.7 → unrealon-2.0.9}/setup.cfg +0 -0
  21. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-browser/src/unrealon_browser/README.md +0 -0
  22. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-browser/src/unrealon_browser/__init__.py +0 -0
  23. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-browser/src/unrealon_browser/cli/__init__.py +0 -0
  24. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-browser/src/unrealon_browser/cli/browser_cli.py +0 -0
  25. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-browser/src/unrealon_browser/cli/cookies_cli.py +0 -0
  26. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-browser/src/unrealon_browser/cli/interactive_mode.py +0 -0
  27. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-browser/src/unrealon_browser/cli/main.py +0 -0
  28. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-browser/src/unrealon_browser/core/__init__.py +0 -0
  29. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-browser/src/unrealon_browser/dto/__init__.py +0 -0
  30. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-browser/src/unrealon_browser/dto/bot_detection.py +0 -0
  31. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-browser/src/unrealon_browser/dto/models/config.py +0 -0
  32. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-browser/src/unrealon_browser/dto/models/core.py +0 -0
  33. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-browser/src/unrealon_browser/dto/models/dataclasses.py +0 -0
  34. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-browser/src/unrealon_browser/dto/models/detection.py +0 -0
  35. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-browser/src/unrealon_browser/dto/models/enums.py +0 -0
  36. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-browser/src/unrealon_browser/dto/models/statistics.py +0 -0
  37. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-browser/src/unrealon_browser/managers/captcha.py +0 -0
  38. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-browser/src/unrealon_browser/managers/cookies.py +0 -0
  39. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-browser/src/unrealon_browser/managers/logger_bridge.py +0 -0
  40. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-browser/src/unrealon_browser/managers/page_wait_manager.py +0 -0
  41. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-browser/src/unrealon_browser/managers/profile.py +0 -0
  42. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-browser/src/unrealon_browser/stealth/__init__.py +0 -0
  43. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-browser/src/unrealon_browser/stealth/bypass_techniques.pyc +0 -0
  44. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-browser/src/unrealon_browser/stealth/nodriver_stealth.pyc +0 -0
  45. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-browser/src/unrealon_browser/stealth/playwright_stealth.pyc +0 -0
  46. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-browser/src/unrealon_browser/stealth/scanner_tester.pyc +0 -0
  47. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-browser/src/unrealon_browser/stealth/undetected_chrome.pyc +0 -0
  48. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/__init__.py +0 -0
  49. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/config/__init__.py +0 -0
  50. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/config/environment.py +0 -0
  51. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/enums/status.py +0 -0
  52. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/error_handling/__init__.py +0 -0
  53. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/error_handling/circuit_breaker.py +0 -0
  54. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/error_handling/error_context.py +0 -0
  55. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/error_handling/recovery.py +0 -0
  56. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/error_handling/retry.py +0 -0
  57. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/exceptions/__init__.py +0 -0
  58. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/exceptions/base.py +0 -0
  59. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/exceptions/communication.py +0 -0
  60. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/exceptions/driver.py +0 -0
  61. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/exceptions/proxy.py +0 -0
  62. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/exceptions/task.py +0 -0
  63. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/exceptions/validation.py +0 -0
  64. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/models/arq_context.py +0 -0
  65. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/models/arq_responses.py +0 -0
  66. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/models/base.py +0 -0
  67. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/models/bridge_stats.py +0 -0
  68. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/models/communication.py +0 -0
  69. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/models/connection_stats.py +0 -0
  70. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/models/driver.py +0 -0
  71. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/models/driver_details.py +0 -0
  72. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/models/logging.py +0 -0
  73. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/models/task.py +0 -0
  74. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/models/typed_responses.py +0 -0
  75. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/models/websocket/__init__.py +0 -0
  76. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/models/websocket/base.py +0 -0
  77. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/models/websocket/broadcast.py +0 -0
  78. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/models/websocket/config.py +0 -0
  79. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/models/websocket/driver.py +0 -0
  80. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/models/websocket/errors.py +0 -0
  81. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/models/websocket/heartbeat.py +0 -0
  82. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/models/websocket/logging.py +0 -0
  83. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/models/websocket/proxy.py +0 -0
  84. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/models/websocket/tasks.py +0 -0
  85. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/models/websocket/utils.py +0 -0
  86. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/models/websocket_session.py +0 -0
  87. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/monitoring/__init__.py +0 -0
  88. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/monitoring/alerts.py +0 -0
  89. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/monitoring/dashboard.py +0 -0
  90. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/monitoring/health_check.py +0 -0
  91. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/monitoring/metrics.py +0 -0
  92. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/utils/__init__.py +0 -0
  93. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/utils/time.py +0 -0
  94. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/version.py +0 -0
  95. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-driver/src/unrealon_driver/__init__.py +0 -0
  96. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-driver/src/unrealon_driver/core_module/__init__.py +0 -0
  97. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-driver/src/unrealon_driver/core_module/base.py +0 -0
  98. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-driver/src/unrealon_driver/core_module/config.py +0 -0
  99. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-driver/src/unrealon_driver/core_module/event_manager.py +0 -0
  100. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-driver/src/unrealon_driver/core_module/protocols.py +0 -0
  101. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-driver/src/unrealon_driver/core_module/registry.py +0 -0
  102. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-driver/src/unrealon_driver/decorators/__init__.py +0 -0
  103. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-driver/src/unrealon_driver/decorators/retry.py +0 -0
  104. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-driver/src/unrealon_driver/decorators/schedule.py +0 -0
  105. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-driver/src/unrealon_driver/decorators/task.py +0 -0
  106. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-driver/src/unrealon_driver/decorators/timing.py +0 -0
  107. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-driver/src/unrealon_driver/driver/__init__.py +0 -0
  108. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-driver/src/unrealon_driver/driver/communication/__init__.py +0 -0
  109. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-driver/src/unrealon_driver/driver/communication/session.py +0 -0
  110. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-driver/src/unrealon_driver/driver/communication/websocket_client.py +0 -0
  111. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-driver/src/unrealon_driver/driver/core/__init__.py +0 -0
  112. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-driver/src/unrealon_driver/driver/core/config.py +0 -0
  113. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-driver/src/unrealon_driver/driver/core/driver.py +0 -0
  114. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-driver/src/unrealon_driver/driver/factory/__init__.py +0 -0
  115. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-driver/src/unrealon_driver/driver/factory/manager_factory.py +0 -0
  116. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-driver/src/unrealon_driver/driver/lifecycle/__init__.py +0 -0
  117. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-driver/src/unrealon_driver/driver/lifecycle/daemon.py +0 -0
  118. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-driver/src/unrealon_driver/driver/lifecycle/initialization.py +0 -0
  119. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-driver/src/unrealon_driver/driver/lifecycle/shutdown.py +0 -0
  120. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-driver/src/unrealon_driver/driver/monitoring/__init__.py +0 -0
  121. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-driver/src/unrealon_driver/driver/monitoring/health.py +0 -0
  122. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-driver/src/unrealon_driver/driver/utilities/__init__.py +0 -0
  123. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-driver/src/unrealon_driver/driver/utilities/logging.py +0 -0
  124. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-driver/src/unrealon_driver/driver/utilities/serialization.py +0 -0
  125. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-driver/src/unrealon_driver/managers/__init__.py +0 -0
  126. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-driver/src/unrealon_driver/managers/base.py +0 -0
  127. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-driver/src/unrealon_driver/managers/cache.py +0 -0
  128. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-driver/src/unrealon_driver/managers/http.py +0 -0
  129. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-driver/src/unrealon_driver/managers/logger.py +0 -0
  130. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-driver/src/unrealon_driver/managers/proxy.py +0 -0
  131. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-driver/src/unrealon_driver/managers/registry.py +0 -0
  132. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-driver/src/unrealon_driver/managers/threading.py +0 -0
  133. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-driver/src/unrealon_driver/managers/update.py +0 -0
  134. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-driver/src/unrealon_driver/utils/__init__.py +0 -0
  135. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-driver/src/unrealon_driver/utils/time.py +0 -0
  136. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon.egg-info/dependency_links.txt +0 -0
  137. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon.egg-info/entry_points.txt +0 -0
  138. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon.egg-info/requires.txt +0 -0
  139. {unrealon-2.0.7 → unrealon-2.0.9}/unrealon.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: unrealon
3
- Version: 2.0.7
3
+ Version: 2.0.9
4
4
  Summary: Enterprise-grade web scraping platform with AI-powered automation and real-time orchestration capabilities
5
5
  Author-email: UnrealOn Team <team@unrealon.com>
6
6
  License: MIT
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "unrealon"
7
- version = "2.0.7"
7
+ version = "2.0.9"
8
8
  description = "Enterprise-grade web scraping platform with AI-powered automation and real-time orchestration capabilities"
9
9
  authors = [
10
10
  {name = "UnrealOn Team", email = "team@unrealon.com"}
@@ -30,6 +30,7 @@ from unrealon_browser.managers import (
30
30
  CaptchaDetector,
31
31
  create_browser_logger_bridge,
32
32
  PageWaitManager,
33
+ ScriptManager,
33
34
  )
34
35
 
35
36
 
@@ -66,6 +67,7 @@ class BrowserManager:
66
67
  self.cookie_manager = None
67
68
  self.captcha_manager = CaptchaDetector()
68
69
  self.page_wait = PageWaitManager(None, self.logger_bridge)
70
+ self.script_manager = ScriptManager(None, self.logger_bridge)
69
71
 
70
72
  # Signal handlers for graceful shutdown
71
73
  self._setup_signal_handlers()
@@ -231,6 +233,9 @@ class BrowserManager:
231
233
 
232
234
  # Update page wait manager with new page
233
235
  self.page_wait.update_page(self._page)
236
+
237
+ # Update script manager with new page
238
+ self.script_manager.update_page(self._page)
234
239
 
235
240
  # 🔥 STEALTH ALWAYS APPLIED TO EVERY PAGE!
236
241
  stealth_success = await self.stealth_manager.apply_stealth(self._page)
@@ -644,6 +649,7 @@ class BrowserManager:
644
649
  finally:
645
650
  self._page = None
646
651
  self.page_wait.update_page(None)
652
+ self.script_manager.update_page(None)
647
653
 
648
654
  # Close context with safety checks
649
655
  if self._context:
@@ -8,6 +8,7 @@ from .logger_bridge import BrowserLoggerBridge, create_browser_logger_bridge
8
8
  from .cookies import CookieManager
9
9
  from .captcha import CaptchaDetector
10
10
  from .page_wait_manager import PageWaitManager
11
+ from .script_manager import ScriptManager
11
12
 
12
13
 
13
14
  __all__ = [
@@ -18,4 +19,5 @@ __all__ = [
18
19
  "CookieManager",
19
20
  "CaptchaDetector",
20
21
  "PageWaitManager",
22
+ "ScriptManager",
21
23
  ]
@@ -0,0 +1,314 @@
1
+ """
2
+ Script Manager - JavaScript execution and evaluation manager
3
+ Layer 2.5: JavaScript Integration - Handles script execution, API calls, and result processing
4
+ """
5
+
6
+ import asyncio
7
+ import json
8
+ from typing import Any, Dict, Optional, Union, List
9
+ from datetime import datetime, timezone
10
+ from playwright.async_api import Page
11
+
12
+ from .logger_bridge import BrowserLoggerBridge as LoggingBridge
13
+
14
+
15
+ class ScriptManager:
16
+ """Manager for JavaScript execution and evaluation"""
17
+
18
+ def __init__(self, page: Optional[Page], logger_bridge: LoggingBridge):
19
+ self._page = page
20
+ self.logger_bridge = logger_bridge
21
+
22
+ # Statistics
23
+ self._scripts_executed = 0
24
+ self._scripts_successful = 0
25
+ self._scripts_failed = 0
26
+ self._api_calls_made = 0
27
+ self._execution_history: List[Dict[str, Any]] = []
28
+
29
+ def update_page(self, page: Optional[Page]):
30
+ """Update the page reference"""
31
+ self._page = page
32
+
33
+ async def execute_script(self, script: str, timeout: int = 30000) -> Any:
34
+ """
35
+ Execute JavaScript code and return result
36
+
37
+ Args:
38
+ script: JavaScript code to execute
39
+ timeout: Timeout in milliseconds
40
+
41
+ Returns:
42
+ Script execution result
43
+ """
44
+ if not self._page:
45
+ raise RuntimeError("No page available for script execution")
46
+
47
+ start_time = datetime.now()
48
+ self._scripts_executed += 1
49
+
50
+ try:
51
+ self.logger_bridge.log_info(f"🔧 Executing JavaScript (timeout: {timeout}ms)")
52
+ self.logger_bridge.log_debug(f"Script preview: {script[:100]}...")
53
+
54
+ # Execute script with timeout
55
+ result = await asyncio.wait_for(
56
+ self._page.evaluate(script),
57
+ timeout=timeout / 1000
58
+ )
59
+
60
+ duration_ms = (datetime.now() - start_time).total_seconds() * 1000
61
+ self._scripts_successful += 1
62
+
63
+ # Log execution details
64
+ execution_record = {
65
+ "timestamp": start_time.isoformat(),
66
+ "duration_ms": duration_ms,
67
+ "success": True,
68
+ "result_type": type(result).__name__,
69
+ "script_length": len(script),
70
+ }
71
+ self._execution_history.append(execution_record)
72
+
73
+ self.logger_bridge.log_info(f"✅ Script executed successfully ({duration_ms:.1f}ms)")
74
+ self.logger_bridge.log_debug(f"Result type: {type(result).__name__}")
75
+
76
+ return result
77
+
78
+ except asyncio.TimeoutError:
79
+ duration_ms = (datetime.now() - start_time).total_seconds() * 1000
80
+ self._scripts_failed += 1
81
+
82
+ execution_record = {
83
+ "timestamp": start_time.isoformat(),
84
+ "duration_ms": duration_ms,
85
+ "success": False,
86
+ "error": "Timeout",
87
+ "script_length": len(script),
88
+ }
89
+ self._execution_history.append(execution_record)
90
+
91
+ self.logger_bridge.log_error(f"⏰ Script execution timeout ({timeout}ms)")
92
+ raise
93
+
94
+ except Exception as e:
95
+ duration_ms = (datetime.now() - start_time).total_seconds() * 1000
96
+ self._scripts_failed += 1
97
+
98
+ execution_record = {
99
+ "timestamp": start_time.isoformat(),
100
+ "duration_ms": duration_ms,
101
+ "success": False,
102
+ "error": str(e),
103
+ "script_length": len(script),
104
+ }
105
+ self._execution_history.append(execution_record)
106
+
107
+ self.logger_bridge.log_error(f"❌ Script execution failed: {e}")
108
+ raise
109
+
110
+ async def execute_api_call(self, api_url: str, headers: Dict[str, str], method: str = "GET", timeout: int = 30000) -> Dict[str, Any]:
111
+ """
112
+ Execute API call via JavaScript fetch
113
+
114
+ Args:
115
+ api_url: API endpoint URL
116
+ headers: HTTP headers
117
+ method: HTTP method
118
+ timeout: Timeout in milliseconds
119
+
120
+ Returns:
121
+ API response data
122
+ """
123
+ self._api_calls_made += 1
124
+
125
+ # Build fetch script
126
+ headers_json = json.dumps(headers)
127
+
128
+ script = f"""
129
+ (async function() {{
130
+ try {{
131
+ const response = await fetch('{api_url}', {{
132
+ method: '{method}',
133
+ headers: {headers_json}
134
+ }});
135
+
136
+ if (!response.ok) {{
137
+ throw new Error('HTTP error! status: ' + response.status);
138
+ }}
139
+
140
+ const data = await response.json();
141
+ return data;
142
+ }} catch (error) {{
143
+ return {{ error: error.message }};
144
+ }}
145
+ }})()
146
+ """
147
+
148
+ self.logger_bridge.log_info(f"🌐 Making API call: {method} {api_url}")
149
+
150
+ result = await self.execute_script(script, timeout)
151
+
152
+ if isinstance(result, dict) and 'error' in result:
153
+ self.logger_bridge.log_error(f"❌ API call failed: {result['error']}")
154
+ else:
155
+ self.logger_bridge.log_info(f"✅ API call successful")
156
+
157
+ return result
158
+
159
+
160
+ async def wait_for_element(self, selector: str, timeout: int = 10000) -> bool:
161
+ """
162
+ Wait for element using JavaScript
163
+
164
+ Args:
165
+ selector: CSS selector
166
+ timeout: Timeout in milliseconds
167
+
168
+ Returns:
169
+ True if element found
170
+ """
171
+ script = f"""
172
+ (function() {{
173
+ return new Promise((resolve) => {{
174
+ const element = document.querySelector('{selector}');
175
+ if (element) {{
176
+ resolve(true);
177
+ return;
178
+ }}
179
+
180
+ const observer = new MutationObserver(() => {{
181
+ const element = document.querySelector('{selector}');
182
+ if (element) {{
183
+ observer.disconnect();
184
+ resolve(true);
185
+ }}
186
+ }});
187
+
188
+ observer.observe(document.body, {{
189
+ childList: true,
190
+ subtree: true
191
+ }});
192
+
193
+ setTimeout(() => {{
194
+ observer.disconnect();
195
+ resolve(false);
196
+ }}, {timeout});
197
+ }});
198
+ }})()
199
+ """
200
+
201
+ self.logger_bridge.log_info(f"🎯 Waiting for element: {selector}")
202
+
203
+ try:
204
+ result = await self.execute_script(script, timeout + 1000)
205
+ if result:
206
+ self.logger_bridge.log_info(f"✅ Element found: {selector}")
207
+ else:
208
+ self.logger_bridge.log_warning(f"⏰ Element timeout: {selector}")
209
+ return result
210
+ except Exception as e:
211
+ self.logger_bridge.log_error(f"❌ Element wait failed: {selector} - {e}")
212
+ return False
213
+
214
+ async def inject_helper_functions(self) -> bool:
215
+ """
216
+ Inject helper JavaScript functions into page
217
+
218
+ Returns:
219
+ True if injection successful
220
+ """
221
+ helper_script = """
222
+ window.unrealonHelpers = {
223
+ // Wait for element with promise
224
+ waitForElement: function(selector, timeout = 10000) {
225
+ return new Promise((resolve) => {
226
+ const element = document.querySelector(selector);
227
+ if (element) {
228
+ resolve(element);
229
+ return;
230
+ }
231
+
232
+ const observer = new MutationObserver(() => {
233
+ const element = document.querySelector(selector);
234
+ if (element) {
235
+ observer.disconnect();
236
+ resolve(element);
237
+ }
238
+ });
239
+
240
+ observer.observe(document.body, {
241
+ childList: true,
242
+ subtree: true
243
+ });
244
+
245
+ setTimeout(() => {
246
+ observer.disconnect();
247
+ resolve(null);
248
+ }, timeout);
249
+ });
250
+ },
251
+
252
+ // Get page info
253
+ getPageInfo: function() {
254
+ return {
255
+ url: window.location.href,
256
+ title: document.title,
257
+ readyState: document.readyState,
258
+ timestamp: new Date().toISOString()
259
+ };
260
+ },
261
+
262
+ // Check if SPA loaded
263
+ isSPAReady: function() {
264
+ return document.readyState === 'complete' &&
265
+ document.querySelector('body').children.length > 0;
266
+ }
267
+ };
268
+
269
+ console.log('🔧 UnrealOn helper functions injected');
270
+ """
271
+
272
+ try:
273
+ await self.execute_script(helper_script)
274
+ self.logger_bridge.log_info("🔧 Helper functions injected successfully")
275
+ return True
276
+ except Exception as e:
277
+ self.logger_bridge.log_error(f"❌ Failed to inject helper functions: {e}")
278
+ return False
279
+
280
+ def get_statistics(self) -> Dict[str, Any]:
281
+ """Get script execution statistics"""
282
+ success_rate = (self._scripts_successful / self._scripts_executed * 100) if self._scripts_executed > 0 else 0
283
+
284
+ return {
285
+ "scripts_executed": self._scripts_executed,
286
+ "scripts_successful": self._scripts_successful,
287
+ "scripts_failed": self._scripts_failed,
288
+ "success_rate": success_rate,
289
+ "api_calls_made": self._api_calls_made,
290
+ "execution_history_count": len(self._execution_history),
291
+ }
292
+
293
+ def print_statistics(self) -> None:
294
+ """Print script execution statistics"""
295
+ stats = self.get_statistics()
296
+
297
+ self.logger_bridge.log_info("\n🔧 Script Manager Statistics:")
298
+ self.logger_bridge.log_info(f" Scripts executed: {stats['scripts_executed']}")
299
+ self.logger_bridge.log_info(f" Successful: {stats['scripts_successful']}")
300
+ self.logger_bridge.log_info(f" Failed: {stats['scripts_failed']}")
301
+ self.logger_bridge.log_info(f" Success rate: {stats['success_rate']:.1f}%")
302
+ self.logger_bridge.log_info(f" API calls made: {stats['api_calls_made']}")
303
+
304
+ # Show recent executions
305
+ if self._execution_history:
306
+ self.logger_bridge.log_info(" Recent executions:")
307
+ for execution in self._execution_history[-3:]: # Show last 3
308
+ status = "✅" if execution["success"] else "❌"
309
+ self.logger_bridge.log_info(f" {status} {execution['duration_ms']:.1f}ms")
310
+
311
+ def clear_history(self) -> None:
312
+ """Clear execution history"""
313
+ self._execution_history.clear()
314
+ self.logger_bridge.log_info("🧹 Cleared script execution history")
@@ -24,6 +24,7 @@ class URLConfig(BaseModel):
24
24
 
25
25
  # Cloud platform URLs
26
26
  cloud_base_url: str = Field(
27
+ default="https://cloud.unrealon.com",
27
28
  description="Base URL for UnrealOn Cloud platform"
28
29
  )
29
30
 
@@ -41,7 +42,7 @@ class URLConfig(BaseModel):
41
42
  if environment == Environment.PRODUCTION:
42
43
  return cls(
43
44
  # scanner_url="https://cloud.unrealon.com/scanner",
44
- cloud_base_url="https://cloud.unrealon.com",
45
+ # cloud_base_url="https://cloud.unrealon.com",
45
46
  api_base_url="https://api.unrealon.com"
46
47
  )
47
48
  # elif environment == Environment.TESTING:
@@ -9,6 +9,8 @@ Phase 1: Foundation enums with strict validation
9
9
 
10
10
  from .status import DriverStatus, TaskStatus, ProxyStatus, LogLevel
11
11
  from .types import MessageType, ProxyType, TaskPriority
12
+ from .events import EventType, SystemEventType, RedisEventType
13
+ from .jobs import ARQJobName
12
14
 
13
15
  __all__ = [
14
16
  # Status enums
@@ -21,4 +23,12 @@ __all__ = [
21
23
  "MessageType",
22
24
  "ProxyType",
23
25
  "TaskPriority",
26
+
27
+ # Event enums
28
+ "EventType",
29
+ "SystemEventType",
30
+ "RedisEventType",
31
+
32
+ # Job enums
33
+ "ARQJobName",
24
34
  ]
@@ -0,0 +1,98 @@
1
+ """
2
+ Event type enums for UnrealOn system.
3
+
4
+ Centralized event type definitions used across all services.
5
+ """
6
+ from enum import Enum
7
+
8
+
9
+ class EventType(str, Enum):
10
+ """
11
+ Event types used in Redis PubSub and system events.
12
+
13
+ These events are used for communication between services:
14
+ - RPC server publishes events
15
+ - Django consumes events via Redis PubSub
16
+ - System events are stored in database
17
+ """
18
+
19
+ # Driver lifecycle events
20
+ DRIVER_REGISTER = "driver_register"
21
+ DRIVER_DISCONNECT = "driver_disconnect"
22
+
23
+ # Parser events (Django-specific naming)
24
+ PARSER_REGISTERED = "parser_registered"
25
+ PARSER_HEARTBEAT = "parser_heartbeat"
26
+ PARSER_DISCONNECTED = "parser_disconnected"
27
+ PARSER_ERROR = "parser_error"
28
+ PARSER_LOG = "parser_log"
29
+
30
+ # Session events
31
+ SESSION_STARTED = "session_started"
32
+ SESSION_COMPLETED = "session_completed"
33
+ SESSION_FAILED = "session_failed"
34
+
35
+ # Command events
36
+ COMMAND_ISSUED = "command_issued"
37
+ COMMAND_COMPLETED = "command_completed"
38
+ COMMAND_FAILED = "command_failed"
39
+
40
+ # System events
41
+ SYSTEM_STARTUP = "system_startup"
42
+ SYSTEM_SHUTDOWN = "system_shutdown"
43
+ SYSTEM_ERROR = "system_error"
44
+
45
+
46
+ class SystemEventType(str, Enum):
47
+ """
48
+ System event types for Django database storage.
49
+
50
+ These match the choices in Django's SystemEvent model.
51
+ """
52
+
53
+ # Parser events
54
+ PARSER_REGISTERED = "parser_registered"
55
+ PARSER_HEARTBEAT = "parser_heartbeat"
56
+ PARSER_DISCONNECTED = "parser_disconnected"
57
+ PARSER_ERROR = "parser_error"
58
+
59
+ # Session events
60
+ SESSION_STARTED = "session_started"
61
+ SESSION_COMPLETED = "session_completed"
62
+ SESSION_FAILED = "session_failed"
63
+
64
+ # Command events
65
+ COMMAND_ISSUED = "command_issued"
66
+ COMMAND_COMPLETED = "command_completed"
67
+ COMMAND_FAILED = "command_failed"
68
+
69
+ # System events
70
+ SYSTEM_STARTUP = "system_startup"
71
+ SYSTEM_SHUTDOWN = "system_shutdown"
72
+ SYSTEM_ERROR = "system_error"
73
+
74
+
75
+ class RedisEventType(str, Enum):
76
+ """
77
+ Redis PubSub event types.
78
+
79
+ These are the event types published to Redis channels
80
+ for inter-service communication.
81
+ """
82
+
83
+ # Driver lifecycle (from RPC to Django)
84
+ DRIVER_REGISTER = "driver_register"
85
+ DRIVER_DISCONNECT = "driver_disconnect"
86
+
87
+ # Parser events (internal Django events)
88
+ PARSER_HEARTBEAT = "parser_heartbeat"
89
+ PARSER_LOG = "parser_log"
90
+
91
+ # Session events
92
+ SESSION_STARTED = "session_started"
93
+ SESSION_COMPLETED = "session_completed"
94
+ SESSION_FAILED = "session_failed"
95
+
96
+ # Command events
97
+ COMMAND_COMPLETED = "command_completed"
98
+ COMMAND_FAILED = "command_failed"
@@ -0,0 +1,32 @@
1
+ """
2
+ ARQ job name enums for UnrealOn system.
3
+
4
+ Centralized job name definitions used across all services.
5
+ """
6
+ from enum import Enum
7
+
8
+
9
+ class ARQJobName(str, Enum):
10
+ """
11
+ ARQ job names used in the system.
12
+
13
+ These are the job function names that can be enqueued
14
+ and processed by ARQ workers.
15
+ """
16
+
17
+ # Driver management jobs
18
+ REGISTER_DRIVER = "register_driver"
19
+ DRIVER_DISCONNECT = "driver_disconnect"
20
+ GET_DRIVER_STATUS = "get_driver_status"
21
+ LIST_AVAILABLE_DRIVERS = "list_available_drivers"
22
+
23
+ # Task management jobs
24
+ ASSIGN_TASK_TO_DRIVER = "assign_task_to_driver"
25
+
26
+ # System jobs
27
+ PING = "ping"
28
+ PROCESS_DRIVER_HEARTBEAT = "process_driver_heartbeat"
29
+
30
+ # Lifecycle jobs
31
+ STARTUP = "startup"
32
+ SHUTDOWN = "shutdown"
@@ -58,6 +58,7 @@ class MessageType(str, Enum):
58
58
  PONG = "pong" # Pong response
59
59
  ERROR = "error" # Error message
60
60
  ACK = "ack" # Acknowledgment
61
+ MONITOR_REGISTER = "monitor_register" # Monitor client registration
61
62
 
62
63
  def is_driver_lifecycle(self) -> bool:
63
64
  """Check if message is related to driver lifecycle."""
@@ -46,6 +46,11 @@ from .logging import (
46
46
  LogMetrics
47
47
  )
48
48
 
49
+ from .authentication import (
50
+ APIKeyAuthRequest,
51
+ APIKeyAuthResponse
52
+ )
53
+
49
54
  __all__ = [
50
55
  # Base models
51
56
  "UnrealOnBaseModel",
@@ -76,4 +81,8 @@ __all__ = [
76
81
  "LogEntry",
77
82
  "LogQuery",
78
83
  "LogMetrics",
84
+
85
+ # Authentication models
86
+ "APIKeyAuthRequest",
87
+ "APIKeyAuthResponse",
79
88
  ]
@@ -0,0 +1,24 @@
1
+ """
2
+ Authentication models for UnrealOn system.
3
+
4
+ Provides Pydantic models for API key authentication between services.
5
+ """
6
+ from typing import Optional, List
7
+ from pydantic import Field
8
+
9
+ from .base import UnrealOnBaseModel
10
+
11
+
12
+ class APIKeyAuthRequest(UnrealOnBaseModel):
13
+ """API key authentication request."""
14
+ api_key: str = Field(min_length=1, description="API key for authentication")
15
+ parser_id: str = Field(min_length=1, description="Parser requesting authentication")
16
+
17
+
18
+ class APIKeyAuthResponse(UnrealOnBaseModel):
19
+ """API key authentication response."""
20
+ success: bool = Field(description="Whether authentication was successful")
21
+ user_id: Optional[int] = Field(default=None, description="Authenticated user ID")
22
+ username: Optional[str] = Field(default=None, description="Authenticated username")
23
+ permissions: List[str] = Field(default_factory=list, description="User permissions")
24
+ error: Optional[str] = Field(default=None, description="Error message if failed")
@@ -14,6 +14,7 @@ class BrowserManagerConfig(ManagerConfig):
14
14
 
15
15
  headless: bool = Field(default=True, description="Run headless")
16
16
  parser_name: str = Field(..., description="Parser name for browser")
17
+ stealth_warmup_enabled: bool = Field(default=False, description="Enable stealth warmup")
17
18
 
18
19
 
19
20
  class BrowserManager(BaseManager):
@@ -51,7 +52,10 @@ class BrowserManager(BaseManager):
51
52
  self.logger.info("🚀 Starting browser (lazy initialization)...")
52
53
 
53
54
  # Create browser config
54
- browser_config = BrowserConfig(parser_name=self.config.parser_name)
55
+ browser_config = BrowserConfig(
56
+ parser_name=self.config.parser_name,
57
+ stealth_warmup_enabled=self.config.stealth_warmup_enabled # Disable stealth warmup to avoid scanner navigation
58
+ )
55
59
 
56
60
  # Create browser manager
57
61
  self.browser = CoreBrowserManager(browser_config)
@@ -96,3 +100,19 @@ class BrowserManager(BaseManager):
96
100
  self.logger.error(f"Get HTML failed: {e}")
97
101
  self.stats.record_operation(False, 0.0)
98
102
  return None
103
+
104
+ async def execute_script_async(self, script: str) -> any:
105
+ """Execute JavaScript on current page via ScriptManager."""
106
+ # Ensure browser is initialized
107
+ if not await self._ensure_browser_initialized():
108
+ raise RuntimeError("Failed to initialize browser")
109
+
110
+ try:
111
+ # Use ScriptManager from CoreBrowserManager
112
+ result = await self.browser.script_manager.execute_script(script)
113
+ self.stats.record_operation(True, 0.0)
114
+ return result
115
+ except Exception as e:
116
+ self.logger.error(f"Script execution failed: {e}")
117
+ self.stats.record_operation(False, 0.0)
118
+ raise
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: unrealon
3
- Version: 2.0.7
3
+ Version: 2.0.9
4
4
  Summary: Enterprise-grade web scraping platform with AI-powered automation and real-time orchestration capabilities
5
5
  Author-email: UnrealOn Team <team@unrealon.com>
6
6
  License: MIT
@@ -25,6 +25,7 @@ unrealon-browser/src/unrealon_browser/managers/cookies.py
25
25
  unrealon-browser/src/unrealon_browser/managers/logger_bridge.py
26
26
  unrealon-browser/src/unrealon_browser/managers/page_wait_manager.py
27
27
  unrealon-browser/src/unrealon_browser/managers/profile.py
28
+ unrealon-browser/src/unrealon_browser/managers/script_manager.py
28
29
  unrealon-browser/src/unrealon_browser/stealth/__init__.py
29
30
  unrealon-browser/src/unrealon_browser/stealth/bypass_techniques.pyc
30
31
  unrealon-browser/src/unrealon_browser/stealth/manager.pyc
@@ -38,6 +39,8 @@ unrealon-core/src/unrealon_core/config/__init__.py
38
39
  unrealon-core/src/unrealon_core/config/environment.py
39
40
  unrealon-core/src/unrealon_core/config/urls.py
40
41
  unrealon-core/src/unrealon_core/enums/__init__.py
42
+ unrealon-core/src/unrealon_core/enums/events.py
43
+ unrealon-core/src/unrealon_core/enums/jobs.py
41
44
  unrealon-core/src/unrealon_core/enums/status.py
42
45
  unrealon-core/src/unrealon_core/enums/types.py
43
46
  unrealon-core/src/unrealon_core/error_handling/__init__.py
@@ -55,6 +58,7 @@ unrealon-core/src/unrealon_core/exceptions/validation.py
55
58
  unrealon-core/src/unrealon_core/models/__init__.py
56
59
  unrealon-core/src/unrealon_core/models/arq_context.py
57
60
  unrealon-core/src/unrealon_core/models/arq_responses.py
61
+ unrealon-core/src/unrealon_core/models/authentication.py
58
62
  unrealon-core/src/unrealon_core/models/base.py
59
63
  unrealon-core/src/unrealon_core/models/bridge_stats.py
60
64
  unrealon-core/src/unrealon_core/models/communication.py
File without changes
File without changes
File without changes
File without changes