unrealon 1.1.6__py3-none-any.whl → 2.0.5__py3-none-any.whl

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 (144) hide show
  1. {unrealon-1.1.6.dist-info/licenses → unrealon-2.0.5.dist-info}/LICENSE +1 -1
  2. unrealon-2.0.5.dist-info/METADATA +491 -0
  3. unrealon-2.0.5.dist-info/RECORD +128 -0
  4. {unrealon-1.1.6.dist-info → unrealon-2.0.5.dist-info}/WHEEL +2 -1
  5. unrealon-2.0.5.dist-info/entry_points.txt +3 -0
  6. unrealon-2.0.5.dist-info/top_level.txt +3 -0
  7. unrealon_browser/__init__.py +5 -6
  8. unrealon_browser/cli/browser_cli.py +18 -9
  9. unrealon_browser/cli/interactive_mode.py +13 -4
  10. unrealon_browser/core/browser_manager.py +29 -16
  11. unrealon_browser/dto/__init__.py +21 -0
  12. unrealon_browser/dto/bot_detection.py +175 -0
  13. unrealon_browser/dto/models/config.py +9 -3
  14. unrealon_browser/managers/__init__.py +1 -1
  15. unrealon_browser/managers/logger_bridge.py +1 -4
  16. unrealon_browser/stealth/__init__.py +27 -0
  17. unrealon_browser/stealth/bypass_techniques.pyc +0 -0
  18. unrealon_browser/stealth/manager.pyc +0 -0
  19. unrealon_browser/stealth/nodriver_stealth.pyc +0 -0
  20. unrealon_browser/stealth/playwright_stealth.pyc +0 -0
  21. unrealon_browser/stealth/scanner_tester.pyc +0 -0
  22. unrealon_browser/stealth/undetected_chrome.pyc +0 -0
  23. unrealon_core/__init__.py +172 -0
  24. unrealon_core/config/__init__.py +16 -0
  25. unrealon_core/config/environment.py +151 -0
  26. unrealon_core/config/urls.py +94 -0
  27. unrealon_core/enums/__init__.py +24 -0
  28. unrealon_core/enums/status.py +216 -0
  29. unrealon_core/enums/types.py +240 -0
  30. unrealon_core/error_handling/__init__.py +45 -0
  31. unrealon_core/error_handling/circuit_breaker.py +292 -0
  32. unrealon_core/error_handling/error_context.py +324 -0
  33. unrealon_core/error_handling/recovery.py +371 -0
  34. unrealon_core/error_handling/retry.py +268 -0
  35. unrealon_core/exceptions/__init__.py +46 -0
  36. unrealon_core/exceptions/base.py +292 -0
  37. unrealon_core/exceptions/communication.py +22 -0
  38. unrealon_core/exceptions/driver.py +11 -0
  39. unrealon_core/exceptions/proxy.py +11 -0
  40. unrealon_core/exceptions/task.py +12 -0
  41. unrealon_core/exceptions/validation.py +17 -0
  42. unrealon_core/models/__init__.py +79 -0
  43. unrealon_core/models/arq_context.py +252 -0
  44. unrealon_core/models/arq_responses.py +125 -0
  45. unrealon_core/models/base.py +291 -0
  46. unrealon_core/models/bridge_stats.py +58 -0
  47. unrealon_core/models/communication.py +39 -0
  48. unrealon_core/models/connection_stats.py +47 -0
  49. unrealon_core/models/driver.py +30 -0
  50. unrealon_core/models/driver_details.py +98 -0
  51. unrealon_core/models/logging.py +28 -0
  52. unrealon_core/models/task.py +21 -0
  53. unrealon_core/models/typed_responses.py +210 -0
  54. unrealon_core/models/websocket/__init__.py +91 -0
  55. unrealon_core/models/websocket/base.py +49 -0
  56. unrealon_core/models/websocket/config.py +200 -0
  57. unrealon_core/models/websocket/driver.py +215 -0
  58. unrealon_core/models/websocket/errors.py +138 -0
  59. unrealon_core/models/websocket/heartbeat.py +100 -0
  60. unrealon_core/models/websocket/logging.py +261 -0
  61. unrealon_core/models/websocket/proxy.py +496 -0
  62. unrealon_core/models/websocket/tasks.py +275 -0
  63. unrealon_core/models/websocket/utils.py +153 -0
  64. unrealon_core/models/websocket_session.py +144 -0
  65. unrealon_core/monitoring/__init__.py +43 -0
  66. unrealon_core/monitoring/alerts.py +398 -0
  67. unrealon_core/monitoring/dashboard.py +307 -0
  68. unrealon_core/monitoring/health_check.py +354 -0
  69. unrealon_core/monitoring/metrics.py +352 -0
  70. unrealon_core/utils/__init__.py +11 -0
  71. unrealon_core/utils/time.py +61 -0
  72. unrealon_core/version.py +219 -0
  73. unrealon_driver/__init__.py +90 -51
  74. unrealon_driver/core_module/__init__.py +34 -0
  75. unrealon_driver/core_module/base.py +184 -0
  76. unrealon_driver/core_module/config.py +30 -0
  77. unrealon_driver/core_module/event_manager.py +127 -0
  78. unrealon_driver/core_module/protocols.py +98 -0
  79. unrealon_driver/core_module/registry.py +146 -0
  80. unrealon_driver/decorators/__init__.py +15 -0
  81. unrealon_driver/decorators/retry.py +117 -0
  82. unrealon_driver/decorators/schedule.py +137 -0
  83. unrealon_driver/decorators/task.py +61 -0
  84. unrealon_driver/decorators/timing.py +132 -0
  85. unrealon_driver/driver/__init__.py +20 -0
  86. unrealon_driver/driver/communication/__init__.py +10 -0
  87. unrealon_driver/driver/communication/session.py +203 -0
  88. unrealon_driver/driver/communication/websocket_client.py +205 -0
  89. unrealon_driver/driver/core/__init__.py +10 -0
  90. unrealon_driver/driver/core/config.py +175 -0
  91. unrealon_driver/driver/core/driver.py +221 -0
  92. unrealon_driver/driver/factory/__init__.py +9 -0
  93. unrealon_driver/driver/factory/manager_factory.py +130 -0
  94. unrealon_driver/driver/lifecycle/__init__.py +11 -0
  95. unrealon_driver/driver/lifecycle/daemon.py +76 -0
  96. unrealon_driver/driver/lifecycle/initialization.py +97 -0
  97. unrealon_driver/driver/lifecycle/shutdown.py +48 -0
  98. unrealon_driver/driver/monitoring/__init__.py +9 -0
  99. unrealon_driver/driver/monitoring/health.py +63 -0
  100. unrealon_driver/driver/utilities/__init__.py +10 -0
  101. unrealon_driver/driver/utilities/logging.py +51 -0
  102. unrealon_driver/driver/utilities/serialization.py +61 -0
  103. unrealon_driver/managers/__init__.py +32 -0
  104. unrealon_driver/managers/base.py +174 -0
  105. unrealon_driver/managers/browser.py +98 -0
  106. unrealon_driver/managers/cache.py +116 -0
  107. unrealon_driver/managers/http.py +107 -0
  108. unrealon_driver/managers/logger.py +286 -0
  109. unrealon_driver/managers/proxy.py +99 -0
  110. unrealon_driver/managers/registry.py +87 -0
  111. unrealon_driver/managers/threading.py +54 -0
  112. unrealon_driver/managers/update.py +107 -0
  113. unrealon_driver/utils/__init__.py +9 -0
  114. unrealon_driver/utils/time.py +10 -0
  115. unrealon-1.1.6.dist-info/METADATA +0 -625
  116. unrealon-1.1.6.dist-info/RECORD +0 -55
  117. unrealon-1.1.6.dist-info/entry_points.txt +0 -9
  118. unrealon_browser/managers/stealth.py +0 -388
  119. unrealon_driver/README.md +0 -0
  120. unrealon_driver/exceptions.py +0 -33
  121. unrealon_driver/html_analyzer/__init__.py +0 -32
  122. unrealon_driver/html_analyzer/cleaner.py +0 -657
  123. unrealon_driver/html_analyzer/config.py +0 -64
  124. unrealon_driver/html_analyzer/manager.py +0 -247
  125. unrealon_driver/html_analyzer/models.py +0 -115
  126. unrealon_driver/html_analyzer/websocket_analyzer.py +0 -157
  127. unrealon_driver/models/__init__.py +0 -31
  128. unrealon_driver/models/websocket.py +0 -98
  129. unrealon_driver/parser/__init__.py +0 -36
  130. unrealon_driver/parser/cli_manager.py +0 -142
  131. unrealon_driver/parser/daemon_manager.py +0 -403
  132. unrealon_driver/parser/managers/__init__.py +0 -25
  133. unrealon_driver/parser/managers/config.py +0 -293
  134. unrealon_driver/parser/managers/error.py +0 -412
  135. unrealon_driver/parser/managers/result.py +0 -321
  136. unrealon_driver/parser/parser_manager.py +0 -458
  137. unrealon_driver/smart_logging/__init__.py +0 -24
  138. unrealon_driver/smart_logging/models.py +0 -44
  139. unrealon_driver/smart_logging/smart_logger.py +0 -406
  140. unrealon_driver/smart_logging/unified_logger.py +0 -525
  141. unrealon_driver/websocket/__init__.py +0 -31
  142. unrealon_driver/websocket/client.py +0 -249
  143. unrealon_driver/websocket/config.py +0 -188
  144. unrealon_driver/websocket/manager.py +0 -90
