Compare commits
69
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4744ef9bba | ||
|
|
fdf061c08d | ||
|
|
d348234cad | ||
|
|
fc5261132e | ||
|
|
4e18c423de | ||
|
|
37e5601207 | ||
|
|
231f6fc01c | ||
|
|
811957f5e1 | ||
|
|
c63a53cb14 | ||
|
|
78b8f7f16e | ||
|
|
4642878c05 | ||
|
|
d7c850ccbb | ||
|
|
4fbb4b5eef | ||
|
|
db2829a5f6 | ||
|
|
13ce1ac172 | ||
|
|
512697ae53 | ||
|
|
dfa89ca063 | ||
|
|
182694d2e5 | ||
|
|
2f10c57a10 | ||
|
|
d685824596 | ||
|
|
e816eb2dac | ||
|
|
d3c099350a | ||
|
|
691ac969dc | ||
|
|
85e8ac6057 | ||
|
|
99da300f6d | ||
|
|
cd413d85ed | ||
|
|
9245e2c268 | ||
|
|
0b5c8cdee2 | ||
|
|
c94cef07c2 | ||
|
|
22b4ab779f | ||
|
|
42061d0cc8 | ||
|
|
d0ea42fd70 | ||
|
|
cd58a0dc9b | ||
|
|
cac4e309f4 | ||
|
|
632cd257d7 | ||
|
|
a11274593c | ||
|
|
ae92965b69 | ||
|
|
3e1f75c4cc | ||
|
|
d668747ca2 | ||
|
|
dedfcd4818 | ||
|
|
f66f2fe6c2 | ||
|
|
f3ca37e846 | ||
|
|
d45709a80f | ||
|
|
e4b6dc84b5 | ||
|
|
67d1b4be3e | ||
|
|
bd514f1a46 | ||
|
|
03b302da69 | ||
|
|
b373e35915 | ||
|
|
0fd116e7ee | ||
|
|
2c84f9781d | ||
|
|
9fcf3121ac | ||
|
|
1df9fa831d | ||
|
|
42039070b9 | ||
|
|
2f9146fff3 | ||
|
|
5738795c8c | ||
|
|
3c77acf266 | ||
|
|
a4f2f55279 | ||
|
|
2ab7c17ceb | ||
|
|
7a2c509cd3 | ||
|
|
8a51ea53c8 | ||
|
|
19d3e9e64e | ||
|
|
9f9f14ead0 | ||
|
|
0a093d82ae | ||
|
|
17fd459fa7 | ||
|
|
fe9aa4d8c9 | ||
|
|
1af3b62739 | ||
|
|
e9cbc3492f | ||
|
|
ca2f78d25b | ||
|
|
9d9ab48345 |
@@ -24,10 +24,6 @@ LOG_ROTATION="100 MB"
|
||||
LOG_RETENTION="3 months"
|
||||
# for database cleanup commands
|
||||
# CLEANUP_WALLETS_DAYS=90
|
||||
# Hard limit for total created users. Set to 0 to disable the limit.
|
||||
# LNBITS_MAX_USERS=0
|
||||
# Hard limit for total installed extensions. Set to 0 to disable the limit.
|
||||
# LNBITS_MAX_EXTENSIONS=0
|
||||
|
||||
# === Admin Settings ===
|
||||
|
||||
|
||||
@@ -69,10 +69,7 @@ jobs:
|
||||
--onefile \
|
||||
--name lnbits \
|
||||
--hidden-import=embit \
|
||||
--hidden-import=bitstring.bitstore_bitarray \
|
||||
--collect-all embit \
|
||||
--collect-all bitstring \
|
||||
--collect-all bitarray \
|
||||
--collect-all lnbits \
|
||||
--collect-all sqlalchemy \
|
||||
--collect-all breez_sdk \
|
||||
|
||||
@@ -65,7 +65,7 @@ jobs:
|
||||
make: openapi
|
||||
|
||||
regtest:
|
||||
needs: [ lint ]
|
||||
needs: [ lint, test-api, test-wallets, test-unit, migration, openapi ]
|
||||
uses: ./.github/workflows/regtest.yml
|
||||
strategy:
|
||||
matrix:
|
||||
|
||||
@@ -6,7 +6,6 @@ __pycache__
|
||||
*$py.class
|
||||
.mypy_cache
|
||||
.vscode
|
||||
.codex
|
||||
*-lock.json
|
||||
.python-version
|
||||
|
||||
|
||||
@@ -12,7 +12,6 @@ from .extensions import (
|
||||
drop_extension_db,
|
||||
get_installed_extension,
|
||||
get_installed_extensions,
|
||||
get_installed_extensions_count,
|
||||
get_user_active_extensions_ids,
|
||||
get_user_extension,
|
||||
get_user_extensions,
|
||||
@@ -59,7 +58,6 @@ from .users import (
|
||||
get_account_by_username,
|
||||
get_account_by_username_or_email,
|
||||
get_accounts,
|
||||
get_accounts_count,
|
||||
get_user,
|
||||
get_user_access_control_lists,
|
||||
get_user_from_account,
|
||||
@@ -119,13 +117,11 @@ __all__ = [
|
||||
"get_account_by_username",
|
||||
"get_account_by_username_or_email",
|
||||
"get_accounts",
|
||||
"get_accounts_count",
|
||||
"get_admin_settings",
|
||||
"get_db_version",
|
||||
"get_db_versions",
|
||||
"get_installed_extension",
|
||||
"get_installed_extensions",
|
||||
"get_installed_extensions_count",
|
||||
"get_latest_payments_by_extension",
|
||||
"get_payment",
|
||||
"get_payments",
|
||||
|
||||
@@ -90,13 +90,6 @@ async def get_installed_extensions(
|
||||
return all_extensions
|
||||
|
||||
|
||||
async def get_installed_extensions_count(conn: Connection | None = None) -> int:
|
||||
row: dict | None = await (conn or db).fetchone(
|
||||
"SELECT COUNT(*) as count FROM installed_extensions"
|
||||
)
|
||||
return int(row["count"]) if row else 0
|
||||
|
||||
|
||||
async def get_user_extension(
|
||||
user_id: str, extension: str, conn: Connection | None = None
|
||||
) -> UserExtension | None:
|
||||
|
||||
@@ -37,13 +37,6 @@ async def create_account(
|
||||
return account
|
||||
|
||||
|
||||
async def get_accounts_count(conn: Connection | None = None) -> int:
|
||||
row: dict | None = await (conn or db).fetchone(
|
||||
"SELECT COUNT(*) as count FROM accounts"
|
||||
)
|
||||
return int(row["count"]) if row else 0
|
||||
|
||||
|
||||
async def update_account(account: Account, conn: Connection | None = None) -> Account:
|
||||
account.updated_at = datetime.now(timezone.utc)
|
||||
await (conn or db).update("accounts", account)
|
||||
|
||||
@@ -9,7 +9,6 @@ from lnbits.core.crud import (
|
||||
delete_installed_extension,
|
||||
get_db_version,
|
||||
get_installed_extension,
|
||||
get_installed_extensions_count,
|
||||
update_installed_extension_state,
|
||||
)
|
||||
from lnbits.core.crud.extensions import (
|
||||
@@ -39,8 +38,6 @@ async def install_extension(
|
||||
if installed_ext and installed_ext.meta:
|
||||
ext_info.meta.payments = installed_ext.meta.payments
|
||||
|
||||
await check_extensions_limit(installed_ext)
|
||||
|
||||
if not skip_download:
|
||||
await ext_info.download_archive()
|
||||
|
||||
@@ -66,15 +63,6 @@ async def install_extension(
|
||||
return extension
|
||||
|
||||
|
||||
async def check_extensions_limit(installed_ext: InstallableExtension | None = None):
|
||||
if settings.lnbits_max_extensions == 0 or installed_ext:
|
||||
return
|
||||
|
||||
extensions_count = await get_installed_extensions_count()
|
||||
if extensions_count >= settings.lnbits_max_extensions:
|
||||
raise ValueError("Max amount of extensions have been installed")
|
||||
|
||||
|
||||
async def uninstall_extension(ext_id: str):
|
||||
await stop_extension_background_work(ext_id)
|
||||
|
||||
|
||||
@@ -23,7 +23,6 @@ from ..crud import (
|
||||
get_account_by_email,
|
||||
get_account_by_pubkey,
|
||||
get_account_by_username,
|
||||
get_accounts_count,
|
||||
get_super_settings,
|
||||
get_user_extensions,
|
||||
get_user_from_account,
|
||||
@@ -56,8 +55,6 @@ async def create_user_account_no_ckeck(
|
||||
conn: Connection | None = None,
|
||||
) -> User:
|
||||
async with db.reuse_conn(conn) if conn else db.connect() as conn:
|
||||
await check_users_limit(conn)
|
||||
|
||||
if account:
|
||||
account.validate_fields()
|
||||
if account.username and await get_account_by_username(
|
||||
@@ -98,15 +95,6 @@ async def create_user_account_no_ckeck(
|
||||
return user
|
||||
|
||||
|
||||
async def check_users_limit(conn: Connection | None = None):
|
||||
if settings.lnbits_max_users == 0:
|
||||
return
|
||||
|
||||
users_count = await get_accounts_count(conn=conn)
|
||||
if users_count >= settings.lnbits_max_users:
|
||||
raise ValueError("Max amount of users have been created")
|
||||
|
||||
|
||||
async def update_user_account(account: Account) -> Account:
|
||||
account.validate_fields()
|
||||
|
||||
|
||||
@@ -98,16 +98,12 @@ async def api_install_extension(data: CreateExtension):
|
||||
ext_info.clean_extension_files()
|
||||
detail = (
|
||||
str(exc)
|
||||
if isinstance(exc, (AssertionError, ValueError))
|
||||
if isinstance(exc, AssertionError)
|
||||
else f"Failed to install extension '{ext_info.id}'."
|
||||
f"({ext_info.installed_version})."
|
||||
)
|
||||
raise HTTPException(
|
||||
status_code=(
|
||||
HTTPStatus.BAD_REQUEST
|
||||
if isinstance(exc, (AssertionError, ValueError))
|
||||
else HTTPStatus.INTERNAL_SERVER_ERROR
|
||||
),
|
||||
status_code=HTTPStatus.INTERNAL_SERVER_ERROR,
|
||||
detail=detail,
|
||||
) from exc
|
||||
|
||||
|
||||
+2
-5
@@ -1007,9 +1007,8 @@ class EnvSettings(LNbitsSettings):
|
||||
debug_database: bool = Field(default=False)
|
||||
bundle_assets: bool = Field(default=True)
|
||||
# When enabled, auth cookies require HTTPS and SSO will reject insecure HTTP.
|
||||
# Keep disabled by default so local HTTP installs continue to work unless
|
||||
# operators explicitly opt into HTTPS-only auth cookies.
|
||||
auth_https_only: bool = Field(default=False)
|
||||
# Set to false for local/dev environments that run without TLS.
|
||||
auth_https_only: bool = Field(default=True)
|
||||
host: str = Field(default="127.0.0.1")
|
||||
port: int = Field(default=5000, gt=0)
|
||||
forwarded_allow_ips: str = Field(default="*")
|
||||
@@ -1027,8 +1026,6 @@ class EnvSettings(LNbitsSettings):
|
||||
|
||||
cleanup_wallets_days: int = Field(default=90, ge=0)
|
||||
funding_source_max_retries: int = Field(default=4, ge=0)
|
||||
lnbits_max_users: int = Field(default=0, ge=0)
|
||||
lnbits_max_extensions: int = Field(default=0, ge=0)
|
||||
|
||||
@property
|
||||
def has_default_extension_path(self) -> bool:
|
||||
|
||||
@@ -75,35 +75,7 @@
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="isSuperUser">
|
||||
<lnbits-admin-funding-sources
|
||||
:form-data="formData"
|
||||
:allowed-funding-sources="settings.lnbits_allowed_funding_sources"
|
||||
/>
|
||||
<div class="row q-col-gutter-md q-my-md">
|
||||
<div class="col-12 col-sm-8">
|
||||
<q-item tag="div">
|
||||
<q-item-section>
|
||||
<q-item-label
|
||||
v-text="$t('funding_source_retries')"
|
||||
></q-item-label>
|
||||
<q-item-label
|
||||
caption
|
||||
v-text="$t('funding_source_retries_desc')"
|
||||
></q-item-label>
|
||||
</q-item-section>
|
||||
<q-item-section>
|
||||
<q-input
|
||||
filled
|
||||
v-model="formData.funding_source_max_retries"
|
||||
type="number"
|
||||
/>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row q-col-gutter-md q-mt-lg">
|
||||
<div class="row q-col-gutter-md">
|
||||
<div class="col-12">
|
||||
<h6 class="q-my-none">
|
||||
<span v-text="$t('routing_fee_reserve_calculations')"></span>
|
||||
@@ -210,6 +182,34 @@
|
||||
></q-input>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="isSuperUser">
|
||||
<lnbits-admin-funding-sources
|
||||
:form-data="formData"
|
||||
:allowed-funding-sources="settings.lnbits_allowed_funding_sources"
|
||||
/>
|
||||
<div class="row q-col-gutter-md q-my-md">
|
||||
<div class="col-12 col-sm-8">
|
||||
<q-item tag="div">
|
||||
<q-item-section>
|
||||
<q-item-label
|
||||
v-text="$t('funding_source_retries')"
|
||||
></q-item-label>
|
||||
<q-item-label
|
||||
caption
|
||||
v-text="$t('funding_source_retries_desc')"
|
||||
></q-item-label>
|
||||
</q-item-section>
|
||||
<q-item-section>
|
||||
<q-input
|
||||
filled
|
||||
v-model="formData.funding_source_max_retries"
|
||||
type="number"
|
||||
/>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<q-separator></q-separator>
|
||||
<h6 class="q-mt-lg q-mb-sm">
|
||||
<p v-text="$t('watchdog')"></p>
|
||||
|
||||
@@ -61,7 +61,6 @@ lnbits-cli = "lnbits.commands:main"
|
||||
breez = ["breez-sdk~=0.8.0", "breez-sdk-liquid~=0.11.11"]
|
||||
liquid = ["wallycore~=1.5.1"]
|
||||
migration = ["psycopg2-binary~=2.9.11"]
|
||||
wasm = ["wasmtime>=43.0.0"]
|
||||
|
||||
[dependency-groups]
|
||||
dev = [
|
||||
|
||||
@@ -135,8 +135,6 @@ async def test_auth_api_first_install_success_and_validation(
|
||||
)
|
||||
assert success.status_code == 200
|
||||
assert success.json()["access_token"]
|
||||
assert "cookie_access_token=" in success.headers["set-cookie"]
|
||||
assert "Secure" not in success.headers["set-cookie"]
|
||||
|
||||
updated_superuser = await get_account(settings.super_user, active_only=False)
|
||||
assert updated_superuser is not None
|
||||
@@ -161,43 +159,3 @@ async def test_auth_api_first_install_success_and_validation(
|
||||
await update_account(restored_superuser)
|
||||
settings.first_install = original_first_install
|
||||
settings.first_install_token = original_first_install_token
|
||||
|
||||
|
||||
@pytest.mark.anyio
|
||||
async def test_auth_api_first_install_uses_secure_cookie_when_enabled(
|
||||
http_client: AsyncClient, settings: Settings
|
||||
):
|
||||
superuser = await get_account(settings.super_user, active_only=False)
|
||||
assert superuser is not None
|
||||
|
||||
original_username = superuser.username
|
||||
original_password_hash = superuser.password_hash
|
||||
original_first_install = settings.first_install
|
||||
original_auth_https_only = settings.auth_https_only
|
||||
|
||||
new_username = f"secure_{uuid4().hex[:8]}"
|
||||
|
||||
try:
|
||||
settings.first_install = True
|
||||
settings.auth_https_only = True
|
||||
|
||||
success = await http_client.put(
|
||||
"/api/v1/auth/first_install",
|
||||
json={
|
||||
"username": new_username,
|
||||
"password": "secret1234",
|
||||
"password_repeat": "secret1234",
|
||||
},
|
||||
)
|
||||
|
||||
assert success.status_code == 200
|
||||
assert "cookie_access_token=" in success.headers["set-cookie"]
|
||||
assert "Secure" in success.headers["set-cookie"]
|
||||
finally:
|
||||
restored_superuser = await get_account(settings.super_user, active_only=False)
|
||||
assert restored_superuser is not None
|
||||
restored_superuser.username = original_username
|
||||
restored_superuser.password_hash = original_password_hash
|
||||
await update_account(restored_superuser)
|
||||
settings.first_install = original_first_install
|
||||
settings.auth_https_only = original_auth_https_only
|
||||
|
||||
+1
-3
@@ -40,9 +40,7 @@ from tests.helpers import (
|
||||
asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())
|
||||
|
||||
ADMIN_USER_ID = uuid4().hex
|
||||
# Snapshot the initialized module settings instead of a fresh Settings() instance.
|
||||
# The module settings include runtime-populated values like `version`.
|
||||
_PURE_SETTINGS = copy.deepcopy(lnbits_settings)
|
||||
_PURE_SETTINGS = Settings()
|
||||
_PURE_SETTINGS_FIELDS = tuple(
|
||||
sorted(
|
||||
{
|
||||
|
||||
+1
-3
@@ -28,7 +28,7 @@ from lnbits.core.models.extensions_builder import (
|
||||
PublicPageFields,
|
||||
SettingsFields,
|
||||
)
|
||||
from lnbits.wallets import get_funding_source, set_funding_source
|
||||
from lnbits.wallets import get_funding_source
|
||||
|
||||
|
||||
class DbTestModel(BaseModel):
|
||||
@@ -182,8 +182,6 @@ def make_lnurl_pay_response(
|
||||
)
|
||||
|
||||
|
||||
set_funding_source()
|
||||
|
||||
funding_source = get_funding_source()
|
||||
is_fake: bool = funding_source.__class__.__name__ == "FakeWallet"
|
||||
is_regtest: bool = not is_fake
|
||||
|
||||
@@ -9,7 +9,15 @@ from loguru import logger
|
||||
from lnbits.wallets import get_funding_source
|
||||
|
||||
funding_source = get_funding_source()
|
||||
is_boltz_wallet = funding_source.__class__.__name__ == "BoltzWallet"
|
||||
|
||||
|
||||
def is_boltz_wallet():
|
||||
print(
|
||||
"### funding_source.__class__.__name__ 2",
|
||||
get_funding_source().__class__.__name__,
|
||||
)
|
||||
return get_funding_source().__class__.__name__ == "BoltzWallet"
|
||||
|
||||
|
||||
docker_lightning_cli = [
|
||||
"docker",
|
||||
|
||||
@@ -21,7 +21,8 @@ async def test_create_invoice(from_wallet):
|
||||
)
|
||||
|
||||
# we cannot know the preimage of the swap yet
|
||||
if not is_boltz_wallet:
|
||||
funding_source = get_funding_source()
|
||||
if not is_boltz_wallet():
|
||||
assert payment.preimage
|
||||
|
||||
invoice = decode(payment.bolt11)
|
||||
@@ -42,7 +43,8 @@ async def test_create_internal_invoice(from_wallet):
|
||||
)
|
||||
|
||||
# we cannot know the preimage of the swap yet
|
||||
if not is_boltz_wallet:
|
||||
funding_source = get_funding_source()
|
||||
if not is_boltz_wallet():
|
||||
assert payment.preimage
|
||||
|
||||
invoice = decode(payment.bolt11)
|
||||
|
||||
@@ -20,7 +20,7 @@ async def test_services_pay_invoice(to_wallet, real_invoice):
|
||||
)
|
||||
assert payment
|
||||
assert payment.memo == description
|
||||
if not is_boltz_wallet:
|
||||
if not is_boltz_wallet():
|
||||
assert payment.status == PaymentState.SUCCESS
|
||||
assert payment.preimage
|
||||
else:
|
||||
|
||||
@@ -252,12 +252,7 @@ async def test_notification_for_internal_payment(
|
||||
assert _payment.bolt11 == payment.bolt11
|
||||
assert _payment.amount == 123_000
|
||||
updated_payment = await get_payment(_payment.checking_id)
|
||||
assert (
|
||||
updated_payment.webhook_status is not None
|
||||
), "Webhook should have been called."
|
||||
assert (
|
||||
int(updated_payment.webhook_status) >= 400
|
||||
), "Webhook should have been called and failed."
|
||||
assert updated_payment.webhook_status == "404"
|
||||
|
||||
|
||||
@pytest.mark.anyio
|
||||
|
||||
@@ -197,7 +197,7 @@ async def test_update_wallet_balance_validates_credit_and_debit(
|
||||
|
||||
settings.lnbits_wallet_limit_max_balance = 0
|
||||
queue_mock = mocker.patch(
|
||||
"lnbits.tasks.internal_invoice_queue_put",
|
||||
"lnbits.core.services.payments.internal_invoice_queue_put",
|
||||
mocker.AsyncMock(),
|
||||
)
|
||||
|
||||
|
||||
@@ -1321,9 +1321,6 @@ liquid = [
|
||||
migration = [
|
||||
{ name = "psycopg2-binary" },
|
||||
]
|
||||
wasm = [
|
||||
{ name = "wasmtime" },
|
||||
]
|
||||
|
||||
[package.dev-dependencies]
|
||||
dev = [
|
||||
@@ -1394,11 +1391,10 @@ requires-dist = [
|
||||
{ name = "uvicorn", specifier = "~=0.40.0" },
|
||||
{ name = "uvloop", specifier = "~=0.22.1" },
|
||||
{ name = "wallycore", marker = "extra == 'liquid'", specifier = "~=1.5.1" },
|
||||
{ name = "wasmtime", marker = "extra == 'wasm'", specifier = ">=43.0.0" },
|
||||
{ name = "websocket-client", specifier = "~=1.9.0" },
|
||||
{ name = "websockets", specifier = "~=15.0.1" },
|
||||
]
|
||||
provides-extras = ["breez", "liquid", "migration", "wasm"]
|
||||
provides-extras = ["breez", "liquid", "migration"]
|
||||
|
||||
[package.metadata.requires-dev]
|
||||
dev = [
|
||||
@@ -2026,11 +2022,11 @@ email = [
|
||||
|
||||
[[package]]
|
||||
name = "pygments"
|
||||
version = "2.20.0"
|
||||
version = "2.19.2"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/c3/b2/bc9c9196916376152d655522fdcebac55e66de6603a76a02bca1b6414f6c/pygments-2.20.0.tar.gz", hash = "sha256:6757cd03768053ff99f3039c1a36d6c0aa0b263438fcab17520b30a303a82b5f", size = 4955991, upload-time = "2026-03-29T13:29:33.898Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/b0/77/a5b8c569bf593b0140bde72ea885a803b82086995367bf2037de0159d924/pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887", size = 4968631, upload-time = "2025-06-21T13:39:12.283Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl", hash = "sha256:81a9e26dd42fd28a23a2d169d86d7ac03b46e2f8b59ed4698fb4785f946d0176", size = 1231151, upload-time = "2026-03-29T13:29:30.038Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2784,25 +2780,6 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/f4/15/38c48fb3319725d946b926090cb3e5fc4dc1fdc15b1fa9fe8474628b6c55/wallycore-1.5.2-cp312-cp312-win_amd64.whl", hash = "sha256:36da969b58cd32f95eba901027595ad35f0326c04c9e5227fa73e0c14203bb4c", size = 1728580, upload-time = "2026-02-02T12:27:01.79Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasmtime"
|
||||
version = "43.0.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/c3/0e/967542865d59d9529bab604b9b88f09a92636e69cc4b1d30c5013e854493/wasmtime-43.0.0.tar.gz", hash = "sha256:eb98b8e2bc35d03dd69c9dd095a388044323622526fc94a9406b8efc48ddc259", size = 117449, upload-time = "2026-03-31T19:26:23.663Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/10/a9/5e598c9ae8791375fa47b0dad377e0030dcd6da1be527a639670c5a3f9d6/wasmtime-43.0.0-py3-none-android_26_arm64_v8a.whl", hash = "sha256:c52d7bd47481958494b6ef9f0ed56d01ba6d7088cc9adbc1414be899b75bc04d", size = 6895231, upload-time = "2026-03-31T19:26:01.774Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/3b/aa/ce764724dcede88f9010963ca7d70d0a79655174599ea85074cb2c656d59/wasmtime-43.0.0-py3-none-android_26_x86_64.whl", hash = "sha256:f65b287290f06751b2c87da3cdb2381b045ac93bc3ee0e3b805c2a6dc5327bc6", size = 7775074, upload-time = "2026-03-31T19:26:04.741Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/2a/ca/67db17c3f098894be798457ce261816fb67c0c1b80c1a53ed1dfa8ed4ff1/wasmtime-43.0.0-py3-none-any.whl", hash = "sha256:9441349d9346230420ed24d357d6f8330fe7251ac5938bb892147728bbe731d7", size = 6472597, upload-time = "2026-03-31T19:26:06.61Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/bf/87/b9727ac8ecf02d2bd9af838fe6004c028034ce3f38215a22f8e94705b83d/wasmtime-43.0.0-py3-none-macosx_10_13_x86_64.whl", hash = "sha256:0ff3815f63122d2f59e58c626aad3c4592f1cabc0b6bd7dcc1edc3890eb46783", size = 7564987, upload-time = "2026-03-31T19:26:08.492Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/08/42/d9588fa6dad9a609e5acaa72d1d5b346b2913f87c2e95d0c7ddadf5e919b/wasmtime-43.0.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:5a03c7aa03519df58fed5115ad8093d6deac46386115add715e725448e89ab25", size = 6615055, upload-time = "2026-03-31T19:26:10.506Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/48/a9/25b27545ad916a169583dbea41a6a03c58fe04c1d05fa39797dc43bd50b9/wasmtime-43.0.0-py3-none-manylinux1_x86_64.whl", hash = "sha256:341542e87caf1f2ef7ff648a78827fcef5751e3e9be2ee07a1fcf3a04413c213", size = 7819110, upload-time = "2026-03-31T19:26:12.335Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d8/9a/4d8760f827931b5b265b83e52316d40b8e0eb999bb8e2d457c2ae172d5cc/wasmtime-43.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:30b042fd4a05d0f8a320baed53fcb971aff8a3789ed6967f4521f87931ace717", size = 6910375, upload-time = "2026-03-31T19:26:14.207Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ce/19/81c748c089a693b102f9a6239f2558a0ffd55fc721fcdd139361aaede1a1/wasmtime-43.0.0-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:34ff18384ad62625cb1438fd0266f6c74b4a72ddcb8ba30c60a66be3632db44b", size = 6938286, upload-time = "2026-03-31T19:26:15.898Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/0f/fa/c37e77c907567a8802696f9ab839b719ea811cf3d59ffc815cc95d894339/wasmtime-43.0.0-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:c7025d477d807df30dad07c9318ea747c6cfc99764c7cb2a8e44e75b8c43e3be", size = 7852033, upload-time = "2026-03-31T19:26:17.915Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/69/67/57c7e361049554cdedd9253e732a6eace5c643488a0e3886ac3f471a4be7/wasmtime-43.0.0-py3-none-win_amd64.whl", hash = "sha256:7e6b0d0641d78012bdf7d3622ca4bc969462dcf1d0a6c147dc5d7aae2f5093a9", size = 6472603, upload-time = "2026-03-31T19:26:19.724Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ec/27/8ecf7dbbb16dc3ab32fcb205f4d798e77cab264118bc1ac52145a76e38fb/wasmtime-43.0.0-py3-none-win_arm64.whl", hash = "sha256:5ddb2ba4b354fc4f055c8ce9285e7bc4cb259c339e5834bb4d0739d644042b8e", size = 5455362, upload-time = "2026-03-31T19:26:21.746Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "websocket-client"
|
||||
version = "1.9.0"
|
||||
|
||||
Reference in New Issue
Block a user