intuned-runtime 1.0.0__py3-none-any.whl → 1.1.0__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 +40 -0
- intuned_cli/commands/__init__.py +18 -0
- intuned_cli/commands/attempt_api_command.py +51 -0
- intuned_cli/commands/attempt_authsession_check_command.py +38 -0
- intuned_cli/commands/attempt_authsession_command.py +12 -0
- intuned_cli/commands/attempt_authsession_create_command.py +44 -0
- intuned_cli/commands/attempt_command.py +12 -0
- intuned_cli/commands/command.py +26 -0
- intuned_cli/commands/deploy_command.py +47 -0
- intuned_cli/commands/init_command.py +21 -0
- intuned_cli/commands/run_api_command.py +69 -0
- intuned_cli/commands/run_authsession_command.py +12 -0
- intuned_cli/commands/run_authsession_create_command.py +50 -0
- intuned_cli/commands/run_authsession_update_command.py +52 -0
- intuned_cli/commands/run_authsession_validate_command.py +49 -0
- intuned_cli/commands/run_command.py +12 -0
- intuned_cli/constants/__init__.py +1 -0
- intuned_cli/constants/readme.py +134 -0
- intuned_cli/controller/__test__/__init__.py +0 -0
- intuned_cli/controller/__test__/test_api.py +529 -0
- intuned_cli/controller/__test__/test_authsession.py +907 -0
- intuned_cli/controller/api.py +212 -0
- intuned_cli/controller/authsession.py +458 -0
- intuned_cli/controller/deploy.py +352 -0
- intuned_cli/controller/init.py +97 -0
- intuned_cli/types.py +33 -0
- intuned_cli/utils/api_helpers.py +32 -0
- intuned_cli/utils/auth_session_helpers.py +57 -0
- intuned_cli/utils/backend.py +5 -0
- intuned_cli/utils/confirmation.py +0 -0
- intuned_cli/utils/console.py +6 -0
- intuned_cli/utils/error.py +27 -0
- intuned_cli/utils/exclusions.py +40 -0
- intuned_cli/utils/get_auth_parameters.py +18 -0
- intuned_cli/utils/import_function.py +15 -0
- intuned_cli/utils/timeout.py +25 -0
- {cli → intuned_internal_cli}/__init__.py +1 -1
- {cli → intuned_internal_cli}/commands/__init__.py +2 -0
- {cli → intuned_internal_cli}/commands/ai_source/deploy.py +1 -1
- {cli → intuned_internal_cli}/commands/project/type_check.py +39 -32
- intuned_internal_cli/commands/root.py +15 -0
- {intuned_runtime-1.0.0.dist-info → intuned_runtime-1.1.0.dist-info}/METADATA +3 -1
- intuned_runtime-1.1.0.dist-info/RECORD +96 -0
- intuned_runtime-1.1.0.dist-info/entry_points.txt +4 -0
- runtime/__init__.py +2 -1
- runtime/backend_functions/_call_backend_function.py +0 -5
- runtime/browser/__init__.py +2 -1
- runtime/browser/launch_chromium.py +68 -49
- runtime/browser/storage_state.py +11 -12
- runtime/errors/run_api_errors.py +14 -10
- runtime/run/playwright_constructs.py +4 -2
- runtime/run/pydantic_encoder.py +15 -0
- runtime/run/run_api.py +5 -4
- runtime/types/run_types.py +16 -0
- intuned_runtime-1.0.0.dist-info/RECORD +0 -58
- intuned_runtime-1.0.0.dist-info/entry_points.txt +0 -3
- {cli → intuned_internal_cli}/commands/ai_source/__init__.py +0 -0
- {cli → intuned_internal_cli}/commands/ai_source/ai_source.py +0 -0
- {cli → intuned_internal_cli}/commands/browser/__init__.py +0 -0
- {cli → intuned_internal_cli}/commands/browser/save_state.py +0 -0
- {cli → intuned_internal_cli}/commands/init.py +0 -0
- {cli → intuned_internal_cli}/commands/project/__init__.py +0 -0
- {cli → intuned_internal_cli}/commands/project/auth_session/__init__.py +0 -0
- {cli → intuned_internal_cli}/commands/project/auth_session/check.py +0 -0
- {cli → intuned_internal_cli}/commands/project/auth_session/create.py +0 -0
- {cli → intuned_internal_cli}/commands/project/auth_session/load.py +0 -0
- {cli → intuned_internal_cli}/commands/project/project.py +0 -0
- {cli → intuned_internal_cli}/commands/project/run.py +0 -0
- {cli → intuned_internal_cli}/commands/project/run_interface.py +0 -0
- {cli → intuned_internal_cli}/commands/project/upgrade.py +0 -0
- {cli → intuned_internal_cli}/commands/publish_packages.py +0 -0
- {cli → intuned_internal_cli}/logger.py +0 -0
- {cli → intuned_internal_cli}/utils/ai_source_project.py +0 -0
- {cli → intuned_internal_cli}/utils/code_tree.py +0 -0
- {cli → intuned_internal_cli}/utils/run_apis.py +0 -0
- {cli → intuned_internal_cli}/utils/unix_socket.py +0 -0
- {intuned_runtime-1.0.0.dist-info → intuned_runtime-1.1.0.dist-info}/LICENSE +0 -0
- {intuned_runtime-1.0.0.dist-info → intuned_runtime-1.1.0.dist-info}/WHEEL +0 -0
@@ -0,0 +1,212 @@
|
|
1
|
+
import json
|
2
|
+
import os
|
3
|
+
from typing import Any
|
4
|
+
|
5
|
+
from anyio import Path
|
6
|
+
from pydantic import BaseModel
|
7
|
+
|
8
|
+
from intuned_cli.controller.authsession import execute_run_validate_auth_session_cli
|
9
|
+
from intuned_cli.controller.authsession import load_auth_session_instance
|
10
|
+
from intuned_cli.utils.api_helpers import assert_api_file_exists
|
11
|
+
from intuned_cli.utils.console import console
|
12
|
+
from intuned_cli.utils.error import CLIError
|
13
|
+
from intuned_cli.utils.error import log_automation_error
|
14
|
+
from intuned_cli.utils.get_auth_parameters import register_get_auth_session_parameters
|
15
|
+
from intuned_cli.utils.timeout import extendable_timeout
|
16
|
+
from runtime.errors.run_api_errors import AutomationError
|
17
|
+
from runtime.run.run_api import import_function_from_api_dir
|
18
|
+
from runtime.run.run_api import run_api
|
19
|
+
from runtime.types.run_types import Auth
|
20
|
+
from runtime.types.run_types import AutomationFunction
|
21
|
+
from runtime.types.run_types import PayloadToAppend
|
22
|
+
from runtime.types.run_types import ProxyConfig
|
23
|
+
from runtime.types.run_types import RunApiParameters
|
24
|
+
from runtime.types.run_types import StandaloneRunOptions
|
25
|
+
from runtime.types.run_types import StateSession
|
26
|
+
from runtime.types.run_types import StorageState
|
27
|
+
|
28
|
+
|
29
|
+
class AuthSessionInput(BaseModel):
|
30
|
+
id: str
|
31
|
+
auto_recreate: bool
|
32
|
+
check_retries: int
|
33
|
+
create_retries: int
|
34
|
+
|
35
|
+
|
36
|
+
async def execute_run_api_cli(
|
37
|
+
*,
|
38
|
+
api_name: str,
|
39
|
+
input_data: Any | None,
|
40
|
+
retries: int,
|
41
|
+
auth_session: AuthSessionInput | None = None,
|
42
|
+
output_file: str | None = None,
|
43
|
+
headless: bool,
|
44
|
+
timeout: float,
|
45
|
+
proxy: str | None = None,
|
46
|
+
):
|
47
|
+
"""
|
48
|
+
Execute API with retries and optional auth session validation.
|
49
|
+
"""
|
50
|
+
await assert_api_file_exists("api", api_name)
|
51
|
+
|
52
|
+
register_get_auth_session_parameters(auth_session.id if auth_session else None)
|
53
|
+
|
54
|
+
console.print(f"[bold]Running API [cyan]{api_name}[/cyan][/bold]")
|
55
|
+
|
56
|
+
for i in range(retries):
|
57
|
+
console.print(f"\n[bold]Executing [cyan]{api_name}[/cyan] [italic](Attempt {i + 1})[/italic]...\n")
|
58
|
+
|
59
|
+
auth_session_instance: StorageState | None = None
|
60
|
+
if auth_session:
|
61
|
+
auth_session_instance = await execute_run_validate_auth_session_cli(
|
62
|
+
id=auth_session.id,
|
63
|
+
auto_recreate=auth_session.auto_recreate,
|
64
|
+
check_retries=auth_session.check_retries,
|
65
|
+
create_retries=auth_session.create_retries,
|
66
|
+
headless=headless,
|
67
|
+
timeout=timeout,
|
68
|
+
proxy=proxy,
|
69
|
+
)
|
70
|
+
|
71
|
+
try:
|
72
|
+
result, extended_payloads = await attempt_api(
|
73
|
+
api_name=api_name,
|
74
|
+
parameters=input_data,
|
75
|
+
auth=auth_session_instance,
|
76
|
+
headless=headless,
|
77
|
+
timeout=timeout,
|
78
|
+
proxy=proxy,
|
79
|
+
)
|
80
|
+
|
81
|
+
return await handle_api_result(
|
82
|
+
result=result,
|
83
|
+
extended_payloads=extended_payloads,
|
84
|
+
file_path=Path(output_file) if output_file else None,
|
85
|
+
)
|
86
|
+
|
87
|
+
except AutomationError as error:
|
88
|
+
log_automation_error(error)
|
89
|
+
console.print(f"[bold red]Attempt {i + 1} failed[/bold red]")
|
90
|
+
continue
|
91
|
+
|
92
|
+
raise CLIError(
|
93
|
+
f"[red][bold]Failed to run API [/bold][bold]{api_name}[/bold]: [bright_red]Exceeded maximum retries of [bold]{retries}[/bold][/bright_red][/red]",
|
94
|
+
auto_color=False,
|
95
|
+
)
|
96
|
+
|
97
|
+
|
98
|
+
async def execute_attempt_api_cli(
|
99
|
+
*,
|
100
|
+
api_name: str,
|
101
|
+
input_data: Any | None,
|
102
|
+
auth_session_id: str | None = None,
|
103
|
+
output_file: str | None = None,
|
104
|
+
headless: bool,
|
105
|
+
timeout: float,
|
106
|
+
proxy: str | None = None,
|
107
|
+
):
|
108
|
+
"""
|
109
|
+
Execute a single API attempt with optional auth session.
|
110
|
+
"""
|
111
|
+
console.print(f"[bold]Execute API attempt for [cyan]{api_name}[/cyan][/bold]")
|
112
|
+
|
113
|
+
await assert_api_file_exists("api", api_name)
|
114
|
+
|
115
|
+
register_get_auth_session_parameters(auth_session_id)
|
116
|
+
|
117
|
+
auth_session_instance: StorageState | None = None
|
118
|
+
if auth_session_id:
|
119
|
+
auth_session_instance, _ = await load_auth_session_instance(auth_session_id)
|
120
|
+
|
121
|
+
result, extended_payloads = await attempt_api(
|
122
|
+
api_name=api_name,
|
123
|
+
parameters=input_data,
|
124
|
+
auth=auth_session_instance,
|
125
|
+
headless=headless,
|
126
|
+
timeout=timeout,
|
127
|
+
proxy=proxy,
|
128
|
+
)
|
129
|
+
|
130
|
+
return await handle_api_result(
|
131
|
+
result=result,
|
132
|
+
extended_payloads=extended_payloads,
|
133
|
+
file_path=Path(output_file) if output_file else None,
|
134
|
+
)
|
135
|
+
|
136
|
+
|
137
|
+
async def handle_api_result(
|
138
|
+
*,
|
139
|
+
result: Any,
|
140
|
+
extended_payloads: list[PayloadToAppend] | None = None,
|
141
|
+
file_path: Path | None = None,
|
142
|
+
):
|
143
|
+
console.print("[bold][green]API executed successfully[/green][/bold]")
|
144
|
+
|
145
|
+
if not file_path:
|
146
|
+
if result is None:
|
147
|
+
console.print("[bold][yellow]No result returned from the API[/yellow][/bold]")
|
148
|
+
else:
|
149
|
+
console.print("[bold][green]Result:[/green][/bold]")
|
150
|
+
console.print(f"{json.dumps(result, indent=2)}")
|
151
|
+
|
152
|
+
if extended_payloads and len(extended_payloads) > 0:
|
153
|
+
console.print(
|
154
|
+
"[bold green]Extended payloads:[/bold green] [italic][bright_green](This will only take effect if this API run was part of a job.)[/bright_green][/italic]"
|
155
|
+
)
|
156
|
+
console.print(f"{json.dumps([p.model_dump(by_alias=True) for p in extended_payloads], indent=2)}")
|
157
|
+
|
158
|
+
return
|
159
|
+
|
160
|
+
await write_results_to_file(
|
161
|
+
file_path=file_path,
|
162
|
+
result=result,
|
163
|
+
extended_payloads=extended_payloads,
|
164
|
+
)
|
165
|
+
|
166
|
+
|
167
|
+
async def write_results_to_file(
|
168
|
+
*,
|
169
|
+
file_path: Path,
|
170
|
+
result: Any,
|
171
|
+
extended_payloads: list[PayloadToAppend] | None = None,
|
172
|
+
):
|
173
|
+
output_json = {"result": result}
|
174
|
+
if extended_payloads:
|
175
|
+
output_json["extendedPayloads"] = [m.model_dump(by_alias=True) for m in extended_payloads]
|
176
|
+
|
177
|
+
try:
|
178
|
+
await file_path.write_text(json.dumps(output_json, indent=2), encoding="utf-8")
|
179
|
+
console.print(f"[bold green]Results written to[/bold green] [underline]{file_path}[/underline]")
|
180
|
+
except Exception as e:
|
181
|
+
raise CLIError(f"Failed to write results to file '{file_path}': {e}") from e
|
182
|
+
|
183
|
+
|
184
|
+
async def attempt_api(
|
185
|
+
*,
|
186
|
+
api_name: str,
|
187
|
+
parameters: Any | None,
|
188
|
+
auth: StorageState | None = None,
|
189
|
+
headless: bool,
|
190
|
+
timeout: float,
|
191
|
+
proxy: str | None = None,
|
192
|
+
):
|
193
|
+
cwd = await Path().resolve()
|
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
|
+
run_check=False,
|
201
|
+
)
|
202
|
+
if auth
|
203
|
+
else None,
|
204
|
+
run_options=StandaloneRunOptions(
|
205
|
+
headless=headless, proxy=ProxyConfig.parse_from_str(proxy) if proxy else None
|
206
|
+
),
|
207
|
+
),
|
208
|
+
import_function=lambda file_path, name=None: import_function_from_api_dir(
|
209
|
+
file_path=file_path, automation_function_name=name, base_dir=os.fspath(cwd)
|
210
|
+
),
|
211
|
+
)
|
212
|
+
return result.result, result.payload_to_append
|
@@ -0,0 +1,458 @@
|
|
1
|
+
import datetime
|
2
|
+
import json
|
3
|
+
import time
|
4
|
+
from typing import Any
|
5
|
+
from typing import Literal
|
6
|
+
|
7
|
+
from anyio import Path
|
8
|
+
from pydantic import BaseModel
|
9
|
+
from pydantic import Field
|
10
|
+
from pydantic import ValidationError
|
11
|
+
|
12
|
+
from intuned_cli.utils.api_helpers import assert_api_file_exists
|
13
|
+
from intuned_cli.utils.console import console
|
14
|
+
from intuned_cli.utils.error import CLIError
|
15
|
+
from intuned_cli.utils.error import log_automation_error
|
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
|
18
|
+
from intuned_cli.utils.timeout import extendable_timeout
|
19
|
+
from runtime.errors.run_api_errors import AutomationError
|
20
|
+
from runtime.run.run_api import run_api
|
21
|
+
from runtime.types.run_types import Auth
|
22
|
+
from runtime.types.run_types import AutomationFunction
|
23
|
+
from runtime.types.run_types import ProxyConfig
|
24
|
+
from runtime.types.run_types import RunApiParameters
|
25
|
+
from runtime.types.run_types import StandaloneRunOptions
|
26
|
+
from runtime.types.run_types import StateSession
|
27
|
+
from runtime.types.run_types import StorageState
|
28
|
+
|
29
|
+
auth_session_instances_dirname = "auth-session-instances"
|
30
|
+
|
31
|
+
|
32
|
+
class AuthSessionMetadata(BaseModel):
|
33
|
+
created_at: str = Field(alias="createdAt")
|
34
|
+
updated_at: str = Field(alias="updatedAt")
|
35
|
+
auth_session_id: str = Field(alias="authSessionId")
|
36
|
+
auth_session_type: Literal["MANUAL", "API"] = Field(alias="authSessionType")
|
37
|
+
auth_session_input: dict[str, Any] | None = Field(alias="authSessionInput", default=None)
|
38
|
+
recorder_start_url: str | None = Field(alias="recorderStartUrl", default=None)
|
39
|
+
recorder_end_url: str | None = Field(alias="recorderEndUrl", default=None)
|
40
|
+
|
41
|
+
|
42
|
+
async def execute_run_validate_auth_session_cli(
|
43
|
+
*,
|
44
|
+
id: str,
|
45
|
+
auto_recreate: bool,
|
46
|
+
check_retries: int,
|
47
|
+
create_retries: int,
|
48
|
+
headless: bool,
|
49
|
+
timeout: float,
|
50
|
+
proxy: str | None = None,
|
51
|
+
) -> StorageState:
|
52
|
+
"""
|
53
|
+
Validate auth session with optional auto-recreation.
|
54
|
+
"""
|
55
|
+
console.print(f"[bold]Validating auth session with id [cyan]{id}[/cyan][/bold]")
|
56
|
+
|
57
|
+
register_get_auth_session_parameters(id)
|
58
|
+
|
59
|
+
# Get auth session instance and path
|
60
|
+
instance, metadata = await load_auth_session_instance(id)
|
61
|
+
|
62
|
+
await assert_api_file_exists("auth-sessions", "check")
|
63
|
+
|
64
|
+
check_result = await run_check_with_retries(
|
65
|
+
auth=instance,
|
66
|
+
retries=check_retries,
|
67
|
+
headless=headless,
|
68
|
+
timeout=timeout,
|
69
|
+
proxy=proxy,
|
70
|
+
)
|
71
|
+
|
72
|
+
if not check_result:
|
73
|
+
if not auto_recreate:
|
74
|
+
raise CLIError("Auto recreate is disabled, please provide a new auth session or update it manually")
|
75
|
+
|
76
|
+
if metadata and metadata.auth_session_type == "MANUAL":
|
77
|
+
raise CLIError("Auth session is recorder-based, please provide a new one or update it manually")
|
78
|
+
|
79
|
+
console.print("[bold]Auto recreate is enabled - trying to re-create it[/bold]")
|
80
|
+
|
81
|
+
await assert_api_file_exists("auth-sessions", "create")
|
82
|
+
|
83
|
+
auth_session_input = (metadata.auth_session_input or {}) if metadata else {}
|
84
|
+
|
85
|
+
instance = await run_create_with_retries(
|
86
|
+
auth_session_id=id,
|
87
|
+
auth_session_input=auth_session_input,
|
88
|
+
retries=create_retries,
|
89
|
+
headless=headless,
|
90
|
+
timeout=timeout,
|
91
|
+
proxy=proxy,
|
92
|
+
metadata=metadata,
|
93
|
+
)
|
94
|
+
|
95
|
+
# Rerun check after refresh
|
96
|
+
check_result = await run_check_with_retries(
|
97
|
+
auth=instance,
|
98
|
+
retries=check_retries,
|
99
|
+
headless=headless,
|
100
|
+
timeout=timeout,
|
101
|
+
proxy=proxy,
|
102
|
+
)
|
103
|
+
if not check_result:
|
104
|
+
raise CLIError("Failed to re-create auth session")
|
105
|
+
|
106
|
+
console.print("[bold][green]Auth session validated successfully[/green][/bold]")
|
107
|
+
return instance
|
108
|
+
|
109
|
+
|
110
|
+
async def execute_run_create_auth_session_cli(
|
111
|
+
*,
|
112
|
+
id: str | None = None,
|
113
|
+
input_data: Any,
|
114
|
+
check_retries: int,
|
115
|
+
create_retries: int,
|
116
|
+
log: bool = True,
|
117
|
+
headless: bool,
|
118
|
+
timeout: float,
|
119
|
+
proxy: str | None = None,
|
120
|
+
metadata: AuthSessionMetadata | None = None,
|
121
|
+
):
|
122
|
+
"""
|
123
|
+
Create a new auth session.
|
124
|
+
"""
|
125
|
+
if id is None:
|
126
|
+
id = f"auth-session-{int(time.time() * 1000)}"
|
127
|
+
|
128
|
+
if log:
|
129
|
+
console.print(f"[bold]Creating auth session with id [cyan]{id}[/cyan][/bold]")
|
130
|
+
|
131
|
+
await assert_api_file_exists("auth-sessions", "create")
|
132
|
+
await assert_api_file_exists("auth-sessions", "check")
|
133
|
+
|
134
|
+
instance = await run_create_with_retries(
|
135
|
+
auth_session_id=id,
|
136
|
+
auth_session_input=input_data,
|
137
|
+
retries=create_retries,
|
138
|
+
headless=headless,
|
139
|
+
timeout=timeout,
|
140
|
+
proxy=proxy,
|
141
|
+
metadata=metadata,
|
142
|
+
)
|
143
|
+
|
144
|
+
check_result = await run_check_with_retries(
|
145
|
+
auth=instance,
|
146
|
+
retries=check_retries,
|
147
|
+
headless=headless,
|
148
|
+
timeout=timeout,
|
149
|
+
proxy=proxy,
|
150
|
+
)
|
151
|
+
if not check_result:
|
152
|
+
raise CLIError("Failed to create auth session")
|
153
|
+
|
154
|
+
if log:
|
155
|
+
console.print("[bold][green]Auth session created successfully[/green][/bold]")
|
156
|
+
|
157
|
+
|
158
|
+
async def execute_run_update_auth_session_cli(
|
159
|
+
*,
|
160
|
+
id: str,
|
161
|
+
input_data: Any | None = None,
|
162
|
+
check_retries: int,
|
163
|
+
create_retries: int,
|
164
|
+
headless: bool,
|
165
|
+
timeout: float,
|
166
|
+
proxy: str | None = None,
|
167
|
+
):
|
168
|
+
"""
|
169
|
+
Update an existing auth session.
|
170
|
+
"""
|
171
|
+
console.print(f"[bold]Updating auth session with id [cyan]{id}[/cyan][/bold]")
|
172
|
+
|
173
|
+
_, metadata = await load_auth_session_instance(id)
|
174
|
+
if metadata and metadata.auth_session_type == "MANUAL":
|
175
|
+
raise CLIError("Auth session is recorder-based, it cannot be updated.")
|
176
|
+
|
177
|
+
if input_data is None:
|
178
|
+
input_data = metadata.auth_session_input if metadata else {}
|
179
|
+
|
180
|
+
await assert_api_file_exists("auth-sessions", "create")
|
181
|
+
await assert_api_file_exists("auth-sessions", "check")
|
182
|
+
|
183
|
+
await execute_run_create_auth_session_cli(
|
184
|
+
id=id,
|
185
|
+
input_data=input_data,
|
186
|
+
check_retries=check_retries,
|
187
|
+
create_retries=create_retries,
|
188
|
+
log=False,
|
189
|
+
headless=headless,
|
190
|
+
timeout=timeout,
|
191
|
+
proxy=proxy,
|
192
|
+
metadata=metadata,
|
193
|
+
)
|
194
|
+
|
195
|
+
console.print("[bold][green]Auth session updated successfully[/green][/bold]")
|
196
|
+
|
197
|
+
|
198
|
+
async def execute_attempt_create_auth_session_cli(
|
199
|
+
*,
|
200
|
+
id: str | None = None,
|
201
|
+
input_data: Any,
|
202
|
+
headless: bool,
|
203
|
+
timeout: float,
|
204
|
+
proxy: str | None = None,
|
205
|
+
):
|
206
|
+
"""
|
207
|
+
Execute a single attempt to create auth session.
|
208
|
+
"""
|
209
|
+
if id is None:
|
210
|
+
id = f"auth-session-attempt-{int(time.time() * 1000)}"
|
211
|
+
|
212
|
+
console.print(f"[bold]Executing create auth session attempt with id [cyan]{id}[/cyan][/bold]")
|
213
|
+
await assert_api_file_exists("auth-sessions", "create")
|
214
|
+
await run_create_with_retries(
|
215
|
+
auth_session_id=id,
|
216
|
+
auth_session_input=input_data,
|
217
|
+
retries=1,
|
218
|
+
headless=headless,
|
219
|
+
timeout=timeout,
|
220
|
+
proxy=proxy,
|
221
|
+
)
|
222
|
+
|
223
|
+
|
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
|
+
):
|
231
|
+
"""
|
232
|
+
Execute a single attempt to check auth session.
|
233
|
+
"""
|
234
|
+
console.print(f"[bold]Executing check auth session attempt with id [cyan]{id}[/cyan][/bold]")
|
235
|
+
await assert_api_file_exists("auth-sessions", "check")
|
236
|
+
|
237
|
+
register_get_auth_session_parameters(id)
|
238
|
+
|
239
|
+
instance, _ = await load_auth_session_instance(id)
|
240
|
+
|
241
|
+
check_result = await run_check_with_retries(
|
242
|
+
auth=instance,
|
243
|
+
retries=1,
|
244
|
+
headless=headless,
|
245
|
+
timeout=timeout,
|
246
|
+
proxy=proxy,
|
247
|
+
)
|
248
|
+
|
249
|
+
if not check_result:
|
250
|
+
raise CLIError("Check failed")
|
251
|
+
|
252
|
+
console.print("[bold green]Auth session check successful[/bold green]")
|
253
|
+
|
254
|
+
|
255
|
+
async def run_check(
|
256
|
+
*,
|
257
|
+
auth: StorageState,
|
258
|
+
headless: bool,
|
259
|
+
timeout: float,
|
260
|
+
proxy: str | None = None,
|
261
|
+
) -> bool:
|
262
|
+
"""
|
263
|
+
Run auth session check.
|
264
|
+
"""
|
265
|
+
async with extendable_timeout(timeout):
|
266
|
+
result = await run_api(
|
267
|
+
RunApiParameters(
|
268
|
+
automation_function=AutomationFunction(
|
269
|
+
name="auth-sessions/check",
|
270
|
+
params=None,
|
271
|
+
),
|
272
|
+
run_options=StandaloneRunOptions(
|
273
|
+
headless=headless, proxy=ProxyConfig.parse_from_str(proxy) if proxy else None
|
274
|
+
),
|
275
|
+
auth=Auth(
|
276
|
+
session=StateSession(
|
277
|
+
state=auth,
|
278
|
+
),
|
279
|
+
run_check=False,
|
280
|
+
),
|
281
|
+
),
|
282
|
+
import_function=await get_cli_import_function(),
|
283
|
+
)
|
284
|
+
|
285
|
+
if not result.result:
|
286
|
+
return False
|
287
|
+
|
288
|
+
return bool(result.result)
|
289
|
+
|
290
|
+
|
291
|
+
async def run_create(
|
292
|
+
*,
|
293
|
+
auth_session_input: dict[str, Any],
|
294
|
+
headless: bool,
|
295
|
+
timeout: float,
|
296
|
+
proxy: str | None = None,
|
297
|
+
) -> StorageState:
|
298
|
+
"""
|
299
|
+
Run auth session create.
|
300
|
+
"""
|
301
|
+
async with extendable_timeout(timeout):
|
302
|
+
result = await run_api(
|
303
|
+
RunApiParameters(
|
304
|
+
automation_function=AutomationFunction(
|
305
|
+
name="auth-sessions/create",
|
306
|
+
params=auth_session_input,
|
307
|
+
),
|
308
|
+
run_options=StandaloneRunOptions(
|
309
|
+
headless=headless, proxy=ProxyConfig.parse_from_str(proxy) if proxy else None
|
310
|
+
),
|
311
|
+
retrieve_session=True,
|
312
|
+
),
|
313
|
+
import_function=await get_cli_import_function(),
|
314
|
+
)
|
315
|
+
if not result.session:
|
316
|
+
raise Exception("Auth session create did not return a session")
|
317
|
+
return result.session
|
318
|
+
|
319
|
+
|
320
|
+
async def run_check_with_retries(
|
321
|
+
*,
|
322
|
+
auth: StorageState,
|
323
|
+
retries: int,
|
324
|
+
headless: bool,
|
325
|
+
timeout: float,
|
326
|
+
proxy: str | None = None,
|
327
|
+
) -> bool:
|
328
|
+
"""
|
329
|
+
Run auth session check with retries.
|
330
|
+
"""
|
331
|
+
for i in range(retries):
|
332
|
+
attempt_text = "" if i == 0 else f" [italic](Attempt {i + 1})[/italic]"
|
333
|
+
console.print(f"\n[bold]Running [cyan]auth session check[/cyan]{attempt_text}...[/bold]\n")
|
334
|
+
|
335
|
+
try:
|
336
|
+
check_result = await run_check(
|
337
|
+
auth=auth,
|
338
|
+
headless=headless,
|
339
|
+
timeout=timeout,
|
340
|
+
proxy=proxy,
|
341
|
+
)
|
342
|
+
|
343
|
+
if check_result:
|
344
|
+
console.print("[bold][green]Auth session check passed[/green][/bold]")
|
345
|
+
return True
|
346
|
+
except AutomationError as e:
|
347
|
+
log_automation_error(e)
|
348
|
+
continue
|
349
|
+
|
350
|
+
console.print(f"[bold][red]Auth session check failed after {retries} attempt(s)[/red][/bold]")
|
351
|
+
return False
|
352
|
+
|
353
|
+
|
354
|
+
async def run_create_with_retries(
|
355
|
+
*,
|
356
|
+
auth_session_id: str,
|
357
|
+
auth_session_input: dict[str, Any],
|
358
|
+
retries: int,
|
359
|
+
headless: bool,
|
360
|
+
timeout: float,
|
361
|
+
proxy: str | None = None,
|
362
|
+
metadata: AuthSessionMetadata | None = None,
|
363
|
+
):
|
364
|
+
"""
|
365
|
+
Run auth session create with retries.
|
366
|
+
"""
|
367
|
+
new_auth_session_instance: StorageState | None = None
|
368
|
+
|
369
|
+
for i in range(retries):
|
370
|
+
attempt_text = "" if i == 0 else f" [italic](Attempt {i + 1})[/italic]"
|
371
|
+
console.print(f"\n[bold]Running [cyan]auth session create[/cyan]{attempt_text}...[/bold]\n")
|
372
|
+
|
373
|
+
try:
|
374
|
+
new_auth_session_instance = await run_create(
|
375
|
+
auth_session_input=auth_session_input,
|
376
|
+
headless=headless,
|
377
|
+
timeout=timeout,
|
378
|
+
proxy=proxy,
|
379
|
+
)
|
380
|
+
console.print("[bold][green]Auth session create succeeded[/green][/bold]")
|
381
|
+
break
|
382
|
+
except AutomationError as e:
|
383
|
+
log_automation_error(e)
|
384
|
+
continue
|
385
|
+
|
386
|
+
if not new_auth_session_instance:
|
387
|
+
raise CLIError(f"Failed to create auth session after {retries} attempt(s)")
|
388
|
+
|
389
|
+
await store_auth_session_instance(new_auth_session_instance, auth_session_id, auth_session_input, metadata=metadata)
|
390
|
+
|
391
|
+
return new_auth_session_instance
|
392
|
+
|
393
|
+
|
394
|
+
async def load_auth_session_instance(auth_session_id: str) -> tuple[StorageState, AuthSessionMetadata]:
|
395
|
+
"""
|
396
|
+
Retrieve auth session instance storage path by ID.
|
397
|
+
"""
|
398
|
+
# Placeholder implementation - will be replaced with actual retrieval logic
|
399
|
+
auth_session_instances_path = get_auth_session_path(auth_session_id)
|
400
|
+
|
401
|
+
instance_path = auth_session_instances_path / "auth-session.json"
|
402
|
+
|
403
|
+
if not await instance_path.exists():
|
404
|
+
raise CLIError(f"Auth session instance with ID {auth_session_id} not found")
|
405
|
+
|
406
|
+
metadata_path = auth_session_instances_path / "metadata.json"
|
407
|
+
|
408
|
+
if not await metadata_path.exists():
|
409
|
+
raise CLIError(f"Metadata for auth session instance with ID {auth_session_id} not found")
|
410
|
+
|
411
|
+
try:
|
412
|
+
instance_text_content = await instance_path.read_text()
|
413
|
+
|
414
|
+
instance = StorageState.model_validate_json(instance_text_content)
|
415
|
+
|
416
|
+
metadata_text_content = await metadata_path.read_text()
|
417
|
+
|
418
|
+
metadata = AuthSessionMetadata.model_validate_json(metadata_text_content)
|
419
|
+
except ValidationError as e:
|
420
|
+
raise CLIError(f"Failed to parse auth session instance or metadata: {e}") from e
|
421
|
+
|
422
|
+
return instance, metadata
|
423
|
+
|
424
|
+
|
425
|
+
async def store_auth_session_instance(
|
426
|
+
auth_session_instance: StorageState,
|
427
|
+
auth_session_id: str,
|
428
|
+
auth_session_input: dict[str, Any],
|
429
|
+
metadata: AuthSessionMetadata | None = None,
|
430
|
+
):
|
431
|
+
"""
|
432
|
+
Store auth session instance with metadata.
|
433
|
+
"""
|
434
|
+
|
435
|
+
# Create directory path
|
436
|
+
auth_session_path = get_auth_session_path(auth_session_id)
|
437
|
+
await auth_session_path.mkdir(parents=True, exist_ok=True)
|
438
|
+
|
439
|
+
# Store the session data
|
440
|
+
instance_file_path = auth_session_path / "auth-session.json"
|
441
|
+
instance_json = json.dumps(auth_session_instance.model_dump(by_alias=True), indent=2)
|
442
|
+
await instance_file_path.write_text(instance_json)
|
443
|
+
# Store metadata
|
444
|
+
metadata = AuthSessionMetadata(
|
445
|
+
createdAt=metadata.created_at if metadata else datetime.datetime.now().isoformat(),
|
446
|
+
updatedAt=datetime.datetime.now().isoformat(),
|
447
|
+
authSessionId=auth_session_id,
|
448
|
+
authSessionInput=auth_session_input,
|
449
|
+
authSessionType="API",
|
450
|
+
)
|
451
|
+
metadata_file_path = auth_session_path / "metadata.json"
|
452
|
+
|
453
|
+
metadata_json = json.dumps(metadata.model_dump(by_alias=True), indent=2)
|
454
|
+
await metadata_file_path.write_text(metadata_json)
|
455
|
+
|
456
|
+
|
457
|
+
def get_auth_session_path(auth_session_id: str):
|
458
|
+
return Path(auth_session_instances_dirname) / auth_session_id
|