Compare commits

..
Author SHA1 Message Date
Arc 3372f7463a defaults 2025-12-17 00:45:33 +00:00
Arc 3f4fd93858 boltz funding source seed fix
Users should be able to have a seed created or replace with their own
2025-12-17 00:42:39 +00:00
47 changed files with 466 additions and 1506 deletions
-7
View File
@@ -23,10 +23,3 @@ mypy.ini
package-lock.json package-lock.json
package.json package.json
pytest.ini pytest.ini
.mypy_cache
.github
.pytest_cache
.vscode
bin
dist
+3
View File
@@ -18,6 +18,7 @@ ENABLE_LOG_TO_FILE=true
# https://loguru.readthedocs.io/en/stable/api/logger.html#file # https://loguru.readthedocs.io/en/stable/api/logger.html#file
LOG_ROTATION="100 MB" LOG_ROTATION="100 MB"
LOG_RETENTION="3 months" LOG_RETENTION="3 months"
# for database cleanup commands # for database cleanup commands
# CLEANUP_WALLETS_DAYS=90 # CLEANUP_WALLETS_DAYS=90
@@ -186,6 +187,7 @@ BOLTZ_CLIENT_ENDPOINT=127.0.0.1:9002
BOLTZ_CLIENT_MACAROON="/home/bob/.boltz/macaroons/admin.macaroon" BOLTZ_CLIENT_MACAROON="/home/bob/.boltz/macaroons/admin.macaroon"
# HEXSTRING instead of path also possible # HEXSTRING instead of path also possible
BOLTZ_CLIENT_CERT="/home/bob/.boltz/tls.cert" BOLTZ_CLIENT_CERT="/home/bob/.boltz/tls.cert"
BOLTZ_CLIENT_WALLET="lnbits"
# StrikeWallet # StrikeWallet
STRIKE_API_ENDPOINT=https://api.strike.me/v1 STRIKE_API_ENDPOINT=https://api.strike.me/v1
@@ -331,3 +333,4 @@ LNBITS_RESERVE_FEE_PERCENT=1.0
###################################### ######################################
###### Logging and Development ####### ###### Logging and Development #######
###################################### ######################################
+1 -8
View File
@@ -75,14 +75,7 @@ jobs:
strategy: strategy:
matrix: matrix:
python-version: ["3.10"] python-version: ["3.10"]
backend-wallet-class: backend-wallet-class: ["LndRestWallet", "LndWallet", "CoreLightningWallet", "CoreLightningRestWallet", "LNbitsWallet", "EclairWallet"]
- BoltzWallet
- LndRestWallet
- LndWallet
- CoreLightningWallet
- CoreLightningRestWallet
- LNbitsWallet
- EclairWallet
with: with:
custom-pytest: "uv run pytest tests/regtest" custom-pytest: "uv run pytest tests/regtest"
python-version: ${{ matrix.python-version }} python-version: ${{ matrix.python-version }}
-1
View File
@@ -62,4 +62,3 @@ jobs:
platforms: linux/amd64,linux/arm64 platforms: linux/amd64,linux/arm64
cache-from: type=local,src=/tmp/.buildx-cache cache-from: type=local,src=/tmp/.buildx-cache
cache-to: type=local,dest=/tmp/.buildx-cache cache-to: type=local,dest=/tmp/.buildx-cache
build-args: LNBITS_TAG=${{ inputs.tag }}
+2 -4
View File
@@ -40,8 +40,8 @@ jobs:
run: | run: |
git clone https://github.com/lnbits/legend-regtest-enviroment.git docker git clone https://github.com/lnbits/legend-regtest-enviroment.git docker
cd docker cd docker
chmod +x ./start-regtest chmod +x ./tests
./start-regtest ./tests
sudo chmod -R a+rwx . sudo chmod -R a+rwx .
- name: Run pytest - name: Run pytest
@@ -63,8 +63,6 @@ jobs:
LNBITS_ENDPOINT: http://localhost:5001 LNBITS_ENDPOINT: http://localhost:5001
LNBITS_KEY: "d08a3313322a4514af75d488bcc27eee" LNBITS_KEY: "d08a3313322a4514af75d488bcc27eee"
ECLAIR_URL: http://127.0.0.1:8082 ECLAIR_URL: http://127.0.0.1:8082
BOLTZ_CLIENT_ENDPOINT: 127.0.0.1:9002
BOLTZ_MNEMONIC: abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about
LNBITS_MAX_OUTGOING_PAYMENT_AMOUNT_SATS: 1000000000 LNBITS_MAX_OUTGOING_PAYMENT_AMOUNT_SATS: 1000000000
LNBITS_MAX_INCOMING_PAYMENT_AMOUNT_SATS: 1000000000 LNBITS_MAX_INCOMING_PAYMENT_AMOUNT_SATS: 1000000000
ECLAIR_PASS: lnbits ECLAIR_PASS: lnbits
-30
View File
@@ -10,29 +10,7 @@ permissions:
jobs: jobs:
release:
runs-on: ubuntu-24.04
outputs:
upload_url: ${{ steps.get_upload_url.outputs.upload_url }}
steps:
- uses: actions/checkout@v4
- name: Create github pre-release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
tag: ${{ github.ref_name }}
run: |
gh release create "$tag" --prerelease --generate-notes --draft
- id: get_upload_url
name: Get upload url of Github release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
tag: ${{ github.ref_name }}
run: |
upload_url=$(gh release view "$tag" --json uploadUrl -q ".uploadUrl")
echo "upload_url=$upload_url" >> "$GITHUB_OUTPUT"
docker: docker:
if: github.repository == 'lnbits/lnbits'
uses: ./.github/workflows/docker.yml uses: ./.github/workflows/docker.yml
with: with:
tag: ${{ github.ref_name }} tag: ${{ github.ref_name }}
@@ -41,7 +19,6 @@ jobs:
DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }} DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
pypi: pypi:
if: github.repository == 'lnbits/lnbits'
runs-on: ubuntu-24.04 runs-on: ubuntu-24.04
steps: steps:
- name: Install dependencies for building secp256k1 - name: Install dependencies for building secp256k1
@@ -53,10 +30,3 @@ jobs:
uses: JRubics/poetry-publish@v1.15 uses: JRubics/poetry-publish@v1.15
with: with:
pypi_token: ${{ secrets.PYPI_API_KEY }} pypi_token: ${{ secrets.PYPI_API_KEY }}
appimage:
needs: [ release ]
uses: ./.github/workflows/appimage.yml
with:
tag_name: ${{ github.ref_name }}
upload_url: ${{ needs.release.outputs.upload_url }}
+2 -8
View File
@@ -14,7 +14,7 @@ jobs:
release: release:
runs-on: ubuntu-24.04 runs-on: ubuntu-24.04
outputs: outputs:
upload_url: ${{ steps.get_upload_url.outputs.upload_url }} upload_url: ${{ steps.create_release.outputs.upload_url }}
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Create github release - name: Create github release
@@ -23,13 +23,7 @@ jobs:
tag: ${{ github.ref_name }} tag: ${{ github.ref_name }}
run: | run: |
gh release create "$tag" --generate-notes --draft gh release create "$tag" --generate-notes --draft
- id: get_upload_url upload_url=$(gh release view "$tag" --repo "${{ github.repository }}" --json uploadUrl -q ".uploadUrl")
name: Get upload url of Github release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
tag: ${{ github.ref_name }}
run: |
upload_url=$(gh release view "$tag" --json uploadUrl -q ".uploadUrl")
echo "upload_url=$upload_url" >> "$GITHUB_OUTPUT" echo "upload_url=$upload_url" >> "$GITHUB_OUTPUT"
docker: docker:
+2 -3
View File
@@ -1,7 +1,6 @@
ARG LNBITS_TAG=latest
FROM boltz/boltz-client:latest AS boltz FROM boltz/boltz-client:latest AS boltz
FROM lnbits/lnbits:${LNBITS_TAG}
FROM lnbits/lnbits:latest
COPY --from=boltz /bin/boltzd /bin/boltzcli /usr/local/bin/ COPY --from=boltz /bin/boltzd /bin/boltzcli /usr/local/bin/
RUN ls -l /usr/local/bin/boltzd RUN ls -l /usr/local/bin/boltzd
+2 -12
View File
@@ -1,4 +1,3 @@
from datetime import datetime, timezone
from time import time from time import time
from typing import Any from typing import Any
@@ -305,16 +304,8 @@ async def update_payment_checking_id(
checking_id: str, new_checking_id: str, conn: Connection | None = None checking_id: str, new_checking_id: str, conn: Connection | None = None
) -> None: ) -> None:
await (conn or db).execute( await (conn or db).execute(
f""" "UPDATE apipayments SET checking_id = :new_id WHERE checking_id = :old_id",
UPDATE apipayments {"new_id": new_checking_id, "old_id": checking_id},
SET checking_id = :new_id, updated_at = {db.timestamp_placeholder('now')}
WHERE checking_id = :old_id
""", # noqa: S608
{
"new_id": new_checking_id,
"old_id": checking_id,
"now": int(time()),
},
) )
@@ -323,7 +314,6 @@ async def update_payment(
new_checking_id: str | None = None, new_checking_id: str | None = None,
conn: Connection | None = None, conn: Connection | None = None,
) -> None: ) -> None:
payment.updated_at = datetime.now(timezone.utc)
await (conn or db).update( await (conn or db).update(
"apipayments", payment, "WHERE checking_id = :checking_id" "apipayments", payment, "WHERE checking_id = :checking_id"
) )
+5 -10
View File
@@ -45,13 +45,17 @@ async def update_wallet(
async def delete_wallet( async def delete_wallet(
*,
user_id: str, user_id: str,
wallet_id: str, wallet_id: str,
deleted: bool = True, deleted: bool = True,
conn: Connection | None = None, conn: Connection | None = None,
) -> None: ) -> None:
_clear_wallet_cache(wallet_id)
now = int(time()) now = int(time())
cached_wallet: BaseWallet | None = cache.pop(f"auth:wallet:{wallet_id}")
if cached_wallet:
cache.pop(f"auth:x-api-key:{cached_wallet.adminkey}")
cache.pop(f"auth:x-api-key:{cached_wallet.inkey}")
await (conn or db).execute( await (conn or db).execute(
# Timestamp placeholder is safe from SQL injection (not user input) # Timestamp placeholder is safe from SQL injection (not user input)
@@ -65,7 +69,6 @@ async def delete_wallet(
async def force_delete_wallet(wallet_id: str, conn: Connection | None = None) -> None: async def force_delete_wallet(wallet_id: str, conn: Connection | None = None) -> None:
_clear_wallet_cache(wallet_id)
await (conn or db).execute( await (conn or db).execute(
"DELETE FROM wallets WHERE id = :wallet", "DELETE FROM wallets WHERE id = :wallet",
{"wallet": wallet_id}, {"wallet": wallet_id},
@@ -75,7 +78,6 @@ async def force_delete_wallet(wallet_id: str, conn: Connection | None = None) ->
async def delete_wallet_by_id( async def delete_wallet_by_id(
wallet_id: str, conn: Connection | None = None wallet_id: str, conn: Connection | None = None
) -> int | None: ) -> int | None:
_clear_wallet_cache(wallet_id)
now = int(time()) now = int(time())
result = await (conn or db).execute( result = await (conn or db).execute(
# Timestamp placeholder is safe from SQL injection (not user input) # Timestamp placeholder is safe from SQL injection (not user input)
@@ -292,10 +294,3 @@ async def get_total_balance(conn: Connection | None = None):
result = await (conn or db).execute("SELECT SUM(balance) as balance FROM balances") result = await (conn or db).execute("SELECT SUM(balance) as balance FROM balances")
row = result.mappings().first() row = result.mappings().first()
return row.get("balance", 0) or 0 return row.get("balance", 0) or 0
def _clear_wallet_cache(wallet_id):
cached_wallet: BaseWallet | None = cache.pop(f"auth:wallet:{wallet_id}")
if cached_wallet:
cache.pop(f"auth:x-api-key:{cached_wallet.adminkey}")
cache.pop(f"auth:x-api-key:{cached_wallet.inkey}")
+1 -27
View File
@@ -12,7 +12,7 @@ from typing import Any
import httpx import httpx
from loguru import logger from loguru import logger
from pydantic import BaseModel, Field from pydantic import BaseModel
from lnbits.helpers import ( from lnbits.helpers import (
download_url, download_url,
@@ -777,32 +777,6 @@ class ExtensionDetailsRequest(BaseModel):
version: str version: str
class ExtensionReviewsStatus(BaseModel):
tag: str
avg_rating: float
review_count: int
class CreateExtensionReview(BaseModel):
tag: str
name: str | None = Field(None)
rating: int = Field(..., ge=0, le=1000)
comment: str | None = Field(None)
class ExtensionReviewPaymentRequest(BaseModel):
payment_hash: str
payment_request: str
class ExtensionReview(BaseModel):
id: str
name: str | None = Field(default=None)
tag: str | None = Field(default=None)
rating: int = Field(default=0, ge=0, le=1000)
comment: str | None = Field(default=None)
async def github_api_get(url: str, error_msg: str | None) -> Any: async def github_api_get(url: str, error_msg: str | None) -> Any:
headers = {"User-Agent": settings.user_agent} headers = {"User-Agent": settings.user_agent}
if settings.lnbits_ext_github_token: if settings.lnbits_ext_github_token:
+1 -1
View File
@@ -16,7 +16,7 @@ async def create_user_asset(user_id: str, file: UploadFile, is_public: bool) ->
if file.content_type.lower() not in settings.lnbits_assets_allowed_mime_types: if file.content_type.lower() not in settings.lnbits_assets_allowed_mime_types:
raise ValueError(f"File type '{file.content_type}' not allowed.") raise ValueError(f"File type '{file.content_type}' not allowed.")
if not settings.is_unlimited_assets_user(user_id): if user_id not in settings.lnbits_assets_no_limit_users:
user_assets_count = await get_user_assets_count(user_id) user_assets_count = await get_user_assets_count(user_id)
if user_assets_count >= settings.lnbits_max_assets_per_user: if user_assets_count >= settings.lnbits_max_assets_per_user:
raise ValueError( raise ValueError(
+2 -13
View File
@@ -752,7 +752,7 @@ async def _pay_internal_invoice(
await update_payment(internal_payment, conn=conn) await update_payment(internal_payment, conn=conn)
logger.success(f"internal payment successful {internal_payment.checking_id}") logger.success(f"internal payment successful {internal_payment.checking_id}")
await _send_payment_notification_in_background(wallet.id, payment, conn=conn) send_payment_notification_in_background(wallet, payment)
# notify receiver asynchronously # notify receiver asynchronously
from lnbits.tasks import internal_invoice_queue from lnbits.tasks import internal_invoice_queue
@@ -825,8 +825,7 @@ async def _pay_external_invoice(
payment = await update_payment_success_status( payment = await update_payment_success_status(
payment, payment_response, conn=conn payment, payment_response, conn=conn
) )
send_payment_notification_in_background(wallet, payment)
await _send_payment_notification_in_background(wallet.id, payment, conn=conn)
logger.success(f"payment successful {payment_response.checking_id}") logger.success(f"payment successful {payment_response.checking_id}")
payment.checking_id = payment_response.checking_id payment.checking_id = payment_response.checking_id
@@ -1034,13 +1033,3 @@ async def cancel_hold_invoice(payment: Payment) -> InvoiceResponse:
await update_payment(payment) await update_payment(payment)
return response return response
async def _send_payment_notification_in_background(
wallet_id: str, payment: Payment, conn: Connection | None = None
):
# fetch balance again
wallet = await get_wallet(wallet_id, conn=conn)
if not wallet:
raise PaymentError(f"Could not fetch wallet '{wallet_id}'.", status="failed")
send_payment_notification_in_background(wallet, payment)
-53
View File
@@ -2,10 +2,8 @@ import sys
import traceback import traceback
from http import HTTPStatus from http import HTTPStatus
import httpx
from bolt11 import decode as bolt11_decode from bolt11 import decode as bolt11_decode
from fastapi import APIRouter, Depends, HTTPException from fastapi import APIRouter, Depends, HTTPException
from fastapi.requests import Request
from loguru import logger from loguru import logger
from lnbits.core.crud.extensions import get_user_extensions from lnbits.core.crud.extensions import get_user_extensions
@@ -16,14 +14,10 @@ from lnbits.core.models import (
) )
from lnbits.core.models.extensions import ( from lnbits.core.models.extensions import (
CreateExtension, CreateExtension,
CreateExtensionReview,
Extension, Extension,
ExtensionConfig, ExtensionConfig,
ExtensionMeta, ExtensionMeta,
ExtensionRelease, ExtensionRelease,
ExtensionReview,
ExtensionReviewPaymentRequest,
ExtensionReviewsStatus,
InstallableExtension, InstallableExtension,
PayToEnableInfo, PayToEnableInfo,
ReleasePaymentInfo, ReleasePaymentInfo,
@@ -40,7 +34,6 @@ from lnbits.core.services.extensions import (
install_extension, install_extension,
uninstall_extension, uninstall_extension,
) )
from lnbits.db import Page
from lnbits.decorators import ( from lnbits.decorators import (
check_account_exists, check_account_exists,
check_account_id_exists, check_account_id_exists,
@@ -596,49 +589,3 @@ async def extensions(account_id: AccountId = Depends(check_account_id_exists)):
for ext in installable_exts for ext in installable_exts
] ]
return extension_data return extension_data
@extension_router.get(
"/reviews/tags",
dependencies=[Depends(check_account_exists)],
)
async def get_extension_reviews_tags() -> list[ExtensionReviewsStatus]:
async with httpx.AsyncClient() as client:
resp = await client.get(settings.lnbits_extensions_reviews_url + "/tags")
resp.raise_for_status()
data = resp.json()
return [ExtensionReviewsStatus(**item) for item in data]
@extension_router.get(
"/reviews/{ext_id}",
dependencies=[Depends(check_account_exists)],
)
async def get_extension_reviews(ext_id: str, request: Request) -> Page[ExtensionReview]:
async with httpx.AsyncClient() as client:
query_string = str(request.query_params)
resp = await client.get(
settings.lnbits_extensions_reviews_url + f"/reviews/{ext_id}?{query_string}"
)
resp.raise_for_status()
reviews = resp.json()
return Page(
data=[ExtensionReview(**item) for item in reviews["data"]],
total=reviews["total"],
)
@extension_router.put(
"/reviews",
dependencies=[Depends(check_account_exists)],
)
async def create_extension_review(
data: CreateExtensionReview,
) -> ExtensionReviewPaymentRequest:
async with httpx.AsyncClient() as client:
resp = await client.post(
settings.lnbits_extensions_reviews_url + "/reviews", json=data.dict()
)
resp.raise_for_status()
payment_request = resp.json()
return ExtensionReviewPaymentRequest(**payment_request)
+2 -2
View File
@@ -337,7 +337,7 @@ async def api_payment(payment_hash, x_api_key: str | None = Header(None)):
return {"paid": False, "status": "failed"} return {"paid": False, "status": "failed"}
try: try:
payment = await update_pending_payment(payment) status = await payment.check_status()
except Exception: except Exception:
if wallet and wallet.id == payment.wallet_id: if wallet and wallet.id == payment.wallet_id:
return {"paid": False, "details": payment} return {"paid": False, "details": payment}
@@ -346,7 +346,7 @@ async def api_payment(payment_hash, x_api_key: str | None = Header(None)):
if wallet and wallet.id == payment.wallet_id: if wallet and wallet.id == payment.wallet_id:
return { return {
"paid": payment.success, "paid": payment.success,
"status": f"{payment.status!s}", "status": f"{status!s}",
"preimage": payment.preimage, "preimage": payment.preimage,
"details": payment, "details": payment,
} }
+7 -5
View File
@@ -20,7 +20,6 @@ from lnbits.core.crud import (
update_admin_settings, update_admin_settings,
update_wallet, update_wallet,
) )
from lnbits.core.crud.wallets import delete_wallet_by_id
from lnbits.core.models import ( from lnbits.core.models import (
AccountFilters, AccountFilters,
AccountOverview, AccountOverview,
@@ -158,8 +157,11 @@ async def api_users_delete_user(
user_id: str, account: Account = Depends(check_admin) user_id: str, account: Account = Depends(check_admin)
) -> SimpleStatus: ) -> SimpleStatus:
wallets = await get_wallets(user_id, deleted=False) wallets = await get_wallets(user_id, deleted=False)
for wallet in wallets: if len(wallets) > 0:
await delete_wallet_by_id(wallet.id) raise HTTPException(
status_code=HTTPStatus.BAD_REQUEST,
detail="Cannot delete user with wallets.",
)
if user_id == settings.super_user: if user_id == settings.super_user:
raise HTTPException( raise HTTPException(
@@ -222,7 +224,7 @@ async def api_users_toggle_admin(user_id: str) -> SimpleStatus:
@users_router.get("/user/{user_id}/wallet", name="Get wallets for user") @users_router.get("/user/{user_id}/wallet", name="Get wallets for user")
async def api_users_get_user_wallet(user_id: str) -> list[Wallet]: async def api_users_get_user_wallet(user_id: str) -> list[Wallet]:
return await get_wallets(user_id, deleted=None) return await get_wallets(user_id)
@users_router.post("/user/{user_id}/wallet", name="Create a new wallet for user") @users_router.post("/user/{user_id}/wallet", name="Create a new wallet for user")
@@ -245,7 +247,7 @@ async def api_users_create_user_wallet(
"/user/{user_id}/wallet/{wallet}/undelete", name="Reactivate deleted wallet" "/user/{user_id}/wallet/{wallet}/undelete", name="Reactivate deleted wallet"
) )
async def api_users_undelete_user_wallet(user_id: str, wallet: str) -> SimpleStatus: async def api_users_undelete_user_wallet(user_id: str, wallet: str) -> SimpleStatus:
wal = await get_wallet(wallet, deleted=True) wal = await get_wallet(wallet)
if not wal: if not wal:
raise HTTPException( raise HTTPException(
status_code=HTTPStatus.NOT_FOUND, status_code=HTTPStatus.NOT_FOUND,
+1 -1
View File
@@ -249,7 +249,7 @@ async def check_account_id_exists(
account_id = cache.get(cache_key) account_id = cache.get(cache_key)
if account_id: if account_id:
r.scope["user_id"] = account_id.id r.scope["user_id"] = account_id.id
await _check_user_access(r, account_id.id, conn=conn) await _check_user_access(r, account_id, conn=conn)
return account_id return account_id
account = await _check_account_exists(r, access_token, usr, conn=conn) account = await _check_account_exists(r, access_token, usr, conn=conn)
-21
View File
@@ -35,7 +35,6 @@ class StripeTerminalOptions(BaseModel):
capture_method: Literal["automatic", "manual"] = "automatic" capture_method: Literal["automatic", "manual"] = "automatic"
metadata: dict[str, str] = Field(default_factory=dict) metadata: dict[str, str] = Field(default_factory=dict)
reader_id: str | None = None
class StripeCheckoutOptions(BaseModel): class StripeCheckoutOptions(BaseModel):
@@ -296,15 +295,6 @@ class StripeWallet(FiatProvider):
r.raise_for_status() r.raise_for_status()
return r.json() return r.json()
async def _process_terminal_payment_intent(
self, reader_id: str, payment_intent_id: str
) -> None:
data = {"payment_intent": payment_intent_id}
r = await self.client.post(
f"/v1/terminal/readers/{reader_id}/process_payment_intent", data=data
)
r.raise_for_status()
async def _create_checkout_invoice( async def _create_checkout_invoice(
self, self,
amount_cents: int, amount_cents: int,
@@ -388,17 +378,6 @@ class StripeWallet(FiatProvider):
ok=False, ok=False,
error_message="Error: missing PaymentIntent or client_secret", error_message="Error: missing PaymentIntent or client_secret",
) )
if term.reader_id:
try:
await self._process_terminal_payment_intent(term.reader_id, pi_id)
except Exception as exc:
logger.warning(exc)
return FiatInvoiceResponse(
ok=False,
error_message=(
"Error: unable to process PaymentIntent on reader"
),
)
return FiatInvoiceResponse( return FiatInvoiceResponse(
ok=True, checking_id=pi_id, payment_request=client_secret ok=True, checking_id=pi_id, payment_request=client_secret
) )
-1
View File
@@ -107,7 +107,6 @@ def template_renderer(additional_folders: list | None = None) -> Jinja2Templates
"LNBITS_DEFAULT_BGIMAGE": settings.lnbits_default_bgimage, "LNBITS_DEFAULT_BGIMAGE": settings.lnbits_default_bgimage,
"VOIDWALLET": settings.lnbits_backend_wallet_class == "VoidWallet", "VOIDWALLET": settings.lnbits_backend_wallet_class == "VoidWallet",
"WEBPUSH_PUBKEY": settings.lnbits_webpush_pubkey, "WEBPUSH_PUBKEY": settings.lnbits_webpush_pubkey,
"LNBITS_EXTENSIONS_REVIEWS_URL": settings.lnbits_extensions_reviews_url,
"LNBITS_DENOMINATION": settings.lnbits_denomination, "LNBITS_DENOMINATION": settings.lnbits_denomination,
"has_holdinvoice": settings.has_holdinvoice, "has_holdinvoice": settings.has_holdinvoice,
"LNBITS_NOSTR_CONFIGURED": settings.is_nostr_notifications_configured(), "LNBITS_NOSTR_CONFIGURED": settings.is_nostr_notifications_configured(),
+20 -14
View File
@@ -6,6 +6,7 @@ import inspect
import json import json
import os import os
import re import re
import secrets
from datetime import datetime, timezone from datetime import datetime, timezone
from enum import Enum from enum import Enum
from os import path from os import path
@@ -18,6 +19,21 @@ from loguru import logger
from pydantic import BaseModel, BaseSettings, Extra, Field, validator from pydantic import BaseModel, BaseSettings, Extra, Field, validator
def generate_default_boltz_mnemonic() -> str | None:
"""
Generate a BIP39 mnemonic using the bundled embit dependency.
If embit is unavailable at runtime, return None to avoid blocking startup.
"""
try:
from embit import bip39
except Exception as exc: # pragma: no cover - dependency missing at runtime
logger.warning(f"Unable to generate Boltz mnemonic (embit missing): {exc}")
return None
entropy = secrets.token_bytes(16) # 128 bits -> 12-word mnemonic
return bip39.mnemonic_from_bytes(entropy)
def list_parse_fallback(v: str): def list_parse_fallback(v: str):
v = v.replace(" ", "") v = v.replace(" ", "")
if len(v) > 0: if len(v) > 0:
@@ -52,13 +68,6 @@ class ExtensionsSettings(LNbitsSettings):
lnbits_user_default_extensions: list[str] = Field(default=[]) lnbits_user_default_extensions: list[str] = Field(default=[])
lnbits_extensions_deactivate_all: bool = Field(default=False) lnbits_extensions_deactivate_all: bool = Field(default=False)
lnbits_extensions_builder_activate_non_admins: bool = Field(default=False) lnbits_extensions_builder_activate_non_admins: bool = Field(default=False)
lnbits_extensions_reviews_url: str = Field(
default="https://demo.lnbits.com/paidreviews/api/v1/AdFzLjzuKFLsdk4Bcnff6r",
description="""
URL for the paid reviews.
Regular users can view this URL (not secret).
""",
)
lnbits_extensions_manifests: list[str] = Field( lnbits_extensions_manifests: list[str] = Field(
default=[ default=[
"https://raw.githubusercontent.com/lnbits/lnbits-extensions/main/extensions.json" "https://raw.githubusercontent.com/lnbits/lnbits-extensions/main/extensions.json"
@@ -315,12 +324,6 @@ class AssetSettings(LNbitsSettings):
lnbits_max_assets_per_user: int = Field(default=1, ge=0) lnbits_max_assets_per_user: int = Field(default=1, ge=0)
lnbits_assets_no_limit_users: list[str] = Field(default=[]) lnbits_assets_no_limit_users: list[str] = Field(default=[])
def is_unlimited_assets_user(self, user_id: str) -> bool:
return (
settings.is_admin_user(user_id)
or user_id in self.lnbits_assets_no_limit_users
)
class FeeSettings(LNbitsSettings): class FeeSettings(LNbitsSettings):
lnbits_reserve_fee_min: int = Field(default=2000, ge=0) lnbits_reserve_fee_min: int = Field(default=2000, ge=0)
@@ -614,9 +617,12 @@ class BreezLiquidSdkFundingSource(LNbitsSettings):
class BoltzFundingSource(LNbitsSettings): class BoltzFundingSource(LNbitsSettings):
boltz_client_endpoint: str | None = Field(default="127.0.0.1:9002") boltz_client_endpoint: str | None = Field(default="127.0.0.1:9002")
boltz_client_macaroon: str | None = Field(default=None) boltz_client_macaroon: str | None = Field(default=None)
boltz_client_wallet: str | None = Field(default="lnbits")
boltz_client_password: str = Field(default="") boltz_client_password: str = Field(default="")
boltz_client_cert: str | None = Field(default=None) boltz_client_cert: str | None = Field(default=None)
boltz_mnemonic: str | None = Field(default=None) boltz_mnemonic: str | None = Field(
default_factory=generate_default_boltz_mnemonic
)
class StrikeFundingSource(LNbitsSettings): class StrikeFundingSource(LNbitsSettings):
File diff suppressed because one or more lines are too long
+10 -10
View File
File diff suppressed because one or more lines are too long
-19
View File
@@ -187,25 +187,6 @@ window.localisation.en = {
'Only admin accounts can create extensions', 'Only admin accounts can create extensions',
admin_only: 'Admin Only', admin_only: 'Admin Only',
new_version: 'New Version', new_version: 'New Version',
reviews_url: 'Reviews URL',
reviews_url_label: 'Reviews server URL',
reviews_url_hint:
'Full PaidReviews URL including the settings id (e.g. https://example.com/paidreviews/SETTINGS_ID)',
reviews_open: 'View reviews',
reviews_leave: 'Leave a review',
reviews_name: 'Your name',
reviews_comment: 'Your review',
reviews_rating: 'Rating',
reviews_submit: 'Submit review',
reviews_loading: 'Loading reviews...',
reviews_refresh: 'Refresh reviews',
reviews_error_load: 'Could not load reviews',
reviews_url_not_configured: 'Reviews URL not configured',
reviews_pay_invoice: 'Pay invoice',
reviews_invoice_paid: 'Invoice paid',
reviews_invoice_title: 'Pay this invoice to submit your review',
reviews_count: 'Reviews',
no_reviews: 'No reviews yet',
extension_has_free_release: 'Has free releases', extension_has_free_release: 'Has free releases',
extension_has_paid_release: 'Has paid releases', extension_has_paid_release: 'Has paid releases',
extension_depends_on: 'Depends on:', extension_depends_on: 'Depends on:',
+1 -2
View File
@@ -13,8 +13,7 @@ window.LNbits = {
wallets: data.wallets, wallets: data.wallets,
fiat_providers: data.fiat_providers || [], fiat_providers: data.fiat_providers || [],
super_user: data.super_user, super_user: data.super_user,
extra: data.extra ?? {}, extra: data.extra ?? {}
hasPassword: data.has_password ?? false
} }
const mapWallet = this.wallet const mapWallet = this.wallet
obj.wallets = obj.wallets.map(mapWallet).sort((a, b) => { obj.wallets = obj.wallets.map(mapWallet).sort((a, b) => {
+1 -28
View File
@@ -3,34 +3,7 @@ window.app.component(QrcodeVue)
window.app.component('lnbits-extension-rating', { window.app.component('lnbits-extension-rating', {
template: '#lnbits-extension-rating', template: '#lnbits-extension-rating',
name: 'lnbits-extension-rating', name: 'lnbits-extension-rating',
props: { props: ['rating']
rating: {
type: Number,
default: 0
},
count: {
type: Number,
default: null
},
clickable: {
type: Boolean,
default: false
}
},
computed: {
displayRating() {
return Math.round((this.rating || 0) * 2) / 2
},
hasData() {
return this.count !== null && this.count !== undefined
}
},
methods: {
handleClick() {
if (!this.clickable) return
this.$emit('click')
}
}
}) })
window.app.component('lnbits-fsat', { window.app.component('lnbits-fsat', {
@@ -89,14 +89,8 @@ window.app.component('lnbits-admin-funding-sources', {
lnd_rest_cert: 'Certificate', lnd_rest_cert: 'Certificate',
lnd_rest_macaroon: 'Macaroon', lnd_rest_macaroon: 'Macaroon',
lnd_rest_macaroon_encrypted: 'Encrypted Macaroon', lnd_rest_macaroon_encrypted: 'Encrypted Macaroon',
lnd_rest_route_hints: { lnd_rest_route_hints: 'Enable Route Hints',
advanced: true, lnd_rest_allow_self_payment: 'Allow Self Payment'
label: 'Enable Route Hints'
},
lnd_rest_allow_self_payment: {
advanced: true,
label: 'Allow Self Payment'
}
} }
], ],
[ [
@@ -166,27 +160,22 @@ window.app.component('lnbits-admin-funding-sources', {
'BoltzWallet', 'BoltzWallet',
'Boltz', 'Boltz',
{ {
boltz_client_endpoint: { boltz_client_endpoint: 'Endpoint',
label: 'Boltz client endpoint',
value: '127.0.0.1:9002'
},
boltz_client_macaroon: { boltz_client_macaroon: {
label: 'Admin Macaroon path or hex', label: 'Admin Macaroon path or hex',
value: '/home/ubuntu/.boltz/macaroons/admin.macaroon' default: '/home/ubuntu/.boltz/macaroons/admin.macaroon'
}, },
boltz_client_cert: { boltz_client_cert: {
label: 'Certificate path or hex', label: 'Certificate path or hex',
value: '/home/ubuntu/.boltz/tls.cert' default: '/home/ben/.boltz/tls.cert'
}, },
boltz_client_wallet: 'Wallet Name',
boltz_client_password: 'Wallet Password (can be empty)',
boltz_mnemonic: { boltz_mnemonic: {
label: 'Liquid seed phrase', label: 'Liquid mnemonic (copy into greenwallet)',
hint: 'Boltz will fetch once connected, but you can change later (can be opened in a liquid wallet) ',
copy: true, copy: true,
qrcode: true qrcode: true,
}, hint: 'Paste or type your liquid mnemonic'
boltz_client_password: {
label: 'Wallet Password (optional)',
advanced: true
} }
} }
], ],
@@ -1,10 +1,9 @@
window.app.component('lnbits-wallet-extra', { window.app.component('lnbits-wallet-extra', {
template: '#lnbits-wallet-extra', template: '#lnbits-wallet-extra',
mixins: [window.windowMixin],
props: ['chartConfig'], props: ['chartConfig'],
computed: { data() {
exportUrl() { return {}
return `${window.location.origin}/wallet?usr=${this.g.user.id}&wal=${this.g.wallet.id}`
}
}, },
methods: { methods: {
handleSendLnurl(lnurl) { handleSendLnurl(lnurl) {
+23 -234
View File
@@ -26,63 +26,7 @@ window.PageExtensions = {
selectedRelease: null, selectedRelease: null,
uninstallAndDropDb: false, uninstallAndDropDb: false,
maxStars: 5, maxStars: 5,
paylinkWebsocket: null, paylinkWebsocket: null
searchToggle: false,
reviewsUrl: null,
reviewsDialog: {
show: false,
extension: null,
loading: false,
submitting: false,
form: {
name: '',
rating: 0,
comment: ''
},
error: null
},
reviews: [],
reviewsTable: {
loading: false,
columns: [
{
name: 'name',
align: 'left',
label: this.$t('Name'),
field: 'name',
sortable: true
},
{
name: 'comment',
align: 'left',
label: this.$t('Comment'),
field: 'comment'
},
{
name: 'created_at',
align: 'left',
label: this.$t('Date'),
field: 'created_at'
},
{
name: 'rating',
align: 'right',
label: 'Rating',
field: 'rating'
}
],
pagination: {
rowsPerPage: 5,
sortBy: 'created_at',
descending: true,
page: 1
}
},
paymentDialog: {
show: false,
invoice: '',
hash: ''
}
} }
}, },
watch: { watch: {
@@ -127,6 +71,7 @@ window.PageExtensions = {
// the install logic has been triggered one way or another // the install logic has been triggered one way or another
this.unsubscribeFromPaylinkWs() this.unsubscribeFromPaylinkWs()
const extension = this.selectedExtension
this.selectedExtension.inProgress = true this.selectedExtension.inProgress = true
this.showManageExtensionDialog = false this.showManageExtensionDialog = false
release.payment_hash = release.payment_hash =
@@ -141,7 +86,6 @@ window.PageExtensions = {
version: release.version version: release.version
}) })
.then(response => { .then(response => {
this.selectedExtension.inProgress = false
const extension = this.extensions.find( const extension = this.extensions.find(
ext => ext.id === this.selectedExtension.id ext => ext.id === this.selectedExtension.id
) )
@@ -156,7 +100,7 @@ window.PageExtensions = {
}) })
.catch(err => { .catch(err => {
console.warn(err) console.warn(err)
this.selectedExtension.inProgress = false extension.inProgress = false
LNbits.utils.notifyApiError(err) LNbits.utils.notifyApiError(err)
}) })
}, },
@@ -340,7 +284,8 @@ window.PageExtensions = {
try { try {
const {data} = await LNbits.api.request( const {data} = await LNbits.api.request(
'GET', 'GET',
`/api/v1/extension/${extension.id}/releases` `/api/v1/extension/${extension.id}/releases`,
this.g.user.wallets[0].adminkey
) )
this.selectedExtensionRepos = data.reduce((repos, release) => { this.selectedExtensionRepos = data.reduce((repos, release) => {
@@ -378,9 +323,6 @@ window.PageExtensions = {
if (!detailsLink) { if (!detailsLink) {
return return
} }
// keep a reference to the extension so we can show rating stats
this.selectedExtension =
this.extensions.find(ext => ext.id === extId) || this.selectedExtension
this.selectedExtensionDetails = null this.selectedExtensionDetails = null
this.showExtensionDetailsDialog = true this.showExtensionDetailsDialog = true
this.slide = 0 this.slide = 0
@@ -389,7 +331,8 @@ window.PageExtensions = {
try { try {
const {data} = await LNbits.api.request( const {data} = await LNbits.api.request(
'GET', 'GET',
`/api/v1/extension/${extId}/details?details_link=${detailsLink}` `/api/v1/extension/${extId}/details?details_link=${detailsLink}`,
this.g.user.wallets[0].inkey
) )
this.selectedExtensionDetails = data this.selectedExtensionDetails = data
@@ -510,7 +453,7 @@ window.PageExtensions = {
const {data} = await LNbits.api.request( const {data} = await LNbits.api.request(
'PUT', 'PUT',
`/api/v1/extension/${extId}/invoice/install`, `/api/v1/extension/${extId}/invoice/install`,
null, this.g.user.wallets[0].adminkey,
{ {
ext_id: extId, ext_id: extId,
archive: release.archive, archive: release.archive,
@@ -526,7 +469,7 @@ window.PageExtensions = {
const {data} = await LNbits.api.request( const {data} = await LNbits.api.request(
'PUT', 'PUT',
`/api/v1/extension/${extId}/invoice/enable`, `/api/v1/extension/${extId}/invoice/enable`,
null, this.g.user.wallets[0].adminkey,
{ {
amount amount
} }
@@ -617,7 +560,8 @@ window.PageExtensions = {
try { try {
const {data} = await LNbits.api.request( const {data} = await LNbits.api.request(
'GET', 'GET',
`/api/v1/extension/release/${org}/${repo}/${release.version}` `/api/v1/extension/release/${org}/${repo}/${release.version}`,
this.g.user.wallets[0].adminkey
) )
release.loaded = true release.loaded = true
release.is_version_compatible = data.is_version_compatible release.is_version_compatible = data.is_version_compatible
@@ -642,13 +586,18 @@ window.PageExtensions = {
continue continue
} }
ext.inProgress = true ext.inProgress = true
await LNbits.api.request('POST', `/api/v1/extension`, null, { await LNbits.api.request(
ext_id: ext.id, 'POST',
archive: ext.latestRelease.archive, `/api/v1/extension`,
source_repo: ext.latestRelease.source_repo, this.g.user.wallets[0].adminkey,
payment_hash: ext.latestRelease.payment_hash, {
version: ext.latestRelease.version ext_id: ext.id,
}) archive: ext.latestRelease.archive,
source_repo: ext.latestRelease.source_repo,
payment_hash: ext.latestRelease.payment_hash,
version: ext.latestRelease.version
}
)
count++ count++
ext.isAvailable = true ext.isAvailable = true
ext.isInstalled = true ext.isInstalled = true
@@ -673,163 +622,6 @@ window.PageExtensions = {
}) })
this.showUpdateAllDialog = false this.showUpdateAllDialog = false
}, },
formatAvg(raw) {
const val = Number(raw || 0)
return Math.round((val / 2 / 100) * 2) / 2
},
async loadReviewStats() {
if (!this.reviewsUrl) {
console.info('Extension reviews are not configured')
return
}
try {
const {data} = await LNbits.api.request(
'GET',
`/api/v1/extension/reviews/tags`
)
const map = {}
data.forEach(stat => {
map[stat.tag] = stat
})
this.extensions.forEach(ext => {
ext.reviewStats = map[ext.id] || null
})
this.filterExtensions(this.searchTerm, this.tab)
} catch (error) {
console.warn(error)
}
},
async openReviews(extension) {
const targetExtension =
extension ||
(this.selectedExtensionDetails
? this.extensions.find(e => e.id === this.selectedExtensionDetails.id)
: null)
if (!targetExtension) {
return
}
if (!this.reviewsUrl) {
Quasar.Notify.create({
type: 'warning',
message: this.$t('reviews_url_not_configured')
})
return
}
this.reviewsDialog.extension = targetExtension
this.selectedExtension = extension
this.reviewsDialog.show = true
await this.getTagReviews()
},
async getTagReviews(props) {
if (!this.reviewsUrl) {
Quasar.Notify.create({
type: 'warning',
message: this.$t('reviews_url_not_configured')
})
return
}
try {
this.reviewsTable.loading = true
const params = LNbits.utils.prepareFilterQuery(this.reviewsTable, props)
const {data} = await LNbits.api.request(
'GET',
`/api/v1/extension/reviews/${this.selectedExtension.id}?${params}`
)
this.reviews = data.data
this.reviewsTable.pagination.rowsNumber = data.total
} catch (e) {
LNbits.utils.notifyApiError(e)
} finally {
this.reviewsTable.loading = false
}
},
formatReviewDate(val) {
if (!val) return ''
const numeric = Number(val)
if (!Number.isNaN(numeric)) {
return this.utils.formatTimestamp(numeric)
}
return this.utils.formatDate(val)
},
async submitReview() {
if (!this.reviewsDialog.extension || !this.reviewsUrl) {
return
}
this.reviewsDialog.submitting = true
try {
const payload = {
tag: this.reviewsDialog.extension.id,
name: this.reviewsDialog.form.name,
rating: this.reviewsDialog.form.rating * 100,
comment: this.reviewsDialog.form.comment
}
const {data} = await LNbits.api.request(
'PUT',
`/api/v1/extension/reviews`,
null,
payload
)
if (data.payment_request) {
this.openInvoiceDialog(data.payment_request, data.payment_hash)
} else {
Quasar.Notify.create({
type: 'positive',
message: 'Review submitted'
})
this.resetReviewForm()
await this.getTagReviews()
await this.loadReviewStats()
}
} catch (error) {
LNbits.utils.notifyApiError(error)
} finally {
this.reviewsDialog.submitting = false
}
},
openInvoiceDialog(invoice, hash) {
this.paymentDialog.invoice = invoice
this.paymentDialog.hash = hash
this.paymentDialog.show = true
this.listenForPayment(hash)
},
resetReviewForm() {
this.reviewsDialog.form = {
name: '',
rating: 0,
comment: ''
}
this.paymentDialog = {
show: false,
invoice: '',
hash: ''
}
},
listenForPayment(hash) {
try {
const base = new URL(this.reviewsUrl)
base.protocol = base.protocol === 'https:' ? 'wss:' : 'ws:'
base.pathname = `/api/v1/ws/${hash}`
const ws = new WebSocket(base)
ws.addEventListener('message', async () => {
Quasar.Notify.create({
type: 'positive',
message: this.$t('reviews_invoice_paid')
})
this.paymentDialog.show = false
this.resetReviewForm()
setTimeout(async () => {
await this.getTagReviews()
}, 1000)
await this.loadReviewStats()
ws.close()
})
} catch (error) {
console.warn(error)
}
},
async fetchAllExtensions() { async fetchAllExtensions() {
try { try {
const {data} = await LNbits.api.request('GET', `/api/v1/extension/all`) const {data} = await LNbits.api.request('GET', `/api/v1/extension/all`)
@@ -844,7 +636,6 @@ window.PageExtensions = {
async created() { async created() {
this.extensions = await this.fetchAllExtensions() this.extensions = await this.fetchAllExtensions()
this.extbuilderEnabled = this.g.user.admin || this.LNBITS_EXT_BUILDER this.extbuilderEnabled = this.g.user.admin || this.LNBITS_EXT_BUILDER
this.reviewsUrl = this.LNBITS_EXTENSIONS_REVIEWS_URL
if (this.g.user.extensions.length === 0) { if (this.g.user.extensions.length === 0) {
this.tab = 'all' this.tab = 'all'
@@ -861,8 +652,6 @@ window.PageExtensions = {
this.hasNewVersion(ext) this.hasNewVersion(ext)
) )
await this.loadReviewStats()
this.filterExtensions(this.searchTerm, this.tab) this.filterExtensions(this.searchTerm, this.tab)
} }
} }
+5 -26
View File
@@ -561,32 +561,11 @@ include('components/lnbits-error.vue') %}
</template> </template>
<template id="lnbits-extension-rating"> <template id="lnbits-extension-rating">
<div class="row items-center q-gutter-xs" style="margin-bottom: 3px"> <div style="margin-bottom: 3px">
<q-rating <q-rating v-model="rating" size="1.5em" :max="5" color="primary"
:model-value="displayRating" ><q-tooltip>
size="1.4em" <span v-text="$t('extension_rating_soon')"></span> </q-tooltip
:max="5" ></q-rating>
color="primary"
icon="star_border"
icon-selected="star"
icon-half="star_half"
readonly
:class="clickable ? 'cursor-pointer' : ''"
@click="handleClick"
>
<q-tooltip v-if="!hasData">
<span v-text="$t('extension_rating_soon')"></span>
</q-tooltip>
<q-tooltip v-else-if="clickable">
<span v-text="$t('reviews_open')"></span>
</q-tooltip>
</q-rating>
<div
class="text-caption text-grey"
v-if="count !== null && count !== undefined"
>
<span v-text="`(${count})`"></span>
</div>
</div> </div>
</template> </template>
@@ -137,19 +137,6 @@
:hint="$t('extension_builder_manifest_url_hint')" :hint="$t('extension_builder_manifest_url_hint')"
></q-input> ></q-input>
</div> </div>
<div class="col-12 col-md-6">
<p>
<span v-text="$t('reviews_url')"></span>
</p>
<q-input
filled
v-model="formData.lnbits_extensions_reviews_url"
:label="$t('reviews_url_label')"
:hint="$t('reviews_url_hint')"
type="url"
autocomplete="off"
></q-input>
</div>
</div> </div>
</div> </div>
</q-card-section> </q-card-section>
@@ -35,9 +35,7 @@
> >
<div <div
class="row" class="row"
v-for="([key, prop], i) in Object.entries( v-for="([key, prop], i) in Object.entries(fundingSources.get(fund))"
fundingSources.get(fund)
).filter(([, p]) => !p.advanced)"
:key="i" :key="i"
> >
<div class="col-12"> <div class="col-12">
@@ -48,7 +46,7 @@
:type="hideInput ? 'password' : 'text'" :type="hideInput ? 'password' : 'text'"
:label="prop.label" :label="prop.label"
:hint="prop.hint" :hint="prop.hint"
:value="prop.value" :readonly="prop.readonly || false"
> >
<q-btn <q-btn
v-if="prop.copy" v-if="prop.copy"
@@ -71,55 +69,6 @@
</q-input> </q-input>
</div> </div>
</div> </div>
<q-expansion-item
v-if="
Object.entries(fundingSources.get(fund)).some(([, p]) => p.advanced)
"
dense
expand-separator
icon="tune"
label="Advanced"
class="q-mt-sm"
>
<div
class="row"
v-for="([key, prop], i) in Object.entries(
fundingSources.get(fund)
).filter(([, p]) => p.advanced)"
:key="`adv-${i}`"
>
<div class="col-12">
<q-input
v-model="formData[key]"
filled
class="q-mt-sm"
:type="hideInput ? 'password' : 'text'"
:label="prop.label"
:hint="prop.hint"
:readonly="prop.readonly || false"
>
<q-btn
v-if="prop.copy"
@click="utils.copyText(formData[key])"
icon="content_copy"
class="cursor-pointer"
color="grey"
flat
dense
></q-btn>
<q-btn
v-if="prop.qrcode"
@click="showQRValue(formData[key])"
icon="qr_code"
class="cursor-pointer"
color="grey"
flat
dense
></q-btn>
</q-input>
</div>
</div>
</q-expansion-item>
</div> </div>
</q-list> </q-list>
<q-dialog v-model="showQRDialog"> <q-dialog v-model="showQRDialog">
@@ -83,7 +83,9 @@
class="text-center" class="text-center"
v-text="$t('export_to_phone_desc')" v-text="$t('export_to_phone_desc')"
></p> ></p>
<lnbits-qrcode :value="exportUrl"></lnbits-qrcode> <lnbits-qrcode
:value="`${baseUrl}wallet?usr=${g.user.id}&wal=${g.wallet.id}`"
></lnbits-qrcode>
</q-card-section> </q-card-section>
</q-card> </q-card>
</q-expansion-item> </q-expansion-item>
+1 -1
View File
@@ -120,7 +120,7 @@
class="q-mb-md" class="q-mb-md"
></q-input> ></q-input>
<q-input <q-input
v-if="g.user.hasPassword" v-if="g.user.has_password"
v-model="credentialsData.oldPassword" v-model="credentialsData.oldPassword"
type="password" type="password"
autocomplete="off" autocomplete="off"
+3 -234
View File
@@ -15,7 +15,6 @@
<q-space></q-space> <q-space></q-space>
<q-input <q-input
v-if="$q.screen.gt.sm"
:label="$t('search_extensions')" :label="$t('search_extensions')"
:dense="dense" :dense="dense"
class="float-right q-pr-xl" class="float-right q-pr-xl"
@@ -34,14 +33,6 @@
</q-icon> </q-icon>
</template> </template>
</q-input> </q-input>
<q-btn
v-else
flat
icon="search"
@click="searchToggle = !searchToggle"
class="q-mr-md"
>
</q-btn>
<q-badge <q-badge
v-if="g.user.admin && updatableExtensions?.length" v-if="g.user.admin && updatableExtensions?.length"
@click="showUpdateAllDialog = true" @click="showUpdateAllDialog = true"
@@ -77,25 +68,6 @@
><q-tooltip v-text="$t('admin_settings')"></q-tooltip ><q-tooltip v-text="$t('admin_settings')"></q-tooltip
></q-btn> ></q-btn>
</q-tabs> </q-tabs>
<div v-if="$q.screen.lt.sm && searchToggle" class="q-pa-sm">
<q-input
:label="$t('search_extensions')"
dense
class=""
v-model="searchTerm"
autofocus
>
<template v-slot:append>
<q-icon
v-if="searchTerm !== ''"
name="close"
@click="searchTerm = ''"
class="cursor-pointer"
>
</q-icon>
</template>
</q-input>
</div>
</div> </div>
</div> </div>
</q-card> </q-card>
@@ -163,22 +135,7 @@
v-text="extension.name" v-text="extension.name"
></div> ></div>
<div style="justify-content: space-between; display: flex"> <div style="justify-content: space-between; display: flex">
<lnbits-extension-rating <lnbits-extension-rating :rating="0" />
:rating="
formatAvg(
extension.reviewStats
? extension.reviewStats.avg_rating
: 0
)
"
:count="
extension.reviewStats
? extension.reviewStats.review_count
: null
"
:clickable="!!reviewsUrl"
@click="openReviews(extension)"
/>
<q-btn-group size="xs" style="margin: 5px 0"> <q-btn-group size="xs" style="margin: 5px 0">
<q-btn <q-btn
v-if="extension.hasFreeRelease" v-if="extension.hasFreeRelease"
@@ -1013,20 +970,8 @@
</div> </div>
<div class="col-sm-12 col-md-4 q-pl-sm"> <div class="col-sm-12 col-md-4 q-pl-sm">
<lnbits-extension-rating <lnbits-extension-rating
:rating=" :rating="0"
formatAvg( size="2.5em"
selectedExtension && selectedExtension.reviewStats
? selectedExtension.reviewStats.avg_rating
: 0
)
"
:count="
selectedExtension && selectedExtension.reviewStats
? selectedExtension.reviewStats.review_count
: null
"
:clickable="!!reviewsUrl"
@click="openReviews(selectedExtension)"
></lnbits-extension-rating> ></lnbits-extension-rating>
<div class="q-mt-md"> <div class="q-mt-md">
<b> <b>
@@ -1084,182 +1029,6 @@
</q-card-section> </q-card-section>
</q-card> </q-card>
</q-dialog> </q-dialog>
<q-dialog v-model="reviewsDialog.show" position="top">
<q-card
class="q-pa-md lnbits__dialog-card"
style="width: 900px; max-width: 95vw"
>
<q-card-section class="q-gutter-y-sm">
<div class="row items-center">
<div class="col">
<div
class="text-h6"
v-text="
(reviewsDialog.extension && reviewsDialog.extension.name) ||
(reviewsDialog.extension && reviewsDialog.extension.id)
"
></div>
<div
class="text-caption text-grey"
v-text="reviewsDialog.extension && reviewsDialog.extension.id"
></div>
</div>
<div class="col-auto">
<lnbits-extension-rating
:rating="
formatAvg(
reviewsDialog.extension && reviewsDialog.extension.reviewStats
? reviewsDialog.extension.reviewStats.avg_rating
: 0
)
"
:count="
reviewsDialog.extension && reviewsDialog.extension.reviewStats
? reviewsDialog.extension.reviewStats.review_count
: null
"
></lnbits-extension-rating>
</div>
</div>
</q-card-section>
<q-separator></q-separator>
<q-card-section v-if="!reviewsUrl">
<div
class="text-negative"
v-text="$t('reviews_url_not_configured')"
></div>
</q-card-section>
<q-card-section v-else>
<div v-if="reviewsDialog.loading" class="row justify-center q-pa-lg">
<q-spinner-bars color="primary" size="2.55em"></q-spinner-bars>
</div>
<div v-else>
<div v-if="reviewsDialog.error" class="text-negative q-mb-md">
<span v-text="reviewsDialog.error"></span>
</div>
<q-form @submit="submitReview" class="q-gutter-md">
<div class="row q-col-gutter-lg">
<div class="col-12 col-md-6">
<q-input
dense
filled
v-model="reviewsDialog.form.name"
:label="$t('reviews_name')"
></q-input>
</div>
<div class="col-12 col-md-6">
<q-rating
v-model="reviewsDialog.form.rating"
max="10"
icon="star_border"
icon-selected="star"
icon-half="star_half"
color="primary"
class="float-right"
></q-rating>
</div>
<div class="col-12 col-md-6">
<q-input
dense
filled
type="textarea"
autogrow
v-model="reviewsDialog.form.comment"
:label="$t('reviews_comment')"
></q-input>
</div>
<div class="col-12 col-md-6">
<q-btn
type="submit"
color="primary"
class="float-right"
unelevated
:loading="reviewsDialog.submitting"
:disable="!reviewsDialog.form.rating"
:label="$t('reviews_submit')"
></q-btn>
</div>
</div>
</q-form>
<q-separator class="q-my-md"></q-separator>
<div class="row q-col-gutter-lg">
<div class="col-12">
<div v-if="reviews.length === 0" class="text-grey q-mb-md">
<span v-text="$t('no_reviews')"></span>
</div>
<div v-else>
<q-table
:rows="reviews"
:columns="reviewsTable.columns"
v-model:pagination="reviewsTable.pagination"
@request="getTagReviews"
:loading="reviewsTable.loading"
row-key="name"
:filter="reviewsTable.search"
>
<template v-slot:body="props">
<q-tr :props="props">
<q-td key="name" :props="props">
<span v-text="props.row.name"></span>
</q-td>
<q-td key="comment" :props="props">
<span v-text="props.row.comment"></span>
</q-td>
<q-td key="created_at" :props="props">
<span
v-text="formatReviewDate(props.row.created_at)"
></span>
</q-td>
<q-td key="rating" :props="props">
<q-rating
class="float-right q-pt-xs"
readonly
icon="star_border"
icon-selected="star"
icon-half="star_half"
:model-value="formatAvg(props.row.rating)"
size="sm"
color="secondary"
></q-rating>
</q-td>
</q-tr>
</template>
</q-table>
</div>
</div>
</div>
</div>
</q-card-section>
<q-separator v-if="reviews.length"></q-separator>
<q-card-section>
<q-btn
@click="reviewsDialog.show = false"
color="grey"
outline
class="float-right"
:label="$t('close')"
></q-btn>
</q-card-section>
</q-card>
</q-dialog>
<q-dialog v-model="paymentDialog.show" position="top">
<q-card class="q-pa-md lnbits__dialog-card">
<q-card-section>
<q-responsive :ratio="1" class="q-mx-xl q-mb-xl">
<lnbits-qrcode
:value="paymentDialog.invoice"
:options="{width: 800}"
class="rounded-borders"
></lnbits-qrcode>
</q-responsive>
</q-card-section>
<q-card-actions align="between">
<q-btn v-close-popup flat color="grey" :label="$t('close')"></q-btn>
</q-card-actions>
</q-card>
</q-dialog>
<q-dialog v-model="showUpdateAllDialog" position="top"> <q-dialog v-model="showUpdateAllDialog" position="top">
<q-card class="q-pa-md q-pt-md lnbits__dialog-card"> <q-card class="q-pa-md q-pt-md lnbits__dialog-card">
<div class="row"> <div class="row">
+59 -137
View File
@@ -5,7 +5,7 @@ from bolt11.decode import decode
from grpc.aio import AioRpcError from grpc.aio import AioRpcError
from loguru import logger from loguru import logger
from lnbits.helpers import normalize_endpoint, sha256s from lnbits.helpers import normalize_endpoint
from lnbits.settings import settings from lnbits.settings import settings
from lnbits.wallets.boltz_grpc_files import boltzrpc_pb2, boltzrpc_pb2_grpc from lnbits.wallets.boltz_grpc_files import boltzrpc_pb2, boltzrpc_pb2_grpc
from lnbits.wallets.lnd_grpc_files.lightning_pb2_grpc import grpc from lnbits.wallets.lnd_grpc_files.lightning_pb2_grpc import grpc
@@ -38,18 +38,21 @@ class BoltzWallet(Wallet):
raise ValueError( raise ValueError(
"cannot initialize BoltzWallet: missing boltz_client_endpoint" "cannot initialize BoltzWallet: missing boltz_client_endpoint"
) )
if not settings.boltz_client_wallet:
raise ValueError(
"cannot initialize BoltzWallet: missing boltz_client_wallet"
)
self.endpoint = normalize_endpoint( self.endpoint = normalize_endpoint(
settings.boltz_client_endpoint, add_proto=True settings.boltz_client_endpoint, add_proto=True
) )
self.metadata = None
if settings.boltz_client_macaroon: if settings.boltz_client_macaroon:
try: self.metadata = [
macaroon = load_macaroon(settings.boltz_client_macaroon) ("macaroon", load_macaroon(settings.boltz_client_macaroon))
self.metadata = [("macaroon", macaroon)] ]
except Exception as e: else:
logger.error(f"BoltzWallet failed to load macaroon: {e}") self.metadata = None
if settings.boltz_client_cert: if settings.boltz_client_cert:
cert = open(settings.boltz_client_cert, "rb").read() cert = open(settings.boltz_client_cert, "rb").read()
@@ -60,21 +63,31 @@ class BoltzWallet(Wallet):
self.rpc = boltzrpc_pb2_grpc.BoltzStub(channel) self.rpc = boltzrpc_pb2_grpc.BoltzStub(channel)
self.wallet_id = 0 self.wallet_id = 0
self.wallet_name = "lnbits"
self.wallet_ready = False # Auto-create wallet if running in Docker mode
async def _init_boltz_wallet():
try:
wallet_name = settings.boltz_client_wallet or "lnbits"
mnemonic = await self._fetch_wallet(wallet_name)
if mnemonic:
logger.info(
"✅ Mnemonic found for Boltz wallet, saving to settings"
)
settings.boltz_mnemonic = mnemonic
from lnbits.core.crud.settings import set_settings_field
await set_settings_field("boltz_mnemonic", mnemonic)
else:
logger.warning("⚠️ No mnemonic returned from Boltz")
except Exception as e:
logger.error(f"❌ Failed to auto-create Boltz wallet: {e}")
self._init_wallet_task = asyncio.create_task(_init_boltz_wallet())
async def status(self) -> StatusResponse: async def status(self) -> StatusResponse:
if self.wallet_ready is False:
self.wallet_ready = True
if settings.boltz_mnemonic: # restore wallet from mnemonic
await self._restore_boltz_wallet(
settings.boltz_mnemonic,
settings.boltz_client_password,
)
else: # create new wallet
await self._create_boltz_wallet()
try: try:
request = boltzrpc_pb2.GetWalletRequest(name=self.wallet_name) request = boltzrpc_pb2.GetWalletRequest(name=settings.boltz_client_wallet)
response: boltzrpc_pb2.Wallet = await self.rpc.GetWallet( response: boltzrpc_pb2.Wallet = await self.rpc.GetWallet(
request, metadata=self.metadata request, metadata=self.metadata
) )
@@ -113,18 +126,12 @@ class BoltzWallet(Wallet):
try: try:
response = await self.rpc.CreateReverseSwap(request, metadata=self.metadata) response = await self.rpc.CreateReverseSwap(request, metadata=self.metadata)
except AioRpcError as exc: except AioRpcError as exc:
logger.warning(exc)
return InvoiceResponse(ok=False, error_message=exc.details()) return InvoiceResponse(ok=False, error_message=exc.details())
fee_msat = response.routing_fee_milli_sat
return InvoiceResponse( return InvoiceResponse(
ok=True, ok=True, checking_id=response.id, payment_request=response.invoice
checking_id=response.id,
payment_request=response.invoice,
fee_msat=fee_msat,
) )
async def pay_invoice(self, bolt11: str, fee_limit_msat: int) -> PaymentResponse: async def pay_invoice(self, bolt11: str, fee_limit_msat: int) -> PaymentResponse:
pair = boltzrpc_pb2.Pair(**{"from": boltzrpc_pb2.LBTC}) pair = boltzrpc_pb2.Pair(**{"from": boltzrpc_pb2.LBTC})
try: try:
pair_info: boltzrpc_pb2.PairInfo pair_info: boltzrpc_pb2.PairInfo
@@ -136,9 +143,8 @@ class BoltzWallet(Wallet):
if not invoice.amount_msat: if not invoice.amount_msat:
raise ValueError("amountless invoice") raise ValueError("amountless invoice")
service_fee: float = invoice.amount_msat * pair_info.fees.percentage / 100 service_fee: float = invoice.amount_msat * pair_info.fees.percentage / 100
estimate = int(service_fee + pair_info.fees.miner_fees * 1000) estimate = service_fee + pair_info.fees.miner_fees * 1000
if estimate > fee_limit_msat: if estimate > fee_limit_msat:
error = f"fee of {estimate} msat exceeds limit of {fee_limit_msat} msat" error = f"fee of {estimate} msat exceeds limit of {fee_limit_msat} msat"
@@ -160,12 +166,11 @@ class BoltzWallet(Wallet):
if response.id == "": if response.id == "":
# note that there is no way to provide a checking id here, # note that there is no way to provide a checking id here,
# but there is no need since it immediately is considered as successfull # but there is no need since it immediately is considered as successfull
logger.warning( return PaymentResponse(
"Boltz invoice paid directly on liquid network using magic routing" ok=True,
checking_id=response.id,
) )
return PaymentResponse(ok=True, checking_id=invoice.payment_hash)
except AioRpcError as exc: except AioRpcError as exc:
logger.warning(exc)
return PaymentResponse(ok=False, error_message=exc.details()) return PaymentResponse(ok=False, error_message=exc.details())
try: try:
@@ -175,15 +180,10 @@ class BoltzWallet(Wallet):
info_request, metadata=self.metadata info_request, metadata=self.metadata
): ):
if info.swap.state == boltzrpc_pb2.SUCCESSFUL: if info.swap.state == boltzrpc_pb2.SUCCESSFUL:
fee_msat = (info.swap.onchain_fee + info.swap.service_fee) * 1000
logger.debug(
f"Boltz swap successful, status: {info.swap.status}"
f"fee_msat: {fee_msat}"
)
return PaymentResponse( return PaymentResponse(
ok=True, ok=True,
checking_id=invoice.payment_hash, checking_id=response.id,
fee_msat=fee_msat, fee_msat=(info.swap.onchain_fee + info.swap.service_fee) * 1000,
preimage=info.swap.preimage, preimage=info.swap.preimage,
) )
elif info.swap.error != "": elif info.swap.error != "":
@@ -192,29 +192,21 @@ class BoltzWallet(Wallet):
ok=False, error_message="stream stopped unexpectedly" ok=False, error_message="stream stopped unexpectedly"
) )
except AioRpcError as exc: except AioRpcError as exc:
logger.warning(exc)
return PaymentResponse(ok=False, error_message=exc.details()) return PaymentResponse(ok=False, error_message=exc.details())
async def get_invoice_status(self, checking_id: str) -> PaymentStatus: async def get_invoice_status(self, checking_id: str) -> PaymentStatus:
try: try:
request = boltzrpc_pb2.GetSwapInfoRequest(id=checking_id)
response: boltzrpc_pb2.GetSwapInfoResponse = await self.rpc.GetSwapInfo( response: boltzrpc_pb2.GetSwapInfoResponse = await self.rpc.GetSwapInfo(
request, boltzrpc_pb2.GetSwapInfoRequest(id=checking_id), metadata=self.metadata
metadata=self.metadata,
) )
swap = response.reverse_swap swap = response.reverse_swap
except AioRpcError as exc: except AioRpcError:
logger.warning(exc)
return PaymentPendingStatus() return PaymentPendingStatus()
if swap.state == boltzrpc_pb2.SwapState.SUCCESSFUL: if swap.state == boltzrpc_pb2.SwapState.SUCCESSFUL:
fee_msat = (
swap.service_fee + swap.onchain_fee
) * 1000 + swap.routing_fee_msat
logger.debug(
f"Boltz swap successful, status: {swap.status}, fee_msat: {fee_msat}"
)
return PaymentSuccessStatus( return PaymentSuccessStatus(
fee_msat=fee_msat, fee_msat=(
(swap.service_fee + swap.onchain_fee) * 1000 + swap.routing_fee_msat
),
preimage=swap.preimage, preimage=swap.preimage,
) )
elif swap.state == boltzrpc_pb2.SwapState.PENDING: elif swap.state == boltzrpc_pb2.SwapState.PENDING:
@@ -224,23 +216,18 @@ class BoltzWallet(Wallet):
async def get_payment_status(self, checking_id: str) -> PaymentStatus: async def get_payment_status(self, checking_id: str) -> PaymentStatus:
try: try:
checking_id_bytes = bytes.fromhex(checking_id)
request = boltzrpc_pb2.GetSwapInfoRequest(payment_hash=checking_id_bytes)
response: boltzrpc_pb2.GetSwapInfoResponse = await self.rpc.GetSwapInfo( response: boltzrpc_pb2.GetSwapInfoResponse = await self.rpc.GetSwapInfo(
request, boltzrpc_pb2.GetSwapInfoRequest(
payment_hash=bytes.fromhex(checking_id)
),
metadata=self.metadata, metadata=self.metadata,
) )
swap = response.swap swap = response.swap
except AioRpcError as exc: except AioRpcError:
logger.warning(exc)
return PaymentPendingStatus() return PaymentPendingStatus()
if swap.state == boltzrpc_pb2.SwapState.SUCCESSFUL: if swap.state == boltzrpc_pb2.SwapState.SUCCESSFUL:
fee_msat = (swap.service_fee + swap.onchain_fee) * 1000
logger.debug(
f"Boltz swap successful, status: {swap.status}, fee_msat: {fee_msat}"
)
return PaymentSuccessStatus( return PaymentSuccessStatus(
fee_msat=fee_msat, fee_msat=(swap.service_fee + swap.onchain_fee) * 1000,
preimage=swap.preimage, preimage=swap.preimage,
) )
elif swap.state == boltzrpc_pb2.SwapState.PENDING: elif swap.state == boltzrpc_pb2.SwapState.PENDING:
@@ -257,16 +244,7 @@ class BoltzWallet(Wallet):
request, metadata=self.metadata request, metadata=self.metadata
): ):
reverse = info.reverse_swap reverse = info.reverse_swap
if ( if reverse and reverse.state == boltzrpc_pb2.SUCCESSFUL:
reverse
and reverse.state == boltzrpc_pb2.SUCCESSFUL
and reverse.status == "invoice.settled"
):
fee_msat = ((reverse.service_fee + reverse.onchain_fee) * 1000,)
logger.debug(
f"Boltz reverse swap settled: {reverse.id}, "
f"fee_msat: {fee_msat}"
)
yield reverse.id yield reverse.id
except Exception as exc: except Exception as exc:
logger.error( logger.error(
@@ -275,80 +253,24 @@ class BoltzWallet(Wallet):
) )
await asyncio.sleep(5) await asyncio.sleep(5)
async def _check_wallet_exists( async def _fetch_wallet(self, wallet_name: str) -> str | None:
self, wallet_name: str
) -> boltzrpc_pb2.Wallet | None:
try: try:
request = boltzrpc_pb2.GetWalletRequest(name=wallet_name) request = boltzrpc_pb2.GetWalletRequest(name=wallet_name)
response = await self.rpc.GetWallet(request, metadata=self.metadata) response = await self.rpc.GetWallet(request, metadata=self.metadata)
return response logger.info(f"Wallet '{wallet_name}' already exists with ID {response.id}")
except AioRpcError: return settings.boltz_mnemonic
return None except AioRpcError as exc:
details = exc.details() or "unknown error"
if exc.code() != grpc.StatusCode.NOT_FOUND:
logger.error(f"Error checking wallet existence: {details}")
raise
async def _delete_wallet(self, wallet_id: int) -> None:
logger.info(f"Deleting wallet '{wallet_id}'")
delete_request = boltzrpc_pb2.RemoveWalletRequest(id=wallet_id)
await self.rpc.RemoveWallet(delete_request, metadata=self.metadata)
async def _restore_wallet(self, wallet_name: str, mnemonic: str, password: str):
logger.info(f"Restoring wallet '{wallet_name}' from mnemonic")
credentials = boltzrpc_pb2.WalletCredentials(mnemonic=mnemonic)
params = boltzrpc_pb2.WalletParams(
name=wallet_name,
currency=boltzrpc_pb2.LBTC,
password=password,
)
restore_request = boltzrpc_pb2.ImportWalletRequest(
credentials=credentials, params=params
)
response = await self.rpc.ImportWallet(restore_request, metadata=self.metadata)
return response
async def _create_wallet(self, wallet_name: str, password: str) -> str:
logger.info(f"Creating new wallet '{wallet_name}'") logger.info(f"Creating new wallet '{wallet_name}'")
params = boltzrpc_pb2.WalletParams( params = boltzrpc_pb2.WalletParams(
name=wallet_name, name=wallet_name,
currency=boltzrpc_pb2.LBTC, currency=boltzrpc_pb2.LBTC,
password=password, password=settings.boltz_client_password,
) )
create_request = boltzrpc_pb2.CreateWalletRequest(params=params) create_request = boltzrpc_pb2.CreateWalletRequest(params=params)
response = await self.rpc.CreateWallet(create_request, metadata=self.metadata) response = await self.rpc.CreateWallet(create_request, metadata=self.metadata)
return response.mnemonic return response.mnemonic
async def _restore_boltz_wallet(self, mnemonic: str, password: str):
try:
# delete the wallet with to name without hashing first if it exists
wallet = await self._check_wallet_exists(self.wallet_name)
if wallet:
await self._delete_wallet(wallet.id)
# recreate the wallet with the hashed name
self.wallet_name = sha256s(mnemonic + password)
wallet = await self._check_wallet_exists(self.wallet_name)
if wallet:
logger.success("✅ Boltz wallet exists.")
return
await self._restore_wallet(self.wallet_name, mnemonic, password)
logger.success("✅ Boltz wallet restored from existing mnemonic")
except Exception as e:
logger.error(f"❌ Failed to restore Boltz wallet: {e}")
async def _create_boltz_wallet(self):
try:
# delete the wallet with to name without hashing first if it exists
wallet = await self._check_wallet_exists(self.wallet_name)
if wallet:
await self._delete_wallet(wallet.id)
logger.info("No Mnemonic found for Boltz wallet, creating wallet...")
mnemonic = await self._create_wallet(
self.wallet_name, settings.boltz_client_password
)
logger.success("✅ Boltz wallet created successfully")
settings.boltz_mnemonic = mnemonic
from lnbits.core.crud.settings import set_settings_field
await set_settings_field("boltz_mnemonic", mnemonic)
except Exception as e:
logger.error(f"❌ Failed to create Boltz wallet: {e}")
+1 -1
View File
@@ -178,7 +178,7 @@ class LndRestWallet(Wallet):
"no_inflight_updates": True, "no_inflight_updates": True,
} }
if settings.lnd_rest_allow_self_payment: if settings.lnd_rest_allow_self_payment:
req["allow_self_payment"] = True req["allow_self_payment"] = 1
try: try:
r = await self.client.post( r = await self.client.post(
Generated
+199 -222
View File
@@ -14,132 +14,98 @@ files = [
[[package]] [[package]]
name = "aiohttp" name = "aiohttp"
version = "3.13.3" version = "3.12.15"
description = "Async http client/server framework (asyncio)" description = "Async http client/server framework (asyncio)"
optional = false optional = false
python-versions = ">=3.9" python-versions = ">=3.9"
groups = ["main"] groups = ["main"]
files = [ files = [
{file = "aiohttp-3.13.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d5a372fd5afd301b3a89582817fdcdb6c34124787c70dbcc616f259013e7eef7"}, {file = "aiohttp-3.12.15-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b6fc902bff74d9b1879ad55f5404153e2b33a82e72a95c89cec5eb6cc9e92fbc"},
{file = "aiohttp-3.13.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:147e422fd1223005c22b4fe080f5d93ced44460f5f9c105406b753612b587821"}, {file = "aiohttp-3.12.15-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:098e92835b8119b54c693f2f88a1dec690e20798ca5f5fe5f0520245253ee0af"},
{file = "aiohttp-3.13.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:859bd3f2156e81dd01432f5849fc73e2243d4a487c4fd26609b1299534ee1845"}, {file = "aiohttp-3.12.15-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:40b3fee496a47c3b4a39a731954c06f0bd9bd3e8258c059a4beb76ac23f8e421"},
{file = "aiohttp-3.13.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:dca68018bf48c251ba17c72ed479f4dafe9dbd5a73707ad8d28a38d11f3d42af"}, {file = "aiohttp-3.12.15-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2ce13fcfb0bb2f259fb42106cdc63fa5515fb85b7e87177267d89a771a660b79"},
{file = "aiohttp-3.13.3-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:fee0c6bc7db1de362252affec009707a17478a00ec69f797d23ca256e36d5940"}, {file = "aiohttp-3.12.15-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3beb14f053222b391bf9cf92ae82e0171067cc9c8f52453a0f1ec7c37df12a77"},
{file = "aiohttp-3.13.3-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c048058117fd649334d81b4b526e94bde3ccaddb20463a815ced6ecbb7d11160"}, {file = "aiohttp-3.12.15-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4c39e87afe48aa3e814cac5f535bc6199180a53e38d3f51c5e2530f5aa4ec58c"},
{file = "aiohttp-3.13.3-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:215a685b6fbbfcf71dfe96e3eba7a6f58f10da1dfdf4889c7dd856abe430dca7"}, {file = "aiohttp-3.12.15-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d5f1b4ce5bc528a6ee38dbf5f39bbf11dd127048726323b72b8e85769319ffc4"},
{file = "aiohttp-3.13.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:de2c184bb1fe2cbd2cefba613e9db29a5ab559323f994b6737e370d3da0ac455"}, {file = "aiohttp-3.12.15-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1004e67962efabbaf3f03b11b4c43b834081c9e3f9b32b16a7d97d4708a9abe6"},
{file = "aiohttp-3.13.3-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:75ca857eba4e20ce9f546cd59c7007b33906a4cd48f2ff6ccf1ccfc3b646f279"}, {file = "aiohttp-3.12.15-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8faa08fcc2e411f7ab91d1541d9d597d3a90e9004180edb2072238c085eac8c2"},
{file = "aiohttp-3.13.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:81e97251d9298386c2b7dbeb490d3d1badbdc69107fb8c9299dd04eb39bddc0e"}, {file = "aiohttp-3.12.15-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:fe086edf38b2222328cdf89af0dde2439ee173b8ad7cb659b4e4c6f385b2be3d"},
{file = "aiohttp-3.13.3-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:c0e2d366af265797506f0283487223146af57815b388623f0357ef7eac9b209d"}, {file = "aiohttp-3.12.15-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:79b26fe467219add81d5e47b4a4ba0f2394e8b7c7c3198ed36609f9ba161aecb"},
{file = "aiohttp-3.13.3-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:4e239d501f73d6db1522599e14b9b321a7e3b1de66ce33d53a765d975e9f4808"}, {file = "aiohttp-3.12.15-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:b761bac1192ef24e16706d761aefcb581438b34b13a2f069a6d343ec8fb693a5"},
{file = "aiohttp-3.13.3-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:0db318f7a6f065d84cb1e02662c526294450b314a02bd9e2a8e67f0d8564ce40"}, {file = "aiohttp-3.12.15-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:e153e8adacfe2af562861b72f8bc47f8a5c08e010ac94eebbe33dc21d677cd5b"},
{file = "aiohttp-3.13.3-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:bfc1cc2fe31a6026a8a88e4ecfb98d7f6b1fec150cfd708adbfd1d2f42257c29"}, {file = "aiohttp-3.12.15-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:fc49c4de44977aa8601a00edbf157e9a421f227aa7eb477d9e3df48343311065"},
{file = "aiohttp-3.13.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:af71fff7bac6bb7508956696dce8f6eec2bbb045eceb40343944b1ae62b5ef11"}, {file = "aiohttp-3.12.15-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:2776c7ec89c54a47029940177e75c8c07c29c66f73464784971d6a81904ce9d1"},
{file = "aiohttp-3.13.3-cp310-cp310-win32.whl", hash = "sha256:37da61e244d1749798c151421602884db5270faf479cf0ef03af0ff68954c9dd"}, {file = "aiohttp-3.12.15-cp310-cp310-win32.whl", hash = "sha256:2c7d81a277fa78b2203ab626ced1487420e8c11a8e373707ab72d189fcdad20a"},
{file = "aiohttp-3.13.3-cp310-cp310-win_amd64.whl", hash = "sha256:7e63f210bc1b57ef699035f2b4b6d9ce096b5914414a49b0997c839b2bd2223c"}, {file = "aiohttp-3.12.15-cp310-cp310-win_amd64.whl", hash = "sha256:83603f881e11f0f710f8e2327817c82e79431ec976448839f3cd05d7afe8f830"},
{file = "aiohttp-3.13.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:5b6073099fb654e0a068ae678b10feff95c5cae95bbfcbfa7af669d361a8aa6b"}, {file = "aiohttp-3.12.15-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:d3ce17ce0220383a0f9ea07175eeaa6aa13ae5a41f30bc61d84df17f0e9b1117"},
{file = "aiohttp-3.13.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1cb93e166e6c28716c8c6aeb5f99dfb6d5ccf482d29fe9bf9a794110e6d0ab64"}, {file = "aiohttp-3.12.15-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:010cc9bbd06db80fe234d9003f67e97a10fe003bfbedb40da7d71c1008eda0fe"},
{file = "aiohttp-3.13.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:28e027cf2f6b641693a09f631759b4d9ce9165099d2b5d92af9bd4e197690eea"}, {file = "aiohttp-3.12.15-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3f9d7c55b41ed687b9d7165b17672340187f87a773c98236c987f08c858145a9"},
{file = "aiohttp-3.13.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3b61b7169ababd7802f9568ed96142616a9118dd2be0d1866e920e77ec8fa92a"}, {file = "aiohttp-3.12.15-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bc4fbc61bb3548d3b482f9ac7ddd0f18c67e4225aaa4e8552b9f1ac7e6bda9e5"},
{file = "aiohttp-3.13.3-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:80dd4c21b0f6237676449c6baaa1039abae86b91636b6c91a7f8e61c87f89540"}, {file = "aiohttp-3.12.15-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:7fbc8a7c410bb3ad5d595bb7118147dfbb6449d862cc1125cf8867cb337e8728"},
{file = "aiohttp-3.13.3-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:65d2ccb7eabee90ce0503c17716fc77226be026dcc3e65cce859a30db715025b"}, {file = "aiohttp-3.12.15-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:74dad41b3458dbb0511e760fb355bb0b6689e0630de8a22b1b62a98777136e16"},
{file = "aiohttp-3.13.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5b179331a481cb5529fca8b432d8d3c7001cb217513c94cd72d668d1248688a3"}, {file = "aiohttp-3.12.15-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3b6f0af863cf17e6222b1735a756d664159e58855da99cfe965134a3ff63b0b0"},
{file = "aiohttp-3.13.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9d4c940f02f49483b18b079d1c27ab948721852b281f8b015c058100e9421dd1"}, {file = "aiohttp-3.12.15-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b5b7fe4972d48a4da367043b8e023fb70a04d1490aa7d68800e465d1b97e493b"},
{file = "aiohttp-3.13.3-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f9444f105664c4ce47a2a7171a2418bce5b7bae45fb610f4e2c36045d85911d3"}, {file = "aiohttp-3.12.15-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6443cca89553b7a5485331bc9bedb2342b08d073fa10b8c7d1c60579c4a7b9bd"},
{file = "aiohttp-3.13.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:694976222c711d1d00ba131904beb60534f93966562f64440d0c9d41b8cdb440"}, {file = "aiohttp-3.12.15-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6c5f40ec615e5264f44b4282ee27628cea221fcad52f27405b80abb346d9f3f8"},
{file = "aiohttp-3.13.3-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:f33ed1a2bf1997a36661874b017f5c4b760f41266341af36febaf271d179f6d7"}, {file = "aiohttp-3.12.15-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:2abbb216a1d3a2fe86dbd2edce20cdc5e9ad0be6378455b05ec7f77361b3ab50"},
{file = "aiohttp-3.13.3-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:e636b3c5f61da31a92bf0d91da83e58fdfa96f178ba682f11d24f31944cdd28c"}, {file = "aiohttp-3.12.15-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:db71ce547012a5420a39c1b744d485cfb823564d01d5d20805977f5ea1345676"},
{file = "aiohttp-3.13.3-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:5d2d94f1f5fcbe40838ac51a6ab5704a6f9ea42e72ceda48de5e6b898521da51"}, {file = "aiohttp-3.12.15-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:ced339d7c9b5030abad5854aa5413a77565e5b6e6248ff927d3e174baf3badf7"},
{file = "aiohttp-3.13.3-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:2be0e9ccf23e8a94f6f0650ce06042cefc6ac703d0d7ab6c7a917289f2539ad4"}, {file = "aiohttp-3.12.15-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:7c7dd29c7b5bda137464dc9bfc738d7ceea46ff70309859ffde8c022e9b08ba7"},
{file = "aiohttp-3.13.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9af5e68ee47d6534d36791bbe9b646d2a7c7deb6fc24d7943628edfbb3581f29"}, {file = "aiohttp-3.12.15-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:421da6fd326460517873274875c6c5a18ff225b40da2616083c5a34a7570b685"},
{file = "aiohttp-3.13.3-cp311-cp311-win32.whl", hash = "sha256:a2212ad43c0833a873d0fb3c63fa1bacedd4cf6af2fee62bf4b739ceec3ab239"}, {file = "aiohttp-3.12.15-cp311-cp311-win32.whl", hash = "sha256:4420cf9d179ec8dfe4be10e7d0fe47d6d606485512ea2265b0d8c5113372771b"},
{file = "aiohttp-3.13.3-cp311-cp311-win_amd64.whl", hash = "sha256:642f752c3eb117b105acbd87e2c143de710987e09860d674e068c4c2c441034f"}, {file = "aiohttp-3.12.15-cp311-cp311-win_amd64.whl", hash = "sha256:edd533a07da85baa4b423ee8839e3e91681c7bfa19b04260a469ee94b778bf6d"},
{file = "aiohttp-3.13.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:b903a4dfee7d347e2d87697d0713be59e0b87925be030c9178c5faa58ea58d5c"}, {file = "aiohttp-3.12.15-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:802d3868f5776e28f7bf69d349c26fc0efadb81676d0afa88ed00d98a26340b7"},
{file = "aiohttp-3.13.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:a45530014d7a1e09f4a55f4f43097ba0fd155089372e105e4bff4ca76cb1b168"}, {file = "aiohttp-3.12.15-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f2800614cd560287be05e33a679638e586a2d7401f4ddf99e304d98878c29444"},
{file = "aiohttp-3.13.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:27234ef6d85c914f9efeb77ff616dbf4ad2380be0cda40b4db086ffc7ddd1b7d"}, {file = "aiohttp-3.12.15-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8466151554b593909d30a0a125d638b4e5f3836e5aecde85b66b80ded1cb5b0d"},
{file = "aiohttp-3.13.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d32764c6c9aafb7fb55366a224756387cd50bfa720f32b88e0e6fa45b27dcf29"}, {file = "aiohttp-3.12.15-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2e5a495cb1be69dae4b08f35a6c4579c539e9b5706f606632102c0f855bcba7c"},
{file = "aiohttp-3.13.3-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:b1a6102b4d3ebc07dad44fbf07b45bb600300f15b552ddf1851b5390202ea2e3"}, {file = "aiohttp-3.12.15-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:6404dfc8cdde35c69aaa489bb3542fb86ef215fc70277c892be8af540e5e21c0"},
{file = "aiohttp-3.13.3-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c014c7ea7fb775dd015b2d3137378b7be0249a448a1612268b5a90c2d81de04d"}, {file = "aiohttp-3.12.15-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3ead1c00f8521a5c9070fcb88f02967b1d8a0544e6d85c253f6968b785e1a2ab"},
{file = "aiohttp-3.13.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2b8d8ddba8f95ba17582226f80e2de99c7a7948e66490ef8d947e272a93e9463"}, {file = "aiohttp-3.12.15-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6990ef617f14450bc6b34941dba4f12d5613cbf4e33805932f853fbd1cf18bfb"},
{file = "aiohttp-3.13.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9ae8dd55c8e6c4257eae3a20fd2c8f41edaea5992ed67156642493b8daf3cecc"}, {file = "aiohttp-3.12.15-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd736ed420f4db2b8148b52b46b88ed038d0354255f9a73196b7bbce3ea97545"},
{file = "aiohttp-3.13.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:01ad2529d4b5035578f5081606a465f3b814c542882804e2e8cda61adf5c71bf"}, {file = "aiohttp-3.12.15-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3c5092ce14361a73086b90c6efb3948ffa5be2f5b6fbcf52e8d8c8b8848bb97c"},
{file = "aiohttp-3.13.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:bb4f7475e359992b580559e008c598091c45b5088f28614e855e42d39c2f1033"}, {file = "aiohttp-3.12.15-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:aaa2234bb60c4dbf82893e934d8ee8dea30446f0647e024074237a56a08c01bd"},
{file = "aiohttp-3.13.3-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:c19b90316ad3b24c69cd78d5c9b4f3aa4497643685901185b65166293d36a00f"}, {file = "aiohttp-3.12.15-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:6d86a2fbdd14192e2f234a92d3b494dd4457e683ba07e5905a0b3ee25389ac9f"},
{file = "aiohttp-3.13.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:96d604498a7c782cb15a51c406acaea70d8c027ee6b90c569baa6e7b93073679"}, {file = "aiohttp-3.12.15-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a041e7e2612041a6ddf1c6a33b883be6a421247c7afd47e885969ee4cc58bd8d"},
{file = "aiohttp-3.13.3-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:084911a532763e9d3dd95adf78a78f4096cd5f58cdc18e6fdbc1b58417a45423"}, {file = "aiohttp-3.12.15-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:5015082477abeafad7203757ae44299a610e89ee82a1503e3d4184e6bafdd519"},
{file = "aiohttp-3.13.3-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:7a4a94eb787e606d0a09404b9c38c113d3b099d508021faa615d70a0131907ce"}, {file = "aiohttp-3.12.15-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:56822ff5ddfd1b745534e658faba944012346184fbfe732e0d6134b744516eea"},
{file = "aiohttp-3.13.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:87797e645d9d8e222e04160ee32aa06bc5c163e8499f24db719e7852ec23093a"}, {file = "aiohttp-3.12.15-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b2acbbfff69019d9014508c4ba0401822e8bae5a5fdc3b6814285b71231b60f3"},
{file = "aiohttp-3.13.3-cp312-cp312-win32.whl", hash = "sha256:b04be762396457bef43f3597c991e192ee7da460a4953d7e647ee4b1c28e7046"}, {file = "aiohttp-3.12.15-cp312-cp312-win32.whl", hash = "sha256:d849b0901b50f2185874b9a232f38e26b9b3d4810095a7572eacea939132d4e1"},
{file = "aiohttp-3.13.3-cp312-cp312-win_amd64.whl", hash = "sha256:e3531d63d3bdfa7e3ac5e9b27b2dd7ec9df3206a98e0b3445fa906f233264c57"}, {file = "aiohttp-3.12.15-cp312-cp312-win_amd64.whl", hash = "sha256:b390ef5f62bb508a9d67cb3bba9b8356e23b3996da7062f1a57ce1a79d2b3d34"},
{file = "aiohttp-3.13.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:5dff64413671b0d3e7d5918ea490bdccb97a4ad29b3f311ed423200b2203e01c"}, {file = "aiohttp-3.12.15-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:9f922ffd05034d439dde1c77a20461cf4a1b0831e6caa26151fe7aa8aaebc315"},
{file = "aiohttp-3.13.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:87b9aab6d6ed88235aa2970294f496ff1a1f9adcd724d800e9b952395a80ffd9"}, {file = "aiohttp-3.12.15-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:2ee8a8ac39ce45f3e55663891d4b1d15598c157b4d494a4613e704c8b43112cd"},
{file = "aiohttp-3.13.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:425c126c0dc43861e22cb1c14ba4c8e45d09516d0a3ae0a3f7494b79f5f233a3"}, {file = "aiohttp-3.12.15-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3eae49032c29d356b94eee45a3f39fdf4b0814b397638c2f718e96cfadf4c4e4"},
{file = "aiohttp-3.13.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7f9120f7093c2a32d9647abcaf21e6ad275b4fbec5b55969f978b1a97c7c86bf"}, {file = "aiohttp-3.12.15-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b97752ff12cc12f46a9b20327104448042fce5c33a624f88c18f66f9368091c7"},
{file = "aiohttp-3.13.3-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:697753042d57f4bf7122cab985bf15d0cef23c770864580f5af4f52023a56bd6"}, {file = "aiohttp-3.12.15-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:894261472691d6fe76ebb7fcf2e5870a2ac284c7406ddc95823c8598a1390f0d"},
{file = "aiohttp-3.13.3-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6de499a1a44e7de70735d0b39f67c8f25eb3d91eb3103be99ca0fa882cdd987d"}, {file = "aiohttp-3.12.15-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5fa5d9eb82ce98959fc1031c28198b431b4d9396894f385cb63f1e2f3f20ca6b"},
{file = "aiohttp-3.13.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:37239e9f9a7ea9ac5bf6b92b0260b01f8a22281996da609206a84df860bc1261"}, {file = "aiohttp-3.12.15-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f0fa751efb11a541f57db59c1dd821bec09031e01452b2b6217319b3a1f34f3d"},
{file = "aiohttp-3.13.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f76c1e3fe7d7c8afad7ed193f89a292e1999608170dcc9751a7462a87dfd5bc0"}, {file = "aiohttp-3.12.15-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5346b93e62ab51ee2a9d68e8f73c7cf96ffb73568a23e683f931e52450e4148d"},
{file = "aiohttp-3.13.3-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:fc290605db2a917f6e81b0e1e0796469871f5af381ce15c604a3c5c7e51cb730"}, {file = "aiohttp-3.12.15-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:049ec0360f939cd164ecbfd2873eaa432613d5e77d6b04535e3d1fbae5a9e645"},
{file = "aiohttp-3.13.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4021b51936308aeea0367b8f006dc999ca02bc118a0cc78c303f50a2ff6afb91"}, {file = "aiohttp-3.12.15-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b52dcf013b57464b6d1e51b627adfd69a8053e84b7103a7cd49c030f9ca44461"},
{file = "aiohttp-3.13.3-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:49a03727c1bba9a97d3e93c9f93ca03a57300f484b6e935463099841261195d3"}, {file = "aiohttp-3.12.15-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:9b2af240143dd2765e0fb661fd0361a1b469cab235039ea57663cda087250ea9"},
{file = "aiohttp-3.13.3-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:3d9908a48eb7416dc1f4524e69f1d32e5d90e3981e4e37eb0aa1cd18f9cfa2a4"}, {file = "aiohttp-3.12.15-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ac77f709a2cde2cc71257ab2d8c74dd157c67a0558a0d2799d5d571b4c63d44d"},
{file = "aiohttp-3.13.3-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:2712039939ec963c237286113c68dbad80a82a4281543f3abf766d9d73228998"}, {file = "aiohttp-3.12.15-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:47f6b962246f0a774fbd3b6b7be25d59b06fdb2f164cf2513097998fc6a29693"},
{file = "aiohttp-3.13.3-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:7bfdc049127717581866fa4708791220970ce291c23e28ccf3922c700740fdc0"}, {file = "aiohttp-3.12.15-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:760fb7db442f284996e39cf9915a94492e1896baac44f06ae551974907922b64"},
{file = "aiohttp-3.13.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8057c98e0c8472d8846b9c79f56766bcc57e3e8ac7bfd510482332366c56c591"}, {file = "aiohttp-3.12.15-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ad702e57dc385cae679c39d318def49aef754455f237499d5b99bea4ef582e51"},
{file = "aiohttp-3.13.3-cp313-cp313-win32.whl", hash = "sha256:1449ceddcdbcf2e0446957863af03ebaaa03f94c090f945411b61269e2cb5daf"}, {file = "aiohttp-3.12.15-cp313-cp313-win32.whl", hash = "sha256:f813c3e9032331024de2eb2e32a88d86afb69291fbc37a3a3ae81cc9917fb3d0"},
{file = "aiohttp-3.13.3-cp313-cp313-win_amd64.whl", hash = "sha256:693781c45a4033d31d4187d2436f5ac701e7bbfe5df40d917736108c1cc7436e"}, {file = "aiohttp-3.12.15-cp313-cp313-win_amd64.whl", hash = "sha256:1a649001580bdb37c6fdb1bebbd7e3bc688e8ec2b5c6f52edbb664662b17dc84"},
{file = "aiohttp-3.13.3-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:ea37047c6b367fd4bd632bff8077449b8fa034b69e812a18e0132a00fae6e808"}, {file = "aiohttp-3.12.15-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:691d203c2bdf4f4637792efbbcdcd157ae11e55eaeb5e9c360c1206fb03d4d98"},
{file = "aiohttp-3.13.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:6fc0e2337d1a4c3e6acafda6a78a39d4c14caea625124817420abceed36e2415"}, {file = "aiohttp-3.12.15-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8e995e1abc4ed2a454c731385bf4082be06f875822adc4c6d9eaadf96e20d406"},
{file = "aiohttp-3.13.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c685f2d80bb67ca8c3837823ad76196b3694b0159d232206d1e461d3d434666f"}, {file = "aiohttp-3.12.15-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:bd44d5936ab3193c617bfd6c9a7d8d1085a8dc8c3f44d5f1dcf554d17d04cf7d"},
{file = "aiohttp-3.13.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:48e377758516d262bde50c2584fc6c578af272559c409eecbdd2bae1601184d6"}, {file = "aiohttp-3.12.15-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:46749be6e89cd78d6068cdf7da51dbcfa4321147ab8e4116ee6678d9a056a0cf"},
{file = "aiohttp-3.13.3-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:34749271508078b261c4abb1767d42b8d0c0cc9449c73a4df494777dc55f0687"}, {file = "aiohttp-3.12.15-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:0c643f4d75adea39e92c0f01b3fb83d57abdec8c9279b3078b68a3a52b3933b6"},
{file = "aiohttp-3.13.3-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:82611aeec80eb144416956ec85b6ca45a64d76429c1ed46ae1b5f86c6e0c9a26"}, {file = "aiohttp-3.12.15-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0a23918fedc05806966a2438489dcffccbdf83e921a1170773b6178d04ade142"},
{file = "aiohttp-3.13.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2fff83cfc93f18f215896e3a190e8e5cb413ce01553901aca925176e7568963a"}, {file = "aiohttp-3.12.15-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:74bdd8c864b36c3673741023343565d95bfbd778ffe1eb4d412c135a28a8dc89"},
{file = "aiohttp-3.13.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bbe7d4cecacb439e2e2a8a1a7b935c25b812af7a5fd26503a66dadf428e79ec1"}, {file = "aiohttp-3.12.15-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0a146708808c9b7a988a4af3821379e379e0f0e5e466ca31a73dbdd0325b0263"},
{file = "aiohttp-3.13.3-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b928f30fe49574253644b1ca44b1b8adbd903aa0da4b9054a6c20fc7f4092a25"}, {file = "aiohttp-3.12.15-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b7011a70b56facde58d6d26da4fec3280cc8e2a78c714c96b7a01a87930a9530"},
{file = "aiohttp-3.13.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7b5e8fe4de30df199155baaf64f2fcd604f4c678ed20910db8e2c66dc4b11603"}, {file = "aiohttp-3.12.15-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:3bdd6e17e16e1dbd3db74d7f989e8af29c4d2e025f9828e6ef45fbdee158ec75"},
{file = "aiohttp-3.13.3-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:8542f41a62bcc58fc7f11cf7c90e0ec324ce44950003feb70640fc2a9092c32a"}, {file = "aiohttp-3.12.15-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:57d16590a351dfc914670bd72530fd78344b885a00b250e992faea565b7fdc05"},
{file = "aiohttp-3.13.3-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:5e1d8c8b8f1d91cd08d8f4a3c2b067bfca6ec043d3ff36de0f3a715feeedf926"}, {file = "aiohttp-3.12.15-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:bc9a0f6569ff990e0bbd75506c8d8fe7214c8f6579cca32f0546e54372a3bb54"},
{file = "aiohttp-3.13.3-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:90455115e5da1c3c51ab619ac57f877da8fd6d73c05aacd125c5ae9819582aba"}, {file = "aiohttp-3.12.15-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:536ad7234747a37e50e7b6794ea868833d5220b49c92806ae2d7e8a9d6b5de02"},
{file = "aiohttp-3.13.3-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:042e9e0bcb5fba81886c8b4fbb9a09d6b8a00245fd8d88e4d989c1f96c74164c"}, {file = "aiohttp-3.12.15-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:f0adb4177fa748072546fb650d9bd7398caaf0e15b370ed3317280b13f4083b0"},
{file = "aiohttp-3.13.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2eb752b102b12a76ca02dff751a801f028b4ffbbc478840b473597fc91a9ed43"}, {file = "aiohttp-3.12.15-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:14954a2988feae3987f1eb49c706bff39947605f4b6fa4027c1d75743723eb09"},
{file = "aiohttp-3.13.3-cp314-cp314-win32.whl", hash = "sha256:b556c85915d8efaed322bf1bdae9486aa0f3f764195a0fb6ee962e5c71ef5ce1"}, {file = "aiohttp-3.12.15-cp39-cp39-win32.whl", hash = "sha256:b784d6ed757f27574dca1c336f968f4e81130b27595e458e69457e6878251f5d"},
{file = "aiohttp-3.13.3-cp314-cp314-win_amd64.whl", hash = "sha256:9bf9f7a65e7aa20dd764151fb3d616c81088f91f8df39c3893a536e279b4b984"}, {file = "aiohttp-3.12.15-cp39-cp39-win_amd64.whl", hash = "sha256:86ceded4e78a992f835209e236617bffae649371c4a50d5e5a3987f237db84b8"},
{file = "aiohttp-3.13.3-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:05861afbbec40650d8a07ea324367cb93e9e8cc7762e04dd4405df99fa65159c"}, {file = "aiohttp-3.12.15.tar.gz", hash = "sha256:4fc61385e9c98d72fcdf47e6dd81833f47b2f77c114c29cd64a361be57a763a2"},
{file = "aiohttp-3.13.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:2fc82186fadc4a8316768d61f3722c230e2c1dcab4200d52d2ebdf2482e47592"},
{file = "aiohttp-3.13.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:0add0900ff220d1d5c5ebbf99ed88b0c1bbf87aa7e4262300ed1376a6b13414f"},
{file = "aiohttp-3.13.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:568f416a4072fbfae453dcf9a99194bbb8bdeab718e08ee13dfa2ba0e4bebf29"},
{file = "aiohttp-3.13.3-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:add1da70de90a2569c5e15249ff76a631ccacfe198375eead4aadf3b8dc849dc"},
{file = "aiohttp-3.13.3-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:10b47b7ba335d2e9b1239fa571131a87e2d8ec96b333e68b2a305e7a98b0bae2"},
{file = "aiohttp-3.13.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3dd4dce1c718e38081c8f35f323209d4c1df7d4db4bab1b5c88a6b4d12b74587"},
{file = "aiohttp-3.13.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:34bac00a67a812570d4a460447e1e9e06fae622946955f939051e7cc895cfab8"},
{file = "aiohttp-3.13.3-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a19884d2ee70b06d9204b2727a7b9f983d0c684c650254679e716b0b77920632"},
{file = "aiohttp-3.13.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:5f8ca7f2bb6ba8348a3614c7918cc4bb73268c5ac2a207576b7afea19d3d9f64"},
{file = "aiohttp-3.13.3-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:b0d95340658b9d2f11d9697f59b3814a9d3bb4b7a7c20b131df4bcef464037c0"},
{file = "aiohttp-3.13.3-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:a1e53262fd202e4b40b70c3aff944a8155059beedc8a89bba9dc1f9ef06a1b56"},
{file = "aiohttp-3.13.3-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:d60ac9663f44168038586cab2157e122e46bdef09e9368b37f2d82d354c23f72"},
{file = "aiohttp-3.13.3-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:90751b8eed69435bac9ff4e3d2f6b3af1f57e37ecb0fbeee59c0174c9e2d41df"},
{file = "aiohttp-3.13.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:fc353029f176fd2b3ec6cfc71be166aba1936fe5d73dd1992ce289ca6647a9aa"},
{file = "aiohttp-3.13.3-cp314-cp314t-win32.whl", hash = "sha256:2e41b18a58da1e474a057b3d35248d8320029f61d70a37629535b16a0c8f3767"},
{file = "aiohttp-3.13.3-cp314-cp314t-win_amd64.whl", hash = "sha256:44531a36aa2264a1860089ffd4dce7baf875ee5a6079d5fb42e261c704ef7344"},
{file = "aiohttp-3.13.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:31a83ea4aead760dfcb6962efb1d861db48c34379f2ff72db9ddddd4cda9ea2e"},
{file = "aiohttp-3.13.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:988a8c5e317544fdf0d39871559e67b6341065b87fceac641108c2096d5506b7"},
{file = "aiohttp-3.13.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:9b174f267b5cfb9a7dba9ee6859cecd234e9a681841eb85068059bc867fb8f02"},
{file = "aiohttp-3.13.3-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:947c26539750deeaee933b000fb6517cc770bbd064bad6033f1cff4803881e43"},
{file = "aiohttp-3.13.3-cp39-cp39-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:9ebf57d09e131f5323464bd347135a88622d1c0976e88ce15b670e7ad57e4bd6"},
{file = "aiohttp-3.13.3-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4ae5b5a0e1926e504c81c5b84353e7a5516d8778fbbff00429fe7b05bb25cbce"},
{file = "aiohttp-3.13.3-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2ba0eea45eb5cc3172dbfc497c066f19c41bac70963ea1a67d51fc92e4cf9a80"},
{file = "aiohttp-3.13.3-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bae5c2ed2eae26cc382020edad80d01f36cb8e746da40b292e68fec40421dc6a"},
{file = "aiohttp-3.13.3-cp39-cp39-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:8a60e60746623925eab7d25823329941aee7242d559baa119ca2b253c88a7bd6"},
{file = "aiohttp-3.13.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:e50a2e1404f063427c9d027378472316201a2290959a295169bcf25992d04558"},
{file = "aiohttp-3.13.3-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:9a9dc347e5a3dc7dfdbc1f82da0ef29e388ddb2ed281bfce9dd8248a313e62b7"},
{file = "aiohttp-3.13.3-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:b46020d11d23fe16551466c77823df9cc2f2c1e63cc965daf67fa5eec6ca1877"},
{file = "aiohttp-3.13.3-cp39-cp39-musllinux_1_2_riscv64.whl", hash = "sha256:69c56fbc1993fa17043e24a546959c0178fe2b5782405ad4559e6c13975c15e3"},
{file = "aiohttp-3.13.3-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:b99281b0704c103d4e11e72a76f1b543d4946fea7dd10767e7e1b5f00d4e5704"},
{file = "aiohttp-3.13.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:40c5e40ecc29ba010656c18052b877a1c28f84344825efa106705e835c28530f"},
{file = "aiohttp-3.13.3-cp39-cp39-win32.whl", hash = "sha256:56339a36b9f1fc708260c76c87e593e2afb30d26de9ae1eb445b5e051b98a7a1"},
{file = "aiohttp-3.13.3-cp39-cp39-win_amd64.whl", hash = "sha256:c6b8568a3bb5819a0ad087f16d40e5a3fb6099f39ea1d5625a3edc1e923fc538"},
{file = "aiohttp-3.13.3.tar.gz", hash = "sha256:a949eee43d3782f2daae4f4a2819b2cb9b0c5d3b7f7a927067cc84dafdbb9f88"},
] ]
[package.dependencies] [package.dependencies]
@@ -153,7 +119,7 @@ propcache = ">=0.2.0"
yarl = ">=1.17.0,<2.0" yarl = ">=1.17.0,<2.0"
[package.extras] [package.extras]
speedups = ["Brotli (>=1.2) ; platform_python_implementation == \"CPython\"", "aiodns (>=3.3.0)", "backports.zstd ; platform_python_implementation == \"CPython\" and python_version < \"3.14\"", "brotlicffi (>=1.2) ; platform_python_implementation != \"CPython\""] speedups = ["Brotli ; platform_python_implementation == \"CPython\"", "aiodns (>=3.3.0)", "brotlicffi ; platform_python_implementation != \"CPython\""]
[[package]] [[package]]
name = "aiosignal" name = "aiosignal"
@@ -715,43 +681,43 @@ files = [
[[package]] [[package]]
name = "breez-sdk-liquid" name = "breez-sdk-liquid"
version = "0.11.11" version = "0.9.1"
description = "Python language bindings for the Breez Liquid SDK" description = "Python language bindings for the Breez Liquid SDK"
optional = true optional = true
python-versions = "*" python-versions = "*"
groups = ["main"] groups = ["main"]
markers = "extra == \"breez\"" markers = "extra == \"breez\""
files = [ files = [
{file = "breez_sdk_liquid-0.11.11-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:0c1da93d69112cee65c07f1bf3efbcfbb9182c5e3d8933ca27adc659eae064e0"}, {file = "breez_sdk_liquid-0.9.1-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:414a7c04dbf869435fe234b3b9987699c15dc2f8d4660d9ca1a51af608331b45"},
{file = "breez_sdk_liquid-0.11.11-cp310-cp310-manylinux_2_31_aarch64.whl", hash = "sha256:c2b2d9a04022e05eb56699b6e8a628e7b53676d6f90b1c461c0b1b38b781d952"}, {file = "breez_sdk_liquid-0.9.1-cp310-cp310-manylinux_2_31_aarch64.whl", hash = "sha256:7f461b6b10ddfe9cfb58119e590e5f67da4d7c93fc580a84a0116ce9fd21dffa"},
{file = "breez_sdk_liquid-0.11.11-cp310-cp310-manylinux_2_31_x86_64.whl", hash = "sha256:6fb44fb16bd55a53fcbd22c7a1982bc8b83de655d0b3e677fe6debd366b41890"}, {file = "breez_sdk_liquid-0.9.1-cp310-cp310-manylinux_2_31_x86_64.whl", hash = "sha256:c27efe35539e4092dddbe5315f5cefffccbdd699017ed8733611d11eb52f4ce0"},
{file = "breez_sdk_liquid-0.11.11-cp310-cp310-win32.whl", hash = "sha256:04719223f8b5a44401c02aef6202076e0e557f28476b7cbe787ed9e7947e641a"}, {file = "breez_sdk_liquid-0.9.1-cp310-cp310-win32.whl", hash = "sha256:375f6322c2552d15d6ba68302a85fdc345a7671eeda8fea92c013a16c5e96505"},
{file = "breez_sdk_liquid-0.11.11-cp310-cp310-win_amd64.whl", hash = "sha256:0d36272277e8d5b0287b45cacce5444934579ae9f6726de377c9de7d4535dc6f"}, {file = "breez_sdk_liquid-0.9.1-cp310-cp310-win_amd64.whl", hash = "sha256:f28d107099fb7caaac4051d5950a4f11bf823e11b56e797976c5fa2a7280d597"},
{file = "breez_sdk_liquid-0.11.11-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:4ab4029773e5d2f946872ced5b3c76c5686e00cf6786b9515b707e16691e40dd"}, {file = "breez_sdk_liquid-0.9.1-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:acefa49896bdb4ca06d351faacbf075646d574dda5539033df11310ec5a94446"},
{file = "breez_sdk_liquid-0.11.11-cp311-cp311-manylinux_2_31_aarch64.whl", hash = "sha256:b3ab95f85f7454710c312443d4c0bc96fd1f06a4d3453305eb2fc9c510e9441e"}, {file = "breez_sdk_liquid-0.9.1-cp311-cp311-manylinux_2_31_aarch64.whl", hash = "sha256:d0e54fd5c8ce542dc2061d8a1ef46e6a1d430dbaea5eab369bb91ae2c4a1be7b"},
{file = "breez_sdk_liquid-0.11.11-cp311-cp311-manylinux_2_31_x86_64.whl", hash = "sha256:bf85cecaad3d433ee9af75814a921d5ae582a74c9f4009c8bc865c820b9f8cd9"}, {file = "breez_sdk_liquid-0.9.1-cp311-cp311-manylinux_2_31_x86_64.whl", hash = "sha256:a5d1bfd4d3286d57c110d925332416b0903dda076dadede02c4b7db67576f0bf"},
{file = "breez_sdk_liquid-0.11.11-cp311-cp311-win32.whl", hash = "sha256:f9b0c5393111f7de3511c061f680f94cfd867f6f2e114904c3f5e31fe1fa2824"}, {file = "breez_sdk_liquid-0.9.1-cp311-cp311-win32.whl", hash = "sha256:3ce2152f0a2ba65f4425fd22efb8e1dafb419e5fcf3b93dfe06fc061b1d1c0c6"},
{file = "breez_sdk_liquid-0.11.11-cp311-cp311-win_amd64.whl", hash = "sha256:7d2862108da64e2b73de46f61ff7d2df5607cbb6bb78a1bc437d19d06caa9f93"}, {file = "breez_sdk_liquid-0.9.1-cp311-cp311-win_amd64.whl", hash = "sha256:8cdb4f247bccc0f4b9bbfff4451faa78d7b17e76a9dc918804880b600f1d4249"},
{file = "breez_sdk_liquid-0.11.11-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:93faa55da3b4c850b1655b66b8822bd36b40a0491990d31d5d6f9000e0e61521"}, {file = "breez_sdk_liquid-0.9.1-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:c463191a89a829afcae19c94f7683dac415667755d68c212afc60d8f2b21ba63"},
{file = "breez_sdk_liquid-0.11.11-cp312-cp312-manylinux_2_31_aarch64.whl", hash = "sha256:337be3e6c59bba6890629fc82e7b8f342bbf19fdb0f9c4a2f0d2aa5e93dfa690"}, {file = "breez_sdk_liquid-0.9.1-cp312-cp312-manylinux_2_31_aarch64.whl", hash = "sha256:52efaeae2c278b498b37de1090e80f73987ee943743e69a363877ed93cd7a31e"},
{file = "breez_sdk_liquid-0.11.11-cp312-cp312-manylinux_2_31_x86_64.whl", hash = "sha256:129baf243381bf5ce4d2927f52dabc68f61f9e173d498ee53d9aef55f4e44fb2"}, {file = "breez_sdk_liquid-0.9.1-cp312-cp312-manylinux_2_31_x86_64.whl", hash = "sha256:68aebea98990319c677bcbd7d1de258627b85063a29720879986694b9d393adb"},
{file = "breez_sdk_liquid-0.11.11-cp312-cp312-win32.whl", hash = "sha256:9acd3eea87c861ed5cde91e188d38e893090d5de925c9ed3c9b21f9be15abe0d"}, {file = "breez_sdk_liquid-0.9.1-cp312-cp312-win32.whl", hash = "sha256:f53e4a1973dfd41df3ac3ecb42cf72acb71f49d5727a8acab25668b51a953bb2"},
{file = "breez_sdk_liquid-0.11.11-cp312-cp312-win_amd64.whl", hash = "sha256:466824ad3124ef22262ccc5ce76f5cedefd4a2540bb0cd0408e9b2f4e67ac58a"}, {file = "breez_sdk_liquid-0.9.1-cp312-cp312-win_amd64.whl", hash = "sha256:6adb1f3f3ccd4b743a11dcc0b307db604c3424f42e2547f94fa939f0afb9bb85"},
{file = "breez_sdk_liquid-0.11.11-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:3708379531b0273da5da7797d857caf2ee8b3837e003e70d36d2592a98f62ee0"}, {file = "breez_sdk_liquid-0.9.1-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:f94432a75bc848e597fb9859a77bab6c703d5e423d470519f37c402fc3c5d79e"},
{file = "breez_sdk_liquid-0.11.11-cp313-cp313-manylinux_2_31_aarch64.whl", hash = "sha256:026d33a1fda6d2fc80bc3c6eae7df2924d7bf101050fb71dddfe79a24c6e641a"}, {file = "breez_sdk_liquid-0.9.1-cp313-cp313-manylinux_2_31_aarch64.whl", hash = "sha256:8d6838e69620162c038d513f95ffade870e112ae5c6a0d713eaa2a3a31d6f212"},
{file = "breez_sdk_liquid-0.11.11-cp313-cp313-manylinux_2_31_x86_64.whl", hash = "sha256:adea3697e464257bc306de8680f82436ae46a6dd3af9390b6a3c55202bba37df"}, {file = "breez_sdk_liquid-0.9.1-cp313-cp313-manylinux_2_31_x86_64.whl", hash = "sha256:d6b9a8601cef5875447e10c75ca3e1579dd1e881ec57cabe9787616b8a6de263"},
{file = "breez_sdk_liquid-0.11.11-cp313-cp313-win32.whl", hash = "sha256:653b8b06a4f891c4a08901dff49a08c8f9f3624089441c6d3f1e558ee7e137fa"}, {file = "breez_sdk_liquid-0.9.1-cp313-cp313-win32.whl", hash = "sha256:d76fc905003ac5a0cfd2132df90ba6343b40b9948164a0be06a68f15b28789a2"},
{file = "breez_sdk_liquid-0.11.11-cp313-cp313-win_amd64.whl", hash = "sha256:6becd498285eb7c9a17c3ccf2a2ae02780919f89e968eadab46003ed39c54099"}, {file = "breez_sdk_liquid-0.9.1-cp313-cp313-win_amd64.whl", hash = "sha256:d6b0fc1d77b7855d9a72799d65cdaaa0bd07a3999d6d4d27050d8ef174ce0fd3"},
{file = "breez_sdk_liquid-0.11.11-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:978faa63b72f272672dfb77f19617dd80a98f739a40af8748bfa3739e6ff783f"}, {file = "breez_sdk_liquid-0.9.1-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:d0d560657c29d7e3b054ad4be07955fc41b63d4b93a2b51b29bb85d1d52341af"},
{file = "breez_sdk_liquid-0.11.11-cp38-cp38-manylinux_2_31_aarch64.whl", hash = "sha256:78cd9f069e277274cf708f4bbc1d84b6cc152222b2b56ce0019e3daf4750bc51"}, {file = "breez_sdk_liquid-0.9.1-cp38-cp38-manylinux_2_31_aarch64.whl", hash = "sha256:2531f788eb15bb00f4b3b505ac5b8ee3de23161dd4f65768a4aa3255ea04d68e"},
{file = "breez_sdk_liquid-0.11.11-cp38-cp38-manylinux_2_31_x86_64.whl", hash = "sha256:315074affc1ffe86440fa380367719d623e469205d14b28e42c4f9bc0277836a"}, {file = "breez_sdk_liquid-0.9.1-cp38-cp38-manylinux_2_31_x86_64.whl", hash = "sha256:f9c9f6255999cf403bc07a9deed99f8c1625a0405ae9231e3dbecb3b6af0fdc7"},
{file = "breez_sdk_liquid-0.11.11-cp38-cp38-win32.whl", hash = "sha256:01600323bf8e273a50baac42d431bbb4779ae5108e225c6e4dbee7c535b6d8d1"}, {file = "breez_sdk_liquid-0.9.1-cp38-cp38-win32.whl", hash = "sha256:5232b25b7e8583100ec54423e7568a305cac7778736adc9f8c735798110350c7"},
{file = "breez_sdk_liquid-0.11.11-cp38-cp38-win_amd64.whl", hash = "sha256:ba21c8bb1f674baad81c077abb046c77ec6994bcb3e4c67f48581173c49f8dc2"}, {file = "breez_sdk_liquid-0.9.1-cp38-cp38-win_amd64.whl", hash = "sha256:67d2b894b70ba9011fc98e04ed1ade2ff18f0413b6f2a0994747e71418d004e4"},
{file = "breez_sdk_liquid-0.11.11-cp39-cp39-macosx_11_0_universal2.whl", hash = "sha256:ffa2303c39fb5aa872e88e8d42d1e9e0aeafd97dd3c132d3149d97496cc9e037"}, {file = "breez_sdk_liquid-0.9.1-cp39-cp39-macosx_11_0_universal2.whl", hash = "sha256:bd77d2ce43a2c0ad77a7f22226e373034ff57677338b38e4ebe3b77eb34fa224"},
{file = "breez_sdk_liquid-0.11.11-cp39-cp39-manylinux_2_31_aarch64.whl", hash = "sha256:0fd15395866c70cffcfbc1faaf2ca0d1e9f602542aefa02dd9f90478dc43ed8d"}, {file = "breez_sdk_liquid-0.9.1-cp39-cp39-manylinux_2_31_aarch64.whl", hash = "sha256:14092d9d65f1b0a9009e64630614e7b8b936e9d382d0f6415f023f0b192f6b45"},
{file = "breez_sdk_liquid-0.11.11-cp39-cp39-manylinux_2_31_x86_64.whl", hash = "sha256:9ee716853388d23466e28b81b79835a9713faba7a7f7648575aa194c9577e080"}, {file = "breez_sdk_liquid-0.9.1-cp39-cp39-manylinux_2_31_x86_64.whl", hash = "sha256:5faa4d5e9a2b47899783aa0c44ac2274d32f74a7f469506af14520deabaabf9f"},
{file = "breez_sdk_liquid-0.11.11-cp39-cp39-win32.whl", hash = "sha256:f768e0e8326e26bdb92efd2dfb9850d9f6b51868d0a123986b7d70790c9446db"}, {file = "breez_sdk_liquid-0.9.1-cp39-cp39-win32.whl", hash = "sha256:b5b2c4bae13655d108475f4f22efdc2b07283f72d99b9c6f99166d9e41e62942"},
{file = "breez_sdk_liquid-0.11.11-cp39-cp39-win_amd64.whl", hash = "sha256:f8272efaae258167befe98a6551755beda397ed2a7e10b45a795419380e2c345"}, {file = "breez_sdk_liquid-0.9.1-cp39-cp39-win_amd64.whl", hash = "sha256:f3ad7c65582558031451538c8a03caa3486a2d2c8906f2fbbccce84e9357d1ea"},
] ]
[[package]] [[package]]
@@ -1348,14 +1314,14 @@ standard-no-fastapi-cloud-cli = ["email-validator (>=2.0.0)", "fastapi-cli[stand
[[package]] [[package]]
name = "fastapi-sso" name = "fastapi-sso"
version = "0.19.0" version = "0.18.0"
description = "FastAPI plugin to enable SSO to most common providers (such as Facebook login, Google login and login via Microsoft Office 365 Account)" description = "FastAPI plugin to enable SSO to most common providers (such as Facebook login, Google login and login via Microsoft Office 365 Account)"
optional = false optional = false
python-versions = "<4.0,>=3.9" python-versions = "<4.0,>=3.9"
groups = ["main"] groups = ["main"]
files = [ files = [
{file = "fastapi_sso-0.19.0-py3-none-any.whl", hash = "sha256:d958c46cd9996234c7b162e192168b4c0807a248224a55b0f877d3a82a16a930"}, {file = "fastapi_sso-0.18.0-py3-none-any.whl", hash = "sha256:727754ad770b70690f1471f7b0a9e17c6dfd8ebd6e477616d3bde1eaf62e53dc"},
{file = "fastapi_sso-0.19.0.tar.gz", hash = "sha256:629f00581f72ea7e57f7b8775f8d2c425629c428c194359a2b4ebaa6bcb8e12b"}, {file = "fastapi_sso-0.18.0.tar.gz", hash = "sha256:d8df5a686af7a6a7be248817544b405cf77f7e9ffcd5d0d7d2a196fd071964bc"},
] ]
[package.dependencies] [package.dependencies]
@@ -1367,16 +1333,21 @@ pyjwt = ">=2.10.1,<3.0.0"
[[package]] [[package]]
name = "filelock" name = "filelock"
version = "3.20.3" version = "3.18.0"
description = "A platform independent file lock." description = "A platform independent file lock."
optional = false optional = false
python-versions = ">=3.10" python-versions = ">=3.9"
groups = ["dev"] groups = ["dev"]
files = [ files = [
{file = "filelock-3.20.3-py3-none-any.whl", hash = "sha256:4b0dda527ee31078689fc205ec4f1c1bf7d56cf88b6dc9426c4f230e46c2dce1"}, {file = "filelock-3.18.0-py3-none-any.whl", hash = "sha256:c401f4f8377c4464e6db25fff06205fd89bdd83b65eb0488ed1b160f780e21de"},
{file = "filelock-3.20.3.tar.gz", hash = "sha256:18c57ee915c7ec61cff0ecf7f0f869936c7c30191bb0cf406f1341778d0834e1"}, {file = "filelock-3.18.0.tar.gz", hash = "sha256:adbc88eabb99d2fec8c9c1b229b171f18afa655400173ddc653d5d01501fb9f2"},
] ]
[package.extras]
docs = ["furo (>=2024.8.6)", "sphinx (>=8.1.3)", "sphinx-autodoc-typehints (>=3)"]
testing = ["covdefaults (>=2.3)", "coverage (>=7.6.10)", "diff-cover (>=9.2.1)", "pytest (>=8.3.4)", "pytest-asyncio (>=0.25.2)", "pytest-cov (>=6)", "pytest-mock (>=3.14)", "pytest-timeout (>=2.3.1)", "virtualenv (>=20.28.1)"]
typing = ["typing-extensions (>=4.12.2) ; python_version < \"3.11\""]
[[package]] [[package]]
name = "filetype" name = "filetype"
version = "1.2.0" version = "1.2.0"
@@ -1505,60 +1476,67 @@ files = [
[[package]] [[package]]
name = "greenlet" name = "greenlet"
version = "3.3.0" version = "3.2.4"
description = "Lightweight in-process concurrent programming" description = "Lightweight in-process concurrent programming"
optional = false optional = false
python-versions = ">=3.10" python-versions = ">=3.9"
groups = ["main"] groups = ["main"]
markers = "platform_machine == \"aarch64\" or platform_machine == \"ppc64le\" or platform_machine == \"x86_64\" or platform_machine == \"amd64\" or platform_machine == \"AMD64\" or platform_machine == \"win32\" or platform_machine == \"WIN32\""
files = [ files = [
{file = "greenlet-3.3.0-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:6f8496d434d5cb2dce025773ba5597f71f5410ae499d5dd9533e0653258cdb3d"}, {file = "greenlet-3.2.4-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:8c68325b0d0acf8d91dde4e6f930967dd52a5302cd4062932a6b2e7c2969f47c"},
{file = "greenlet-3.3.0-cp310-cp310-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b96dc7eef78fd404e022e165ec55327f935b9b52ff355b067eb4a0267fc1cffb"}, {file = "greenlet-3.2.4-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:94385f101946790ae13da500603491f04a76b6e4c059dab271b3ce2e283b2590"},
{file = "greenlet-3.3.0-cp310-cp310-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:73631cd5cccbcfe63e3f9492aaa664d278fda0ce5c3d43aeda8e77317e38efbd"}, {file = "greenlet-3.2.4-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:f10fd42b5ee276335863712fa3da6608e93f70629c631bf77145021600abc23c"},
{file = "greenlet-3.3.0-cp310-cp310-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b299a0cb979f5d7197442dccc3aee67fce53500cd88951b7e6c35575701c980b"}, {file = "greenlet-3.2.4-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:c8c9e331e58180d0d83c5b7999255721b725913ff6bc6cf39fa2a45841a4fd4b"},
{file = "greenlet-3.3.0-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7dee147740789a4632cace364816046e43310b59ff8fb79833ab043aefa72fd5"}, {file = "greenlet-3.2.4-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:58b97143c9cc7b86fc458f215bd0932f1757ce649e05b640fea2e79b54cedb31"},
{file = "greenlet-3.3.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:39b28e339fc3c348427560494e28d8a6f3561c8d2bcf7d706e1c624ed8d822b9"}, {file = "greenlet-3.2.4-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c2ca18a03a8cfb5b25bc1cbe20f3d9a4c80d8c3b13ba3df49ac3961af0b1018d"},
{file = "greenlet-3.3.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b3c374782c2935cc63b2a27ba8708471de4ad1abaa862ffdb1ef45a643ddbb7d"}, {file = "greenlet-3.2.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:9fe0a28a7b952a21e2c062cd5756d34354117796c6d9215a87f55e38d15402c5"},
{file = "greenlet-3.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:b49e7ed51876b459bd645d83db257f0180e345d3f768a35a85437a24d5a49082"}, {file = "greenlet-3.2.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8854167e06950ca75b898b104b63cc646573aa5fef1353d4508ecdd1ee76254f"},
{file = "greenlet-3.3.0-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:e29f3018580e8412d6aaf5641bb7745d38c85228dacf51a73bd4e26ddf2a6a8e"}, {file = "greenlet-3.2.4-cp310-cp310-win_amd64.whl", hash = "sha256:73f49b5368b5359d04e18d15828eecc1806033db5233397748f4ca813ff1056c"},
{file = "greenlet-3.3.0-cp311-cp311-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a687205fb22794e838f947e2194c0566d3812966b41c78709554aa883183fb62"}, {file = "greenlet-3.2.4-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:96378df1de302bc38e99c3a9aa311967b7dc80ced1dcc6f171e99842987882a2"},
{file = "greenlet-3.3.0-cp311-cp311-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4243050a88ba61842186cb9e63c7dfa677ec146160b0efd73b855a3d9c7fcf32"}, {file = "greenlet-3.2.4-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:1ee8fae0519a337f2329cb78bd7a8e128ec0f881073d43f023c7b8d4831d5246"},
{file = "greenlet-3.3.0-cp311-cp311-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:670d0f94cd302d81796e37299bcd04b95d62403883b24225c6b5271466612f45"}, {file = "greenlet-3.2.4-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:94abf90142c2a18151632371140b3dba4dee031633fe614cb592dbb6c9e17bc3"},
{file = "greenlet-3.3.0-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6cb3a8ec3db4a3b0eb8a3c25436c2d49e3505821802074969db017b87bc6a948"}, {file = "greenlet-3.2.4-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:4d1378601b85e2e5171b99be8d2dc85f594c79967599328f95c1dc1a40f1c633"},
{file = "greenlet-3.3.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:2de5a0b09eab81fc6a382791b995b1ccf2b172a9fec934747a7a23d2ff291794"}, {file = "greenlet-3.2.4-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:0db5594dce18db94f7d1650d7489909b57afde4c580806b8d9203b6e79cdc079"},
{file = "greenlet-3.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:4449a736606bd30f27f8e1ff4678ee193bc47f6ca810d705981cfffd6ce0d8c5"}, {file = "greenlet-3.2.4-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2523e5246274f54fdadbce8494458a2ebdcdbc7b802318466ac5606d3cded1f8"},
{file = "greenlet-3.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:7652ee180d16d447a683c04e4c5f6441bae7ba7b17ffd9f6b3aff4605e9e6f71"}, {file = "greenlet-3.2.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:1987de92fec508535687fb807a5cea1560f6196285a4cde35c100b8cd632cc52"},
{file = "greenlet-3.3.0-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:b01548f6e0b9e9784a2c99c5651e5dc89ffcbe870bc5fb2e5ef864e9cc6b5dcb"}, {file = "greenlet-3.2.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:55e9c5affaa6775e2c6b67659f3a71684de4c549b3dd9afca3bc773533d284fa"},
{file = "greenlet-3.3.0-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:349345b770dc88f81506c6861d22a6ccd422207829d2c854ae2af8025af303e3"}, {file = "greenlet-3.2.4-cp311-cp311-win_amd64.whl", hash = "sha256:9c40adce87eaa9ddb593ccb0fa6a07caf34015a29bf8d344811665b573138db9"},
{file = "greenlet-3.3.0-cp312-cp312-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e8e18ed6995e9e2c0b4ed264d2cf89260ab3ac7e13555b8032b25a74c6d18655"}, {file = "greenlet-3.2.4-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:3b67ca49f54cede0186854a008109d6ee71f66bd57bb36abd6d0a0267b540cdd"},
{file = "greenlet-3.3.0-cp312-cp312-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c024b1e5696626890038e34f76140ed1daf858e37496d33f2af57f06189e70d7"}, {file = "greenlet-3.2.4-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:ddf9164e7a5b08e9d22511526865780a576f19ddd00d62f8a665949327fde8bb"},
{file = "greenlet-3.3.0-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:047ab3df20ede6a57c35c14bf5200fcf04039d50f908270d3f9a7a82064f543b"}, {file = "greenlet-3.2.4-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:f28588772bb5fb869a8eb331374ec06f24a83a9c25bfa1f38b6993afe9c1e968"},
{file = "greenlet-3.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2d9ad37fc657b1102ec880e637cccf20191581f75c64087a549e66c57e1ceb53"}, {file = "greenlet-3.2.4-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:5c9320971821a7cb77cfab8d956fa8e39cd07ca44b6070db358ceb7f8797c8c9"},
{file = "greenlet-3.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:83cd0e36932e0e7f36a64b732a6f60c2fc2df28c351bae79fbaf4f8092fe7614"}, {file = "greenlet-3.2.4-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c60a6d84229b271d44b70fb6e5fa23781abb5d742af7b808ae3f6efd7c9c60f6"},
{file = "greenlet-3.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:a7a34b13d43a6b78abf828a6d0e87d3385680eaf830cd60d20d52f249faabf39"}, {file = "greenlet-3.2.4-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3b3812d8d0c9579967815af437d96623f45c0f2ae5f04e366de62a12d83a8fb0"},
{file = "greenlet-3.3.0-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:a1e41a81c7e2825822f4e068c48cb2196002362619e2d70b148f20a831c00739"}, {file = "greenlet-3.2.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:abbf57b5a870d30c4675928c37278493044d7c14378350b3aa5d484fa65575f0"},
{file = "greenlet-3.3.0-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9f515a47d02da4d30caaa85b69474cec77b7929b2e936ff7fb853d42f4bf8808"}, {file = "greenlet-3.2.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:20fb936b4652b6e307b8f347665e2c615540d4b42b3b4c8a321d8286da7e520f"},
{file = "greenlet-3.3.0-cp313-cp313-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7d2d9fd66bfadf230b385fdc90426fcd6eb64db54b40c495b72ac0feb5766c54"}, {file = "greenlet-3.2.4-cp312-cp312-win_amd64.whl", hash = "sha256:a7d4e128405eea3814a12cc2605e0e6aedb4035bf32697f72deca74de4105e02"},
{file = "greenlet-3.3.0-cp313-cp313-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:30a6e28487a790417d036088b3bcb3f3ac7d8babaa7d0139edbaddebf3af9492"}, {file = "greenlet-3.2.4-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:1a921e542453fe531144e91e1feedf12e07351b1cf6c9e8a3325ea600a715a31"},
{file = "greenlet-3.3.0-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:087ea5e004437321508a8d6f20efc4cfec5e3c30118e1417ea96ed1d93950527"}, {file = "greenlet-3.2.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:cd3c8e693bff0fff6ba55f140bf390fa92c994083f838fece0f63be121334945"},
{file = "greenlet-3.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ab97cf74045343f6c60a39913fa59710e4bd26a536ce7ab2397adf8b27e67c39"}, {file = "greenlet-3.2.4-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:710638eb93b1fa52823aa91bf75326f9ecdfd5e0466f00789246a5280f4ba0fc"},
{file = "greenlet-3.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5375d2e23184629112ca1ea89a53389dddbffcf417dad40125713d88eb5f96e8"}, {file = "greenlet-3.2.4-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:c5111ccdc9c88f423426df3fd1811bfc40ed66264d35aa373420a34377efc98a"},
{file = "greenlet-3.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:9ee1942ea19550094033c35d25d20726e4f1c40d59545815e1128ac58d416d38"}, {file = "greenlet-3.2.4-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d76383238584e9711e20ebe14db6c88ddcedc1829a9ad31a584389463b5aa504"},
{file = "greenlet-3.3.0-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:60c2ef0f578afb3c8d92ea07ad327f9a062547137afe91f38408f08aacab667f"}, {file = "greenlet-3.2.4-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:23768528f2911bcd7e475210822ffb5254ed10d71f4028387e5a99b4c6699671"},
{file = "greenlet-3.3.0-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0a5d554d0712ba1de0a6c94c640f7aeba3f85b3a6e1f2899c11c2c0428da9365"}, {file = "greenlet-3.2.4-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:00fadb3fedccc447f517ee0d3fd8fe49eae949e1cd0f6a611818f4f6fb7dc83b"},
{file = "greenlet-3.3.0-cp314-cp314-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:3a898b1e9c5f7307ebbde4102908e6cbfcb9ea16284a3abe15cab996bee8b9b3"}, {file = "greenlet-3.2.4-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:d25c5091190f2dc0eaa3f950252122edbbadbb682aa7b1ef2f8af0f8c0afefae"},
{file = "greenlet-3.3.0-cp314-cp314-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:dcd2bdbd444ff340e8d6bdf54d2f206ccddbb3ccfdcd3c25bf4afaa7b8f0cf45"}, {file = "greenlet-3.2.4-cp313-cp313-win_amd64.whl", hash = "sha256:554b03b6e73aaabec3745364d6239e9e012d64c68ccd0b8430c64ccc14939a8b"},
{file = "greenlet-3.3.0-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5773edda4dc00e173820722711d043799d3adb4f01731f40619e07ea2750b955"}, {file = "greenlet-3.2.4-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:49a30d5fda2507ae77be16479bdb62a660fa51b1eb4928b524975b3bde77b3c0"},
{file = "greenlet-3.3.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ac0549373982b36d5fd5d30beb8a7a33ee541ff98d2b502714a09f1169f31b55"}, {file = "greenlet-3.2.4-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:299fd615cd8fc86267b47597123e3f43ad79c9d8a22bebdce535e53550763e2f"},
{file = "greenlet-3.3.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:d198d2d977460358c3b3a4dc844f875d1adb33817f0613f663a656f463764ccc"}, {file = "greenlet-3.2.4-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:c17b6b34111ea72fc5a4e4beec9711d2226285f0386ea83477cbb97c30a3f3a5"},
{file = "greenlet-3.3.0-cp314-cp314-win_amd64.whl", hash = "sha256:73f51dd0e0bdb596fb0417e475fa3c5e32d4c83638296e560086b8d7da7c4170"}, {file = "greenlet-3.2.4-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:b4a1870c51720687af7fa3e7cda6d08d801dae660f75a76f3845b642b4da6ee1"},
{file = "greenlet-3.3.0-cp314-cp314t-macosx_11_0_universal2.whl", hash = "sha256:d6ed6f85fae6cdfdb9ce04c9bf7a08d666cfcfb914e7d006f44f840b46741931"}, {file = "greenlet-3.2.4-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:061dc4cf2c34852b052a8620d40f36324554bc192be474b9e9770e8c042fd735"},
{file = "greenlet-3.3.0-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d9125050fcf24554e69c4cacb086b87b3b55dc395a8b3ebe6487b045b2614388"}, {file = "greenlet-3.2.4-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:44358b9bf66c8576a9f57a590d5f5d6e72fa4228b763d0e43fee6d3b06d3a337"},
{file = "greenlet-3.3.0-cp314-cp314t-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:87e63ccfa13c0a0f6234ed0add552af24cc67dd886731f2261e46e241608bee3"}, {file = "greenlet-3.2.4-cp314-cp314-win_amd64.whl", hash = "sha256:e37ab26028f12dbb0ff65f29a8d3d44a765c61e729647bf2ddfbbed621726f01"},
{file = "greenlet-3.3.0-cp314-cp314t-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2662433acbca297c9153a4023fe2161c8dcfdcc91f10433171cf7e7d94ba2221"}, {file = "greenlet-3.2.4-cp39-cp39-macosx_11_0_universal2.whl", hash = "sha256:b6a7c19cf0d2742d0809a4c05975db036fdff50cd294a93632d6a310bf9ac02c"},
{file = "greenlet-3.3.0-cp314-cp314t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3c6e9b9c1527a78520357de498b0e709fb9e2f49c3a513afd5a249007261911b"}, {file = "greenlet-3.2.4-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:27890167f55d2387576d1f41d9487ef171849ea0359ce1510ca6e06c8bece11d"},
{file = "greenlet-3.3.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:286d093f95ec98fdd92fcb955003b8a3d054b4e2cab3e2707a5039e7b50520fd"}, {file = "greenlet-3.2.4-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:18d9260df2b5fbf41ae5139e1be4e796d99655f023a636cd0e11e6406cca7d58"},
{file = "greenlet-3.3.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6c10513330af5b8ae16f023e8ddbfb486ab355d04467c4679c5cfe4659975dd9"}, {file = "greenlet-3.2.4-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:671df96c1f23c4a0d4077a325483c1503c96a1b7d9db26592ae770daa41233d4"},
{file = "greenlet-3.3.0.tar.gz", hash = "sha256:a82bb225a4e9e4d653dd2fb7b8b2d36e4fb25bc0165422a11e48b88e9e6f78fb"}, {file = "greenlet-3.2.4-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:16458c245a38991aa19676900d48bd1a6f2ce3e16595051a4db9d012154e8433"},
{file = "greenlet-3.2.4-cp39-cp39-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c9913f1a30e4526f432991f89ae263459b1c64d1608c0d22a5c79c287b3c70df"},
{file = "greenlet-3.2.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b90654e092f928f110e0007f572007c9727b5265f7632c2fa7415b4689351594"},
{file = "greenlet-3.2.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:81701fd84f26330f0d5f4944d4e92e61afe6319dcd9775e39396e39d7c3e5f98"},
{file = "greenlet-3.2.4-cp39-cp39-win32.whl", hash = "sha256:65458b409c1ed459ea899e939f0e1cdb14f58dbc803f2f93c5eab5694d32671b"},
{file = "greenlet-3.2.4-cp39-cp39-win_amd64.whl", hash = "sha256:d2e685ade4dafd447ede19c31277a224a239a0a1a4eca4e6390efedf20260cfb"},
{file = "greenlet-3.2.4.tar.gz", hash = "sha256:0dca0d95ff849f9a364385f36ab49f50065d76964944638be9691e1832e9f86d"},
] ]
[package.extras] [package.extras]
@@ -4082,14 +4060,14 @@ files = [
[[package]] [[package]]
name = "urllib3" name = "urllib3"
version = "2.6.3" version = "2.6.0"
description = "HTTP library with thread-safe connection pooling, file post, and more." description = "HTTP library with thread-safe connection pooling, file post, and more."
optional = false optional = false
python-versions = ">=3.9" python-versions = ">=3.9"
groups = ["main", "dev"] groups = ["main", "dev"]
files = [ files = [
{file = "urllib3-2.6.3-py3-none-any.whl", hash = "sha256:bf272323e553dfb2e87d9bfd225ca7b0f467b919d7bbd355436d3fd37cb0acd4"}, {file = "urllib3-2.6.0-py3-none-any.whl", hash = "sha256:c90f7a39f716c572c4e3e58509581ebd83f9b59cced005b7db7ad2d22b0db99f"},
{file = "urllib3-2.6.3.tar.gz", hash = "sha256:1b62b6884944a57dbe321509ab94fd4d3b307075e0c2eae991ac71ee15ad38ed"}, {file = "urllib3-2.6.0.tar.gz", hash = "sha256:cb9bcef5a4b345d5da5d145dc3e30834f58e8018828cbc724d30b4cb7d4d49f1"},
] ]
[package.extras] [package.extras]
@@ -4172,21 +4150,20 @@ test = ["aiohttp (>=3.10.5)", "flake8 (>=5.0,<6.0)", "mypy (>=0.800)", "psutil",
[[package]] [[package]]
name = "virtualenv" name = "virtualenv"
version = "20.36.1" version = "20.31.2"
description = "Virtual Python Environment builder" description = "Virtual Python Environment builder"
optional = false optional = false
python-versions = ">=3.8" python-versions = ">=3.8"
groups = ["dev"] groups = ["dev"]
files = [ files = [
{file = "virtualenv-20.36.1-py3-none-any.whl", hash = "sha256:575a8d6b124ef88f6f51d56d656132389f961062a9177016a50e4f507bbcc19f"}, {file = "virtualenv-20.31.2-py3-none-any.whl", hash = "sha256:36efd0d9650ee985f0cad72065001e66d49a6f24eb44d98980f630686243cf11"},
{file = "virtualenv-20.36.1.tar.gz", hash = "sha256:8befb5c81842c641f8ee658481e42641c68b5eab3521d8e092d18320902466ba"}, {file = "virtualenv-20.31.2.tar.gz", hash = "sha256:e10c0a9d02835e592521be48b332b6caee6887f332c111aa79a09b9e79efc2af"},
] ]
[package.dependencies] [package.dependencies]
distlib = ">=0.3.7,<1" distlib = ">=0.3.7,<1"
filelock = {version = ">=3.20.1,<4", markers = "python_version >= \"3.10\""} filelock = ">=3.12.2,<4"
platformdirs = ">=3.9.1,<5" platformdirs = ">=3.9.1,<5"
typing-extensions = {version = ">=4.13.2", markers = "python_version < \"3.11\""}
[package.extras] [package.extras]
docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.2,!=7.3)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"] docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.2,!=7.3)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"]
@@ -4337,14 +4314,14 @@ files = [
[[package]] [[package]]
name = "werkzeug" name = "werkzeug"
version = "3.1.5" version = "3.1.4"
description = "The comprehensive WSGI web application library." description = "The comprehensive WSGI web application library."
optional = false optional = false
python-versions = ">=3.9" python-versions = ">=3.9"
groups = ["dev"] groups = ["dev"]
files = [ files = [
{file = "werkzeug-3.1.5-py3-none-any.whl", hash = "sha256:5111e36e91086ece91f93268bb39b4a35c1e6f1feac762c9c822ded0a4e322dc"}, {file = "werkzeug-3.1.4-py3-none-any.whl", hash = "sha256:2ad50fb9ed09cc3af22c54698351027ace879a0b60a3b5edf5730b2f7d876905"},
{file = "werkzeug-3.1.5.tar.gz", hash = "sha256:6a548b0e88955dd07ccb25539d7d0cc97417ee9e179677d22c7041c8f078ce67"}, {file = "werkzeug-3.1.4.tar.gz", hash = "sha256:cd3cd98b1b92dc3b7b3995038826c68097dcb16f9baa63abe35f20eafeb9fe5e"},
] ]
[package.dependencies] [package.dependencies]
@@ -4587,4 +4564,4 @@ migration = ["psycopg2-binary"]
[metadata] [metadata]
lock-version = "2.1" lock-version = "2.1"
python-versions = ">=3.10,<3.13" python-versions = ">=3.10,<3.13"
content-hash = "b5509b4d38ab0c064d293d93105f075fa19eff10760c1bba27fbe5b96a464ac3" content-hash = "13f4b6c9c33e051dba10dfa6833c11bb3aabdd4cce395fa8480d1fa4ee9ddb96"
+3 -4
View File
@@ -1,6 +1,6 @@
[project] [project]
name = "lnbits" name = "lnbits"
version = "1.4.2" version = "1.4.0-rc2"
requires-python = ">=3.10,<3.13" requires-python = ">=3.10,<3.13"
description = "LNbits, free and open-source Lightning wallet and accounts system." description = "LNbits, free and open-source Lightning wallet and accounts system."
authors = [{ name = "Alan Bits", email = "alan@lnbits.com" }] authors = [{ name = "Alan Bits", email = "alan@lnbits.com" }]
@@ -38,7 +38,7 @@ dependencies = [
"bolt11==2.1.1", "bolt11==2.1.1",
"pyjwt==2.10.1", "pyjwt==2.10.1",
"itsdangerous==2.2.0", "itsdangerous==2.2.0",
"fastapi-sso==0.19.0", "fastapi-sso==0.18.0",
# needed for boltz, lnurldevice, watchonly extensions # needed for boltz, lnurldevice, watchonly extensions
"embit==0.8.0", "embit==0.8.0",
# needed for scheduler extension # needed for scheduler extension
@@ -51,7 +51,6 @@ dependencies = [
"jsonpath-ng==1.7.0", "jsonpath-ng==1.7.0",
"pillow>=12.0.0", "pillow>=12.0.0",
"python-dotenv>=1.2.1", "python-dotenv>=1.2.1",
"greenlet (>=3.3.0,<4.0.0)",
] ]
[project.scripts] [project.scripts]
@@ -59,7 +58,7 @@ lnbits = "lnbits.server:main"
lnbits-cli = "lnbits.commands:main" lnbits-cli = "lnbits.commands:main"
[project.optional-dependencies] [project.optional-dependencies]
breez = ["breez-sdk==0.8.0", "breez-sdk-liquid==0.11.11"] breez = ["breez-sdk==0.8.0", "breez-sdk-liquid==0.9.1"]
liquid = ["wallycore==1.4.0"] liquid = ["wallycore==1.4.0"]
migration = ["psycopg2-binary==2.9.10"] migration = ["psycopg2-binary==2.9.10"]
-100
View File
@@ -5,7 +5,6 @@ import pytest
import shortuuid import shortuuid
from httpx import AsyncClient from httpx import AsyncClient
from lnbits.core.crud.wallets import get_wallets
from lnbits.core.models.users import Account, User from lnbits.core.models.users import Account, User
from lnbits.core.services.users import create_user_account from lnbits.core.services.users import create_user_account
from lnbits.settings import Settings from lnbits.settings import Settings
@@ -511,102 +510,3 @@ async def test_search_users(http_client: AsyncClient, superuser_token):
data = create_resp.json() data = create_resp.json()
assert data["total"] == 1 assert data["total"] == 1
assert data["data"][0]["username"] == users[0].username assert data["data"][0]["username"] == users[0].username
@pytest.mark.anyio
async def test_delete_user_success(http_client: AsyncClient, superuser_token):
# Create a user first
tiny_id = shortuuid.uuid()[:8]
data = {
"username": f"delete_{tiny_id}",
"password": "secret1234",
"password_repeat": "secret1234",
"email": f"delete_{tiny_id}@lnbits.com",
}
create_resp = await http_client.post(
"/users/api/v1/user",
json=data,
headers={"Authorization": f"Bearer {superuser_token}"},
)
assert create_resp.status_code == 200
user = create_resp.json()
user_id = user["id"]
wallets = await get_wallets(user_id=user_id)
assert len(wallets) == 1
# Delete the user
delete_resp = await http_client.delete(
f"/users/api/v1/user/{user_id}",
headers={"Authorization": f"Bearer {superuser_token}"},
)
assert delete_resp.status_code == 200
assert delete_resp.json()["success"] is True
# Ensure user is deleted
get_resp = await http_client.get(
f"/users/api/v1/user/{user_id}",
headers={"Authorization": f"Bearer {superuser_token}"},
)
assert get_resp.status_code == 404
wallets = await get_wallets(user_id=user_id)
assert len(wallets) == 0
@pytest.mark.anyio
async def test_delete_and_undelete_wallet(http_client: AsyncClient, superuser_token):
# Create a user
tiny_id = shortuuid.uuid()[:8]
user_data = {
"username": f"walletuser_{tiny_id}",
"password": "secret1234",
"password_repeat": "secret1234",
"email": f"walletuser_{tiny_id}@lnbits.com",
}
user_resp = await http_client.post(
"/users/api/v1/user",
json=user_data,
headers={"Authorization": f"Bearer {superuser_token}"},
)
assert user_resp.status_code == 200
user = user_resp.json()
user_id = user["id"]
# Create a wallet for the user
wallet_resp = await http_client.post(
f"/users/api/v1/user/{user_id}/wallet",
json={"name": "Test Wallet"},
headers={"Authorization": f"Bearer {superuser_token}"},
)
assert wallet_resp.status_code == 200
wallet = wallet_resp.json()
wallet_id = wallet["id"]
# Delete the wallet (soft delete)
delete_resp = await http_client.delete(
f"/users/api/v1/user/{user_id}/wallet/{wallet_id}",
headers={"Authorization": f"Bearer {superuser_token}"},
)
assert delete_resp.status_code == 200
assert delete_resp.json()["success"] is True
# Wallet should be marked as deleted
wallets = await get_wallets(user_id=user_id, deleted=True)
deleted_wallet = next((w for w in wallets if w.id == wallet_id), None)
assert deleted_wallet is not None
assert deleted_wallet.deleted is True
# Undelete the wallet
undelete_resp = await http_client.put(
f"/users/api/v1/user/{user_id}/wallet/{wallet_id}/undelete",
headers={"Authorization": f"Bearer {superuser_token}"},
)
assert undelete_resp.status_code == 200
assert undelete_resp.json()["success"] is True
# Wallet should be active again
wallets = await get_wallets(user_id=user_id, deleted=False)
undeleted_wallet = next((w for w in wallets if w.id == wallet_id), None)
assert undeleted_wallet is not None
assert undeleted_wallet.deleted is False
+2 -2
View File
@@ -331,8 +331,8 @@ def _settings_cleanup(settings: Settings):
settings.lnbits_allowed_users = [] settings.lnbits_allowed_users = []
settings.auth_allowed_methods = AuthMethods.all() settings.auth_allowed_methods = AuthMethods.all()
settings.auth_credetials_update_threshold = 120 settings.auth_credetials_update_threshold = 120
settings.lnbits_reserve_fee_percent = 2 settings.lnbits_reserve_fee_percent = 1
settings.lnbits_reserve_fee_min = 20000 settings.lnbits_reserve_fee_min = 2000
settings.lnbits_service_fee = 0 settings.lnbits_service_fee = 0
settings.lnbits_reserve_fee_percent = 0 settings.lnbits_reserve_fee_percent = 0
settings.lnbits_wallet_limit_daily_max_withdraw = 0 settings.lnbits_wallet_limit_daily_max_withdraw = 0
+1 -22
View File
@@ -6,11 +6,6 @@ from subprocess import PIPE, Popen, TimeoutExpired
from loguru import logger from loguru import logger
from lnbits.wallets import get_funding_source
funding_source = get_funding_source()
is_boltz_wallet = funding_source.__class__.__name__ == "BoltzWallet"
docker_lightning_cli = [ docker_lightning_cli = [
"docker", "docker",
"exec", "exec",
@@ -32,16 +27,6 @@ docker_bitcoin_cli = [
] ]
docker_elements_cli = [
"docker",
"exec",
"lnbits-elementsd-1",
"elements-cli",
"-rpcport=18884",
"-chain=liquidregtest",
]
docker_lightning_unconnected_cli = [ docker_lightning_unconnected_cli = [
"docker", "docker",
"exec", "exec",
@@ -65,7 +50,7 @@ docker_lightning_noroute_cli = [
def run_cmd(cmd: list) -> str: def run_cmd(cmd: list) -> str:
timeout = 30 timeout = 10
process = Popen(cmd, stdout=PIPE, stderr=PIPE) process = Popen(cmd, stdout=PIPE, stderr=PIPE)
logger.debug(f"running command: {cmd}") logger.debug(f"running command: {cmd}")
@@ -143,12 +128,6 @@ def mine_blocks(blocks: int = 1) -> str:
return run_cmd(cmd) return run_cmd(cmd)
def mine_blocks_liquid(blocks: int = 1) -> str:
cmd = docker_elements_cli.copy()
cmd.extend(["-generate", str(blocks)])
return run_cmd(cmd)
def get_unconnected_node_uri() -> str: def get_unconnected_node_uri() -> str:
cmd = docker_lightning_unconnected_cli.copy() cmd = docker_lightning_unconnected_cli.copy()
cmd.append("getinfo") cmd.append("getinfo")
+4 -12
View File
@@ -18,7 +18,6 @@ from ..helpers import FakeError, is_fake, is_regtest
from .helpers import ( from .helpers import (
cancel_invoice, cancel_invoice,
get_real_invoice, get_real_invoice,
mine_blocks_liquid,
pay_real_invoice, pay_real_invoice,
settle_invoice, settle_invoice,
) )
@@ -67,7 +66,7 @@ async def test_pay_real_invoice(
await asyncio.sleep(1) await asyncio.sleep(1)
balance = await get_node_balance_sats() balance = await get_node_balance_sats()
assert prev_balance - balance == 100 + abs(payment.fee // 1000) assert prev_balance - balance == 100
@pytest.mark.anyio @pytest.mark.anyio
@@ -154,8 +153,7 @@ async def test_create_real_invoice(client, adminkey_headers_from, inkey_headers_
async def on_paid(payment: Payment): async def on_paid(payment: Payment):
assert payment.payment_hash == invoice["payment_hash"] assert payment.checking_id == invoice["payment_hash"]
assert payment.checking_id == invoice["checking_id"]
response = await client.get( response = await client.get(
f'/api/v1/payments/{invoice["payment_hash"]}', headers=inkey_headers_from f'/api/v1/payments/{invoice["payment_hash"]}', headers=inkey_headers_from
@@ -166,8 +164,7 @@ async def test_create_real_invoice(client, adminkey_headers_from, inkey_headers_
await asyncio.sleep(1) await asyncio.sleep(1)
balance = await get_node_balance_sats() balance = await get_node_balance_sats()
fee = abs(payment_status.get("details", {}).get("fee", 0) // 1000) assert balance - prev_balance == create_invoice.amount
assert balance - prev_balance == create_invoice.amount - fee
assert payment_status.get("preimage") is not None assert payment_status.get("preimage") is not None
@@ -203,8 +200,6 @@ async def test_pay_real_invoice_set_pending_and_check_state(
assert len(invoice["payment_hash"]) == 64 assert len(invoice["payment_hash"]) == 64
assert len(invoice["checking_id"]) > 0 assert len(invoice["checking_id"]) > 0
mine_blocks_liquid(1)
await asyncio.sleep(1)
# check the payment status # check the payment status
response = await client.get( response = await client.get(
f'/api/v1/payments/{invoice["payment_hash"]}', headers=inkey_headers_from f'/api/v1/payments/{invoice["payment_hash"]}', headers=inkey_headers_from
@@ -346,7 +341,6 @@ async def test_pay_hold_invoice_check_pending_and_fail_cancel_payment_task_in_me
assert preimage_hash == invoice_obj.payment_hash assert preimage_hash == invoice_obj.payment_hash
cancel_invoice(preimage_hash) cancel_invoice(preimage_hash)
mine_blocks_liquid(1)
# check if paid # check if paid
await asyncio.sleep(1) await asyncio.sleep(1)
@@ -388,9 +382,7 @@ async def test_receive_real_invoice_set_pending_and_check_state(
assert not payment_status["paid"] assert not payment_status["paid"]
async def on_paid(payment: Payment): async def on_paid(payment: Payment):
assert payment.checking_id == invoice["payment_hash"]
assert payment.payment_hash == invoice["payment_hash"]
assert payment.checking_id == invoice["checking_id"]
response = await client.get( response = await client.get(
f'/api/v1/payments/{invoice["payment_hash"]}', headers=inkey_headers_from f'/api/v1/payments/{invoice["payment_hash"]}', headers=inkey_headers_from
+2 -10
View File
@@ -7,8 +7,6 @@ from lnbits.core.services import (
from lnbits.wallets import get_funding_source from lnbits.wallets import get_funding_source
from lnbits.wallets.base import PaymentStatus from lnbits.wallets.base import PaymentStatus
from .helpers import is_boltz_wallet
description = "test create invoice" description = "test create invoice"
@@ -19,10 +17,7 @@ async def test_create_invoice(from_wallet):
amount=1000, amount=1000,
memo=description, memo=description,
) )
assert payment.preimage
# we cannot know the preimage of the swap yet
if not is_boltz_wallet:
assert payment.preimage
invoice = decode(payment.bolt11) invoice = decode(payment.bolt11)
assert invoice.payment_hash == payment.payment_hash assert invoice.payment_hash == payment.payment_hash
@@ -40,10 +35,7 @@ async def test_create_internal_invoice(from_wallet):
payment = await create_invoice( payment = await create_invoice(
wallet_id=from_wallet.id, amount=1000, memo=description, internal=True wallet_id=from_wallet.id, amount=1000, memo=description, internal=True
) )
assert payment.preimage
# we cannot know the preimage of the swap yet
if not is_boltz_wallet:
assert payment.preimage
invoice = decode(payment.bolt11) invoice = decode(payment.bolt11)
assert invoice.payment_hash == payment.payment_hash assert invoice.payment_hash == payment.payment_hash
+2 -7
View File
@@ -6,8 +6,6 @@ from lnbits.core.services import (
) )
from lnbits.exceptions import PaymentError from lnbits.exceptions import PaymentError
from .helpers import is_boltz_wallet
description = "test pay invoice" description = "test pay invoice"
@@ -19,12 +17,9 @@ async def test_services_pay_invoice(to_wallet, real_invoice):
description=description, description=description,
) )
assert payment assert payment
assert payment.status == PaymentState.SUCCESS
assert payment.memo == description assert payment.memo == description
if not is_boltz_wallet: assert payment.preimage
assert payment.status == PaymentState.SUCCESS
assert payment.preimage
else:
assert payment.status == PaymentState.PENDING
@pytest.mark.anyio @pytest.mark.anyio
-12
View File
@@ -1,5 +1,3 @@
import asyncio
import pytest import pytest
from lnbits.core.crud import ( from lnbits.core.crud import (
@@ -8,7 +6,6 @@ from lnbits.core.crud import (
get_payments_paginated, get_payments_paginated,
update_payment, update_payment,
) )
from lnbits.core.crud.payments import get_standalone_payment
from lnbits.core.models import PaymentFilters, PaymentState from lnbits.core.models import PaymentFilters, PaymentState
from lnbits.core.services import ( from lnbits.core.services import (
create_invoice, create_invoice,
@@ -42,15 +39,6 @@ async def test_crud_get_payments(app):
filters = Filters(limit=100) filters = Filters(limit=100)
payments = await get_payments(wallet_id=wallet.id, filters=filters) payments = await get_payments(wallet_id=wallet.id, filters=filters)
assert len(payments) == 22, "should return 22 successful payments" assert len(payments) == 22, "should return 22 successful payments"
first_payment = payments[0]
first_payment_updated_at = first_payment.updated_at.replace()
await update_payment(first_payment)
await asyncio.sleep(0.1) # ensure updated_at will be different
first_payment_updated = await get_standalone_payment(first_payment.checking_id)
assert first_payment_updated, "Updated payment not found"
assert (
first_payment_updated.updated_at > first_payment_updated_at
), "Updated payment timestamp is not newer"
payments = await get_payments(wallet_id=wallet.id, incoming=True, filters=filters) payments = await get_payments(wallet_id=wallet.id, incoming=True, filters=filters)
assert len(payments) == 11, "should return 11 successful incoming payments" assert len(payments) == 11, "should return 11 successful incoming payments"
+16 -53
View File
@@ -8,21 +8,19 @@ import os
import sqlite3 import sqlite3
import sys import sys
from loguru import logger
from lnbits.settings import settings from lnbits.settings import settings
try: try:
import psycopg2 # type: ignore import psycopg2 # type: ignore
except ImportError: except ImportError:
logger.warning("Please install psycopg2") print("Please install psycopg2")
sys.exit(1) sys.exit(1)
sqfolder = settings.lnbits_data_folder sqfolder = settings.lnbits_data_folder
db_url = settings.lnbits_database_url db_url = settings.lnbits_database_url
if db_url is None: if db_url is None:
logger.warning("missing LNBITS_DATABASE_URL") print("missing LNBITS_DATABASE_URL")
sys.exit(1) sys.exit(1)
else: else:
# parse postgres://lnbits:postgres@localhost:5432/lnbits # parse postgres://lnbits:postgres@localhost:5432/lnbits
@@ -68,7 +66,7 @@ def check_db_versions(sqdb):
postgres.close() postgres.close()
connection.close() connection.close()
logger.info("Database versions OK, converting") print("Database versions OK, converting")
def fix_id(seq, values): def fix_id(seq, values):
@@ -97,11 +95,11 @@ def insert_to_pg(query, data):
cursor.execute(query, d) cursor.execute(query, d)
except Exception as exc: except Exception as exc:
if args.ignore_errors: if args.ignore_errors:
logger.error(exc) print(exc)
logger.error(f"Failed to insert {d}") print(f"Failed to insert {d}")
else: else:
logger.error("query:", query) print("query:", query)
logger.error("data:", d) print("data:", d)
raise ValueError(f"Failed to insert {d}") from exc raise ValueError(f"Failed to insert {d}") from exc
connection.commit() connection.commit()
@@ -112,20 +110,17 @@ def insert_to_pg(query, data):
def migrate_core(file: str, exclude_tables: list[str] | None = None): def migrate_core(file: str, exclude_tables: list[str] | None = None):
if exclude_tables is None: if exclude_tables is None:
exclude_tables = [] exclude_tables = []
logger.info(f"Migrating core: {file}") print(f"Migrating core: {file}")
migrate_db(file, "public", exclude_tables) migrate_db(file, "public", exclude_tables)
logger.info("✅ Migrated core") print("✅ Migrated core")
def migrate_ext(file: str): def migrate_ext(file: str):
filename = os.path.basename(file) filename = os.path.basename(file)
schema = filename.replace("ext_", "").split(".")[0] schema = filename.replace("ext_", "").split(".")[0]
try: print(f"Migrating ext: {schema} from file {file}")
logger.info(f"Migrating ext: {schema} from file {file}") migrate_db(file, schema)
migrate_db(file, schema) print(f"✅ Migrated ext: {schema}")
logger.info(f"✅ Migrated ext: {schema}")
except Exception as exc:
logger.error(f"🛑 Failed to migrate extension {schema}: {exc}")
def migrate_db(file: str, schema: str, exclude_tables: list[str] | None = None): def migrate_db(file: str, schema: str, exclude_tables: list[str] | None = None):
@@ -144,7 +139,7 @@ def migrate_db(file: str, schema: str, exclude_tables: list[str] | None = None):
for table in tables: for table in tables:
table_name = table[0] table_name = table[0]
logger.info(f"Migrating table {table_name}") print(f"Migrating table {table_name}")
# hard coded skip for dbversions (already produced during startup) # hard coded skip for dbversions (already produced during startup)
if table_name == "dbversions": if table_name == "dbversions":
continue continue
@@ -157,7 +152,7 @@ def migrate_db(file: str, schema: str, exclude_tables: list[str] | None = None):
data = cursor.execute(f"SELECT * FROM {table_name};").fetchall() data = cursor.execute(f"SELECT * FROM {table_name};").fetchall()
if len(data) == 0: if len(data) == 0:
logger.warning(f"🛑 You sneaky dev! Table {table_name} is empty!") print(f"🛑 You sneaky dev! Table {table_name} is empty!")
insert_to_pg(q, data) insert_to_pg(q, data)
cursor.close() cursor.close()
@@ -166,44 +161,12 @@ def migrate_db(file: str, schema: str, exclude_tables: list[str] | None = None):
def build_insert_query(schema, table_name, columns): def build_insert_query(schema, table_name, columns):
to_columns = ", ".join([f'"{column[1].lower()}"' for column in columns]) to_columns = ", ".join([f'"{column[1].lower()}"' for column in columns])
values = ", ".join([to_column_type(column[2]) for column in columns]) values = ", ".join([to_column_type(column[2]) for column in columns])
on_conflict_update = build_on_conflict_query_statement(schema, table_name, columns)
return f""" return f"""
INSERT INTO {schema}.{table_name}({to_columns}) INSERT INTO {schema}.{table_name}({to_columns})
VALUES ({values}) VALUES ({values});
{on_conflict_update}
""" """
def build_on_conflict_query_statement(schema, table_name, columns):
unique_cols = table_unique_columns(schema, table_name)
if len(unique_cols) == 0:
return ""
return f"""
ON CONFLICT ({", ".join([f'"{col}"' for col in unique_cols])})
DO UPDATE SET
{", ".join([
f'"{column[1].lower()}"=EXCLUDED."{column[1].lower()}"'
for column in columns
])}
"""
def table_unique_columns(schema, table_name):
cursor = get_postgres_cursor()
query = f"""
SELECT a.attname
FROM pg_index i
JOIN pg_attribute a ON a.attrelid = i.indrelid
AND a.attnum = ANY(i.indkey)
WHERE i.indrelid = '{schema}.{table_name}'::regclass
AND i.indisunique;
"""
cursor.execute(query)
columns = [row[0] for row in cursor.fetchall()]
cursor.close()
return columns
def to_column_type(column_type): def to_column_type(column_type):
if column_type == "TIMESTAMP": if column_type == "TIMESTAMP":
return "to_timestamp(%s)" return "to_timestamp(%s)"
@@ -255,7 +218,7 @@ parser.add_argument(
args = parser.parse_args() args = parser.parse_args()
logger.info("Selected path: ", args.sqlite_path) print("Selected path: ", args.sqlite_path)
if os.path.isdir(args.sqlite_path): if os.path.isdir(args.sqlite_path):
exclude_tables = ["dbversions"] exclude_tables = ["dbversions"]
Generated
+63 -56
View File
@@ -407,24 +407,24 @@ wheels = [
[[package]] [[package]]
name = "breez-sdk-liquid" name = "breez-sdk-liquid"
version = "0.11.11" version = "0.9.1"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
wheels = [ wheels = [
{ url = "https://files.pythonhosted.org/packages/1f/ba/38408250e136343c5e7ee063f187df29a391c233fac32f8bf924f0d00c85/breez_sdk_liquid-0.11.11-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:0c1da93d69112cee65c07f1bf3efbcfbb9182c5e3d8933ca27adc659eae064e0", size = 24855120, upload-time = "2025-12-01T16:16:31.212Z" }, { url = "https://files.pythonhosted.org/packages/a6/18/82738bb946fbd5a62fe363f2e9b608a7ca9e2e9ca8d566787da56af3b93f/breez_sdk_liquid-0.9.1-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:414a7c04dbf869435fe234b3b9987699c15dc2f8d4660d9ca1a51af608331b45", size = 26024860, upload-time = "2025-05-22T12:42:07.945Z" },
{ url = "https://files.pythonhosted.org/packages/e0/0a/73a0f2ce7550c04bb78939709d7f0c4c0d8222821457d8ec0791f0c0dd3d/breez_sdk_liquid-0.11.11-cp310-cp310-manylinux_2_31_aarch64.whl", hash = "sha256:c2b2d9a04022e05eb56699b6e8a628e7b53676d6f90b1c461c0b1b38b781d952", size = 16045266, upload-time = "2025-12-01T16:16:33.679Z" }, { url = "https://files.pythonhosted.org/packages/95/e2/8c86e571c2e1798b5d0ef20ebb588e6e76a85ebf0136b600fbfb334b7153/breez_sdk_liquid-0.9.1-cp310-cp310-manylinux_2_31_aarch64.whl", hash = "sha256:7f461b6b10ddfe9cfb58119e590e5f67da4d7c93fc580a84a0116ce9fd21dffa", size = 16400772, upload-time = "2025-05-22T12:42:10.925Z" },
{ url = "https://files.pythonhosted.org/packages/75/e9/ddc34c2ebd2a2181c61669bebc5f40853ff7a72aad0bea8162d8c6329b65/breez_sdk_liquid-0.11.11-cp310-cp310-manylinux_2_31_x86_64.whl", hash = "sha256:6fb44fb16bd55a53fcbd22c7a1982bc8b83de655d0b3e677fe6debd366b41890", size = 15214330, upload-time = "2025-12-01T16:16:35.994Z" }, { url = "https://files.pythonhosted.org/packages/96/41/9f49558415ac13df2371fc9d486aaf0d07d49735caf845dd944b3cbe5f3c/breez_sdk_liquid-0.9.1-cp310-cp310-manylinux_2_31_x86_64.whl", hash = "sha256:c27efe35539e4092dddbe5315f5cefffccbdd699017ed8733611d11eb52f4ce0", size = 15658538, upload-time = "2025-05-22T12:42:13.421Z" },
{ url = "https://files.pythonhosted.org/packages/f7/19/84f59b425683a1be127b0fe203d3040ee21fbd7f773dbe6e6153b288372d/breez_sdk_liquid-0.11.11-cp310-cp310-win32.whl", hash = "sha256:04719223f8b5a44401c02aef6202076e0e557f28476b7cbe787ed9e7947e641a", size = 10214705, upload-time = "2025-12-01T16:16:39.137Z" }, { url = "https://files.pythonhosted.org/packages/7d/f4/81fe1dbb63b13611e5541d5aae70e6a0166f73208e0d01aa56a954bb521a/breez_sdk_liquid-0.9.1-cp310-cp310-win32.whl", hash = "sha256:375f6322c2552d15d6ba68302a85fdc345a7671eeda8fea92c013a16c5e96505", size = 10526907, upload-time = "2025-05-22T12:42:16.258Z" },
{ url = "https://files.pythonhosted.org/packages/eb/d0/2d94e9afa5a7900a3c75b8a428386c3ba48de8a383eecd2b5403ad4d2b1d/breez_sdk_liquid-0.11.11-cp310-cp310-win_amd64.whl", hash = "sha256:0d36272277e8d5b0287b45cacce5444934579ae9f6726de377c9de7d4535dc6f", size = 10743378, upload-time = "2025-12-01T16:16:40.884Z" }, { url = "https://files.pythonhosted.org/packages/38/11/b8f2f0daa02f97fb1b23c32cad5f195fcf30bf7093dda982d01d58d4f51e/breez_sdk_liquid-0.9.1-cp310-cp310-win_amd64.whl", hash = "sha256:f28d107099fb7caaac4051d5950a4f11bf823e11b56e797976c5fa2a7280d597", size = 11079422, upload-time = "2025-05-22T12:42:18.709Z" },
{ url = "https://files.pythonhosted.org/packages/a7/c8/324891a06997e7c8a9713891484b4350613754db663067fac89fd5d0025f/breez_sdk_liquid-0.11.11-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:4ab4029773e5d2f946872ced5b3c76c5686e00cf6786b9515b707e16691e40dd", size = 24855121, upload-time = "2025-12-01T16:16:43.094Z" }, { url = "https://files.pythonhosted.org/packages/7e/70/b428e714c433d9193ef6917059f4d9d8e9d1c32d1d2eee632ce65efdca3b/breez_sdk_liquid-0.9.1-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:acefa49896bdb4ca06d351faacbf075646d574dda5539033df11310ec5a94446", size = 26024861, upload-time = "2025-05-22T12:42:21.166Z" },
{ url = "https://files.pythonhosted.org/packages/82/04/93adc12245f6e53fb036f4f51eb59b463e629f372543c6a72a31a3903a82/breez_sdk_liquid-0.11.11-cp311-cp311-manylinux_2_31_aarch64.whl", hash = "sha256:b3ab95f85f7454710c312443d4c0bc96fd1f06a4d3453305eb2fc9c510e9441e", size = 16045269, upload-time = "2025-12-01T16:16:45.194Z" }, { url = "https://files.pythonhosted.org/packages/42/ab/f92f258ba54053a48948b54912f72d9124e92699c809267473034c2a3797/breez_sdk_liquid-0.9.1-cp311-cp311-manylinux_2_31_aarch64.whl", hash = "sha256:d0e54fd5c8ce542dc2061d8a1ef46e6a1d430dbaea5eab369bb91ae2c4a1be7b", size = 16400775, upload-time = "2025-05-22T12:42:23.886Z" },
{ url = "https://files.pythonhosted.org/packages/04/51/e831d1c0d2639a33b4123e991acbc594838c4a22ac356b9f027e09ac1d32/breez_sdk_liquid-0.11.11-cp311-cp311-manylinux_2_31_x86_64.whl", hash = "sha256:bf85cecaad3d433ee9af75814a921d5ae582a74c9f4009c8bc865c820b9f8cd9", size = 15214332, upload-time = "2025-12-01T16:16:48.287Z" }, { url = "https://files.pythonhosted.org/packages/0d/e3/0fec9245a1006151fe572d46cf50f3c882c5ca15cef306a63f1b467d2bf7/breez_sdk_liquid-0.9.1-cp311-cp311-manylinux_2_31_x86_64.whl", hash = "sha256:a5d1bfd4d3286d57c110d925332416b0903dda076dadede02c4b7db67576f0bf", size = 15658540, upload-time = "2025-05-22T12:42:25.914Z" },
{ url = "https://files.pythonhosted.org/packages/81/ad/c46ae0bcbf3479f41a4c4f1d11e9d6d7152bfcea84e85de2fe53077c0093/breez_sdk_liquid-0.11.11-cp311-cp311-win32.whl", hash = "sha256:f9b0c5393111f7de3511c061f680f94cfd867f6f2e114904c3f5e31fe1fa2824", size = 10214707, upload-time = "2025-12-01T16:16:50.345Z" }, { url = "https://files.pythonhosted.org/packages/83/2c/4c508330a2735a49a815e06ae7876a57fb75a41e256f5dd70994df8f0f20/breez_sdk_liquid-0.9.1-cp311-cp311-win32.whl", hash = "sha256:3ce2152f0a2ba65f4425fd22efb8e1dafb419e5fcf3b93dfe06fc061b1d1c0c6", size = 10526908, upload-time = "2025-05-22T12:42:27.803Z" },
{ url = "https://files.pythonhosted.org/packages/cc/2b/262bd6dbba9a9ce021290b8fa724eabed7dd562dd1a419147ef92fd3e6b2/breez_sdk_liquid-0.11.11-cp311-cp311-win_amd64.whl", hash = "sha256:7d2862108da64e2b73de46f61ff7d2df5607cbb6bb78a1bc437d19d06caa9f93", size = 10743377, upload-time = "2025-12-01T16:16:52.028Z" }, { url = "https://files.pythonhosted.org/packages/3f/c4/1ac65ea96afd5e847f3027eeab67c629e03f19d5fb95fe6f36d6042812cc/breez_sdk_liquid-0.9.1-cp311-cp311-win_amd64.whl", hash = "sha256:8cdb4f247bccc0f4b9bbfff4451faa78d7b17e76a9dc918804880b600f1d4249", size = 11079420, upload-time = "2025-05-22T12:42:29.988Z" },
{ url = "https://files.pythonhosted.org/packages/ec/ad/1733513975b1363844fb341194f67f53b78ce0fe942b5cc9650b93630974/breez_sdk_liquid-0.11.11-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:93faa55da3b4c850b1655b66b8822bd36b40a0491990d31d5d6f9000e0e61521", size = 24855161, upload-time = "2025-12-01T16:16:54.455Z" }, { url = "https://files.pythonhosted.org/packages/00/6b/0adb00ea6ac9f9c8b917a690859e16f01f097533808c8ebe261c71171bf0/breez_sdk_liquid-0.9.1-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:c463191a89a829afcae19c94f7683dac415667755d68c212afc60d8f2b21ba63", size = 2113486, upload-time = "2025-05-22T12:42:31.709Z" },
{ url = "https://files.pythonhosted.org/packages/e0/40/400ac6ce7f3c1cdf58558d6d4cc42dbee6a4a8fd46dde362a0c979aac400/breez_sdk_liquid-0.11.11-cp312-cp312-manylinux_2_31_aarch64.whl", hash = "sha256:337be3e6c59bba6890629fc82e7b8f342bbf19fdb0f9c4a2f0d2aa5e93dfa690", size = 16045270, upload-time = "2025-12-01T16:16:56.668Z" }, { url = "https://files.pythonhosted.org/packages/d3/c2/5d3f8feeaf61d04c5266385df5f96bc86c0f2f30536c0aea195d02018dcd/breez_sdk_liquid-0.9.1-cp312-cp312-manylinux_2_31_aarch64.whl", hash = "sha256:52efaeae2c278b498b37de1090e80f73987ee943743e69a363877ed93cd7a31e", size = 16400811, upload-time = "2025-05-22T12:42:33.062Z" },
{ url = "https://files.pythonhosted.org/packages/1c/6a/5428ba3ce098ee4c62d4da9212d08a9017a83614df796e8224aee791745b/breez_sdk_liquid-0.11.11-cp312-cp312-manylinux_2_31_x86_64.whl", hash = "sha256:129baf243381bf5ce4d2927f52dabc68f61f9e173d498ee53d9aef55f4e44fb2", size = 15214331, upload-time = "2025-12-01T16:16:58.766Z" }, { url = "https://files.pythonhosted.org/packages/90/90/78e5394e103861bddfa96cf57346e525789825e5f86beb650796f9c3bdc9/breez_sdk_liquid-0.9.1-cp312-cp312-manylinux_2_31_x86_64.whl", hash = "sha256:68aebea98990319c677bcbd7d1de258627b85063a29720879986694b9d393adb", size = 15658577, upload-time = "2025-05-22T12:42:35.501Z" },
{ url = "https://files.pythonhosted.org/packages/ca/0c/e8f64c8ca1e8468abc7a17efa5a248029b724417cdb9181125178cffe83b/breez_sdk_liquid-0.11.11-cp312-cp312-win32.whl", hash = "sha256:9acd3eea87c861ed5cde91e188d38e893090d5de925c9ed3c9b21f9be15abe0d", size = 10214706, upload-time = "2025-12-01T16:17:00.776Z" }, { url = "https://files.pythonhosted.org/packages/d6/82/0384263df1d6f214faacdedb2e4080ec63c26749249262dab51a06695147/breez_sdk_liquid-0.9.1-cp312-cp312-win32.whl", hash = "sha256:f53e4a1973dfd41df3ac3ecb42cf72acb71f49d5727a8acab25668b51a953bb2", size = 10526907, upload-time = "2025-05-22T12:42:37.851Z" },
{ url = "https://files.pythonhosted.org/packages/5c/8f/d7aa56c865ac060a540eb6fb214d6ea597c7f3408980ef5d0b1555c5984b/breez_sdk_liquid-0.11.11-cp312-cp312-win_amd64.whl", hash = "sha256:466824ad3124ef22262ccc5ce76f5cedefd4a2540bb0cd0408e9b2f4e67ac58a", size = 10743378, upload-time = "2025-12-01T16:17:02.784Z" }, { url = "https://files.pythonhosted.org/packages/0c/6e/8b3fe3e0d89c0d5ca6d85bdbdd6e99be31faf07a716666bd3c605f8d1a06/breez_sdk_liquid-0.9.1-cp312-cp312-win_amd64.whl", hash = "sha256:6adb1f3f3ccd4b743a11dcc0b307db604c3424f42e2547f94fa939f0afb9bb85", size = 11079422, upload-time = "2025-05-22T12:42:40.968Z" },
] ]
[[package]] [[package]]
@@ -784,7 +784,7 @@ wheels = [
[[package]] [[package]]
name = "fastapi-sso" name = "fastapi-sso"
version = "0.19.0" version = "0.18.0"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
dependencies = [ dependencies = [
{ name = "fastapi" }, { name = "fastapi" },
@@ -793,18 +793,18 @@ dependencies = [
{ name = "pydantic", extra = ["email"] }, { name = "pydantic", extra = ["email"] },
{ name = "pyjwt" }, { name = "pyjwt" },
] ]
sdist = { url = "https://files.pythonhosted.org/packages/74/fc/644bc8f82fc887fffcf9a3eab8eb3dea06ee9ea160ef20441455ed7a0001/fastapi_sso-0.19.0.tar.gz", hash = "sha256:629f00581f72ea7e57f7b8775f8d2c425629c428c194359a2b4ebaa6bcb8e12b", size = 17278, upload-time = "2025-12-17T15:18:06.721Z" } sdist = { url = "https://files.pythonhosted.org/packages/d2/57/cc971c018af5d09eb5f8d1cd12abdd99ab4c59ea5c0b0b1b96349ffe117d/fastapi_sso-0.18.0.tar.gz", hash = "sha256:d8df5a686af7a6a7be248817544b405cf77f7e9ffcd5d0d7d2a196fd071964bc", size = 16811, upload-time = "2025-03-20T17:09:09.958Z" }
wheels = [ wheels = [
{ url = "https://files.pythonhosted.org/packages/d7/61/d2ac0800cb1f390ec2aad464ea4cc5944de285fabc8f987327da4633f17d/fastapi_sso-0.19.0-py3-none-any.whl", hash = "sha256:d958c46cd9996234c7b162e192168b4c0807a248224a55b0f877d3a82a16a930", size = 26419, upload-time = "2025-12-17T15:18:05.439Z" }, { url = "https://files.pythonhosted.org/packages/6e/03/70ca13994f5569d343a9f99dba2930c8ae3471171f161b8887d44b6c526f/fastapi_sso-0.18.0-py3-none-any.whl", hash = "sha256:727754ad770b70690f1471f7b0a9e17c6dfd8ebd6e477616d3bde1eaf62e53dc", size = 26103, upload-time = "2025-03-20T17:09:08.656Z" },
] ]
[[package]] [[package]]
name = "filelock" name = "filelock"
version = "3.20.3" version = "3.20.0"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/1d/65/ce7f1b70157833bf3cb851b556a37d4547ceafc158aa9b34b36782f23696/filelock-3.20.3.tar.gz", hash = "sha256:18c57ee915c7ec61cff0ecf7f0f869936c7c30191bb0cf406f1341778d0834e1", size = 19485, upload-time = "2026-01-09T17:55:05.421Z" } sdist = { url = "https://files.pythonhosted.org/packages/58/46/0028a82567109b5ef6e4d2a1f04a583fb513e6cf9527fcdd09afd817deeb/filelock-3.20.0.tar.gz", hash = "sha256:711e943b4ec6be42e1d4e6690b48dc175c822967466bb31c0c293f34334c13f4", size = 18922, upload-time = "2025-10-08T18:03:50.056Z" }
wheels = [ wheels = [
{ url = "https://files.pythonhosted.org/packages/b5/36/7fb70f04bf00bc646cd5bb45aa9eddb15e19437a28b8fb2b4a5249fac770/filelock-3.20.3-py3-none-any.whl", hash = "sha256:4b0dda527ee31078689fc205ec4f1c1bf7d56cf88b6dc9426c4f230e46c2dce1", size = 16701, upload-time = "2026-01-09T17:55:04.334Z" }, { url = "https://files.pythonhosted.org/packages/76/91/7216b27286936c16f5b4d0c530087e4a54eead683e6b0b73dd0c64844af6/filelock-3.20.0-py3-none-any.whl", hash = "sha256:339b4732ffda5cd79b13f4e2711a31b0365ce445d95d243bb996273d072546a2", size = 16054, upload-time = "2025-10-08T18:03:48.35Z" },
] ]
[[package]] [[package]]
@@ -878,34 +878,43 @@ wheels = [
[[package]] [[package]]
name = "greenlet" name = "greenlet"
version = "3.3.0" version = "3.2.4"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/c7/e5/40dbda2736893e3e53d25838e0f19a2b417dfc122b9989c91918db30b5d3/greenlet-3.3.0.tar.gz", hash = "sha256:a82bb225a4e9e4d653dd2fb7b8b2d36e4fb25bc0165422a11e48b88e9e6f78fb", size = 190651, upload-time = "2025-12-04T14:49:44.05Z" } sdist = { url = "https://files.pythonhosted.org/packages/03/b8/704d753a5a45507a7aab61f18db9509302ed3d0a27ac7e0359ec2905b1a6/greenlet-3.2.4.tar.gz", hash = "sha256:0dca0d95ff849f9a364385f36ab49f50065d76964944638be9691e1832e9f86d", size = 188260, upload-time = "2025-08-07T13:24:33.51Z" }
wheels = [ wheels = [
{ url = "https://files.pythonhosted.org/packages/32/6a/33d1702184d94106d3cdd7bfb788e19723206fce152e303473ca3b946c7b/greenlet-3.3.0-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:6f8496d434d5cb2dce025773ba5597f71f5410ae499d5dd9533e0653258cdb3d", size = 273658, upload-time = "2025-12-04T14:23:37.494Z" }, { url = "https://files.pythonhosted.org/packages/7d/ed/6bfa4109fcb23a58819600392564fea69cdc6551ffd5e69ccf1d52a40cbc/greenlet-3.2.4-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:8c68325b0d0acf8d91dde4e6f930967dd52a5302cd4062932a6b2e7c2969f47c", size = 271061, upload-time = "2025-08-07T13:17:15.373Z" },
{ url = "https://files.pythonhosted.org/packages/d6/b7/2b5805bbf1907c26e434f4e448cd8b696a0b71725204fa21a211ff0c04a7/greenlet-3.3.0-cp310-cp310-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b96dc7eef78fd404e022e165ec55327f935b9b52ff355b067eb4a0267fc1cffb", size = 574810, upload-time = "2025-12-04T14:50:04.154Z" }, { url = "https://files.pythonhosted.org/packages/2a/fc/102ec1a2fc015b3a7652abab7acf3541d58c04d3d17a8d3d6a44adae1eb1/greenlet-3.2.4-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:94385f101946790ae13da500603491f04a76b6e4c059dab271b3ce2e283b2590", size = 629475, upload-time = "2025-08-07T13:42:54.009Z" },
{ url = "https://files.pythonhosted.org/packages/94/38/343242ec12eddf3d8458c73f555c084359883d4ddc674240d9e61ec51fd6/greenlet-3.3.0-cp310-cp310-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:73631cd5cccbcfe63e3f9492aaa664d278fda0ce5c3d43aeda8e77317e38efbd", size = 586248, upload-time = "2025-12-04T14:57:39.35Z" }, { url = "https://files.pythonhosted.org/packages/c5/26/80383131d55a4ac0fb08d71660fd77e7660b9db6bdb4e8884f46d9f2cc04/greenlet-3.2.4-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:f10fd42b5ee276335863712fa3da6608e93f70629c631bf77145021600abc23c", size = 640802, upload-time = "2025-08-07T13:45:25.52Z" },
{ url = "https://files.pythonhosted.org/packages/f0/d0/0ae86792fb212e4384041e0ef8e7bc66f59a54912ce407d26a966ed2914d/greenlet-3.3.0-cp310-cp310-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b299a0cb979f5d7197442dccc3aee67fce53500cd88951b7e6c35575701c980b", size = 597403, upload-time = "2025-12-04T15:07:10.831Z" }, { url = "https://files.pythonhosted.org/packages/9f/7c/e7833dbcd8f376f3326bd728c845d31dcde4c84268d3921afcae77d90d08/greenlet-3.2.4-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:c8c9e331e58180d0d83c5b7999255721b725913ff6bc6cf39fa2a45841a4fd4b", size = 636703, upload-time = "2025-08-07T13:53:12.622Z" },
{ url = "https://files.pythonhosted.org/packages/b6/a8/15d0aa26c0036a15d2659175af00954aaaa5d0d66ba538345bd88013b4d7/greenlet-3.3.0-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7dee147740789a4632cace364816046e43310b59ff8fb79833ab043aefa72fd5", size = 586910, upload-time = "2025-12-04T14:25:59.705Z" }, { url = "https://files.pythonhosted.org/packages/e9/49/547b93b7c0428ede7b3f309bc965986874759f7d89e4e04aeddbc9699acb/greenlet-3.2.4-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:58b97143c9cc7b86fc458f215bd0932f1757ce649e05b640fea2e79b54cedb31", size = 635417, upload-time = "2025-08-07T13:18:25.189Z" },
{ url = "https://files.pythonhosted.org/packages/e1/9b/68d5e3b7ccaba3907e5532cf8b9bf16f9ef5056a008f195a367db0ff32db/greenlet-3.3.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:39b28e339fc3c348427560494e28d8a6f3561c8d2bcf7d706e1c624ed8d822b9", size = 1547206, upload-time = "2025-12-04T15:04:21.027Z" }, { url = "https://files.pythonhosted.org/packages/7f/91/ae2eb6b7979e2f9b035a9f612cf70f1bf54aad4e1d125129bef1eae96f19/greenlet-3.2.4-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c2ca18a03a8cfb5b25bc1cbe20f3d9a4c80d8c3b13ba3df49ac3961af0b1018d", size = 584358, upload-time = "2025-08-07T13:18:23.708Z" },
{ url = "https://files.pythonhosted.org/packages/66/bd/e3086ccedc61e49f91e2cfb5ffad9d8d62e5dc85e512a6200f096875b60c/greenlet-3.3.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b3c374782c2935cc63b2a27ba8708471de4ad1abaa862ffdb1ef45a643ddbb7d", size = 1613359, upload-time = "2025-12-04T14:27:26.548Z" }, { url = "https://files.pythonhosted.org/packages/f7/85/433de0c9c0252b22b16d413c9407e6cb3b41df7389afc366ca204dbc1393/greenlet-3.2.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:9fe0a28a7b952a21e2c062cd5756d34354117796c6d9215a87f55e38d15402c5", size = 1113550, upload-time = "2025-08-07T13:42:37.467Z" },
{ url = "https://files.pythonhosted.org/packages/f4/6b/d4e73f5dfa888364bbf02efa85616c6714ae7c631c201349782e5b428925/greenlet-3.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:b49e7ed51876b459bd645d83db257f0180e345d3f768a35a85437a24d5a49082", size = 300740, upload-time = "2025-12-04T14:47:52.773Z" }, { url = "https://files.pythonhosted.org/packages/a1/8d/88f3ebd2bc96bf7747093696f4335a0a8a4c5acfcf1b757717c0d2474ba3/greenlet-3.2.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8854167e06950ca75b898b104b63cc646573aa5fef1353d4508ecdd1ee76254f", size = 1137126, upload-time = "2025-08-07T13:18:20.239Z" },
{ url = "https://files.pythonhosted.org/packages/1f/cb/48e964c452ca2b92175a9b2dca037a553036cb053ba69e284650ce755f13/greenlet-3.3.0-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:e29f3018580e8412d6aaf5641bb7745d38c85228dacf51a73bd4e26ddf2a6a8e", size = 274908, upload-time = "2025-12-04T14:23:26.435Z" }, { url = "https://files.pythonhosted.org/packages/f1/29/74242b7d72385e29bcc5563fba67dad94943d7cd03552bac320d597f29b2/greenlet-3.2.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f47617f698838ba98f4ff4189aef02e7343952df3a615f847bb575c3feb177a7", size = 1544904, upload-time = "2025-11-04T12:42:04.763Z" },
{ url = "https://files.pythonhosted.org/packages/28/da/38d7bff4d0277b594ec557f479d65272a893f1f2a716cad91efeb8680953/greenlet-3.3.0-cp311-cp311-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a687205fb22794e838f947e2194c0566d3812966b41c78709554aa883183fb62", size = 577113, upload-time = "2025-12-04T14:50:05.493Z" }, { url = "https://files.pythonhosted.org/packages/c8/e2/1572b8eeab0f77df5f6729d6ab6b141e4a84ee8eb9bc8c1e7918f94eda6d/greenlet-3.2.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:af41be48a4f60429d5cad9d22175217805098a9ef7c40bfef44f7669fb9d74d8", size = 1611228, upload-time = "2025-11-04T12:42:08.423Z" },
{ url = "https://files.pythonhosted.org/packages/3c/f2/89c5eb0faddc3ff014f1c04467d67dee0d1d334ab81fadbf3744847f8a8a/greenlet-3.3.0-cp311-cp311-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4243050a88ba61842186cb9e63c7dfa677ec146160b0efd73b855a3d9c7fcf32", size = 590338, upload-time = "2025-12-04T14:57:41.136Z" }, { url = "https://files.pythonhosted.org/packages/d6/6f/b60b0291d9623c496638c582297ead61f43c4b72eef5e9c926ef4565ec13/greenlet-3.2.4-cp310-cp310-win_amd64.whl", hash = "sha256:73f49b5368b5359d04e18d15828eecc1806033db5233397748f4ca813ff1056c", size = 298654, upload-time = "2025-08-07T13:50:00.469Z" },
{ url = "https://files.pythonhosted.org/packages/80/d7/db0a5085035d05134f8c089643da2b44cc9b80647c39e93129c5ef170d8f/greenlet-3.3.0-cp311-cp311-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:670d0f94cd302d81796e37299bcd04b95d62403883b24225c6b5271466612f45", size = 601098, upload-time = "2025-12-04T15:07:11.898Z" }, { url = "https://files.pythonhosted.org/packages/a4/de/f28ced0a67749cac23fecb02b694f6473f47686dff6afaa211d186e2ef9c/greenlet-3.2.4-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:96378df1de302bc38e99c3a9aa311967b7dc80ced1dcc6f171e99842987882a2", size = 272305, upload-time = "2025-08-07T13:15:41.288Z" },
{ url = "https://files.pythonhosted.org/packages/dc/a6/e959a127b630a58e23529972dbc868c107f9d583b5a9f878fb858c46bc1a/greenlet-3.3.0-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6cb3a8ec3db4a3b0eb8a3c25436c2d49e3505821802074969db017b87bc6a948", size = 590206, upload-time = "2025-12-04T14:26:01.254Z" }, { url = "https://files.pythonhosted.org/packages/09/16/2c3792cba130000bf2a31c5272999113f4764fd9d874fb257ff588ac779a/greenlet-3.2.4-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:1ee8fae0519a337f2329cb78bd7a8e128ec0f881073d43f023c7b8d4831d5246", size = 632472, upload-time = "2025-08-07T13:42:55.044Z" },
{ url = "https://files.pythonhosted.org/packages/48/60/29035719feb91798693023608447283b266b12efc576ed013dd9442364bb/greenlet-3.3.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:2de5a0b09eab81fc6a382791b995b1ccf2b172a9fec934747a7a23d2ff291794", size = 1550668, upload-time = "2025-12-04T15:04:22.439Z" }, { url = "https://files.pythonhosted.org/packages/ae/8f/95d48d7e3d433e6dae5b1682e4292242a53f22df82e6d3dda81b1701a960/greenlet-3.2.4-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:94abf90142c2a18151632371140b3dba4dee031633fe614cb592dbb6c9e17bc3", size = 644646, upload-time = "2025-08-07T13:45:26.523Z" },
{ url = "https://files.pythonhosted.org/packages/0a/5f/783a23754b691bfa86bd72c3033aa107490deac9b2ef190837b860996c9f/greenlet-3.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:4449a736606bd30f27f8e1ff4678ee193bc47f6ca810d705981cfffd6ce0d8c5", size = 1615483, upload-time = "2025-12-04T14:27:28.083Z" }, { url = "https://files.pythonhosted.org/packages/d5/5e/405965351aef8c76b8ef7ad370e5da58d57ef6068df197548b015464001a/greenlet-3.2.4-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:4d1378601b85e2e5171b99be8d2dc85f594c79967599328f95c1dc1a40f1c633", size = 640519, upload-time = "2025-08-07T13:53:13.928Z" },
{ url = "https://files.pythonhosted.org/packages/1d/d5/c339b3b4bc8198b7caa4f2bd9fd685ac9f29795816d8db112da3d04175bb/greenlet-3.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:7652ee180d16d447a683c04e4c5f6441bae7ba7b17ffd9f6b3aff4605e9e6f71", size = 301164, upload-time = "2025-12-04T14:42:51.577Z" }, { url = "https://files.pythonhosted.org/packages/25/5d/382753b52006ce0218297ec1b628e048c4e64b155379331f25a7316eb749/greenlet-3.2.4-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:0db5594dce18db94f7d1650d7489909b57afde4c580806b8d9203b6e79cdc079", size = 639707, upload-time = "2025-08-07T13:18:27.146Z" },
{ url = "https://files.pythonhosted.org/packages/f8/0a/a3871375c7b9727edaeeea994bfff7c63ff7804c9829c19309ba2e058807/greenlet-3.3.0-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:b01548f6e0b9e9784a2c99c5651e5dc89ffcbe870bc5fb2e5ef864e9cc6b5dcb", size = 276379, upload-time = "2025-12-04T14:23:30.498Z" }, { url = "https://files.pythonhosted.org/packages/1f/8e/abdd3f14d735b2929290a018ecf133c901be4874b858dd1c604b9319f064/greenlet-3.2.4-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2523e5246274f54fdadbce8494458a2ebdcdbc7b802318466ac5606d3cded1f8", size = 587684, upload-time = "2025-08-07T13:18:25.164Z" },
{ url = "https://files.pythonhosted.org/packages/43/ab/7ebfe34dce8b87be0d11dae91acbf76f7b8246bf9d6b319c741f99fa59c6/greenlet-3.3.0-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:349345b770dc88f81506c6861d22a6ccd422207829d2c854ae2af8025af303e3", size = 597294, upload-time = "2025-12-04T14:50:06.847Z" }, { url = "https://files.pythonhosted.org/packages/5d/65/deb2a69c3e5996439b0176f6651e0052542bb6c8f8ec2e3fba97c9768805/greenlet-3.2.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:1987de92fec508535687fb807a5cea1560f6196285a4cde35c100b8cd632cc52", size = 1116647, upload-time = "2025-08-07T13:42:38.655Z" },
{ url = "https://files.pythonhosted.org/packages/a4/39/f1c8da50024feecd0793dbd5e08f526809b8ab5609224a2da40aad3a7641/greenlet-3.3.0-cp312-cp312-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e8e18ed6995e9e2c0b4ed264d2cf89260ab3ac7e13555b8032b25a74c6d18655", size = 607742, upload-time = "2025-12-04T14:57:42.349Z" }, { url = "https://files.pythonhosted.org/packages/3f/cc/b07000438a29ac5cfb2194bfc128151d52f333cee74dd7dfe3fb733fc16c/greenlet-3.2.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:55e9c5affaa6775e2c6b67659f3a71684de4c549b3dd9afca3bc773533d284fa", size = 1142073, upload-time = "2025-08-07T13:18:21.737Z" },
{ url = "https://files.pythonhosted.org/packages/77/cb/43692bcd5f7a0da6ec0ec6d58ee7cddb606d055ce94a62ac9b1aa481e969/greenlet-3.3.0-cp312-cp312-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c024b1e5696626890038e34f76140ed1daf858e37496d33f2af57f06189e70d7", size = 622297, upload-time = "2025-12-04T15:07:13.552Z" }, { url = "https://files.pythonhosted.org/packages/67/24/28a5b2fa42d12b3d7e5614145f0bd89714c34c08be6aabe39c14dd52db34/greenlet-3.2.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c9c6de1940a7d828635fbd254d69db79e54619f165ee7ce32fda763a9cb6a58c", size = 1548385, upload-time = "2025-11-04T12:42:11.067Z" },
{ url = "https://files.pythonhosted.org/packages/75/b0/6bde0b1011a60782108c01de5913c588cf51a839174538d266de15e4bf4d/greenlet-3.3.0-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:047ab3df20ede6a57c35c14bf5200fcf04039d50f908270d3f9a7a82064f543b", size = 609885, upload-time = "2025-12-04T14:26:02.368Z" }, { url = "https://files.pythonhosted.org/packages/6a/05/03f2f0bdd0b0ff9a4f7b99333d57b53a7709c27723ec8123056b084e69cd/greenlet-3.2.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:03c5136e7be905045160b1b9fdca93dd6727b180feeafda6818e6496434ed8c5", size = 1613329, upload-time = "2025-11-04T12:42:12.928Z" },
{ url = "https://files.pythonhosted.org/packages/49/0e/49b46ac39f931f59f987b7cd9f34bfec8ef81d2a1e6e00682f55be5de9f4/greenlet-3.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2d9ad37fc657b1102ec880e637cccf20191581f75c64087a549e66c57e1ceb53", size = 1567424, upload-time = "2025-12-04T15:04:23.757Z" }, { url = "https://files.pythonhosted.org/packages/d8/0f/30aef242fcab550b0b3520b8e3561156857c94288f0332a79928c31a52cf/greenlet-3.2.4-cp311-cp311-win_amd64.whl", hash = "sha256:9c40adce87eaa9ddb593ccb0fa6a07caf34015a29bf8d344811665b573138db9", size = 299100, upload-time = "2025-08-07T13:44:12.287Z" },
{ url = "https://files.pythonhosted.org/packages/05/f5/49a9ac2dff7f10091935def9165c90236d8f175afb27cbed38fb1d61ab6b/greenlet-3.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:83cd0e36932e0e7f36a64b732a6f60c2fc2df28c351bae79fbaf4f8092fe7614", size = 1636017, upload-time = "2025-12-04T14:27:29.688Z" }, { url = "https://files.pythonhosted.org/packages/44/69/9b804adb5fd0671f367781560eb5eb586c4d495277c93bde4307b9e28068/greenlet-3.2.4-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:3b67ca49f54cede0186854a008109d6ee71f66bd57bb36abd6d0a0267b540cdd", size = 274079, upload-time = "2025-08-07T13:15:45.033Z" },
{ url = "https://files.pythonhosted.org/packages/6c/79/3912a94cf27ec503e51ba493692d6db1e3cd8ac7ac52b0b47c8e33d7f4f9/greenlet-3.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:a7a34b13d43a6b78abf828a6d0e87d3385680eaf830cd60d20d52f249faabf39", size = 301964, upload-time = "2025-12-04T14:36:58.316Z" }, { url = "https://files.pythonhosted.org/packages/46/e9/d2a80c99f19a153eff70bc451ab78615583b8dac0754cfb942223d2c1a0d/greenlet-3.2.4-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:ddf9164e7a5b08e9d22511526865780a576f19ddd00d62f8a665949327fde8bb", size = 640997, upload-time = "2025-08-07T13:42:56.234Z" },
{ url = "https://files.pythonhosted.org/packages/3b/16/035dcfcc48715ccd345f3a93183267167cdd162ad123cd93067d86f27ce4/greenlet-3.2.4-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:f28588772bb5fb869a8eb331374ec06f24a83a9c25bfa1f38b6993afe9c1e968", size = 655185, upload-time = "2025-08-07T13:45:27.624Z" },
{ url = "https://files.pythonhosted.org/packages/31/da/0386695eef69ffae1ad726881571dfe28b41970173947e7c558d9998de0f/greenlet-3.2.4-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:5c9320971821a7cb77cfab8d956fa8e39cd07ca44b6070db358ceb7f8797c8c9", size = 649926, upload-time = "2025-08-07T13:53:15.251Z" },
{ url = "https://files.pythonhosted.org/packages/68/88/69bf19fd4dc19981928ceacbc5fd4bb6bc2215d53199e367832e98d1d8fe/greenlet-3.2.4-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c60a6d84229b271d44b70fb6e5fa23781abb5d742af7b808ae3f6efd7c9c60f6", size = 651839, upload-time = "2025-08-07T13:18:30.281Z" },
{ url = "https://files.pythonhosted.org/packages/19/0d/6660d55f7373b2ff8152401a83e02084956da23ae58cddbfb0b330978fe9/greenlet-3.2.4-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3b3812d8d0c9579967815af437d96623f45c0f2ae5f04e366de62a12d83a8fb0", size = 607586, upload-time = "2025-08-07T13:18:28.544Z" },
{ url = "https://files.pythonhosted.org/packages/8e/1a/c953fdedd22d81ee4629afbb38d2f9d71e37d23caace44775a3a969147d4/greenlet-3.2.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:abbf57b5a870d30c4675928c37278493044d7c14378350b3aa5d484fa65575f0", size = 1123281, upload-time = "2025-08-07T13:42:39.858Z" },
{ url = "https://files.pythonhosted.org/packages/3f/c7/12381b18e21aef2c6bd3a636da1088b888b97b7a0362fac2e4de92405f97/greenlet-3.2.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:20fb936b4652b6e307b8f347665e2c615540d4b42b3b4c8a321d8286da7e520f", size = 1151142, upload-time = "2025-08-07T13:18:22.981Z" },
{ url = "https://files.pythonhosted.org/packages/27/45/80935968b53cfd3f33cf99ea5f08227f2646e044568c9b1555b58ffd61c2/greenlet-3.2.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ee7a6ec486883397d70eec05059353b8e83eca9168b9f3f9a361971e77e0bcd0", size = 1564846, upload-time = "2025-11-04T12:42:15.191Z" },
{ url = "https://files.pythonhosted.org/packages/69/02/b7c30e5e04752cb4db6202a3858b149c0710e5453b71a3b2aec5d78a1aab/greenlet-3.2.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:326d234cbf337c9c3def0676412eb7040a35a768efc92504b947b3e9cfc7543d", size = 1633814, upload-time = "2025-11-04T12:42:17.175Z" },
{ url = "https://files.pythonhosted.org/packages/e9/08/b0814846b79399e585f974bbeebf5580fbe59e258ea7be64d9dfb253c84f/greenlet-3.2.4-cp312-cp312-win_amd64.whl", hash = "sha256:a7d4e128405eea3814a12cc2605e0e6aedb4035bf32697f72deca74de4105e02", size = 299899, upload-time = "2025-08-07T13:38:53.448Z" },
] ]
[[package]] [[package]]
@@ -1238,7 +1247,7 @@ wheels = [
[[package]] [[package]]
name = "lnbits" name = "lnbits"
version = "1.4.2" version = "1.4.0rc2"
source = { editable = "." } source = { editable = "." }
dependencies = [ dependencies = [
{ name = "aiosqlite" }, { name = "aiosqlite" },
@@ -1252,7 +1261,6 @@ dependencies = [
{ name = "fastapi" }, { name = "fastapi" },
{ name = "fastapi-sso" }, { name = "fastapi-sso" },
{ name = "filetype" }, { name = "filetype" },
{ name = "greenlet" },
{ name = "grpcio" }, { name = "grpcio" },
{ name = "httpx" }, { name = "httpx" },
{ name = "itsdangerous" }, { name = "itsdangerous" },
@@ -1329,14 +1337,13 @@ requires-dist = [
{ name = "bech32", specifier = "==1.2.0" }, { name = "bech32", specifier = "==1.2.0" },
{ name = "bolt11", specifier = "==2.1.1" }, { name = "bolt11", specifier = "==2.1.1" },
{ name = "breez-sdk", marker = "extra == 'breez'", specifier = "==0.8.0" }, { name = "breez-sdk", marker = "extra == 'breez'", specifier = "==0.8.0" },
{ name = "breez-sdk-liquid", marker = "extra == 'breez'", specifier = "==0.11.11" }, { name = "breez-sdk-liquid", marker = "extra == 'breez'", specifier = "==0.9.1" },
{ name = "click", specifier = "==8.2.1" }, { name = "click", specifier = "==8.2.1" },
{ name = "ecdsa", specifier = "==0.19.1" }, { name = "ecdsa", specifier = "==0.19.1" },
{ name = "embit", specifier = "==0.8.0" }, { name = "embit", specifier = "==0.8.0" },
{ name = "fastapi", specifier = "==0.116.1" }, { name = "fastapi", specifier = "==0.116.1" },
{ name = "fastapi-sso", specifier = "==0.19.0" }, { name = "fastapi-sso", specifier = "==0.18.0" },
{ name = "filetype", specifier = "==1.2.0" }, { name = "filetype", specifier = "==1.2.0" },
{ name = "greenlet", specifier = ">=3.3.0,<4.0.0" },
{ name = "grpcio", specifier = "==1.69.0" }, { name = "grpcio", specifier = "==1.69.0" },
{ name = "httpx", specifier = "==0.27.0" }, { name = "httpx", specifier = "==0.27.0" },
{ name = "itsdangerous", specifier = "==2.2.0" }, { name = "itsdangerous", specifier = "==2.2.0" },
@@ -2684,7 +2691,7 @@ wheels = [
[[package]] [[package]]
name = "virtualenv" name = "virtualenv"
version = "20.36.1" version = "20.35.4"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
dependencies = [ dependencies = [
{ name = "distlib" }, { name = "distlib" },
@@ -2692,9 +2699,9 @@ dependencies = [
{ name = "platformdirs" }, { name = "platformdirs" },
{ name = "typing-extensions", marker = "python_full_version < '3.11'" }, { name = "typing-extensions", marker = "python_full_version < '3.11'" },
] ]
sdist = { url = "https://files.pythonhosted.org/packages/aa/a3/4d310fa5f00863544e1d0f4de93bddec248499ccf97d4791bc3122c9d4f3/virtualenv-20.36.1.tar.gz", hash = "sha256:8befb5c81842c641f8ee658481e42641c68b5eab3521d8e092d18320902466ba", size = 6032239, upload-time = "2026-01-09T18:21:01.296Z" } sdist = { url = "https://files.pythonhosted.org/packages/20/28/e6f1a6f655d620846bd9df527390ecc26b3805a0c5989048c210e22c5ca9/virtualenv-20.35.4.tar.gz", hash = "sha256:643d3914d73d3eeb0c552cbb12d7e82adf0e504dbf86a3182f8771a153a1971c", size = 6028799, upload-time = "2025-10-29T06:57:40.511Z" }
wheels = [ wheels = [
{ url = "https://files.pythonhosted.org/packages/6a/2a/dc2228b2888f51192c7dc766106cd475f1b768c10caaf9727659726f7391/virtualenv-20.36.1-py3-none-any.whl", hash = "sha256:575a8d6b124ef88f6f51d56d656132389f961062a9177016a50e4f507bbcc19f", size = 6008258, upload-time = "2026-01-09T18:20:59.425Z" }, { url = "https://files.pythonhosted.org/packages/79/0c/c05523fa3181fdf0c9c52a6ba91a23fbf3246cc095f26f6516f9c60e6771/virtualenv-20.35.4-py3-none-any.whl", hash = "sha256:c21c9cede36c9753eeade68ba7d523529f228a403463376cf821eaae2b650f1b", size = 6005095, upload-time = "2025-10-29T06:57:37.598Z" },
] ]
[[package]] [[package]]