intuned-runtime 1.3.0rc0__py3-none-any.whl → 1.3.2__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.
- intuned_cli/__init__.py +15 -24
- intuned_cli/commands/__init__.py +6 -1
- intuned_cli/commands/attempt_api_command.py +8 -0
- intuned_cli/commands/attempt_authsession_check_command.py +8 -0
- intuned_cli/commands/attempt_authsession_command.py +4 -4
- intuned_cli/commands/attempt_authsession_create_command.py +9 -1
- intuned_cli/commands/attempt_command.py +4 -4
- intuned_cli/commands/authsession_command.py +12 -0
- intuned_cli/commands/authsession_record_command.py +54 -0
- intuned_cli/commands/command.py +6 -4
- intuned_cli/commands/deploy_command.py +2 -0
- intuned_cli/commands/init_command.py +2 -0
- intuned_cli/commands/run_api_command.py +9 -1
- intuned_cli/commands/run_authsession_command.py +4 -4
- intuned_cli/commands/run_authsession_create_command.py +34 -4
- intuned_cli/commands/run_authsession_update_command.py +33 -4
- intuned_cli/commands/run_authsession_validate_command.py +32 -3
- intuned_cli/commands/run_command.py +4 -4
- intuned_cli/commands/save_command.py +2 -0
- intuned_cli/controller/__test__/test_api.py +159 -18
- intuned_cli/controller/__test__/test_authsession.py +497 -6
- intuned_cli/controller/api.py +40 -39
- intuned_cli/controller/authsession.py +213 -110
- intuned_cli/controller/deploy.py +3 -3
- intuned_cli/controller/save.py +47 -48
- intuned_cli/types.py +14 -0
- intuned_cli/utils/__test__/test_browser.py +132 -0
- intuned_cli/utils/__test__/test_traces.py +27 -0
- intuned_cli/utils/api_helpers.py +54 -5
- intuned_cli/utils/auth_session_helpers.py +42 -7
- intuned_cli/utils/backend.py +4 -1
- intuned_cli/utils/browser.py +63 -0
- intuned_cli/utils/error.py +14 -0
- intuned_cli/utils/exclusions.py +1 -0
- intuned_cli/utils/help.py +9 -0
- intuned_cli/utils/traces.py +31 -0
- intuned_cli/utils/wrapper.py +58 -0
- intuned_internal_cli/__init__.py +7 -0
- {intuned_runtime-1.3.0rc0.dist-info → intuned_runtime-1.3.2.dist-info}/METADATA +4 -2
- {intuned_runtime-1.3.0rc0.dist-info → intuned_runtime-1.3.2.dist-info}/RECORD +45 -37
- runtime/browser/launch_chromium.py +19 -8
- runtime/types/settings_types.py +13 -4
- {intuned_runtime-1.3.0rc0.dist-info → intuned_runtime-1.3.2.dist-info}/WHEEL +0 -0
- {intuned_runtime-1.3.0rc0.dist-info → intuned_runtime-1.3.2.dist-info}/entry_points.txt +0 -0
- {intuned_runtime-1.3.0rc0.dist-info → intuned_runtime-1.3.2.dist-info}/licenses/LICENSE +0 -0
intuned_cli/controller/api.py
CHANGED
@@ -1,27 +1,29 @@
|
|
1
1
|
import json
|
2
|
-
import os
|
3
2
|
from typing import Any
|
3
|
+
from typing import Unpack
|
4
4
|
|
5
5
|
from anyio import Path
|
6
6
|
from pydantic import BaseModel
|
7
7
|
|
8
8
|
from intuned_cli.controller.authsession import execute_run_validate_auth_session_cli
|
9
9
|
from intuned_cli.controller.authsession import load_auth_session_instance
|
10
|
+
from intuned_cli.types import BaseExecuteCommandOptionsWithoutTrace
|
10
11
|
from intuned_cli.utils.api_helpers import assert_api_file_exists
|
12
|
+
from intuned_cli.utils.browser import get_cli_run_options
|
11
13
|
from intuned_cli.utils.console import console
|
12
14
|
from intuned_cli.utils.error import CLIError
|
13
15
|
from intuned_cli.utils.error import log_automation_error
|
14
16
|
from intuned_cli.utils.get_auth_parameters import register_get_auth_session_parameters
|
17
|
+
from intuned_cli.utils.import_function import get_cli_import_function
|
15
18
|
from intuned_cli.utils.timeout import extendable_timeout
|
19
|
+
from intuned_cli.utils.traces import cli_trace
|
16
20
|
from runtime.errors.run_api_errors import AutomationError
|
17
|
-
from runtime.run.run_api import import_function_from_api_dir
|
18
21
|
from runtime.run.run_api import run_api
|
19
22
|
from runtime.types.run_types import Auth
|
20
23
|
from runtime.types.run_types import AutomationFunction
|
21
24
|
from runtime.types.run_types import PayloadToAppend
|
22
25
|
from runtime.types.run_types import ProxyConfig
|
23
26
|
from runtime.types.run_types import RunApiParameters
|
24
|
-
from runtime.types.run_types import StandaloneRunOptions
|
25
27
|
from runtime.types.run_types import StateSession
|
26
28
|
from runtime.types.run_types import StorageState
|
27
29
|
|
@@ -40,9 +42,8 @@ async def execute_run_api_cli(
|
|
40
42
|
retries: int,
|
41
43
|
auth_session: AuthSessionInput | None = None,
|
42
44
|
output_file: str | None = None,
|
43
|
-
|
44
|
-
|
45
|
-
proxy: str | None = None,
|
45
|
+
trace: bool,
|
46
|
+
**kwargs: Unpack[BaseExecuteCommandOptionsWithoutTrace],
|
46
47
|
):
|
47
48
|
"""
|
48
49
|
Execute API with retries and optional auth session validation.
|
@@ -63,9 +64,8 @@ async def execute_run_api_cli(
|
|
63
64
|
auto_recreate=auth_session.auto_recreate,
|
64
65
|
check_retries=auth_session.check_retries,
|
65
66
|
create_retries=auth_session.create_retries,
|
66
|
-
|
67
|
-
|
68
|
-
proxy=proxy,
|
67
|
+
trace=trace,
|
68
|
+
**kwargs,
|
69
69
|
)
|
70
70
|
|
71
71
|
try:
|
@@ -73,9 +73,8 @@ async def execute_run_api_cli(
|
|
73
73
|
api_name=api_name,
|
74
74
|
parameters=input_data,
|
75
75
|
auth=auth_session_instance,
|
76
|
-
|
77
|
-
|
78
|
-
proxy=proxy,
|
76
|
+
trace_id=f"{api_name}-attempt-{i + 1}" if trace else None,
|
77
|
+
**kwargs,
|
79
78
|
)
|
80
79
|
|
81
80
|
return await handle_api_result(
|
@@ -101,9 +100,8 @@ async def execute_attempt_api_cli(
|
|
101
100
|
input_data: Any | None,
|
102
101
|
auth_session_id: str | None = None,
|
103
102
|
output_file: str | None = None,
|
104
|
-
|
105
|
-
|
106
|
-
proxy: str | None = None,
|
103
|
+
trace: bool,
|
104
|
+
**kwargs: Unpack[BaseExecuteCommandOptionsWithoutTrace],
|
107
105
|
):
|
108
106
|
"""
|
109
107
|
Execute a single API attempt with optional auth session.
|
@@ -122,9 +120,8 @@ async def execute_attempt_api_cli(
|
|
122
120
|
api_name=api_name,
|
123
121
|
parameters=input_data,
|
124
122
|
auth=auth_session_instance,
|
125
|
-
|
126
|
-
|
127
|
-
proxy=proxy,
|
123
|
+
trace_id=f"{api_name}-attempt" if trace else None,
|
124
|
+
**kwargs,
|
128
125
|
)
|
129
126
|
|
130
127
|
return await handle_api_result(
|
@@ -186,26 +183,30 @@ async def attempt_api(
|
|
186
183
|
api_name: str,
|
187
184
|
parameters: Any | None,
|
188
185
|
auth: StorageState | None = None,
|
189
|
-
|
190
|
-
|
191
|
-
proxy: str | None = None,
|
186
|
+
trace_id: str | None = None,
|
187
|
+
**kwargs: Unpack[BaseExecuteCommandOptionsWithoutTrace],
|
192
188
|
):
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
189
|
+
timeout = kwargs.get("timeout")
|
190
|
+
headless = kwargs.get("headless")
|
191
|
+
proxy = kwargs.get("proxy")
|
192
|
+
keep_browser_open = kwargs.get("keep_browser_open")
|
193
|
+
with cli_trace(trace_id) as tracing:
|
194
|
+
async with extendable_timeout(timeout):
|
195
|
+
result = await run_api(
|
196
|
+
RunApiParameters(
|
197
|
+
automation_function=AutomationFunction(name=f"api/{api_name}", params=parameters),
|
198
|
+
auth=Auth(
|
199
|
+
session=StateSession(state=auth),
|
200
|
+
)
|
201
|
+
if auth
|
202
|
+
else None,
|
203
|
+
run_options=await get_cli_run_options(
|
204
|
+
headless=headless,
|
205
|
+
proxy=ProxyConfig.parse_from_str(proxy) if proxy else None,
|
206
|
+
keep_browser_open=keep_browser_open,
|
207
|
+
),
|
208
|
+
tracing=tracing,
|
205
209
|
),
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
),
|
210
|
-
)
|
211
|
-
return result.result, result.payload_to_append
|
210
|
+
import_function=await get_cli_import_function(),
|
211
|
+
)
|
212
|
+
return result.result, result.payload_to_append
|
@@ -1,31 +1,41 @@
|
|
1
|
+
import asyncio
|
1
2
|
import datetime
|
2
3
|
import json
|
3
4
|
import time
|
4
5
|
from typing import Any
|
5
6
|
from typing import Literal
|
7
|
+
from typing import TYPE_CHECKING
|
8
|
+
from typing import Unpack
|
6
9
|
|
7
10
|
from anyio import Path
|
8
11
|
from pydantic import BaseModel
|
9
12
|
from pydantic import Field
|
10
13
|
from pydantic import ValidationError
|
11
14
|
|
15
|
+
from intuned_cli.types import BaseExecuteCommandOptions
|
16
|
+
from intuned_cli.types import BaseExecuteCommandOptionsWithoutTrace
|
12
17
|
from intuned_cli.utils.api_helpers import assert_api_file_exists
|
18
|
+
from intuned_cli.utils.browser import get_cli_run_options
|
13
19
|
from intuned_cli.utils.console import console
|
14
20
|
from intuned_cli.utils.error import CLIError
|
15
21
|
from intuned_cli.utils.error import log_automation_error
|
16
22
|
from intuned_cli.utils.get_auth_parameters import register_get_auth_session_parameters
|
17
23
|
from intuned_cli.utils.import_function import get_cli_import_function
|
18
24
|
from intuned_cli.utils.timeout import extendable_timeout
|
25
|
+
from intuned_cli.utils.traces import cli_trace
|
26
|
+
from runtime.browser.storage_state import get_storage_state
|
19
27
|
from runtime.errors.run_api_errors import AutomationError
|
20
28
|
from runtime.run.run_api import run_api
|
21
29
|
from runtime.types.run_types import Auth
|
22
30
|
from runtime.types.run_types import AutomationFunction
|
23
31
|
from runtime.types.run_types import ProxyConfig
|
24
32
|
from runtime.types.run_types import RunApiParameters
|
25
|
-
from runtime.types.run_types import StandaloneRunOptions
|
26
33
|
from runtime.types.run_types import StateSession
|
27
34
|
from runtime.types.run_types import StorageState
|
28
35
|
|
36
|
+
if TYPE_CHECKING:
|
37
|
+
from playwright.async_api import ProxySettings
|
38
|
+
|
29
39
|
auth_session_instances_dirname = "auth-session-instances"
|
30
40
|
|
31
41
|
|
@@ -45,9 +55,7 @@ async def execute_run_validate_auth_session_cli(
|
|
45
55
|
auto_recreate: bool,
|
46
56
|
check_retries: int,
|
47
57
|
create_retries: int,
|
48
|
-
|
49
|
-
timeout: float,
|
50
|
-
proxy: str | None = None,
|
58
|
+
**kwargs: Unpack[BaseExecuteCommandOptions],
|
51
59
|
) -> StorageState:
|
52
60
|
"""
|
53
61
|
Validate auth session with optional auto-recreation.
|
@@ -64,13 +72,13 @@ async def execute_run_validate_auth_session_cli(
|
|
64
72
|
check_result = await run_check_with_retries(
|
65
73
|
auth=instance,
|
66
74
|
retries=check_retries,
|
67
|
-
|
68
|
-
timeout=timeout,
|
69
|
-
proxy=proxy,
|
75
|
+
**kwargs,
|
70
76
|
)
|
71
77
|
|
72
78
|
if not check_result:
|
73
79
|
if not auto_recreate:
|
80
|
+
if metadata and metadata.auth_session_type == "MANUAL":
|
81
|
+
raise CLIError("Auth session validation failed")
|
74
82
|
raise CLIError("Auto recreate is disabled, please provide a new auth session or update it manually")
|
75
83
|
|
76
84
|
if metadata and metadata.auth_session_type == "MANUAL":
|
@@ -86,19 +94,15 @@ async def execute_run_validate_auth_session_cli(
|
|
86
94
|
auth_session_id=id,
|
87
95
|
auth_session_input=auth_session_input,
|
88
96
|
retries=create_retries,
|
89
|
-
headless=headless,
|
90
|
-
timeout=timeout,
|
91
|
-
proxy=proxy,
|
92
97
|
metadata=metadata,
|
98
|
+
**kwargs,
|
93
99
|
)
|
94
100
|
|
95
101
|
# Rerun check after refresh
|
96
102
|
check_result = await run_check_with_retries(
|
97
103
|
auth=instance,
|
98
104
|
retries=check_retries,
|
99
|
-
|
100
|
-
timeout=timeout,
|
101
|
-
proxy=proxy,
|
105
|
+
**kwargs,
|
102
106
|
)
|
103
107
|
if not check_result:
|
104
108
|
raise CLIError("Failed to re-create auth session")
|
@@ -114,16 +118,14 @@ async def execute_run_create_auth_session_cli(
|
|
114
118
|
check_retries: int,
|
115
119
|
create_retries: int,
|
116
120
|
log: bool = True,
|
117
|
-
headless: bool,
|
118
|
-
timeout: float,
|
119
|
-
proxy: str | None = None,
|
120
121
|
metadata: AuthSessionMetadata | None = None,
|
122
|
+
**kwargs: Unpack[BaseExecuteCommandOptions],
|
121
123
|
):
|
122
124
|
"""
|
123
125
|
Create a new auth session.
|
124
126
|
"""
|
125
127
|
if id is None:
|
126
|
-
id =
|
128
|
+
id = generate_auth_session_id()
|
127
129
|
|
128
130
|
if log:
|
129
131
|
console.print(f"[bold]Creating auth session with id [cyan]{id}[/cyan][/bold]")
|
@@ -135,18 +137,14 @@ async def execute_run_create_auth_session_cli(
|
|
135
137
|
auth_session_id=id,
|
136
138
|
auth_session_input=input_data,
|
137
139
|
retries=create_retries,
|
138
|
-
headless=headless,
|
139
|
-
timeout=timeout,
|
140
|
-
proxy=proxy,
|
141
140
|
metadata=metadata,
|
141
|
+
**kwargs,
|
142
142
|
)
|
143
143
|
|
144
144
|
check_result = await run_check_with_retries(
|
145
145
|
auth=instance,
|
146
146
|
retries=check_retries,
|
147
|
-
|
148
|
-
timeout=timeout,
|
149
|
-
proxy=proxy,
|
147
|
+
**kwargs,
|
150
148
|
)
|
151
149
|
if not check_result:
|
152
150
|
raise CLIError("Failed to create auth session")
|
@@ -161,9 +159,7 @@ async def execute_run_update_auth_session_cli(
|
|
161
159
|
input_data: Any | None = None,
|
162
160
|
check_retries: int,
|
163
161
|
create_retries: int,
|
164
|
-
|
165
|
-
timeout: float,
|
166
|
-
proxy: str | None = None,
|
162
|
+
**kwargs: Unpack[BaseExecuteCommandOptions],
|
167
163
|
):
|
168
164
|
"""
|
169
165
|
Update an existing auth session.
|
@@ -186,10 +182,8 @@ async def execute_run_update_auth_session_cli(
|
|
186
182
|
check_retries=check_retries,
|
187
183
|
create_retries=create_retries,
|
188
184
|
log=False,
|
189
|
-
headless=headless,
|
190
|
-
timeout=timeout,
|
191
|
-
proxy=proxy,
|
192
185
|
metadata=metadata,
|
186
|
+
**kwargs,
|
193
187
|
)
|
194
188
|
|
195
189
|
console.print("[bold][green]Auth session updated successfully[/green][/bold]")
|
@@ -199,35 +193,25 @@ async def execute_attempt_create_auth_session_cli(
|
|
199
193
|
*,
|
200
194
|
id: str | None = None,
|
201
195
|
input_data: Any,
|
202
|
-
|
203
|
-
timeout: float,
|
204
|
-
proxy: str | None = None,
|
196
|
+
**kwargs: Unpack[BaseExecuteCommandOptions],
|
205
197
|
):
|
206
198
|
"""
|
207
199
|
Execute a single attempt to create auth session.
|
208
200
|
"""
|
209
201
|
if id is None:
|
210
|
-
id =
|
202
|
+
id = generate_auth_session_id(is_attempt=True)
|
211
203
|
|
212
204
|
console.print(f"[bold]Executing create auth session attempt with id [cyan]{id}[/cyan][/bold]")
|
213
205
|
await assert_api_file_exists("auth-sessions", "create")
|
214
206
|
await run_create_with_retries(
|
215
207
|
auth_session_id=id,
|
216
208
|
auth_session_input=input_data,
|
217
|
-
retries=
|
218
|
-
|
219
|
-
timeout=timeout,
|
220
|
-
proxy=proxy,
|
209
|
+
retries=None,
|
210
|
+
**kwargs,
|
221
211
|
)
|
222
212
|
|
223
213
|
|
224
|
-
async def execute_attempt_check_auth_session_cli(
|
225
|
-
*,
|
226
|
-
id: str,
|
227
|
-
headless: bool,
|
228
|
-
timeout: float,
|
229
|
-
proxy: str | None = None,
|
230
|
-
):
|
214
|
+
async def execute_attempt_check_auth_session_cli(*, id: str, **kwargs: Unpack[BaseExecuteCommandOptions]):
|
231
215
|
"""
|
232
216
|
Execute a single attempt to check auth session.
|
233
217
|
"""
|
@@ -240,10 +224,8 @@ async def execute_attempt_check_auth_session_cli(
|
|
240
224
|
|
241
225
|
check_result = await run_check_with_retries(
|
242
226
|
auth=instance,
|
243
|
-
retries=
|
244
|
-
|
245
|
-
timeout=timeout,
|
246
|
-
proxy=proxy,
|
227
|
+
retries=None,
|
228
|
+
**kwargs,
|
247
229
|
)
|
248
230
|
|
249
231
|
if not check_result:
|
@@ -253,90 +235,105 @@ async def execute_attempt_check_auth_session_cli(
|
|
253
235
|
|
254
236
|
|
255
237
|
async def run_check(
|
256
|
-
*,
|
257
|
-
auth: StorageState,
|
258
|
-
headless: bool,
|
259
|
-
timeout: float,
|
260
|
-
proxy: str | None = None,
|
238
|
+
*, auth: StorageState, trace_id: str | None = None, **kwargs: Unpack[BaseExecuteCommandOptionsWithoutTrace]
|
261
239
|
) -> bool:
|
262
240
|
"""
|
263
241
|
Run auth session check.
|
264
242
|
"""
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
243
|
+
timeout = kwargs.get("timeout")
|
244
|
+
headless = kwargs.get("headless")
|
245
|
+
proxy = kwargs.get("proxy")
|
246
|
+
keep_browser_open = kwargs.get("keep_browser_open")
|
247
|
+
with cli_trace(trace_id) as tracing:
|
248
|
+
async with extendable_timeout(timeout):
|
249
|
+
result = await run_api(
|
250
|
+
RunApiParameters(
|
251
|
+
automation_function=AutomationFunction(
|
252
|
+
name="auth-sessions/check",
|
253
|
+
params=None,
|
254
|
+
),
|
255
|
+
run_options=await get_cli_run_options(
|
256
|
+
headless=headless,
|
257
|
+
proxy=ProxyConfig.parse_from_str(proxy) if proxy else None,
|
258
|
+
keep_browser_open=keep_browser_open,
|
278
259
|
),
|
260
|
+
auth=Auth(
|
261
|
+
session=StateSession(
|
262
|
+
state=auth,
|
263
|
+
),
|
264
|
+
),
|
265
|
+
tracing=tracing,
|
279
266
|
),
|
280
|
-
|
281
|
-
|
282
|
-
)
|
267
|
+
import_function=await get_cli_import_function(),
|
268
|
+
)
|
283
269
|
|
284
|
-
|
285
|
-
|
270
|
+
if not result.result:
|
271
|
+
return False
|
286
272
|
|
287
|
-
|
273
|
+
return bool(result.result)
|
288
274
|
|
289
275
|
|
290
276
|
async def run_create(
|
291
277
|
*,
|
292
278
|
auth_session_input: dict[str, Any],
|
293
|
-
|
294
|
-
|
295
|
-
proxy: str | None = None,
|
279
|
+
trace_id: str | None = None,
|
280
|
+
**kwargs: Unpack[BaseExecuteCommandOptionsWithoutTrace],
|
296
281
|
) -> StorageState:
|
297
282
|
"""
|
298
283
|
Run auth session create.
|
299
284
|
"""
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
285
|
+
|
286
|
+
timeout = kwargs.get("timeout")
|
287
|
+
headless = kwargs.get("headless")
|
288
|
+
proxy = kwargs.get("proxy")
|
289
|
+
keep_browser_open = kwargs.get("keep_browser_open")
|
290
|
+
with cli_trace(trace_id) as tracing:
|
291
|
+
async with extendable_timeout(timeout):
|
292
|
+
result = await run_api(
|
293
|
+
RunApiParameters(
|
294
|
+
automation_function=AutomationFunction(
|
295
|
+
name="auth-sessions/create",
|
296
|
+
params=auth_session_input,
|
297
|
+
),
|
298
|
+
run_options=await get_cli_run_options(
|
299
|
+
headless=headless,
|
300
|
+
proxy=ProxyConfig.parse_from_str(proxy) if proxy else None,
|
301
|
+
keep_browser_open=keep_browser_open,
|
302
|
+
),
|
303
|
+
retrieve_session=True,
|
304
|
+
tracing=tracing,
|
309
305
|
),
|
310
|
-
|
311
|
-
)
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
raise Exception("Auth session create did not return a session")
|
316
|
-
return result.session
|
306
|
+
import_function=await get_cli_import_function(),
|
307
|
+
)
|
308
|
+
if not result.session:
|
309
|
+
raise Exception("Auth session create did not return a session")
|
310
|
+
return result.session
|
317
311
|
|
318
312
|
|
319
313
|
async def run_check_with_retries(
|
320
314
|
*,
|
321
315
|
auth: StorageState,
|
322
|
-
retries: int,
|
323
|
-
|
324
|
-
|
325
|
-
proxy: str | None = None,
|
316
|
+
retries: int | None,
|
317
|
+
trace: bool,
|
318
|
+
**kwargs: Unpack[BaseExecuteCommandOptionsWithoutTrace],
|
326
319
|
) -> bool:
|
327
320
|
"""
|
328
321
|
Run auth session check with retries.
|
329
322
|
"""
|
330
|
-
for i in range(retries):
|
323
|
+
for i in range(retries or 1):
|
331
324
|
attempt_text = "" if i == 0 else f" [italic](Attempt {i + 1})[/italic]"
|
332
325
|
console.print(f"\n[bold]Running [cyan]auth session check[/cyan]{attempt_text}...[/bold]\n")
|
333
326
|
|
334
327
|
try:
|
328
|
+
trace_id: str | None = None
|
329
|
+
if trace:
|
330
|
+
trace_id = "authsession-check-attempt"
|
331
|
+
if retries is not None:
|
332
|
+
trace_id += f"-{i+1}"
|
335
333
|
check_result = await run_check(
|
336
334
|
auth=auth,
|
337
|
-
|
338
|
-
|
339
|
-
proxy=proxy,
|
335
|
+
trace_id=trace_id,
|
336
|
+
**kwargs,
|
340
337
|
)
|
341
338
|
|
342
339
|
if check_result:
|
@@ -354,27 +351,31 @@ async def run_create_with_retries(
|
|
354
351
|
*,
|
355
352
|
auth_session_id: str,
|
356
353
|
auth_session_input: dict[str, Any],
|
357
|
-
retries: int,
|
358
|
-
headless: bool,
|
359
|
-
timeout: float,
|
360
|
-
proxy: str | None = None,
|
354
|
+
retries: int | None,
|
361
355
|
metadata: AuthSessionMetadata | None = None,
|
356
|
+
trace: bool,
|
357
|
+
**kwargs: Unpack[BaseExecuteCommandOptionsWithoutTrace],
|
362
358
|
):
|
363
359
|
"""
|
364
360
|
Run auth session create with retries.
|
365
361
|
"""
|
366
362
|
new_auth_session_instance: StorageState | None = None
|
367
363
|
|
368
|
-
for i in range(retries):
|
364
|
+
for i in range(retries or 1):
|
369
365
|
attempt_text = "" if i == 0 else f" [italic](Attempt {i + 1})[/italic]"
|
370
366
|
console.print(f"\n[bold]Running [cyan]auth session create[/cyan]{attempt_text}...[/bold]\n")
|
371
367
|
|
372
368
|
try:
|
369
|
+
trace_id: str | None = None
|
370
|
+
if trace:
|
371
|
+
trace_id = "authsession-create-attempt"
|
372
|
+
if retries is not None:
|
373
|
+
trace_id += f"-{i+1}"
|
374
|
+
|
373
375
|
new_auth_session_instance = await run_create(
|
374
376
|
auth_session_input=auth_session_input,
|
375
|
-
|
376
|
-
|
377
|
-
proxy=proxy,
|
377
|
+
trace_id=trace_id,
|
378
|
+
**kwargs,
|
378
379
|
)
|
379
380
|
console.print("[bold][green]Auth session create succeeded[/green][/bold]")
|
380
381
|
break
|
@@ -424,7 +425,7 @@ async def load_auth_session_instance(auth_session_id: str) -> tuple[StorageState
|
|
424
425
|
async def store_auth_session_instance(
|
425
426
|
auth_session_instance: StorageState,
|
426
427
|
auth_session_id: str,
|
427
|
-
auth_session_input: dict[str, Any],
|
428
|
+
auth_session_input: dict[str, Any] | None = None,
|
428
429
|
metadata: AuthSessionMetadata | None = None,
|
429
430
|
):
|
430
431
|
"""
|
@@ -445,13 +446,115 @@ async def store_auth_session_instance(
|
|
445
446
|
updatedAt=datetime.datetime.now().isoformat(),
|
446
447
|
authSessionId=auth_session_id,
|
447
448
|
authSessionInput=auth_session_input,
|
448
|
-
authSessionType="API",
|
449
|
+
authSessionType=metadata.auth_session_type if metadata else "API",
|
449
450
|
)
|
450
451
|
metadata_file_path = auth_session_path / "metadata.json"
|
451
452
|
|
452
|
-
metadata_json = json.dumps(metadata.model_dump(by_alias=True), indent=2)
|
453
|
+
metadata_json = json.dumps(metadata.model_dump(by_alias=True, exclude_none=True), indent=2)
|
453
454
|
await metadata_file_path.write_text(metadata_json)
|
454
455
|
|
455
456
|
|
456
457
|
def get_auth_session_path(auth_session_id: str):
|
457
458
|
return Path(auth_session_instances_dirname) / auth_session_id
|
459
|
+
|
460
|
+
|
461
|
+
async def execute_record_auth_session_cli(
|
462
|
+
*,
|
463
|
+
start_url: str,
|
464
|
+
finish_url: str,
|
465
|
+
id: str | None = None,
|
466
|
+
check_retries: int = 1,
|
467
|
+
**kwargs: Unpack[BaseExecuteCommandOptions],
|
468
|
+
):
|
469
|
+
"""
|
470
|
+
Record a new auth session using a browser.
|
471
|
+
"""
|
472
|
+
|
473
|
+
from playwright.async_api import ProxySettings
|
474
|
+
|
475
|
+
if id is None:
|
476
|
+
id = generate_auth_session_id()
|
477
|
+
|
478
|
+
console.print(f"[bold]Recording auth session with id [cyan]{id}[/cyan][/bold]")
|
479
|
+
proxy = kwargs.get("proxy")
|
480
|
+
|
481
|
+
proxy_settings: ProxySettings | None = None
|
482
|
+
if proxy:
|
483
|
+
proxy_settings = ProxySettings(server=proxy)
|
484
|
+
|
485
|
+
try:
|
486
|
+
auth_session = await record_auth_session(
|
487
|
+
start_url=start_url,
|
488
|
+
finish_url=finish_url,
|
489
|
+
timeout=kwargs.get("timeout"),
|
490
|
+
proxy=proxy_settings,
|
491
|
+
)
|
492
|
+
except CLIError as e:
|
493
|
+
raise CLIError(f"Failed to record auth session: {e}") from e
|
494
|
+
|
495
|
+
await store_auth_session_instance(
|
496
|
+
auth_session_instance=auth_session,
|
497
|
+
auth_session_id=id,
|
498
|
+
metadata=AuthSessionMetadata(
|
499
|
+
createdAt=datetime.datetime.now().isoformat(),
|
500
|
+
updatedAt=datetime.datetime.now().isoformat(),
|
501
|
+
authSessionId=id,
|
502
|
+
authSessionInput=None,
|
503
|
+
authSessionType="MANUAL",
|
504
|
+
recorderStartUrl=start_url,
|
505
|
+
recorderEndUrl=finish_url,
|
506
|
+
),
|
507
|
+
)
|
508
|
+
|
509
|
+
await execute_run_validate_auth_session_cli(
|
510
|
+
id=id,
|
511
|
+
create_retries=1,
|
512
|
+
check_retries=check_retries,
|
513
|
+
auto_recreate=False,
|
514
|
+
**kwargs,
|
515
|
+
)
|
516
|
+
|
517
|
+
console.print(f"[bold][green]Auth session [cyan]{id}[/cyan] recorded successfully[/green][/bold]")
|
518
|
+
|
519
|
+
|
520
|
+
async def record_auth_session(
|
521
|
+
*,
|
522
|
+
start_url: str,
|
523
|
+
finish_url: str,
|
524
|
+
timeout: float = 300,
|
525
|
+
proxy: "ProxySettings | None" = None,
|
526
|
+
):
|
527
|
+
from runtime.browser import launch_chromium
|
528
|
+
|
529
|
+
async with launch_chromium(
|
530
|
+
proxy=proxy,
|
531
|
+
headless=False,
|
532
|
+
app_mode_initial_url=start_url,
|
533
|
+
) as (context, page):
|
534
|
+
if not page.url.startswith(start_url):
|
535
|
+
await page.goto(start_url)
|
536
|
+
console.print(f"[bold]Navigated to[/bold] [underline]{start_url}[/underline]")
|
537
|
+
console.print(f"[bold]Waiting for[/bold] [underline]{finish_url}[/underline]...")
|
538
|
+
|
539
|
+
try:
|
540
|
+
async with asyncio.timeout(timeout):
|
541
|
+
while True:
|
542
|
+
if len(context.pages) == 0:
|
543
|
+
raise CLIError("Browser was closed before reaching the finish URL")
|
544
|
+
if context.pages[0].url.startswith(finish_url):
|
545
|
+
break
|
546
|
+
await asyncio.sleep(1)
|
547
|
+
|
548
|
+
console.print("[bold]Finish URL reached, capturing auth session...[/bold]")
|
549
|
+
await page.wait_for_load_state("load")
|
550
|
+
auth_session = await get_storage_state(context)
|
551
|
+
return auth_session
|
552
|
+
except asyncio.TimeoutError as e:
|
553
|
+
raise CLIError("Timeout waiting for finish URL") from e
|
554
|
+
|
555
|
+
|
556
|
+
def generate_auth_session_id(is_attempt: bool = False) -> str:
|
557
|
+
timestamp = int(time.time() * 1000)
|
558
|
+
if is_attempt:
|
559
|
+
return f"auth-session-attempt-{timestamp}"
|
560
|
+
return f"auth-session-{timestamp}"
|