hardpy 0.12.0__py3-none-any.whl → 0.13.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.
- hardpy/cli/cli.py +16 -11
- hardpy/common/stand_cloud/connector.py +142 -135
- hardpy/common/stand_cloud/oauth2.py +88 -0
- hardpy/common/stand_cloud/registration.py +50 -211
- hardpy/common/stand_cloud/token_manager.py +119 -0
- hardpy/common/stand_cloud/utils.py +33 -0
- hardpy/hardpy_panel/frontend/dist/assets/{allPaths-B26356fZ.js → allPaths-Cg7WZDXy.js} +1 -1
- hardpy/hardpy_panel/frontend/dist/assets/{allPathsLoader-0BeGWuiy.js → allPathsLoader-C79wUwqR.js} +2 -2
- hardpy/hardpy_panel/frontend/dist/assets/{index-Bl_IX0Up.js → index-De5CJ3kt.js} +2 -2
- hardpy/hardpy_panel/frontend/dist/assets/{splitPathsBySizeLoader-BEs5IL5-.js → splitPathsBySizeLoader-hWuLTMwD.js} +1 -1
- hardpy/hardpy_panel/frontend/dist/index.html +1 -1
- hardpy/pytest_hardpy/plugin.py +48 -24
- hardpy/pytest_hardpy/pytest_call.py +7 -3
- hardpy/pytest_hardpy/reporter/base.py +8 -0
- hardpy/pytest_hardpy/reporter/hook_reporter.py +40 -5
- {hardpy-0.12.0.dist-info → hardpy-0.13.0.dist-info}/METADATA +2 -1
- {hardpy-0.12.0.dist-info → hardpy-0.13.0.dist-info}/RECORD +20 -19
- hardpy/common/stand_cloud/oauth_callback.py +0 -95
- hardpy/common/stand_cloud/token_storage.py +0 -27
- {hardpy-0.12.0.dist-info → hardpy-0.13.0.dist-info}/WHEEL +0 -0
- {hardpy-0.12.0.dist-info → hardpy-0.13.0.dist-info}/entry_points.txt +0 -0
- {hardpy-0.12.0.dist-info → hardpy-0.13.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,236 +1,75 @@
|
|
|
1
|
-
# Copyright (c)
|
|
1
|
+
# Copyright (c) 2025 Everypin
|
|
2
2
|
# GNU General Public License v3.0 (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt)
|
|
3
3
|
|
|
4
4
|
from __future__ import annotations
|
|
5
5
|
|
|
6
|
-
import
|
|
7
|
-
import
|
|
8
|
-
import json
|
|
9
|
-
import os
|
|
10
|
-
import re
|
|
11
|
-
import secrets
|
|
12
|
-
import socket
|
|
13
|
-
import subprocess
|
|
14
|
-
import sys
|
|
15
|
-
from contextlib import suppress
|
|
16
|
-
from platform import system
|
|
17
|
-
from time import sleep
|
|
6
|
+
from datetime import timedelta
|
|
7
|
+
from io import StringIO
|
|
18
8
|
from typing import TYPE_CHECKING
|
|
19
|
-
from urllib.parse import urlencode
|
|
20
9
|
|
|
21
|
-
import
|
|
22
|
-
from
|
|
23
|
-
from
|
|
24
|
-
from
|
|
25
|
-
from oauthlib.oauth2 import WebApplicationClient
|
|
26
|
-
from oauthlib.oauth2.rfc6749.errors import InvalidClientIdError
|
|
10
|
+
from oauthlib.oauth2.rfc6749.errors import OAuth2Error
|
|
11
|
+
from qrcode import QRCode
|
|
12
|
+
from requests.exceptions import ConnectionError as RequestConnectionError, HTTPError
|
|
13
|
+
from requests_oauth2client.tokens import ExpiredAccessToken
|
|
27
14
|
|
|
28
|
-
from hardpy.common.stand_cloud.
|
|
29
|
-
from hardpy.common.stand_cloud.
|
|
15
|
+
from hardpy.common.stand_cloud.exception import StandCloudError
|
|
16
|
+
from hardpy.common.stand_cloud.token_manager import TokenManager
|
|
30
17
|
|
|
31
18
|
if TYPE_CHECKING:
|
|
32
|
-
from
|
|
19
|
+
from hardpy.common.stand_cloud.connector import StandCloudConnector
|
|
33
20
|
|
|
34
21
|
|
|
35
|
-
def login(
|
|
22
|
+
def login(sc_connector: StandCloudConnector) -> None:
|
|
36
23
|
"""Login HardPy in StandCloud.
|
|
37
24
|
|
|
38
25
|
Args:
|
|
39
|
-
|
|
26
|
+
sc_connector (StandCloudConnector): StandCloud connector
|
|
40
27
|
"""
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
port = _reserve_socket_port()
|
|
54
|
-
callback_process = _create_callback_process(port)
|
|
55
|
-
state = secrets.token_urlsafe(16)
|
|
56
|
-
code_verifier = _code_verifier()
|
|
57
|
-
data = _par_data(code_verifier, client_id, port, state, sc_connector.url.api)
|
|
58
|
-
timeout = 10
|
|
59
|
-
|
|
60
|
-
# fmt: off
|
|
61
|
-
# pushed authorization response
|
|
62
|
-
try:
|
|
63
|
-
response = json.loads(requests.post(sc_connector.url.par, data=data, verify=verify_ssl, timeout=timeout).content)
|
|
64
|
-
except Exception as e: # noqa: BLE001
|
|
65
|
-
print(f"Authentication server is unavailable: {e}")
|
|
66
|
-
sys.exit(1)
|
|
67
|
-
url = (sc_connector.url.auth + "?" + urlencode({"client_id": client_id, "request_uri": response["request_uri"]}))
|
|
68
|
-
|
|
69
|
-
# OAuth authorization code request
|
|
70
|
-
print(f"\nOpen the provided URL and authorize HardPy to use StandCloud\n\n{url}")
|
|
71
|
-
|
|
72
|
-
# use subprocess
|
|
73
|
-
first_line = next(callback_process.stdout) # type: ignore
|
|
74
|
-
sleep(1)
|
|
75
|
-
|
|
76
|
-
# OAuth authorization code grant
|
|
77
|
-
response = json.loads(first_line)
|
|
78
|
-
callback_process.kill()
|
|
79
|
-
|
|
80
|
-
_check_incorrect_response(response, state)
|
|
81
|
-
|
|
82
|
-
code = response["code"]
|
|
83
|
-
uri = _redirect_uri(port)
|
|
84
|
-
data = client.prepare_request_body(code=code, client_id=client_id, redirect_uri=uri, code_verifier=code_verifier)
|
|
85
|
-
|
|
86
|
-
# OAuth access token request
|
|
87
|
-
data = dict(urldecode(data))
|
|
88
|
-
response = requests.post(sc_connector.url.token, data=data, verify=verify_ssl, timeout=timeout)
|
|
89
|
-
# fmt: on
|
|
28
|
+
token = sc_connector.get_access_token()
|
|
29
|
+
if token is None or sc_connector.is_refresh_token_valid() is False:
|
|
30
|
+
try:
|
|
31
|
+
response = sc_connector.get_verification_url()
|
|
32
|
+
except (RequestConnectionError, StandCloudError) as e:
|
|
33
|
+
print(f"Connection error to StandCloud: {sc_connector.addr}. \nError: {e}")
|
|
34
|
+
return
|
|
35
|
+
url = response["verification_uri_complete"]
|
|
36
|
+
_print_user_action_request(url)
|
|
37
|
+
token = sc_connector.wait_verification(response)
|
|
38
|
+
|
|
39
|
+
sc_connector.update_token(token)
|
|
90
40
|
|
|
91
41
|
try:
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
42
|
+
sc_connector.healthcheck()
|
|
43
|
+
except ExpiredAccessToken as e:
|
|
44
|
+
time_diff = timedelta(seconds=abs(e.args[0].expires_in))
|
|
45
|
+
print(f"API access error: token is expired for {time_diff}")
|
|
46
|
+
except OAuth2Error as e:
|
|
47
|
+
print(e.description)
|
|
48
|
+
except HTTPError as e:
|
|
95
49
|
print(e)
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
_store_password(client.token)
|
|
50
|
+
else:
|
|
51
|
+
print(f"HardPy login to {sc_connector.addr} success")
|
|
99
52
|
|
|
100
53
|
|
|
101
|
-
def logout() -> bool:
|
|
54
|
+
def logout(addr: str) -> bool:
|
|
102
55
|
"""Logout HardPy from StandCloud.
|
|
103
56
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
"""
|
|
107
|
-
service_name = "HardPy"
|
|
108
|
-
|
|
109
|
-
try:
|
|
110
|
-
while cred := get_credential(service_name, None):
|
|
111
|
-
delete_password(service_name, cred.username)
|
|
112
|
-
except KeyringError:
|
|
113
|
-
return False
|
|
114
|
-
# TODO(xorialexandrov): fix keyring clearing
|
|
115
|
-
# Windows does not clear refresh token by itself
|
|
116
|
-
if system() == "Windows":
|
|
117
|
-
storage_keyring, _ = get_token_store()
|
|
118
|
-
with suppress(KeyringError):
|
|
119
|
-
storage_keyring.delete_password(service_name, "refresh_token")
|
|
120
|
-
return True
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
def _redirect_uri(port: str) -> str:
|
|
124
|
-
return f"http://127.0.0.1:{port}/oauth2/callback"
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
def _reserve_socket_port() -> str:
|
|
128
|
-
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
129
|
-
sock.bind(("127.0.0.1", 0))
|
|
130
|
-
port = sock.getsockname()[1]
|
|
131
|
-
sock.close()
|
|
132
|
-
|
|
133
|
-
return str(port)
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
def _code_verifier() -> str:
|
|
137
|
-
code_verifier = base64.urlsafe_b64encode(os.urandom(40)).decode("utf-8")
|
|
138
|
-
return re.sub("[^a-zA-Z0-9]+", "", code_verifier)
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
def _code_challenge(code_verifier: str) -> str:
|
|
142
|
-
code_challenge = hashlib.sha256(code_verifier.encode("utf-8")).digest()
|
|
143
|
-
code_challenge = base64.urlsafe_b64encode(code_challenge).decode("utf-8")
|
|
144
|
-
return code_challenge.replace("=", "")
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
def _create_callback_process(port: str) -> subprocess.Popen:
|
|
148
|
-
args = [
|
|
149
|
-
sys.executable,
|
|
150
|
-
"-m",
|
|
151
|
-
"uvicorn",
|
|
152
|
-
"hardpy.common.stand_cloud.oauth_callback:app",
|
|
153
|
-
"--host=127.0.0.1",
|
|
154
|
-
f"--port={port}",
|
|
155
|
-
"--log-level=error",
|
|
156
|
-
]
|
|
157
|
-
|
|
158
|
-
if system() == "Windows":
|
|
159
|
-
env = os.environ.copy()
|
|
160
|
-
env["PYTHONUNBUFFERED"] = "1"
|
|
161
|
-
|
|
162
|
-
return subprocess.Popen( # noqa: S603
|
|
163
|
-
args,
|
|
164
|
-
stdout=subprocess.PIPE,
|
|
165
|
-
bufsize=1,
|
|
166
|
-
universal_newlines=True,
|
|
167
|
-
env=env,
|
|
168
|
-
creationflags=subprocess.CREATE_NEW_PROCESS_GROUP, # type: ignore
|
|
169
|
-
)
|
|
170
|
-
return subprocess.Popen( # noqa: S603
|
|
171
|
-
args,
|
|
172
|
-
stdout=subprocess.PIPE,
|
|
173
|
-
bufsize=1,
|
|
174
|
-
universal_newlines=True,
|
|
175
|
-
env=dict(PYTHONUNBUFFERED="1"), # noqa: C408
|
|
176
|
-
)
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
def _store_password(token: BearerToken) -> None:
|
|
180
|
-
storage_keyring, mem_keyring = get_token_store()
|
|
181
|
-
|
|
182
|
-
storage_keyring.set_password(
|
|
183
|
-
"HardPy",
|
|
184
|
-
"refresh_token",
|
|
185
|
-
token["refresh_token"],
|
|
186
|
-
)
|
|
187
|
-
token_data = {
|
|
188
|
-
"access_token": token["access_token"],
|
|
189
|
-
"expires_at": token["expires_at"],
|
|
190
|
-
}
|
|
191
|
-
try:
|
|
192
|
-
mem_keyring.set_password("HardPy", "access_token", json.dumps(token_data))
|
|
193
|
-
except KeyringError as e:
|
|
194
|
-
print(e)
|
|
195
|
-
return
|
|
196
|
-
print("\nRegistration completed successfully")
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
def _check_incorrect_response(response: dict, state: str) -> None:
|
|
200
|
-
if response["state"] != state:
|
|
201
|
-
print("Wrong state in response")
|
|
202
|
-
sys.exit(1)
|
|
203
|
-
|
|
204
|
-
if "error" in response:
|
|
205
|
-
error = response["error"]
|
|
206
|
-
error_description = response["error_description"]
|
|
207
|
-
print(f"{error}: {error_description}")
|
|
208
|
-
sys.exit(1)
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
def _par_data(
|
|
212
|
-
code_verifier: str,
|
|
213
|
-
client_id: str,
|
|
214
|
-
port: str,
|
|
215
|
-
state: str,
|
|
216
|
-
api_url: str,
|
|
217
|
-
) -> dict:
|
|
218
|
-
"""Create pushed authorization request data.
|
|
57
|
+
Args:
|
|
58
|
+
addr (str): StandCloud address
|
|
219
59
|
|
|
220
60
|
Returns:
|
|
221
|
-
|
|
61
|
+
bool: True if successful else False
|
|
222
62
|
"""
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
}
|
|
63
|
+
token_manager = TokenManager(addr)
|
|
64
|
+
return token_manager.remove_token()
|
|
65
|
+
|
|
66
|
+
def _print_user_action_request(url_complete: str) -> None:
|
|
67
|
+
qr = QRCode()
|
|
68
|
+
qr.add_data(url_complete)
|
|
69
|
+
f = StringIO()
|
|
70
|
+
qr.print_ascii(out=f)
|
|
71
|
+
f.seek(0)
|
|
72
|
+
|
|
73
|
+
print(f.read())
|
|
74
|
+
print("Scan the QR code or, using a browser on another device, visit:")
|
|
75
|
+
print(url_complete, end="\n\n")
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# Copyright (c) 2025 Everypin
|
|
2
|
+
# GNU General Public License v3.0 (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt)
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
import sys
|
|
7
|
+
from contextlib import suppress
|
|
8
|
+
from copy import deepcopy
|
|
9
|
+
from datetime import datetime, timezone
|
|
10
|
+
from platform import system
|
|
11
|
+
from typing import TYPE_CHECKING
|
|
12
|
+
|
|
13
|
+
from keyring import delete_password, get_credential
|
|
14
|
+
from keyring.core import load_keyring
|
|
15
|
+
from keyring.errors import KeyringError
|
|
16
|
+
from requests_oauth2client import BearerToken
|
|
17
|
+
|
|
18
|
+
if TYPE_CHECKING:
|
|
19
|
+
from keyring.backend import KeyringBackend
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class TokenManager:
|
|
23
|
+
"""Token manager.
|
|
24
|
+
|
|
25
|
+
Manage token in keyring storage.
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
def __init__(self, service_name: str) -> None:
|
|
29
|
+
self._service_name = f"HardPy_{service_name}"
|
|
30
|
+
|
|
31
|
+
def remove_token(self) -> bool:
|
|
32
|
+
"""Remove token from keyring storage.
|
|
33
|
+
|
|
34
|
+
Returns:
|
|
35
|
+
bool: True if successful else False
|
|
36
|
+
"""
|
|
37
|
+
try:
|
|
38
|
+
while cred := get_credential(self._service_name, None):
|
|
39
|
+
delete_password(self._service_name, cred.username)
|
|
40
|
+
except KeyringError:
|
|
41
|
+
return False
|
|
42
|
+
# TODO(xorialexandrov): fix keyring clearing
|
|
43
|
+
# Windows does not clear refresh token by itself
|
|
44
|
+
if system() == "Windows":
|
|
45
|
+
storage_keyring, _ = self._get_store()
|
|
46
|
+
with suppress(KeyringError):
|
|
47
|
+
storage_keyring.delete_password(self._service_name, "refresh_token")
|
|
48
|
+
return True
|
|
49
|
+
|
|
50
|
+
def save_token_info(self, token: BearerToken | dict) -> None:
|
|
51
|
+
"""Save token to keyring storage.
|
|
52
|
+
|
|
53
|
+
Args:
|
|
54
|
+
token (BearerToken | dict): token
|
|
55
|
+
"""
|
|
56
|
+
# fmt: off
|
|
57
|
+
storage_keyring, mem_keyring = self._get_store()
|
|
58
|
+
storage_keyring.set_password(self._service_name, "refresh_token", token["refresh_token"]) # noqa: E501
|
|
59
|
+
|
|
60
|
+
token_info = deepcopy(token)
|
|
61
|
+
token_info.pop("expires_in")
|
|
62
|
+
token_info.pop("refresh_token")
|
|
63
|
+
|
|
64
|
+
try:
|
|
65
|
+
mem_keyring.set_password(self._service_name, "access_token", json.dumps(token_info)) # noqa: E501
|
|
66
|
+
except KeyringError as e:
|
|
67
|
+
print(e) # noqa: T201
|
|
68
|
+
sys.exit(1)
|
|
69
|
+
# fmt: on
|
|
70
|
+
|
|
71
|
+
def read_access_token(self) -> BearerToken:
|
|
72
|
+
"""Read access token from token store.
|
|
73
|
+
|
|
74
|
+
Returns:
|
|
75
|
+
BearerToken: access token
|
|
76
|
+
"""
|
|
77
|
+
_, mem_keyring = self._get_store()
|
|
78
|
+
token_info = mem_keyring.get_password(self._service_name, "access_token")
|
|
79
|
+
secret = self._add_expires_in(json.loads(token_info)) # type: ignore
|
|
80
|
+
return BearerToken(**secret)
|
|
81
|
+
|
|
82
|
+
def read_refresh_token(self) -> str | None:
|
|
83
|
+
"""Read refresh token from token store.
|
|
84
|
+
|
|
85
|
+
Returns:
|
|
86
|
+
str | None: refresh token
|
|
87
|
+
"""
|
|
88
|
+
storage_keyring, _ = self._get_store()
|
|
89
|
+
service_name = self._service_name
|
|
90
|
+
return storage_keyring.get_password(service_name, "refresh_token")
|
|
91
|
+
|
|
92
|
+
def _get_store(self) -> tuple[KeyringBackend, KeyringBackend]:
|
|
93
|
+
"""Get token store.
|
|
94
|
+
|
|
95
|
+
Returns:
|
|
96
|
+
tuple[KeyringBackend, KeyringBackend]: token store
|
|
97
|
+
"""
|
|
98
|
+
if system() == "Linux":
|
|
99
|
+
storage_keyring = load_keyring("keyring.backends.SecretService.Keyring")
|
|
100
|
+
elif system() == "Windows":
|
|
101
|
+
storage_keyring = load_keyring("keyring.backends.Windows.WinVaultKeyring")
|
|
102
|
+
# TODO(xorialexandrov): add memory keyring or other store
|
|
103
|
+
mem_keyring = storage_keyring
|
|
104
|
+
|
|
105
|
+
return storage_keyring, mem_keyring
|
|
106
|
+
|
|
107
|
+
def _add_expires_in(self, secret: dict) -> dict:
|
|
108
|
+
if "expires_at" in secret:
|
|
109
|
+
expires_at = secret["expires_at"]
|
|
110
|
+
elif "id_token" in secret and "exp" in secret["id_token"]:
|
|
111
|
+
expires_at = secret["id_token"]["exp"]
|
|
112
|
+
expires_at_datetime = datetime.fromtimestamp(expires_at, timezone.utc)
|
|
113
|
+
|
|
114
|
+
expires_in_datetime = expires_at_datetime - datetime.now(timezone.utc)
|
|
115
|
+
expires_in = int(expires_in_datetime.total_seconds())
|
|
116
|
+
|
|
117
|
+
secret["expires_in"] = expires_in
|
|
118
|
+
|
|
119
|
+
return secret
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Copyright (c) 2024 Everypin
|
|
2
|
+
# GNU General Public License v3.0 (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt)
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from enum import Enum
|
|
6
|
+
from typing import NamedTuple
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class StandCloudAddr(NamedTuple):
|
|
10
|
+
"""StandCloud address.
|
|
11
|
+
|
|
12
|
+
domain: StandCloud address
|
|
13
|
+
api: API address
|
|
14
|
+
token: token address
|
|
15
|
+
auth: auth address
|
|
16
|
+
device: device-authorization address
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
domain: str
|
|
20
|
+
api: str
|
|
21
|
+
token: str
|
|
22
|
+
auth: str
|
|
23
|
+
device: str
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class StandCloudAPIMode(str, Enum):
|
|
27
|
+
"""StandCloud API mode.
|
|
28
|
+
|
|
29
|
+
HARDPY for test stand, integration for third-party service.
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
HARDPY = "hardpy"
|
|
33
|
+
INTEGRATION = "integration"
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{I as n}from"./index-xb4M2ucX.js";import{I as e}from"./index-BMEat_ws.js";import{p as r,I as s}from"./index-
|
|
1
|
+
import{I as n}from"./index-xb4M2ucX.js";import{I as e}from"./index-BMEat_ws.js";import{p as r,I as s}from"./index-De5CJ3kt.js";function I(o,t){var a=r(o);return t===s.STANDARD?n[a]:e[a]}function p(o){return r(o)}export{n as IconSvgPaths16,e as IconSvgPaths20,I as getIconPaths,p as iconNameToPathsRecordKey};
|
hardpy/hardpy_panel/frontend/dist/assets/{allPathsLoader-0BeGWuiy.js → allPathsLoader-C79wUwqR.js}
RENAMED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/allPaths-
|
|
2
|
-
import{_ as o,a as n,b as i}from"./index-
|
|
1
|
+
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/allPaths-Cg7WZDXy.js","assets/index-xb4M2ucX.js","assets/index-BMEat_ws.js","assets/index-De5CJ3kt.js","assets/index-BwCQzehg.css"])))=>i.map(i=>d[i]);
|
|
2
|
+
import{_ as o,a as n,b as i}from"./index-De5CJ3kt.js";var _=function(e,a){return o(void 0,void 0,void 0,function(){var t;return n(this,function(r){switch(r.label){case 0:return[4,i(()=>import("./allPaths-Cg7WZDXy.js"),__vite__mapDeps([0,1,2,3,4]))];case 1:return t=r.sent().getIconPaths,[2,t(e,a)]}})})};export{_ as allPathsLoader};
|