@@ -0,0 +1,215 @@
1
+ """
2
+ Driver WebSocket Models.
3
+
4
+ Strictly typed models for driver registration and responses.
5
+ No raw dictionaries - all data structures are Pydantic models.
6
+
7
+ Phase 2: Core Systems - WebSocket Bridge
8
+ """
9
+
10
+ from typing import List, Optional
11
+ from pydantic import Field, ConfigDict, field_validator
12
+
13
+ from ..base import UnrealOnBaseModel
14
+ from .base import WebSocketMessage, MessageType
15
+ from ...version import get_driver_version
16
+
17
+
18
+ class DriverMetadata(UnrealOnBaseModel):
19
+ """Driver metadata with strict typing."""
20
+
21
+ model_config = ConfigDict(
22
+ validate_assignment=True,
23
+ extra="forbid"
24
+ )
25
+
26
+ region: Optional[str] = Field(
27
+ default=None,
28
+ description="Driver deployment region"
29
+ )
30
+
31
+ environment: Optional[str] = Field(
32
+ default="production",
33
+ description="Environment (development, staging, production)"
34
+ )
35
+
36
+ max_concurrent_tasks: Optional[int] = Field(
37
+ default=1,
38
+ ge=1,
39
+ le=100,
40
+ description="Maximum concurrent tasks"
41
+ )
42
+
43
+ tags: List[str] = Field(
44
+ default_factory=list,
45
+ description="Driver tags for filtering"
46
+ )
47
+
48
+
49
+ class DriverRegistrationData(UnrealOnBaseModel):
50
+ """Driver registration data payload - strictly typed."""
51
+
52
+ model_config = ConfigDict(
53
+ validate_assignment=True,
54
+ extra="forbid"
55
+ )
56
+
57
+ driver_id: str = Field(
58
+ min_length=1,
59
+ max_length=100,
60
+ description="Unique driver identifier"
61
+ )
62
+
63
+ driver_name: str = Field(
64
+ min_length=1,
65
+ max_length=200,
66
+ description="Human-readable driver name"
67
+ )
68
+
69
+ driver_type: str = Field(
70
+ min_length=1,
71
+ max_length=50,
72
+ description="Type of driver (universal, ecommerce, etc.)"
73
+ )
74
+
75
+ capabilities: List[str] = Field(
76
+ default_factory=list,
77
+ description="List of supported task types"
78
+ )
79
+
80
+ version: str = Field(
81
+ default_factory=get_driver_version,
82
+ pattern=r"^\d+\.\d+\.\d+$",
83
+ description="Driver version (semver)"
84
+ )
85
+
86
+ metadata: DriverMetadata = Field(
87
+ default_factory=DriverMetadata,
88
+ description="Driver metadata"
89
+ )
90
+
91
+ @field_validator('capabilities')
92
+ @classmethod
93
+ def validate_capabilities(cls, v: List[str]) -> List[str]:
94
+ """Validate capabilities list."""
95
+ if not v:
96
+ raise ValueError("Driver must have at least one capability")
97
+
98
+ # Remove duplicates while preserving order
99
+ seen = set()
100
+ unique_caps = []
101
+ for cap in v:
102
+ if cap not in seen:
103
+ seen.add(cap)
104
+ unique_caps.append(cap)
105
+
106
+ return unique_caps
107
+
108
+
109
+ class DriverRegistrationMessage(WebSocketMessage):
110
+ """Driver registration message (Driver → Server)."""
111
+
112
+ model_config = ConfigDict(
113
+ validate_assignment=True,
114
+ extra="forbid"
115
+ )
116
+
117
+ type: MessageType = Field(
118
+ default=MessageType.DRIVER_REGISTER,
119
+ frozen=True
120
+ )
121
+
122
+ data: DriverRegistrationData = Field(
123
+ description="Driver registration data"
124
+ )
125
+
126
+
127
+ class DriverConfiguration(UnrealOnBaseModel):
128
+ """Driver configuration from server - strictly typed."""
129
+
130
+ model_config = ConfigDict(
131
+ validate_assignment=True,
132
+ extra="forbid"
133
+ )
134
+
135
+ heartbeat_interval: int = Field(
136
+ default=30,
137
+ ge=5,
138
+ le=300,
139
+ description="Heartbeat interval in seconds"
140
+ )
141
+
142
+ log_level: str = Field(
143
+ default="INFO",
144
+ pattern=r"^(DEBUG|INFO|WARNING|ERROR|CRITICAL)$",
145
+ description="Logging level"
146
+ )
147
+
148
+ batch_size: int = Field(
149
+ default=10,
150
+ ge=1,
151
+ le=100,
152
+ description="Log batch size"
153
+ )
154
+
155
+ max_retries: int = Field(
156
+ default=3,
157
+ ge=0,
158
+ le=10,
159
+ description="Maximum task retries"
160
+ )
161
+
162
+ timeout_seconds: int = Field(
163
+ default=300,
164
+ ge=30,
165
+ le=3600,
166
+ description="Default task timeout"
167
+ )
168
+
169
+
170
+ class RegistrationResponseData(UnrealOnBaseModel):
171
+ """Registration response data payload - strictly typed."""
172
+
173
+ model_config = ConfigDict(
174
+ validate_assignment=True,
175
+ extra="forbid"
176
+ )
177
+
178
+ success: bool = Field(
179
+ description="Whether registration was successful"
180
+ )
181
+
182
+ driver_id: str = Field(
183
+ description="Confirmed driver ID"
184
+ )
185
+
186
+ session_id: str = Field(
187
+ description="WebSocket session ID"
188
+ )
189
+
190
+ message: str = Field(
191
+ description="Registration status message"
192
+ )
193
+
194
+ configuration: DriverConfiguration = Field(
195
+ default_factory=DriverConfiguration,
196
+ description="Driver configuration from server"
197
+ )
198
+
199
+
200
+ class RegistrationResponseMessage(WebSocketMessage):
201
+ """Registration response message (Server → Driver)."""
202
+
203
+ model_config = ConfigDict(
204
+ validate_assignment=True,
205
+ extra="forbid"
206
+ )
207
+
208
+ type: MessageType = Field(
209
+ default=MessageType.DRIVER_REGISTER_RESPONSE,
210
+ frozen=True
211
+ )
212
+
213
+ data: RegistrationResponseData = Field(
214
+ description="Registration response data"
215
+ )
@@ -0,0 +1,138 @@
1
+ """
2
+ Error and Acknowledgment WebSocket Models.
3
+
4
+ Strictly typed models for error messages and acknowledgments.
5
+ No raw dictionaries - all data structures are Pydantic models.
6
+
7
+ Phase 2: Core Systems - WebSocket Bridge
8
+ """
9
+
10
+ from typing import Optional, List
11
+ from pydantic import Field, ConfigDict
12
+
13
+ from ..base import UnrealOnBaseModel
14
+ from .base import WebSocketMessage, MessageType
15
+
16
+
17
+ class ErrorDetails(UnrealOnBaseModel):
18
+ """Error details - strictly typed."""
19
+
20
+ model_config = ConfigDict(
21
+ validate_assignment=True,
22
+ extra="forbid"
23
+ )
24
+
25
+ field_errors: List[str] = Field(
26
+ default_factory=list,
27
+ description="Field validation errors"
28
+ )
29
+
30
+ stack_trace: Optional[str] = Field(
31
+ default=None,
32
+ description="Stack trace (if available)"
33
+ )
34
+
35
+ request_id: Optional[str] = Field(
36
+ default=None,
37
+ description="Request ID that caused the error"
38
+ )
39
+
40
+ timestamp: Optional[str] = Field(
41
+ default=None,
42
+ description="Error timestamp"
43
+ )
44
+
45
+
46
+ class ErrorData(UnrealOnBaseModel):
47
+ """Error data payload - strictly typed."""
48
+
49
+ model_config = ConfigDict(
50
+ validate_assignment=True,
51
+ extra="forbid"
52
+ )
53
+
54
+ error_code: str = Field(
55
+ min_length=1,
56
+ max_length=100,
57
+ description="Error code identifier"
58
+ )
59
+
60
+ error_message: str = Field(
61
+ min_length=1,
62
+ max_length=1000,
63
+ description="Human-readable error message"
64
+ )
65
+
66
+ details: Optional[ErrorDetails] = Field(
67
+ default=None,
68
+ description="Additional error details"
69
+ )
70
+
71
+ retry_after: Optional[int] = Field(
72
+ default=None,
73
+ ge=0,
74
+ le=3600,
75
+ description="Retry after seconds (if retryable)"
76
+ )
77
+
78
+
79
+ class ErrorMessage(WebSocketMessage):
80
+ """Error message (Bidirectional)."""
81
+
82
+ model_config = ConfigDict(
83
+ validate_assignment=True,
84
+ extra="forbid"
85
+ )
86
+
87
+ type: MessageType = Field(
88
+ default=MessageType.ERROR,
89
+ frozen=True
90
+ )
91
+
92
+ data: ErrorData = Field(
93
+ description="Error data"
94
+ )
95
+
96
+
97
+ class AckData(UnrealOnBaseModel):
98
+ """Acknowledgment data payload - strictly typed."""
99
+
100
+ model_config = ConfigDict(
101
+ validate_assignment=True,
102
+ extra="forbid"
103
+ )
104
+
105
+ acknowledged: bool = Field(
106
+ default=True,
107
+ description="Acknowledgment status"
108
+ )
109
+
110
+ message: Optional[str] = Field(
111
+ default=None,
112
+ max_length=500,
113
+ description="Optional acknowledgment message"
114
+ )
115
+
116
+ processing_time_ms: Optional[float] = Field(
117
+ default=None,
118
+ ge=0.0,
119
+ description="Processing time in milliseconds"
120
+ )
121
+
122
+
123
+ class AckMessage(WebSocketMessage):
124
+ """Acknowledgment message (Bidirectional)."""
125
+
126
+ model_config = ConfigDict(
127
+ validate_assignment=True,
128
+ extra="forbid"
129
+ )
130
+
131
+ type: MessageType = Field(
132
+ default=MessageType.ACK,
133
+ frozen=True
134
+ )
135
+
136
+ data: AckData = Field(
137
+ description="Acknowledgment data"
138
+ )
@@ -0,0 +1,100 @@
1
+ """
2
+ Heartbeat WebSocket Models.
3
+
4
+ Strictly typed models for driver heartbeat messages.
5
+ No raw dictionaries - all data structures are Pydantic models.
6
+
7
+ Phase 2: Core Systems - WebSocket Bridge
8
+ """
9
+
10
+ from typing import Optional
11
+ from pydantic import Field, ConfigDict
12
+
13
+ from ..base import UnrealOnBaseModel
14
+ from .base import WebSocketMessage, MessageType
15
+
16
+
17
+ class HeartbeatData(UnrealOnBaseModel):
18
+ """Heartbeat data payload - strictly typed."""
19
+
20
+ model_config = ConfigDict(
21
+ validate_assignment=True,
22
+ extra="forbid"
23
+ )
24
+
25
+ driver_status: str = Field(
26
+ default="ready",
27
+ pattern=r"^(ready|busy|idle|error|maintenance)$",
28
+ description="Current driver status"
29
+ )
30
+
31
+ active_tasks: int = Field(
32
+ default=0,
33
+ ge=0,
34
+ le=1000,
35
+ description="Number of active tasks"
36
+ )
37
+
38
+ completed_tasks: int = Field(
39
+ default=0,
40
+ ge=0,
41
+ description="Total completed tasks"
42
+ )
43
+
44
+ failed_tasks: int = Field(
45
+ default=0,
46
+ ge=0,
47
+ description="Total failed tasks"
48
+ )
49
+
50
+ uptime_seconds: float = Field(
51
+ default=0.0,
52
+ ge=0.0,
53
+ description="Driver uptime in seconds"
54
+ )
55
+
56
+ memory_usage_mb: Optional[float] = Field(
57
+ default=None,
58
+ ge=0.0,
59
+ le=100000.0, # 100GB max
60
+ description="Memory usage in MB"
61
+ )
62
+
63
+ cpu_usage_percent: Optional[float] = Field(
64
+ default=None,
65
+ ge=0.0,
66
+ le=100.0,
67
+ description="CPU usage percentage"
68
+ )
69
+
70
+ def get_success_rate(self) -> float:
71
+ """Calculate task success rate."""
72
+ total_tasks = self.completed_tasks + self.failed_tasks
73
+ if total_tasks == 0:
74
+ return 1.0
75
+ return self.completed_tasks / total_tasks
76
+
77
+ def is_healthy(self) -> bool:
78
+ """Check if driver is healthy."""
79
+ return (
80
+ self.driver_status in ["ready", "busy", "idle"] and
81
+ self.get_success_rate() >= 0.8 # 80% success rate threshold
82
+ )
83
+
84
+
85
+ class HeartbeatMessage(WebSocketMessage):
86
+ """Heartbeat message (Driver → Server)."""
87
+
88
+ model_config = ConfigDict(
89
+ validate_assignment=True,
90
+ extra="forbid"
91
+ )
92
+
93
+ type: MessageType = Field(
94
+ default=MessageType.DRIVER_HEARTBEAT,
95
+ frozen=True
96
+ )
97
+
98
+ data: HeartbeatData = Field(
99
+ description="Heartbeat data"
100
+ )
@@ -0,0 +1,261 @@
1
+ """
2
+ Logging WebSocket Models.
3
+
4
+ Strictly typed models for log entries and batches.
5
+ No raw dictionaries - all data structures are Pydantic models.
6
+
7
+ Phase 2: Core Systems - WebSocket Bridge
8
+ """
9
+
10
+ from typing import List, Optional
11
+ from pydantic import Field, ConfigDict, field_validator
12
+
13
+ from ..base import UnrealOnBaseModel
14
+ from .base import WebSocketMessage, MessageType
15
+
16
+
17
+ class LogContext(UnrealOnBaseModel):
18
+ """Log context data - strictly typed for centralized logging."""
19
+
20
+ model_config = ConfigDict(
21
+ validate_assignment=True,
22
+ extra="forbid"
23
+ )
24
+
25
+ # Task context
26
+ task_id: Optional[str] = Field(
27
+ default=None,
28
+ max_length=100,
29
+ description="Associated task ID"
30
+ )
31
+
32
+ url: Optional[str] = Field(
33
+ default=None,
34
+ max_length=2000,
35
+ description="Associated URL"
36
+ )
37
+
38
+ # Performance metrics
39
+ duration_ms: Optional[float] = Field(
40
+ default=None,
41
+ ge=0.0,
42
+ description="Operation duration in milliseconds"
43
+ )
44
+
45
+ memory_usage_mb: Optional[float] = Field(
46
+ default=None,
47
+ ge=0.0,
48
+ description="Memory usage in MB"
49
+ )
50
+
51
+ cpu_usage_percent: Optional[float] = Field(
52
+ default=None,
53
+ ge=0.0,
54
+ le=100.0,
55
+ description="CPU usage percentage"
56
+ )
57
+
58
+ # Error context
59
+ error_code: Optional[str] = Field(
60
+ default=None,
61
+ max_length=50,
62
+ description="Error code if applicable"
63
+ )
64
+
65
+ stack_trace: Optional[str] = Field(
66
+ default=None,
67
+ max_length=5000,
68
+ description="Stack trace for errors"
69
+ )
70
+
71
+ # Network context
72
+ user_agent: Optional[str] = Field(
73
+ default=None,
74
+ max_length=500,
75
+ description="User agent used"
76
+ )
77
+
78
+ proxy_id: Optional[str] = Field(
79
+ default=None,
80
+ max_length=100,
81
+ description="Proxy ID used"
82
+ )
83
+
84
+ response_code: Optional[int] = Field(
85
+ default=None,
86
+ ge=100,
87
+ le=599,
88
+ description="HTTP response code"
89
+ )
90
+
91
+ # Driver context
92
+ driver_version: Optional[str] = Field(
93
+ default=None,
94
+ max_length=50,
95
+ description="Driver version"
96
+ )
97
+
98
+ session_id: Optional[str] = Field(
99
+ default=None,
100
+ max_length=100,
101
+ description="Driver session ID"
102
+ )
103
+
104
+
105
+ class LogEntryData(UnrealOnBaseModel):
106
+ """Log entry data payload - strictly typed for centralized logging."""
107
+
108
+ model_config = ConfigDict(
109
+ validate_assignment=True,
110
+ extra="forbid"
111
+ )
112
+
113
+ # Core log fields
114
+ level: str = Field(
115
+ pattern=r"^(DEBUG|INFO|WARNING|ERROR|CRITICAL)$",
116
+ description="Log level"
117
+ )
118
+
119
+ message: str = Field(
120
+ min_length=1,
121
+ max_length=2000,
122
+ description="Log message"
123
+ )
124
+
125
+ timestamp: str = Field(
126
+ description="Log timestamp in ISO format"
127
+ )
128
+
129
+ # Source identification
130
+ logger_name: str = Field(
131
+ default="driver",
132
+ min_length=1,
133
+ max_length=100,
134
+ description="Logger name"
135
+ )
136
+
137
+ module: Optional[str] = Field(
138
+ default=None,
139
+ max_length=200,
140
+ description="Module that generated the log"
141
+ )
142
+
143
+ function_name: Optional[str] = Field(
144
+ default=None,
145
+ max_length=100,
146
+ description="Function that generated the log"
147
+ )
148
+
149
+ line_number: Optional[int] = Field(
150
+ default=None,
151
+ ge=1,
152
+ description="Line number where log was generated"
153
+ )
154
+
155
+ # Driver identification
156
+ driver_id: str = Field(
157
+ min_length=1,
158
+ max_length=100,
159
+ description="Unique driver identifier"
160
+ )
161
+
162
+ driver_type: str = Field(
163
+ default="unrealon_driver",
164
+ max_length=50,
165
+ description="Type of driver"
166
+ )
167
+
168
+ # Environment
169
+ environment: str = Field(
170
+ default="production",
171
+ pattern=r"^(development|staging|production)$",
172
+ description="Environment where log was generated"
173
+ )
174
+
175
+ # Rich context
176
+ context: LogContext = Field(
177
+ default_factory=LogContext,
178
+ description="Additional log context"
179
+ )
180
+
181
+ @field_validator('timestamp')
182
+ @classmethod
183
+ def validate_timestamp(cls, v: str) -> str:
184
+ """Validate ISO timestamp format."""
185
+ from datetime import datetime
186
+ try:
187
+ datetime.fromisoformat(v.replace('Z', '+00:00'))
188
+ return v
189
+ except ValueError:
190
+ raise ValueError("timestamp must be valid ISO format")
191
+
192
+
193
+ class LogEntryMessage(WebSocketMessage):
194
+ """Log entry message (Driver → Server)."""
195
+
196
+ model_config = ConfigDict(
197
+ validate_assignment=True,
198
+ extra="forbid"
199
+ )
200
+
201
+ type: MessageType = Field(
202
+ default=MessageType.LOG_MESSAGE,
203
+ frozen=True
204
+ )
205
+
206
+ data: LogEntryData = Field(
207
+ description="Log entry data"
208
+ )
209
+
210
+
211
+ class LogBatchData(UnrealOnBaseModel):
212
+ """Log batch data payload - strictly typed."""
213
+
214
+ model_config = ConfigDict(
215
+ validate_assignment=True,
216
+ extra="forbid"
217
+ )
218
+
219
+ logs: List[LogEntryData] = Field(
220
+ min_length=1,
221
+ max_length=100,
222
+ description="Batch of log entries"
223
+ )
224
+
225
+ driver_id: str = Field(
226
+ min_length=1,
227
+ description="Driver ID for the batch"
228
+ )
229
+
230
+ batch_timestamp: str = Field(
231
+ description="Timestamp when batch was created (ISO format)"
232
+ )
233
+
234
+ @field_validator('batch_timestamp')
235
+ @classmethod
236
+ def validate_timestamp(cls, v: str) -> str:
237
+ """Validate ISO timestamp format."""
238
+ from datetime import datetime
239
+ try:
240
+ datetime.fromisoformat(v.replace('Z', '+00:00'))
241
+ return v
242
+ except ValueError:
243
+ raise ValueError("batch_timestamp must be valid ISO format")
244
+
245
+
246
+ class LogBatchMessage(WebSocketMessage):
247
+ """Log batch message (Driver → Server)."""
248
+
249
+ model_config = ConfigDict(
250
+ validate_assignment=True,
251
+ extra="forbid"
252
+ )
253
+
254
+ type: MessageType = Field(
255
+ default=MessageType.LOG_BATCH,
256
+ frozen=True
257
+ )
258
+
259
+ data: LogBatchData = Field(
260
+ description="Log batch data"
261
+ )