Compare commits
19
Commits
v1.5.1-rc1
..
v1.5.2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2329770acd | ||
|
|
7d98c6b080 | ||
|
|
5f4e889d3a | ||
|
|
fe774ae1a1 | ||
|
|
21e02cb20e | ||
|
|
a3d7b463ae | ||
|
|
e1e2112461 | ||
|
|
92fc9a130f | ||
|
|
e15f3cd207 | ||
|
|
041b358310 | ||
|
|
cbd3de88c4 | ||
|
|
156ab10ad6 | ||
|
|
b77c103020 | ||
|
|
1f34357ab7 | ||
|
|
d9eda48298 | ||
|
|
1be2d1a680 | ||
|
|
b55ae9daaf | ||
|
|
1f98aa2cdb | ||
|
|
55ec3f1812 |
+4
-2
@@ -326,10 +326,12 @@ LNBITS_SERVICE_FEE=0.0
|
||||
# disable fees for internal transactions
|
||||
# LNBITS_SERVICE_FEE_IGNORE_INTERNAL=true
|
||||
|
||||
# value in millisats
|
||||
# The minimum fee reserved per payment (millisats)
|
||||
LNBITS_RESERVE_FEE_MIN=2000
|
||||
# value in percent
|
||||
# The percentage of the payment amount to reserve for routing fees (percent)
|
||||
LNBITS_RESERVE_FEE_PERCENT=1.0
|
||||
# The default time to wait to for status response from the funding source when paying an invoice
|
||||
LNBITS_FUNDING_SOURCE_PAY_INVOICE_WAIT_SECONDS=5
|
||||
|
||||
# limit the maximum balance for each wallet
|
||||
# throw an error if the wallet attempts to create a new invoice
|
||||
|
||||
@@ -33,6 +33,7 @@ jobs:
|
||||
|
||||
docker:
|
||||
if: github.repository == 'lnbits/lnbits'
|
||||
needs: [ release ]
|
||||
uses: ./.github/workflows/docker.yml
|
||||
with:
|
||||
tag: ${{ github.ref_name }}
|
||||
@@ -40,6 +41,16 @@ jobs:
|
||||
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
|
||||
DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
|
||||
|
||||
docker-latest-rc:
|
||||
if: github.repository == 'lnbits/lnbits'
|
||||
needs: [ release ]
|
||||
uses: ./.github/workflows/docker.yml
|
||||
with:
|
||||
tag: latest-rc
|
||||
secrets:
|
||||
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
|
||||
DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
|
||||
|
||||
pypi:
|
||||
if: github.repository == 'lnbits/lnbits'
|
||||
runs-on: ubuntu-24.04
|
||||
|
||||
@@ -52,6 +52,16 @@ jobs:
|
||||
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
|
||||
DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
|
||||
|
||||
docker-latest-rc:
|
||||
if: github.repository == 'lnbits/lnbits'
|
||||
needs: [ release ]
|
||||
uses: ./.github/workflows/docker.yml
|
||||
with:
|
||||
tag: latest-rc
|
||||
secrets:
|
||||
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
|
||||
DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
|
||||
|
||||
pypi:
|
||||
if: github.repository == 'lnbits/lnbits'
|
||||
runs-on: ubuntu-24.04
|
||||
|
||||
@@ -18,7 +18,7 @@ RUN uv sync --all-extras
|
||||
ENV LNBITS_PORT="5000"
|
||||
ENV LNBITS_HOST="0.0.0.0"
|
||||
ENV LNBITS_BACKEND_WALLET_CLASS="BoltzWallet"
|
||||
ENV FUNDING_SOURCE_MAX_RETRIES=10
|
||||
ENV FUNDING_SOURCE_MAX_RETRIES="10"
|
||||
|
||||
# Boltzd
|
||||
ENV BOLTZ_CLIENT_ENDPOINT="127.0.0.1:9002"
|
||||
|
||||
@@ -2,15 +2,17 @@ ARG LNBITS_TAG=latest
|
||||
|
||||
FROM lnbits/lnbits:${LNBITS_TAG}
|
||||
|
||||
RUN curl -fsSL https://deb.nodesource.com/setup_lts.x | bash -
|
||||
|
||||
RUN apt-get update && apt-get -y upgrade
|
||||
RUN apt-get install -y netcat-openbsd npm nodejs git
|
||||
RUN apt-get install -y ca-certificates curl gnupg netcat-openbsd git nodejs
|
||||
|
||||
RUN curl -LsSf https://astral.sh/uv/install.sh | sh
|
||||
ENV PATH="/root/.local/bin:$PATH"
|
||||
|
||||
# install sparksidecar
|
||||
RUN git clone https://github.com/lnbits/spark_sidecar
|
||||
RUN cd spark_sidecar && npm install
|
||||
RUN cd spark_sidecar && npm ci
|
||||
|
||||
# Reinstall dependencies for lnbits just in case (needed for CMD usage)
|
||||
RUN uv sync --all-extras
|
||||
@@ -19,13 +21,16 @@ RUN uv sync --all-extras
|
||||
ENV LNBITS_PORT="5000"
|
||||
ENV LNBITS_HOST="0.0.0.0"
|
||||
ENV LNBITS_BACKEND_WALLET_CLASS="SparkL2Wallet"
|
||||
ENV FUNDING_SOURCE_MAX_RETRIES=10
|
||||
ENV LNBITS_RESERVE_FEE_MIN="20000"
|
||||
ENV LNBITS_RESERVE_FEE_PERCENT="1"
|
||||
ENV LNBITS_FUNDING_SOURCE_PAY_INVOICE_WAIT_SECONDS="20"
|
||||
ENV FUNDING_SOURCE_MAX_RETRIES="10"
|
||||
|
||||
# spark sidecar
|
||||
ENV SPARK_MNEMONIC="bottom bottom bottom bottom bottom bottom bottom bottom bottom bottom bottom bottom"
|
||||
ENV SPARK_NETWORK="MAINNET"
|
||||
ENV SPARK_SIDECAR_PORT="8765"
|
||||
ENV SPARK_PAY_WAIT_MS="20000"
|
||||
ENV SPARK_MULTIPLICITY="3"
|
||||
|
||||
EXPOSE 5000
|
||||
|
||||
|
||||
@@ -36,6 +36,8 @@ lnurl_router = APIRouter(tags=["LNURL"])
|
||||
|
||||
async def _handle(lnurl: str) -> LnurlResponseModel:
|
||||
try:
|
||||
if "@" in lnurl: # lower case lightning addresses
|
||||
lnurl = lnurl.lower()
|
||||
res = await lnurl_handle(lnurl, user_agent=settings.user_agent, timeout=5)
|
||||
if isinstance(res, LnurlErrorResponse):
|
||||
raise HTTPException(status_code=HTTPStatus.BAD_REQUEST, detail=res.reason)
|
||||
|
||||
+2
-3
@@ -7,15 +7,14 @@ from typing import Any
|
||||
from urllib import request
|
||||
from urllib.parse import urlparse
|
||||
|
||||
import jinja2
|
||||
import jwt
|
||||
import shortuuid
|
||||
from fastapi.routing import APIRoute
|
||||
from loguru import logger
|
||||
from packaging import version
|
||||
from pydantic.schema import field_schema
|
||||
from starlette.templating import Jinja2Templates
|
||||
|
||||
from lnbits.jinja2_templating import Jinja2Templates
|
||||
from lnbits.settings import settings
|
||||
from lnbits.utils.crypto import AESCipher
|
||||
from lnbits.utils.exchange_rates import currencies
|
||||
@@ -66,7 +65,7 @@ def template_renderer(additional_folders: list | None = None) -> Jinja2Templates
|
||||
for f in additional_folders
|
||||
]
|
||||
folders.extend(additional_folders)
|
||||
t = Jinja2Templates(loader=jinja2.FileSystemLoader(folders))
|
||||
t = Jinja2Templates(directory=folders)
|
||||
t.env.globals["static_url_for"] = static_url_for
|
||||
t.env.globals["normalize_path"] = normalize_path
|
||||
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
import typing
|
||||
|
||||
from jinja2 import BaseLoader, Environment, pass_context
|
||||
from starlette.datastructures import QueryParams
|
||||
from starlette.requests import Request
|
||||
from starlette.templating import Jinja2Templates as SuperJinja2Templates
|
||||
|
||||
|
||||
class Jinja2Templates(SuperJinja2Templates):
|
||||
def __init__(self, loader: BaseLoader) -> None:
|
||||
self.env = self.get_environment(loader)
|
||||
super().__init__(env=self.env)
|
||||
|
||||
def get_environment(self, loader: BaseLoader) -> Environment:
|
||||
@pass_context
|
||||
def url_for(context: dict, name: str, **path_params: typing.Any) -> str:
|
||||
request: Request = context["request"]
|
||||
return request.app.url_path_for(name, **path_params)
|
||||
|
||||
def url_params_update(init: QueryParams, **new: typing.Any) -> QueryParams:
|
||||
values = dict(init)
|
||||
values.update(new)
|
||||
return QueryParams(**values)
|
||||
|
||||
env = Environment(loader=loader, autoescape=True)
|
||||
env.globals["url_for"] = url_for
|
||||
env.globals["url_params_update"] = url_params_update
|
||||
return env
|
||||
@@ -76,7 +76,7 @@ class LndRestNode(Node):
|
||||
return response.json()
|
||||
|
||||
def get(self, path: str, **kwargs):
|
||||
return self.request("GET", path, **kwargs)
|
||||
return self.request("GET", path, timeout=30, **kwargs)
|
||||
|
||||
async def _get_id(self) -> str:
|
||||
info = await self.get("/v1/getinfo")
|
||||
@@ -99,11 +99,12 @@ class LndRestNode(Node):
|
||||
"perm": True,
|
||||
"timeout": 30,
|
||||
},
|
||||
timeout=30,
|
||||
)
|
||||
|
||||
async def disconnect_peer(self, peer_id: str):
|
||||
try:
|
||||
await self.request("DELETE", "/v1/peers/" + peer_id)
|
||||
await self.request("DELETE", "/v1/peers/" + peer_id, timeout=30)
|
||||
except HTTPException as exc:
|
||||
if "unable to disconnect" in exc.detail:
|
||||
raise HTTPException(
|
||||
@@ -141,6 +142,7 @@ class LndRestNode(Node):
|
||||
"local_funding_amount": local_amount,
|
||||
"push_sat": push_amount,
|
||||
},
|
||||
timeout=30,
|
||||
)
|
||||
return ChannelPoint(
|
||||
# WHY IS THIS REVERSED?!
|
||||
@@ -214,6 +216,7 @@ class LndRestNode(Node):
|
||||
# 'min_htlc_msat': <uint64>,
|
||||
# 'inbound_fee': <InboundFee>,
|
||||
},
|
||||
timeout=30,
|
||||
)
|
||||
|
||||
async def get_channel(self, channel_id: str) -> NodeChannel | None:
|
||||
|
||||
Vendored
+11
-11
File diff suppressed because one or more lines are too long
+394
-15
@@ -6,6 +6,7 @@ window.localisation.br = {
|
||||
funding: 'Financiamento',
|
||||
users: 'Usuários',
|
||||
audit: 'Auditoria',
|
||||
api_watch: 'Relógio da API',
|
||||
apps: 'Aplicativos',
|
||||
channels: 'Canais',
|
||||
transactions: 'Transações',
|
||||
@@ -21,13 +22,17 @@ window.localisation.br = {
|
||||
active_channels: 'Canais Ativos',
|
||||
connect_peer: 'Conectar Par',
|
||||
connect: 'Conectar',
|
||||
reconnect: 'Reconectar',
|
||||
open_channel: 'Canal Aberto',
|
||||
open: 'Abrir',
|
||||
clear: 'Limpar',
|
||||
close_channel: 'Fechar Canal',
|
||||
close: 'Fechar',
|
||||
restart: 'Reiniciar servidor',
|
||||
image_library: 'Biblioteca de Imagens',
|
||||
save: 'Salvar',
|
||||
save_tooltip: 'Salvar suas alterações',
|
||||
must_save: 'Você tem alterações não salvas',
|
||||
credit_debit: 'Crédito / Débito',
|
||||
credit_hint: 'Pressione Enter para creditar a conta',
|
||||
credit_label: '{denomination} para creditar',
|
||||
@@ -46,24 +51,47 @@ window.localisation.br = {
|
||||
export_to_phone: 'Exportar para o telefone com código QR',
|
||||
export_to_phone_desc:
|
||||
'Este código QR contém a URL da sua carteira com acesso total. Você pode escaneá-lo do seu telefone para abrir sua carteira a partir dele.',
|
||||
access_wallet_on_mobile: 'Acesso Móvel',
|
||||
stored_paylinks: 'Links LNURL de pagamento armazenados',
|
||||
wallet: 'Carteira:',
|
||||
wallet_name: 'Nome da carteira',
|
||||
wallet_type: 'Tipo de carteira',
|
||||
shared_wallet: 'Carteira Compartilhada',
|
||||
share_wallet: 'Compartilhar Carteira',
|
||||
update_permissions: 'Atualizar Permissões',
|
||||
shared_wallet_id: 'ID da Carteira Compartilhada',
|
||||
shared_wallet_desc:
|
||||
'Você foi convidado(a) para ter acesso à carteira de outra pessoa.',
|
||||
wallets: 'Carteiras',
|
||||
exclude_wallets: 'Excluir Carteiras',
|
||||
add_wallet: 'Adicionar nova carteira',
|
||||
reject_wallet: 'Rejeitar carteira',
|
||||
add_new_wallet: 'Adicionar uma nova carteira',
|
||||
pin_wallet: 'Fixar carteira',
|
||||
delete_wallet: 'Excluir carteira',
|
||||
delete_wallet_desc:
|
||||
'Toda a carteira será excluída, os fundos serão IRRECUPERÁVEIS.',
|
||||
rename_wallet: 'Renomear carteira',
|
||||
update_name: 'Atualizar nome',
|
||||
fiat_tracking: 'Rastreamento Fiat',
|
||||
fiat_providers: 'Provedores fiat',
|
||||
fiat_warning_bitcoin:
|
||||
'Provedores Fiat podem ficar nervosos com qualquer coisa relacionada ao bitcoin, portanto, evite usar a palavra "bitcoin" nos seus memorandos!',
|
||||
currency: 'Moeda',
|
||||
update_currency: 'Atualizar moeda',
|
||||
press_to_claim: 'Pressione para solicitar bitcoin',
|
||||
claim_desc:
|
||||
'Parece que você tem um valor resgatável de bitcoin, mas ainda não tem uma carteira. Pressione o botão abaixo para reivindicá-lo. Isso criará uma nova carteira para você.',
|
||||
donate: 'Doar',
|
||||
view_github: 'Ver no GitHub',
|
||||
voidwallet_active: 'VoidWallet está ativo! Pagamentos desabilitados',
|
||||
use_with_caution: 'USE COM CAUTELA - a carteira {name} ainda está em BETA',
|
||||
service_fee: 'Taxa de serviço: {amount} % por transação',
|
||||
service_fee_max: 'Taxa de serviço: {amount} % por transação (máx {max} sats)',
|
||||
voidwallet_active_user:
|
||||
'Fonte de financiamento indisponível. Por favor, entre em contato com seu administrador para configurar.',
|
||||
voidwallet_active_admin:
|
||||
'Fonte de financiamento indisponível. Clique aqui para configurar.',
|
||||
service_fee_badge: 'Taxa de serviço: {amount} % por transação',
|
||||
service_fee_max_badge:
|
||||
'Taxa de serviço: {amount} % por transação (máximo {max} {denom})',
|
||||
service_fee_tooltip:
|
||||
'Taxa de serviço cobrada pelo administrador do servidor LNbits por transação de saída',
|
||||
toggle_darkmode: 'Alternar modo escuro',
|
||||
@@ -79,6 +107,7 @@ window.localisation.br = {
|
||||
create_invoice: 'Criar Fatura',
|
||||
camera_tooltip: 'Usar a câmara para escanear uma fatura / QR',
|
||||
export_csv: 'Exportar para CSV',
|
||||
export_csv_details: 'Exportar para CSV com detalhes',
|
||||
chart_tooltip: 'Mostrar gráfico',
|
||||
pending: 'Pendente',
|
||||
copy_invoice: 'Copiar fatura',
|
||||
@@ -86,15 +115,27 @@ window.localisation.br = {
|
||||
cancel: 'Cancelar',
|
||||
scan: 'Escanear',
|
||||
read: 'Ler',
|
||||
write: 'Escrever',
|
||||
pay: 'Pagar',
|
||||
memo: 'Memo',
|
||||
date: 'Data',
|
||||
path: 'Caminho',
|
||||
internal_memo: 'Memorando interno (opcional)',
|
||||
internal_memo_hint_receive:
|
||||
'Este memorando não é mostrado ao pagador, mas é armazenado na fatura para sua referência.',
|
||||
internal_memo_hint_pay:
|
||||
'Este memorando não é exibido ao beneficiário, mas é armazenado no pagamento para sua referência.',
|
||||
payment_processing: 'Processando pagamento...',
|
||||
payment_successful: 'Pagamento bem-sucedido!',
|
||||
payment_pending: 'Pagamento pendente...',
|
||||
payment_check: 'Cheque pagamento',
|
||||
not_enough_funds: 'Fundos insuficientes!',
|
||||
search_by_tag_memo_amount: 'Pesquisar por tag, memo, quantidade',
|
||||
search: 'Buscar',
|
||||
invoice_waiting: 'Fatura aguardando pagamento',
|
||||
payment_received: 'Pagamento Recebido',
|
||||
payment_sent: 'Pagamento Enviado',
|
||||
payment_failed: 'Pagamento Falhou',
|
||||
receive: 'receber',
|
||||
send: 'enviar',
|
||||
outgoing_payment_pending: 'Pagamento pendente de saída',
|
||||
@@ -112,7 +153,10 @@ window.localisation.br = {
|
||||
extensions: 'Extensões',
|
||||
no_extensions: 'Você não possui nenhuma extensão instalada :(',
|
||||
created: 'Criado',
|
||||
created_at: 'Criado em',
|
||||
updated_at: 'Atualizado em',
|
||||
search_extensions: 'Extensões de pesquisa',
|
||||
search_wallets: 'Pesquisar carteiras',
|
||||
extension_sources: 'Fontes de Extensão',
|
||||
ext_sources_hint: 'Repositórios de onde as extensões podem ser baixadas',
|
||||
ext_sources_label:
|
||||
@@ -121,10 +165,13 @@ window.localisation.br = {
|
||||
repository: 'Repositório',
|
||||
confirm_continue: 'Você tem certeza de que deseja continuar?',
|
||||
manage_extension_details: 'Instalar/desinstalar extensão',
|
||||
upload: 'Enviar',
|
||||
install: 'Instalar',
|
||||
uninstall: 'Desinstalar',
|
||||
drop_db: 'Remover Dados',
|
||||
enable: 'Ativar',
|
||||
enabled: 'Habilitado',
|
||||
disabled: 'Desativado',
|
||||
pay_to_enable: 'Pague para Habilitar',
|
||||
enable_extension_details: 'Ativar extensão para o usuário atual',
|
||||
disable: 'Desativar',
|
||||
@@ -132,6 +179,8 @@ window.localisation.br = {
|
||||
installed: 'Instalado',
|
||||
activated: 'Ativado',
|
||||
deactivated: 'Desativado',
|
||||
activate: 'Ativar',
|
||||
deactivate: 'Desativar',
|
||||
release_notes: 'Notas de Lançamento',
|
||||
activate_extension_details:
|
||||
'Tornar a extensão disponível/indisponível para usuários',
|
||||
@@ -139,8 +188,33 @@ window.localisation.br = {
|
||||
all: 'Tudo',
|
||||
only_admins_can_install:
|
||||
'Apenas contas de administrador podem instalar extensões.',
|
||||
only_admins_can_create_extensions:
|
||||
'Apenas contas de administrador podem criar extensões',
|
||||
admin_only: 'Apenas para Administração',
|
||||
make_user_admin: 'Tornar usuário administrador',
|
||||
revoke_admin: 'Revogar Admin',
|
||||
new_version: 'Nova Versão',
|
||||
reviews_url: 'URL de Avaliações',
|
||||
reviews_url_label: 'URL do servidor de avaliações',
|
||||
reviews_url_hint:
|
||||
'URL completa do PaidReviews incluindo o id das configurações (por exemplo, https://example.com/paidreviews/SETTINGS_ID)',
|
||||
reviews_open: 'Ver avaliações',
|
||||
reviews_leave: 'Deixe uma avaliação',
|
||||
reviews_name: 'Seu nome',
|
||||
reviews_comment: 'Sua avaliação',
|
||||
reviews_rating: 'Avaliação',
|
||||
reviews_submit: 'Enviar avaliação',
|
||||
reviews_loading: 'Carregando avaliações...',
|
||||
reviews_refresh: 'Atualizar avaliações',
|
||||
reviews_error_load: 'Não foi possível carregar as avaliações',
|
||||
reviews_url_not_configured: 'URL de avaliações não configurada',
|
||||
reviews_pay_invoice: 'Pagar fatura',
|
||||
reviews_invoice_paid: 'Fatura paga',
|
||||
reviews_invoice_title: 'Pague esta fatura para enviar sua avaliação',
|
||||
reviews_count: 'Avaliações',
|
||||
no_reviews: 'Ainda não há avaliações',
|
||||
extension_has_free_release: 'Tem lançamentos gratuitos',
|
||||
extension_has_paid_release: 'Tem lançamentos pagos',
|
||||
extension_depends_on: 'Depende de:',
|
||||
extension_rating_soon: 'Avaliações estarão disponíveis em breve',
|
||||
extension_installed_version: 'Versão instalada',
|
||||
@@ -155,26 +229,122 @@ window.localisation.br = {
|
||||
'Esta versão requer no mínimo a versão do LNbits',
|
||||
min_version: 'Mínimo (incluído)',
|
||||
max_version: 'Máximo (excluído)',
|
||||
preimage: 'Pré-imagem',
|
||||
preimage_hint: 'Pré-imagem para liquidar a fatura de retenção',
|
||||
hold_invoice: 'Reter Fatura',
|
||||
hold_invoice_description:
|
||||
'Esta fatura está em espera e requer uma pré-imagem para ser liquidada.',
|
||||
payment_hash: 'Hash de pagamento',
|
||||
invoice_cancelled: 'Fatura Cancelada',
|
||||
invoice_settled: 'Fatura Liquidada',
|
||||
hold_invoice_payment_hash:
|
||||
'Hash de pagamento para fatura em espera (opcional)',
|
||||
settle_invoice: 'Liquidar Fatura',
|
||||
cancel_invoice: 'Cancelar Fatura',
|
||||
fee: 'Taxa',
|
||||
amount: 'Quantidade',
|
||||
amount_limits: 'Limites de Quantia',
|
||||
amount_sats: 'Quantidade (sats)',
|
||||
faucest_wallet: 'Carteira de Torneira',
|
||||
faucest_wallet_desc_1:
|
||||
'Toda vez que um pagamento for confirmado pelo provedor {provider}, os fundos serão subtraídos desta carteira.',
|
||||
faucest_wallet_desc_2:
|
||||
'Isso ajuda a monitorar todos os pagamentos do {provider} e seu status.',
|
||||
faucest_wallet_desc_3:
|
||||
'Esta carteira deve ser recarregada com a quantia de sats que o administrador está disposto a oferecer em troca da moeda fiduciária.',
|
||||
faucest_wallet_desc_4:
|
||||
'Se esta carteira estiver configurada, mas estiver vazia, os pagamentos de {provider} não serão processados.',
|
||||
faucest_wallet_desc_5:
|
||||
'Esta carteira pode eventualmente ficar com saldo negativo se pagamentos fiduciários paralelos forem feitos.',
|
||||
faucest_wallet_id: 'ID da Carteira de Torneira (opcional)',
|
||||
faucest_wallet_id_hint:
|
||||
'ID da carteira a ser usado para a torneira. Será usado para enviar os fundos ao usuário.',
|
||||
tag: 'Etiqueta',
|
||||
unit: 'Unidade',
|
||||
description: 'Descrição',
|
||||
expiry: 'Validade',
|
||||
webhook: 'Webhook',
|
||||
webhook_url: 'URL do Webhook',
|
||||
webhook_url_hint:
|
||||
'URL de Webhook para enviar os detalhes do pagamento. Será chamada quando o pagamento for concluído.',
|
||||
copy_webhook_url: 'Copiar URL do webhook',
|
||||
webhook_events_list:
|
||||
'Os seguintes eventos devem ser suportados pelo webhook:',
|
||||
webhook_stripe_description:
|
||||
'No lado do Stripe, você deve configurar um webhook com um URL que aponta para o seu servidor LNbits.',
|
||||
payment_proof: 'Comprovante de pagamento',
|
||||
update: 'Atualizar',
|
||||
update_available: 'Atualização {version} disponível!',
|
||||
funding_sources: 'Fontes de Financiamento',
|
||||
latest_update: 'Você está na versão mais recente {version}.',
|
||||
notifications: 'Notificações',
|
||||
no_notifications: 'Sem notificações',
|
||||
notifications_disabled:
|
||||
'As notificações de status do LNbits estão desativadas.',
|
||||
enable_notifications: 'Ativar notificações',
|
||||
enable_notifications_desc:
|
||||
'Se ativado, ele buscará as últimas atualizações de status do LNbits, como incidentes de segurança e atualizações.',
|
||||
notifications_configure: 'Configurar Notificações',
|
||||
notifications_nostr_config: 'Configuração do Nostr',
|
||||
notifications_enable_nostr: 'Ativar Nostr',
|
||||
notifications_enable_nostr_desc: 'Enviar notificações pelo Nostr',
|
||||
notifications_nostr_private_key: 'Chave Privada Nostr',
|
||||
notifications_nostr_private_key_desc:
|
||||
'Chave privada (hex ou nsec) para assinar as mensagens enviadas para Nostr',
|
||||
notifications_nostr_identifier: 'Identificador Nostr',
|
||||
notifications_nostr_identifier_desc:
|
||||
'Identificador Nip5 para enviar notificações para',
|
||||
notifications_nostr_identifiers: 'Identificadores Nostr',
|
||||
notifications_nostr_identifiers_desc:
|
||||
'Lista de identificadores para enviar notificações.',
|
||||
notifications_telegram_config: 'Configuração do Telegram',
|
||||
notifications_enable_telegram: 'Ativar Telegram',
|
||||
notifications_enable_telegram_desc: 'Enviar notificações pelo Telegram',
|
||||
notifications_telegram_access_token: 'Token de Acesso',
|
||||
notifications_telegram_access_token_desc: 'Token de acesso para o bot',
|
||||
notifications_chat_id: 'ID de bate-papo do Telegram',
|
||||
notifications_chat_id_desc:
|
||||
'ID do chat do Telegram para enviar as notificações para',
|
||||
notifications_excluded_wallets_desc:
|
||||
'Não envie notificações para essas carteiras',
|
||||
notifications_email_config: 'Configuração de Email',
|
||||
notifications_enable_email: 'Habilitar Email',
|
||||
notifications_enable_email_desc: 'Enviar notificações por e-mail',
|
||||
notifications_send_test_email: 'Enviar e-mail de teste',
|
||||
notifications_send_email: 'Enviar e-mail',
|
||||
notifications_send_email_desc: 'Email que você enviará de',
|
||||
notifications_send_email_username: 'Nome de usuário',
|
||||
notifications_send_email_username_desc:
|
||||
'Nome de usuário, usará o e-mail se não estiver definido',
|
||||
notifications_send_email_password: 'Enviar senha de e-mail',
|
||||
notifications_send_email_password_desc:
|
||||
'Senha para o e-mail que você enviará de',
|
||||
notifications_send_email_server_port: 'Enviar e-mail porta SMTP',
|
||||
notifications_send_email_server_port_desc: 'Porta para o servidor SMTP',
|
||||
notifications_send_email_server: 'Enviar e-mail servidor SMTP',
|
||||
notifications_send_email_server_desc:
|
||||
'Servidor SMTP para o e-mail de que você enviará',
|
||||
notifications_send_to_emails: 'Emails para enviar para',
|
||||
notifications_send_to_emails_desc:
|
||||
'Notificações de e-mails serão enviadas para',
|
||||
notification_settings_update: 'Configurações atualizadas',
|
||||
notification_settings_update_desc:
|
||||
'Notificar quando as configurações do servidor forem atualizadas',
|
||||
notification_server_start_stop: 'Iniciar/Parar Servidor',
|
||||
notification_server_start_stop_desc:
|
||||
'Notificar quando o servidor tiver sido iniciado/parado',
|
||||
notification_watchdog_limit: 'Notificação de Limite do Watchdog',
|
||||
notification_watchdog_limit_desc:
|
||||
'Notifique quando o limite do watchdog for alcançado (não afeta a fonte de financiamento)',
|
||||
notification_server_status: 'Status do Servidor',
|
||||
notification_server_status_desc:
|
||||
'Enviar notificações regulares sobre o status do servidor (valor do intervalo em horas)',
|
||||
notification_incoming_payment: 'Pagamentos Recebidos',
|
||||
notification_incoming_payment_desc:
|
||||
'Notificar quando uma carteira tiver recebido um pagamento acima do valor especificado (sats)',
|
||||
notification_outgoing_payment: 'Pagamentos Saída',
|
||||
notification_outgoing_payment_desc:
|
||||
'Notificar quando uma carteira tiver enviado um pagamento acima do valor especificado (sats)',
|
||||
notification_credit_debit: 'Crédito / Débito',
|
||||
notification_credit_debit_desc:
|
||||
'Notificar quando uma carteira tiver sido creditada/debitada pelo superusuário',
|
||||
notification_balance_delta_changed: 'Mudança no Delta de Saldo',
|
||||
notification_balance_delta_changed_desc:
|
||||
'Notifique quando a diferença entre o saldo do nó e o saldo do LNbits tiver mudado mais do que a quantidade especificada (em sats). Defina como 0 para desativar. Isso é executado a cada minuto.',
|
||||
enable_watchdog: 'Ativar Watchdog',
|
||||
enable_watchdog_desc:
|
||||
'Se ativado, ele mudará automaticamente sua fonte de financiamento para VoidWallet se o seu saldo for inferior ao saldo do LNbits. Você precisará ativar manualmente após uma atualização.',
|
||||
@@ -189,6 +359,7 @@ window.localisation.br = {
|
||||
notification_source_label:
|
||||
'URL de origem (use apenas a fonte de status oficial do LNbits e fontes de confiança)',
|
||||
more: 'mais',
|
||||
more_count: 'Mais {count}',
|
||||
less: 'menos',
|
||||
releases: 'Lançamentos',
|
||||
watchdog: 'Cão de guarda',
|
||||
@@ -200,15 +371,24 @@ window.localisation.br = {
|
||||
allow_access_hint: 'Permitir acesso por IP (substituirá os IPs bloqueados)',
|
||||
enter_ip: 'Digite o IP e pressione enter',
|
||||
rate_limiter: 'Limitador de Taxa',
|
||||
callback_url_rules: 'Regras de URL de Retorno',
|
||||
enter_callback_url_rule: 'Digite a regra de URL como regex e pressione enter',
|
||||
callback_url_rule_hint:
|
||||
'URLs de retorno de chamada (como a de LNURL) serão validados conforme estas regras. Pelo menos uma regra deve corresponder. Nenhuma regra significa que todas as URLs são permitidas.',
|
||||
wallet_limiter: 'Limitador de Carteira',
|
||||
wallet_config: 'Configuração da Carteira',
|
||||
wallet_charts: 'Gráficos da Carteira',
|
||||
wallet_limit_max_withdraw_per_day:
|
||||
'Retirada máxima diária da carteira em sats (0 para desativar)',
|
||||
wallet_max_ballance: 'Saldo máximo da carteira em sats (0 para desativar)',
|
||||
wallet_limit_secs_between_trans:
|
||||
'Minutos e segundos entre transações por carteira (0 para desativar)',
|
||||
only_incoming_payments_allowed: 'Apenas pagamentos recebidos são permitidos',
|
||||
disable_outgoing_payments: 'Desativar pagamentos de saída',
|
||||
number_of_requests: 'Número de solicitações',
|
||||
time_unit: 'Unidade de tempo',
|
||||
minute: 'minuto',
|
||||
settings: 'Configurações',
|
||||
second: 'segundo',
|
||||
hour: 'hora',
|
||||
disable_server_log: 'Desativar Log do Servidor',
|
||||
@@ -219,49 +399,108 @@ window.localisation.br = {
|
||||
login_with_user_id: 'Faça login com ID do usuário',
|
||||
or: 'ou',
|
||||
create_new_wallet: 'Criar Nova Carteira',
|
||||
delete_all_wallets: 'Excluir Todas as Carteiras',
|
||||
confirm_delete_all_wallets:
|
||||
'Tem certeza de que deseja excluir TODAS as carteiras deste usuário?',
|
||||
login_to_account: 'Faça login na sua conta',
|
||||
create_account: 'Criar conta',
|
||||
account_settings: 'Configurações da Conta',
|
||||
signin_with_oauth: 'Entrar com',
|
||||
signin_with_oauth_or: 'ou entre com',
|
||||
signin_with_nostr: 'Continuar com Nostr',
|
||||
signin_with_google: 'Entrar com o Google',
|
||||
signin_with_github: 'Entrar com GitHub',
|
||||
signin_with_keycloak: 'Entrar com Keycloak',
|
||||
signin_with_custom_org: 'Entrar com {custom_org}',
|
||||
username_or_email: 'Nome de usuário ou E-mail',
|
||||
password: 'Senha',
|
||||
password_config: 'Configuração de Senha',
|
||||
password_repeat: 'Repetição de senha',
|
||||
update_password: 'Atualizar Senha',
|
||||
change_password: 'Alterar Senha',
|
||||
update_credentials: 'Atualizar credenciais',
|
||||
update_pubkey: 'Atualizar Chave Pública',
|
||||
nostr_pubkey_tooltip:
|
||||
'Insira a chave pública Nostr deste usuário (valor hexadecimal)',
|
||||
set_password: 'Definir Senha',
|
||||
set_password_tooltip: 'Defina uma senha para este usuário',
|
||||
invalid_password: 'A senha deve ter pelo menos 8 caracteres',
|
||||
invalid_password_repeat: 'As senhas não coincidem',
|
||||
reset_key_generated: 'Uma chave de reinicialização foi gerada.',
|
||||
reset_key_copy:
|
||||
'Clique em OK para copiar o URL de redefinição para sua área de transferência.',
|
||||
login: 'Entrar',
|
||||
register: 'Registrar',
|
||||
username: 'Nome de usuário',
|
||||
pubkey: 'Chave Pública',
|
||||
user_id: 'ID do Usuário',
|
||||
id: 'ID',
|
||||
email: 'E-mail',
|
||||
first_name: 'Primeiro Nome',
|
||||
last_name: 'Sobrenome',
|
||||
picture: 'Foto',
|
||||
user_picture_desc:
|
||||
'URL para uma imagem a ser usada como foto de perfil. Você pode carregá-la como um ativo.',
|
||||
verify_email: 'Verifique o e-mail com',
|
||||
account: 'Conta',
|
||||
update_account: 'Atualizar Conta',
|
||||
invalid_username: 'Nome de usuário inválido',
|
||||
auth_provider: 'Provedor de Autenticação',
|
||||
external_id: 'ID Externo',
|
||||
my_account: 'Minha Conta',
|
||||
existing_account_question: 'Já tem uma conta?',
|
||||
background_image: 'Imagem de Fundo',
|
||||
back: 'Voltar',
|
||||
logout: 'Sair',
|
||||
look_and_feel: 'Aparência',
|
||||
endpoint: 'Ponto de extremidade',
|
||||
api: 'API',
|
||||
api_stripe: 'API',
|
||||
api_token: 'Token de API',
|
||||
api_tokens: 'Tokens da API',
|
||||
access_control_list: 'Lista de Controle de Acesso',
|
||||
access_control_list_admin_warning:
|
||||
'Esta é uma conta de administrador. Os tokens gerados terão privilégios de administrador.',
|
||||
new_api_acl: 'Nova Lista de Controle de Acesso',
|
||||
api_token_id: 'Id do Token',
|
||||
toggle_gradient: 'Alternar Gradiente',
|
||||
gradient_background: 'Fundo em Degradê',
|
||||
rounded_ui: 'Cartões e Botões Arredondados',
|
||||
toggle_rounded_ui: 'Alternar cantos arredondados para cartões e botões',
|
||||
card_gradient: 'Gradiente do Cartão',
|
||||
toggle_card_gradient: 'Alternar gradiente nos cartões',
|
||||
card_shadow: 'Sombra do Cartão',
|
||||
toggle_card_shadow: 'Alternar sombra nas cartas',
|
||||
language: 'Idioma',
|
||||
assets: 'Ativos',
|
||||
max_asset_size_mb: 'Tamanho Máximo do Ativo (MB)',
|
||||
max_asset_size_mb_desc:
|
||||
'O tamanho máximo permitido para uploads de ativos em megabytes (pode usar valores decimais).',
|
||||
assets_allowed_mime_types: 'Tipos MIME permitidos',
|
||||
assets_allowed_mime_types_desc:
|
||||
'Os tipos MIME permitidos para uploads de ativos. Nenhum valor significa que todos os uploads são permitidos.',
|
||||
thumbnail_width: 'Largura da Miniatura',
|
||||
thumbnail_width_desc: 'Largura da miniatura gerada em pixels.',
|
||||
thumbnail_height: 'Altura da miniatura',
|
||||
thumbnail_height_desc: 'Altura da miniatura gerada em pixels.',
|
||||
thumbnail_format: 'Formato da Miniatura',
|
||||
thumbnail_format_desc:
|
||||
'Formato de imagem da miniatura gerada (PNG, JPEG, etc.).',
|
||||
max_assets_per_user: 'Máximo de ativos por usuário',
|
||||
max_assets_per_user_desc:
|
||||
'O número máximo de ativos que um usuário pode fazer upload. Zero significa que o upload está proibido.',
|
||||
assets_no_limit_users: 'Usuários sem Limites de Ativos',
|
||||
assets_no_limit_users_desc:
|
||||
'Esses usuários podem enviar um número ilimitado de ativos (com base no ID do usuário).',
|
||||
color_scheme: 'Esquema de Cores',
|
||||
visible_wallet_count: 'Contagem de Carteiras Visíveis',
|
||||
admin_settings: 'Configurações do Administrador',
|
||||
extension_cost: 'Este lançamento requer um pagamento mínimo de {cost} sats.',
|
||||
extension_paid_sats: 'Você já pagou {paid_sats} sats.',
|
||||
create_extension: 'Criar Extensão',
|
||||
release_details_error: 'Não é possível obter os detalhes da versão.',
|
||||
pay_from_wallet: 'Pagar com a Carteira',
|
||||
pay_with: 'Pague com {provider}',
|
||||
select_payment_provider: 'Selecione o provedor de pagamento',
|
||||
wallet_required: 'Carteira *',
|
||||
show_qr: 'Exibir QR',
|
||||
retry_install: 'Repetir Instalação',
|
||||
@@ -274,6 +513,9 @@ window.localisation.br = {
|
||||
'A extensão {name} requer um pagamento mínimo de {amount} sats para habilitar.',
|
||||
hide_empty_wallets: 'Ocultar carteiras vazias',
|
||||
recheck: 'Verificar novamente',
|
||||
check: 'Verificar',
|
||||
check_connection: 'Verificar Conexão',
|
||||
check_webhook: 'Verificar Webhook',
|
||||
contributors: 'Contribuidores',
|
||||
license: 'Licença',
|
||||
reset_key: 'Redefinir Chave',
|
||||
@@ -286,6 +528,7 @@ window.localisation.br = {
|
||||
hash: 'Hash:',
|
||||
welcome_lnbits: 'Bem-vindo ao LNbits',
|
||||
setup_su_account: 'Configure a conta Superuser abaixo.',
|
||||
first_install_token: 'Primeiro Token de Instalação',
|
||||
create_ticker_converter: 'Criar Conversor de Ticker de Moeda',
|
||||
enable_audit: 'Habilitar Auditoria',
|
||||
recommended: 'Recomendado',
|
||||
@@ -326,9 +569,16 @@ window.localisation.br = {
|
||||
user_default_extensions_label: 'Extensões do usuário',
|
||||
user_default_extensions_hint:
|
||||
'Extensões que serão ativadas por padrão para os usuários.',
|
||||
extension_builder: 'Construtor de Extensão',
|
||||
extension_builder_manifest_url: 'URL do Manifesto do Criador de Extensões',
|
||||
extension_builder_manifest_url_hint:
|
||||
'URL para um arquivo JSON manifest com detalhes do extension builder',
|
||||
miscellanous: 'Diversos',
|
||||
misc_disable_extensions: 'Desativar extensões',
|
||||
misc_disable_extensions_label: 'Desativar todas as extensões',
|
||||
misc_disable_extensions_builder: 'Habilitar Extensions Builder',
|
||||
misc_disable_extensions_builder_label:
|
||||
'Habilitar Extensions Builder para usuários não administradores.',
|
||||
misc_hide_api: 'Ocultar API',
|
||||
misc_hide_api_label:
|
||||
'Oculta a API de carteira, extensões podem optar por honrar',
|
||||
@@ -346,16 +596,33 @@ window.localisation.br = {
|
||||
toggle_transactions_node_ui:
|
||||
'Guia de Transações (Desativar em nós grandes CLN)',
|
||||
invoice_expiry: 'Expiração da Fatura',
|
||||
invoice_expiry_label: 'Validade da fatura (segundos)',
|
||||
fee_reserve: 'Reserva de Taxa',
|
||||
fee_reserve_msats: 'Taxa de reserva em msats',
|
||||
fee_reserve_percent: 'Taxa de reserva em porcentagem',
|
||||
invoice_expiry_label: 'Validade da fatura',
|
||||
routing_fee_reserve_calculations: 'Cálculos de Reserva de Taxa de Roteamento',
|
||||
routing_fee_reserve_calculations_desc:
|
||||
'LNbits reserva um "valor de reserva" para cada pagamento para cobrir as taxas de roteamento. A taxa de roteamento máxima passada para a fonte de financiamento é a que for maior: a <strong>reserva mínima de taxa de roteamento</strong> ou a <strong>percentagem de reserva de taxa de roteamento</strong>.',
|
||||
millisats: 'milissats',
|
||||
fee_reserve: 'Reserva Mínima de Taxa de Encaminhamento',
|
||||
fee_reserve_percent: 'Porcentagem da Reserva de Taxa de Roteamento',
|
||||
fee_reserve_min_hint:
|
||||
'A taxa mínima reservada por pagamento.<br>Isso atua como um piso - a taxa de roteamento máxima nunca será inferior a este valor, independentemente do tamanho do pagamento.',
|
||||
fee_reserve_percent_hint:
|
||||
'A porcentagem do valor do pagamento a reservar para taxas de roteamento.',
|
||||
payment_timeouts: 'Tempos de Espera de Pagamento',
|
||||
payment_wait_time: 'Tempo de Espera do Pagamento',
|
||||
seconds: 'segundos',
|
||||
payment_wait_time_desc:
|
||||
'Tempo de espera antes de marcar um pagamento de saída como pendente. Padrão: 5s; aumentar para faturas de liquidação lenta.',
|
||||
payment_wait_time_tooltip:
|
||||
'Controla quanto tempo o LNbits espera para uma tentativa de pagamento de saída ser confirmada antes de marcá-la como pendente. Valores mais altos ajudam ao pagar faturas de liquidação lenta (por exemplo, faturas HODL, Boltz). O pagamento será verificado novamente mais tarde e atualizado automaticamente ou manualmente.',
|
||||
server_management: 'Gerenciamento de Servidor',
|
||||
base_url: 'URL base',
|
||||
base_url_label: 'URL estática/base para o servidor',
|
||||
authentication: 'Autenticação',
|
||||
auth_token_expiry_label: 'Minutos para expiração do token',
|
||||
auth_token_expiry_hint: 'Tempo em minutos até o token expirar',
|
||||
auth_authentication_cache_label: 'Tempo de cache (minutos)',
|
||||
auth_authentication_cache_hint:
|
||||
'Tempo em minutos para armazenar em cache a autenticação bem-sucedida (0 para desativar)',
|
||||
auth_allowed_methods_label: 'Métodos de autorização permitidos',
|
||||
auth_allowed_methods_hint: 'Selecione métodos de autorização',
|
||||
auth_nostr_label: 'URL de Solicitação Nostr',
|
||||
@@ -373,13 +640,26 @@ window.localisation.br = {
|
||||
auth_keycloak_ci_hint:
|
||||
'Certifique-se de que a URL de retorno de chamada de autorização esteja definida para https://{domain}/api/v1/auth/keycloak/token',
|
||||
auth_keycloak_cs_label: 'Segredo do Cliente Keycloak',
|
||||
auth_keycloak_custom_org_label: 'Keycloak Custom Organization',
|
||||
auth_keycloak_custom_icon_label: 'Ícone Personalizado do Keycloak (URL)',
|
||||
currency_settings: 'Configurações de Moeda',
|
||||
allowed_currencies: 'Moedas Permitidas',
|
||||
allowed_currencies_hint: 'Limite o número de moedas fiduciárias disponíveis',
|
||||
default_account_currency: 'Moeda Padrão da Conta',
|
||||
default_account_currency_hint: 'Moeda padrão para contabilidade',
|
||||
min_incoming_payment_amount: 'Quantia Mínima de Pagamento de Entrada',
|
||||
min_incoming_payment_amount_desc:
|
||||
'Quantidade mínima permitida para gerar uma fatura',
|
||||
max_incoming_payment_amount: 'Valor Máximo do Pagamento Recebido',
|
||||
max_incoming_payment_amount_desc:
|
||||
'Quantidade máxima permitida para gerar uma fatura',
|
||||
max_outgoing_payment_amount: 'Valor Máximo de Pagamento de Saída',
|
||||
max_outgoing_payment_amount_desc:
|
||||
'Valor máximo permitido para efetuar um pagamento',
|
||||
service_fee: 'Taxa de serviço: {amount} % por transação',
|
||||
service_fee_label: 'Taxa de serviço (%)',
|
||||
service_fee_hint: 'Taxa cobrada por tx (%)',
|
||||
service_fee_max: 'Taxa de serviço: {amount} % por transação (máx {max} sats)',
|
||||
service_fee_max_label: 'Taxa de serviço máx (sats)',
|
||||
service_fee_max_hint: 'Taxa máxima de serviço a cobrar em (sats)',
|
||||
fee_wallet: 'Carteira de Taxas',
|
||||
@@ -391,6 +671,8 @@ window.localisation.br = {
|
||||
'Desativar Taxa de Serviço para Pagamentos Internos Lightning',
|
||||
ui_management: 'Gerenciamento de UI',
|
||||
ui_site_title: 'Título do Site',
|
||||
ui_changing_remove_lnbits_elements:
|
||||
'(alterar removerá os elementos LNbits na página inicial e rodapé)',
|
||||
ui_site_tagline: 'Tagline do site',
|
||||
ui_elements_enable: 'Habilitar elementos na página inicial',
|
||||
ui_elements_disable: 'Desativar elementos na página inicial',
|
||||
@@ -399,11 +681,27 @@ window.localisation.br = {
|
||||
ui_site_description: 'Descrição do Site',
|
||||
ui_site_description_hint: 'Use texto simples, Markdown ou HTML bruto',
|
||||
ui_default_wallet_name: 'Nome Padrão da Carteira',
|
||||
ui_default_theme: 'Tema Padrão',
|
||||
wallet_featured_button_label: 'Carteira Rótulo do Botão em Destaque',
|
||||
wallet_featured_button_label_hint:
|
||||
'Mostrar botão em destaque na página inicial da carteira',
|
||||
wallet_featured_button_url: 'URL do Botão em Destaque',
|
||||
wallet_featured_button_url_hint:
|
||||
'Ao clicar, o botão abrirá este URL. Deixe em branco para ocultar o botão.',
|
||||
wallet_featured_button_icon: 'Ícone do Botão em Destaque',
|
||||
wallet_featured_button_icon_hint:
|
||||
'Ícone mostrado no botão de destaque (verifique os ícones quasar)',
|
||||
lnbits_wallet: 'Carteira LNbits',
|
||||
denomination: 'Denominação',
|
||||
denomination_hint: 'O nome para o token FakeWallet',
|
||||
denomination_error: 'A denominação deve ter 3 caracteres ou `sats`.',
|
||||
ui_qr_code_logo: 'Logo do QR Code',
|
||||
ui_qr_code_logo_hint: 'URL para imagem de logo no código QR',
|
||||
ui_apple_touch_icon: 'Ícone de Toque da Apple',
|
||||
ui_apple_touch_icon_hint: 'URL do ícone de toque da Apple',
|
||||
ui_custom_image: 'Imagem Personalizada',
|
||||
ui_custom_image_label: 'URL para imagem personalizada',
|
||||
ui_custom_image_hint: 'Imagem exibida na página inicial/login',
|
||||
ui_custom_badge: 'Distintivo Personalizado',
|
||||
ui_custom_badge_label:
|
||||
"Distintivo Personalizado 'USE COM CUIDADO - a carteira LNbits ainda está em BETA'",
|
||||
@@ -426,14 +724,95 @@ window.localisation.br = {
|
||||
admin_users_label: 'ID do Usuário',
|
||||
allowed_users: 'Usuários Permitidos',
|
||||
allowed_users_hint: 'Somente esses usuários podem usar o LNbits',
|
||||
allowed_users_hint_feature: 'Somente estes usuários podem usar {feature}',
|
||||
allowed_users_label: 'ID do Usuário',
|
||||
allow_creation_user: 'Permitir a criação de novos usuários',
|
||||
allow_creation_user_desc:
|
||||
'Permitir a criação de novos usuários na página de índice',
|
||||
require_user_activation: 'Requer ativação do usuário',
|
||||
require_user_activation_desc:
|
||||
'Novos usuários serão ativados somente após passarem por um dos métodos de confirmação. Administradores podem ativar usuários manualmente a partir do painel de administração.',
|
||||
reusable_activation_code: 'Código de ativação reutilizável',
|
||||
reusable_activation_code_label: 'Código de ativação reutilizável',
|
||||
reusable_activation_code_hint:
|
||||
'Este código de ativação pode ser usado várias vezes por diferentes usuários.',
|
||||
one_time_activation_code: 'Códigos de ativação única',
|
||||
one_time_activation_code_label: 'Adicionar código de ativação',
|
||||
one_time_activation_code_hint:
|
||||
'Lista de códigos de ativação únicos. Cada código pode ser usado apenas uma vez, depois será removido da lista.',
|
||||
invitation_code: 'Código de Convite',
|
||||
invitation_code_hint: 'O código de convite que você recebeu.',
|
||||
email_confirmation_hint:
|
||||
'Endereço de e-mail para enviar o código de confirmação.',
|
||||
nostr_identifier: 'Identificador Nostr',
|
||||
nostr_identifier_hint:
|
||||
'Identificador nostr nip5 ou <npub> para enviar o código de confirmação.',
|
||||
new_user_not_allowed: 'O registro está desativado.',
|
||||
start_user_impersonation: 'Personificar este usuário',
|
||||
stop_user_impersonation: 'Parar a Personificação do Usuário',
|
||||
components: 'Componentes',
|
||||
long_running_endpoints: 'Top 5 Endpoints de Longa Execução',
|
||||
http_request_methods: 'Métodos de Requisição HTTP',
|
||||
http_response_codes: 'Códigos de Resposta HTTP',
|
||||
request_details: 'Detalhes do Pedido',
|
||||
http_request_details: 'Detalhes da Requisição HTTP'
|
||||
http_request_details: 'Detalhes da Requisição HTTP',
|
||||
payment_details: 'Detalhes do Pagamento',
|
||||
payment_details_desc: 'Informações detalhadas sobre o pagamento',
|
||||
payments: 'Pagamentos',
|
||||
payment_show_internal: 'Mostrar Pagamentos Internos',
|
||||
payment_chart_flow: 'Fluxo de Pagamento Mensal',
|
||||
payment_chart_status: 'Status do Pagamento',
|
||||
payment_chart_tx_per_wallet: 'Transações por Carteira (saldo/contagem)',
|
||||
payment_details_back: 'Voltar para Pagamentos',
|
||||
payment_chart_tags: 'Pagamentos por Tags',
|
||||
payments_balance_in_out: 'Entradas/Saídas de Saldo',
|
||||
payments_count_in_out: 'Contar Entrada/Saída',
|
||||
payments_status_chart: 'Gráfico de Status',
|
||||
payments_tag_chart: 'Gráfico de Marcadores',
|
||||
payments_balance_chart: 'Gráfico de Saldo',
|
||||
payments_wallets_chart: 'Gráfico de Carteiras',
|
||||
payments_balance_in_out_chart: 'Gráfico de Entrada/Saída de Saldo',
|
||||
payments_count_in_out_chart: 'Gráfico de Entrada/Saída',
|
||||
reset_wallet_keys: 'Redefinir Chaves',
|
||||
reset_wallet_keys_desc:
|
||||
'Redefina as chaves de API para esta carteira. Isso invalidará as chaves atuais e gerará novas.',
|
||||
view_list: 'Visualizar carteiras como lista',
|
||||
view_column: 'Visualizar carteiras como linhas',
|
||||
filter_payments: 'Filtrar pagamentos',
|
||||
filter_labels: 'Rótulos de filtro',
|
||||
filter_date: 'Filtrar por data',
|
||||
websocket_example: 'Exemplo de Websocket',
|
||||
client_id: 'ID do Cliente',
|
||||
secret_key: 'Chave Secreta',
|
||||
signing_secret: 'Segredo de Assinatura',
|
||||
signing_secret_hint:
|
||||
'Segredo de assinatura para o webhook. As mensagens serão assinadas com este segredo.',
|
||||
webhook_id: 'ID do Webhook',
|
||||
webhook_id_hint:
|
||||
'ID do webhook do PayPal usado para verificar eventos recebidos.',
|
||||
webhook_paypal_description:
|
||||
'No lado do PayPal, configure um webhook apontando para o seu servidor LNbits.',
|
||||
callback_success_url: 'URL de Sucesso de Callback',
|
||||
callback_success_url_hint:
|
||||
'O usuário será redirecionado para este URL após o pagamento ser bem-sucedido.',
|
||||
connected: 'Conectado',
|
||||
not_connected: 'Não Conectado',
|
||||
free: 'Grátis',
|
||||
paid: 'Pago',
|
||||
funding_source_retries: 'Máximo de tentativas',
|
||||
funding_source_retries_desc:
|
||||
'Número máximo de tentativas para fontes de financiamento, antes de voltar para VoidWallet.',
|
||||
add_label: 'Adicionar Rótulo',
|
||||
label: 'Etiqueta',
|
||||
labels: 'Rótulos',
|
||||
label_filter: 'Filtro de Rótulo',
|
||||
no_labels_defined: 'Ainda não há rótulos definidos',
|
||||
manage_labels: 'Gerenciar Etiquetas',
|
||||
update_label: 'Atualizar Rótulo',
|
||||
delete_label: 'Excluir Rótulo',
|
||||
add_remove_labels: 'Adicionar ou Remover Rótulos',
|
||||
payment_labels_updated: 'Rótulos de pagamento atualizados',
|
||||
color: 'Cor',
|
||||
sort: 'Ordenar',
|
||||
sort_by: 'Ordenar por'
|
||||
}
|
||||
|
||||
+103
-90
@@ -6,7 +6,7 @@ window.localisation.en = {
|
||||
funding: 'Funding',
|
||||
users: 'Users',
|
||||
audit: 'Audit',
|
||||
api_watch: 'Api Watch',
|
||||
api_watch: 'API Watch',
|
||||
apps: 'Apps',
|
||||
channels: 'Channels',
|
||||
transactions: 'Transactions',
|
||||
@@ -271,12 +271,16 @@ window.localisation.en = {
|
||||
update: 'Update',
|
||||
update_available: 'Update {version} available!',
|
||||
funding_sources: 'Funding Sources',
|
||||
funding_source: 'Funding Source',
|
||||
requires_server_restart:
|
||||
'Changing these settings requires a server restart to take effect.',
|
||||
funding_source_info: 'Select the active funding wallet',
|
||||
latest_update: 'You are on the latest version {version}.',
|
||||
notifications: 'Notifications',
|
||||
notifications_configure: 'Configure Notifications',
|
||||
notifications_nostr_config: 'Nostr Configuration',
|
||||
notifications_enable_nostr: 'Enable Nostr',
|
||||
notifications_enable_nostr_desc: 'Send notfications over Nostr',
|
||||
notifications_enable_nostr_desc: 'Send notifications over Nostr',
|
||||
notifications_nostr_private_key: 'Nostr Private Key',
|
||||
notifications_nostr_private_key_desc:
|
||||
'Private key (hex or nsec) to sign the messages sent to Nostr',
|
||||
@@ -289,7 +293,7 @@ window.localisation.en = {
|
||||
|
||||
notifications_telegram_config: 'Telegram Configuration',
|
||||
notifications_enable_telegram: 'Enable Telegram',
|
||||
notifications_enable_telegram_desc: 'Send notfications over Telegram',
|
||||
notifications_enable_telegram_desc: 'Send notifications over Telegram',
|
||||
notifications_telegram_access_token: 'Access Token',
|
||||
notifications_telegram_access_token_desc: 'Access token for the bot',
|
||||
notifications_chat_id: 'Telegram Chat ID',
|
||||
@@ -318,15 +322,15 @@ window.localisation.en = {
|
||||
|
||||
notification_settings_update: 'Settings updated',
|
||||
notification_settings_update_desc:
|
||||
'Notify when server settings have been updated',
|
||||
'Send a notification when server settings have been updated',
|
||||
|
||||
notification_server_start_stop: 'Server Start/Stop',
|
||||
notification_server_start_stop_desc:
|
||||
'Notify when the server has been started/stopped',
|
||||
'Send a notification when the server has been started/stopped',
|
||||
|
||||
notification_watchdog_limit: 'Watchdog Limit Notification',
|
||||
notification_watchdog_limit_desc:
|
||||
'Notify when the watchdog limit has been reached (does not affect the funding source)',
|
||||
'Send a notification when the watchdog limit has been reached (does not affect the funding source)',
|
||||
|
||||
notification_server_status: 'Server Status',
|
||||
notification_server_status_desc:
|
||||
@@ -334,29 +338,31 @@ window.localisation.en = {
|
||||
|
||||
notification_incoming_payment: 'Incoming Payments',
|
||||
notification_incoming_payment_desc:
|
||||
'Notify when a wallet has received a payment above the specified amount (sats)',
|
||||
'Send a notification when a wallet has received a payment above the specified amount (sats)',
|
||||
|
||||
notification_outgoing_payment: 'Outgoing Payments',
|
||||
notification_outgoing_payment_desc:
|
||||
'Notify when a wallet has sent a payment above the specified amount (sats)',
|
||||
'Send a notification when a wallet has sent a payment above the specified amount (sats)',
|
||||
|
||||
notification_credit_debit: 'Credit / Debit',
|
||||
notification_credit_debit_desc:
|
||||
'Notify when a wallet has been credited/debited by the superuser',
|
||||
'Send a notification when a wallet has been credited/debited by the superuser',
|
||||
|
||||
notification_balance_delta_changed: 'Balance Delta Changed',
|
||||
notification_balance_delta_changed_desc:
|
||||
'Notify when the difference between the node balance and the LNbits balance has changed by more than the specified amount (in sats). Set to 0 to disable. This runs every minute.',
|
||||
'Send a notification when the difference between the node balance and the LNbits balance has changed by more than the specified amount (in sats). Set to 0 to disable. This runs every minute.',
|
||||
|
||||
enable_watchdog: 'Enable Watchdog Switch',
|
||||
watchdog_introduction:
|
||||
"Watchdog is a feature that allows you to automatically switch the LNbits funding source to VoidWallet if your node balance is lower than the LNbits balance by a certain threshold. This can help prevent overspending and keep your node's funds safe.",
|
||||
enable_watchdog: 'Enable Watchdog',
|
||||
enable_watchdog_desc:
|
||||
'If enabled it will change your funding source to VoidWallet automatically if your balance is lower than the LNbits balance. You will need to enable manually after an update.',
|
||||
watchdog_interval: 'Watchdog Interval',
|
||||
'You will need to re-enable this manually after an update.',
|
||||
watchdog_interval: 'Watchdog Check Interval',
|
||||
watchdog_interval_desc:
|
||||
'How often the background task should check for a killswitch signal in the watchdog delta [node_balance - lnbits_balance] (in minutes).',
|
||||
watchdog_delta: 'Watchdog Delta',
|
||||
'How often LNbits should check for a killswitch signal in the watchdog threshold delta value [node_balance - lnbits_balance] (in minutes).',
|
||||
watchdog_delta: 'Watchdog Threshold Delta',
|
||||
watchdog_delta_desc:
|
||||
'Limit before killswitch changes funding source to VoidWallet [lnbits_balance - node_balance > delta]',
|
||||
"The LNbit's > Node balance delta threshold. If this threshold is exceeded, the funding source is changed to VoidWallet.",
|
||||
status: 'Status',
|
||||
notification_source: 'Notification Source',
|
||||
notification_source_label:
|
||||
@@ -367,12 +373,12 @@ window.localisation.en = {
|
||||
releases: 'Releases',
|
||||
watchdog: 'Watchdog',
|
||||
server_logs: 'Server Logs',
|
||||
ip_blocker: 'IP Blocker',
|
||||
ip_blocker: 'IP Blacklist/Whitelist',
|
||||
security: 'Security',
|
||||
security_tools: 'Security tools',
|
||||
security_tools: 'Security Tools',
|
||||
block_access_hint: 'Block access by IP',
|
||||
allow_access_hint: 'Allow access by IP (will override blocked IPs)',
|
||||
enter_ip: 'Enter IP and hit enter',
|
||||
enter_ip: 'Enter an IP address and press enter',
|
||||
rate_limiter: 'Rate Limiter',
|
||||
callback_url_rules: 'Callback URL Rules',
|
||||
enter_callback_url_rule: 'Enter URL rule as regex and hit enter',
|
||||
@@ -386,14 +392,16 @@ window.localisation.en = {
|
||||
wallet_max_ballance: 'Wallet max balance in sats (0 to disable)',
|
||||
wallet_limit_secs_between_trans:
|
||||
'Min secs between transactions per wallet (0 to disable)',
|
||||
only_incoming_payments_allowed: 'Only incoming payments allowed',
|
||||
only_incoming_payments_allowed: 'Allow incoming payments only',
|
||||
disable_outgoing_payments: 'Disable outgoing payments',
|
||||
number_of_requests: 'Number of requests',
|
||||
number_of_requests: 'Number of requests to allow',
|
||||
number_of_requests_hint:
|
||||
'Number of requests to allow per "time unit" for the rate limiter. Set to 0 to disable.',
|
||||
time_unit: 'Time unit',
|
||||
minute: 'minute',
|
||||
minute: 'Minute',
|
||||
settings: 'Settings',
|
||||
second: 'second',
|
||||
hour: 'hour',
|
||||
second: 'Second',
|
||||
hour: 'Hour',
|
||||
disable_server_log: 'Disable Server Log',
|
||||
enable_server_log: 'Enable Server Log',
|
||||
coming_soon: 'Feature coming soon',
|
||||
@@ -533,33 +541,30 @@ window.localisation.en = {
|
||||
create_ticker_converter: 'Create Currency Ticker Converter',
|
||||
enable_audit: 'Enable Audit',
|
||||
recommended: 'Recommended',
|
||||
audit_desc: 'Record HTTP requests according with the specified filters',
|
||||
audit_record_req: 'Record Request Body',
|
||||
audit_record_warning: 'Warning: ',
|
||||
audit_record_req_warning_1:
|
||||
'confidential data (like passwords) will be logged.',
|
||||
audit_record_req_warning_2: 'the request body can have large size.',
|
||||
audit_record_use: 'Use it with caution.',
|
||||
audit_ip: 'Record IP Address',
|
||||
audit_ip_desc: 'Record the IP address of the client',
|
||||
audit_path_params: 'Record Path Parameters',
|
||||
audit_query_params: 'Record Query Parameters',
|
||||
audit_desc: 'Log HTTP requests according to the filters specified below.',
|
||||
audit_record_req: 'Log Request Body',
|
||||
audit_record_warning: 'Warning!',
|
||||
audit_record_req_warning_1: 'Sensitive data (like passwords) will be logged.',
|
||||
audit_record_req_warning_2:
|
||||
'The request body can be large. This can fill up your logs quickly.',
|
||||
audit_record_use: 'Use this with caution!',
|
||||
audit_ip: 'Log IP Address',
|
||||
audit_ip_desc: 'Log the IP address of users making requests to LNbits.',
|
||||
audit_path_params: 'Log Path Parameters',
|
||||
audit_query_params: 'Log Query Parameters',
|
||||
audit_http_methods: 'Include HTTP Methods',
|
||||
audit_http_methods_hint:
|
||||
'List of HTTP methods to be included. Empty lists means all.',
|
||||
audit_http_methods_label: 'HTTP Methods',
|
||||
audit_resp_codes: 'Include HTTP Response Codes',
|
||||
'List of HTTP methods to be logged. No value means all methods will be logged.',
|
||||
audit_http_methods_label: 'HTTP Methods to Log',
|
||||
audit_resp_codes_hint:
|
||||
'List of HTTP codes to be included (regex match). Empty lists means all. Eg: 4.*, 5.*',
|
||||
audit_resp_codes_label: 'HTTP Response code (regex)',
|
||||
audit_paths: 'Include Paths',
|
||||
audit_resp_codes_label: 'HTTP Response Codes to Log (regex)',
|
||||
audit_paths_hint:
|
||||
'List of paths to be included (regex match). Empty list means all.',
|
||||
audit_paths_label: 'HTTP Path (regex)',
|
||||
audit_paths_exclude: 'Exclude Paths',
|
||||
audit_paths_label: 'HTTP Paths to Log (regex)',
|
||||
audit_paths_exclude_hint:
|
||||
'List of paths to be excluded (regex match). Empty list means none.',
|
||||
audit_paths_exclude_label: 'HTTP Path (regex)',
|
||||
audit_paths_exclude_label: 'HTTP Paths to Exclude from Logging (regex)',
|
||||
exchange_providers: 'Exchange Providers',
|
||||
admin_extensions: 'Admin Extensions',
|
||||
admin_extensions_label: 'Admin extensions',
|
||||
@@ -579,41 +584,47 @@ window.localisation.en = {
|
||||
misc_disable_extensions_builder_label:
|
||||
'Enable Extensions Builder for non admin users.',
|
||||
misc_hide_api: 'Hide API',
|
||||
misc_hide_api_label: 'Hides wallet api, extensions can choose to honor',
|
||||
misc_hide_api_label: 'Hides wallet API, extensions can choose to honor',
|
||||
wallets_management: 'Wallets Management',
|
||||
funding_source_info: 'Funding Source Info',
|
||||
funding_source: 'Funding Source: {wallet_class}',
|
||||
node_balance: 'Node Balance: {balance} sats',
|
||||
lnbits_balance: 'LNbits Balance: {balance} sats',
|
||||
funding_reserve_percent: 'Reserve Percent: {percent} %',
|
||||
funding_source_info: 'Funding Source Information',
|
||||
funding_source: 'Funding source: {wallet_class}',
|
||||
node_balance: 'Node balance: {balance} sats',
|
||||
lnbits_balance: 'LNbits balance: {balance} sats',
|
||||
funding_reserve_percent: 'Funding reserve percentage: {percent} %',
|
||||
node_management: 'Node Management',
|
||||
node_management_not_supported:
|
||||
'Node Management not supported by active funding source',
|
||||
'Node management is not supported by the active funding source',
|
||||
toggle_node_ui: 'Node UI',
|
||||
toggle_public_node_ui: 'Public Node UI',
|
||||
toggle_transactions_node_ui: 'Transactions Tab (Disable on large CLN nodes)',
|
||||
invoice_expiry: 'Invoice Expiry',
|
||||
invoice_expiry_label: 'Invoice expiry (seconds)',
|
||||
fee_reserve: 'Fee Reserve',
|
||||
fee_reserve_percent: 'Fee Reserve Percent',
|
||||
fee_reserve_msats: 'Reserve fee in msats',
|
||||
reserve_fee_in_percent: 'Reserve fee in percent',
|
||||
payment_wait_time: 'Payment Wait Time (sec)',
|
||||
routing_fee_reserve_calculations: 'Routing Fee Reserve Calculations',
|
||||
routing_fee_reserve_calculations_desc:
|
||||
'LNbits sets aside a “reserve amount” for each payment to cover routing fees. The maximum routing fee passed to the funding source is whichever is higher: the <strong>minimum routing fee reserve</strong> or the <strong>routing fee reserve percentage</strong>.',
|
||||
millisats: 'millisats',
|
||||
fee_reserve: 'Minimum Routing Fee Reserve',
|
||||
fee_reserve_percent: 'Routing Fee Reserve Percentage',
|
||||
fee_reserve_min_hint:
|
||||
'The minimum fee reserved per payment.<br>This acts as a floor - the maximum allowed routing fee will never be lower than this value regardless of payment size.',
|
||||
fee_reserve_percent_hint:
|
||||
'The percentage of the payment amount to reserve for routing fees.',
|
||||
payment_timeouts: 'Payment Timeouts',
|
||||
payment_wait_time: 'Payment Wait Time',
|
||||
seconds: 'seconds',
|
||||
payment_wait_time_desc:
|
||||
'Wait time before marking an outgoing payment as pending. Default: 5s; raise for slow-settling invoices.',
|
||||
payment_wait_time_tooltip:
|
||||
'Controls how long LNbits waits for an outgoing payment attempt to confirm before marking it as pending. Higher values help when paying slow-settling invoices (e.g., HODL invoices, Boltz). The payment will be rechecked later and updated automatically or manually.',
|
||||
server_management: 'Server Management',
|
||||
base_url: 'Base URL',
|
||||
base_url_label: 'Static/Base url for the server',
|
||||
base_url_label: 'Base URL of the server',
|
||||
authentication: 'Authentication',
|
||||
auth_token_expiry_label: 'Token expire minutes',
|
||||
auth_token_expiry_label: 'Token expiry (minutes)',
|
||||
auth_token_expiry_hint: 'Time in minutes until the token expires',
|
||||
auth_authentication_cache_label: 'Cache time (minutes)',
|
||||
auth_authentication_cache_hint:
|
||||
'Time in minutes to cache successful authentication (0 to disable)',
|
||||
auth_allowed_methods_label: 'Allowed authorization methods',
|
||||
auth_allowed_methods_hint: 'Select authorization methods',
|
||||
auth_allowed_methods_hint: 'Select allowed authorization methods',
|
||||
auth_nostr_label: 'Nostr Request URL',
|
||||
auth_nostr_hint: 'Absolute URL that the clients will use to login.',
|
||||
auth_google_ci_label: 'Google Client ID',
|
||||
@@ -633,31 +644,27 @@ window.localisation.en = {
|
||||
auth_keycloak_custom_icon_label: 'Keycloak Custom Icon (URL)',
|
||||
currency_settings: 'Currency Settings',
|
||||
allowed_currencies: 'Allowed Currencies',
|
||||
allowed_currencies_hint: 'Limit the number of available fiat currencies',
|
||||
default_account_currency: 'Default Account Currency',
|
||||
default_account_currency_hint: 'Default currency for accounting',
|
||||
allowed_currencies_hint:
|
||||
'Set the allowed fiat currencies for the exchange features',
|
||||
default_account_currency: 'Default Accounting Currency',
|
||||
default_account_currency_hint:
|
||||
'The default currency to use for accounting features.',
|
||||
min_incoming_payment_amount: 'Min Incoming Payment Amount',
|
||||
min_incoming_payment_amount_desc:
|
||||
'Minimum amount allowed for generating an invoice',
|
||||
max_incoming_payment_amount: 'Max Incoming Payment Amount',
|
||||
max_incoming_payment_amount: 'Maximum Incoming Payment Amount',
|
||||
max_incoming_payment_amount_desc:
|
||||
'Maximum amount allowed for generating an invoice',
|
||||
max_outgoing_payment_amount: 'Max Outgoing Payment Amount',
|
||||
'Maximum amount allowed when generating an invoice',
|
||||
max_outgoing_payment_amount: 'Maximum Outgoing Payment Amount',
|
||||
max_outgoing_payment_amount_desc:
|
||||
'Maximum amount allowed for making a payment',
|
||||
'Maximum amount allowed when making a payment',
|
||||
service_fees: 'Service Fees',
|
||||
service_fee: 'Service Fee',
|
||||
service_fee_label: 'Service fee (%)',
|
||||
service_fee_hint: 'Fee charged per tx (%)',
|
||||
service_fee_max: 'Service Fee Max',
|
||||
service_fee_max_label: 'Service fee max (sats)',
|
||||
service_fee_max_hint: 'Max service fee to charge in (sats)',
|
||||
fee_wallet: 'Fee Wallet',
|
||||
fee_wallet_label: 'Fee wallet (wallet ID)',
|
||||
fee_wallet_hint: 'Wallet ID to send funds to',
|
||||
disable_fee: 'Disable Fee',
|
||||
disable_fee_internal: 'Disable Service Fee for Internal Payments',
|
||||
disable_fee_internal_desc:
|
||||
'Disable Service Fee for Internal Lightning Payments',
|
||||
service_fee_label: 'Service Fee Charged Per Transaction',
|
||||
service_fee_max_label: 'Maximum Service Fee Limit',
|
||||
fee_wallet_label: 'Service Fee Wallet ID',
|
||||
fee_wallet_hint: 'The ID of the wallet to which to send service funds',
|
||||
disable_fee: 'Disable Service Fees for Internal Payments',
|
||||
ui_management: 'UI Management',
|
||||
ui_site_title: 'Site Title',
|
||||
ui_changing_remove_lnbits_elements:
|
||||
@@ -670,6 +677,7 @@ window.localisation.en = {
|
||||
ui_site_description_hint: 'Use plain text, Markdown, or raw HTML',
|
||||
ui_default_wallet_name: 'Default Wallet Name',
|
||||
ui_default_theme: 'Default Theme',
|
||||
wallet_featured_button_title: 'Wallet - Featured Button',
|
||||
wallet_featured_button_label: 'Wallet Featured Button Label',
|
||||
wallet_featured_button_label_hint:
|
||||
'Show featured button on the wallet homepage',
|
||||
@@ -678,33 +686,38 @@ window.localisation.en = {
|
||||
'On click the button will open this URL. Leave empty to hide the button.',
|
||||
wallet_featured_button_icon: 'Featured Button Icon',
|
||||
wallet_featured_button_icon_hint:
|
||||
'Icon shown on the featured button (check quasar icons)',
|
||||
'Icon shown on the featured button (Quasar icon name e.g. "bolt")',
|
||||
lnbits_wallet: 'LNbits wallet',
|
||||
denomination: 'Denomination',
|
||||
denomination_hint: 'The name for the FakeWallet token',
|
||||
denomination_error: 'Denomination must be 3 characters, or `sats`',
|
||||
ui_qr_code_logo: 'QR Code/Favicon Logo',
|
||||
ui_qr_code_logo_hint: 'QR code and favicon logo url',
|
||||
ui_qr_code_logo_hint: 'QR code icon and favicon logo URL',
|
||||
ui_apple_touch_icon: 'Apple Touch Icon',
|
||||
ui_apple_touch_icon_hint: 'Apple touch icon url',
|
||||
ui_apple_touch_icon_hint: 'Apple touch icon URL',
|
||||
ui_custom_image: 'Custom Image',
|
||||
ui_custom_image_label: 'URL to custom image',
|
||||
ui_custom_image_hint: 'Image showed at homepage/login',
|
||||
ui_custom_badge: 'Custom Badge',
|
||||
ui_custom_image_hint:
|
||||
'This image is shown on the LNbits homepage and login screen.',
|
||||
ui_custom_badge_title: 'Custom Badge Settings',
|
||||
ui_custom_badge_desc: 'Show a custom badge in the header of LNbits',
|
||||
ui_custom_badge: 'Custom Badge Text',
|
||||
ui_custom_badge_label: "Custom Badge 'USE WITH CAUTION'",
|
||||
ui_custom_badge_color_label: 'Custom Badge Color',
|
||||
themes: 'Themes',
|
||||
themes_hint: 'Choose themes available for users',
|
||||
custom_logo: 'Custom Logo',
|
||||
custom_logo_hint: 'URL to logo image',
|
||||
ad_space_title: 'Ad Space Title',
|
||||
ad_space_title_label: 'Supported by',
|
||||
ad_space_section_title: 'Advertisement Space',
|
||||
ad_space_section_desc:
|
||||
'Configure the advertisement space on the wallet sidebar.',
|
||||
ad_space_title: 'Advertisement Space Title',
|
||||
ad_space_title_hint: 'Title shown above the advertisement space',
|
||||
ad_slots: 'Advertisement Slots',
|
||||
ad_slots_hint:
|
||||
'Ad url and image filepaths in CSV format, extensions can choose to honor',
|
||||
ad_slots_label: 'url;img_light_url;img_dark_url, url...',
|
||||
ads_enabled: 'Ads Enabled',
|
||||
ads_disabled: 'Ads Disabled',
|
||||
'Advertisement image filepaths in CSV format, extensions can choose to honor. Format: url;img_light_url;img_dark_url, url..',
|
||||
ads_enabled: 'Enable Advertisement',
|
||||
ads_disabled: 'Disabled Advertisement',
|
||||
user_management: 'User Management',
|
||||
admin_users: 'Admin Users',
|
||||
admin_users_hint: 'Users with admin privileges',
|
||||
|
||||
Vendored
+131
-114
@@ -7,13 +7,13 @@
|
||||
exports.noConflict = function () { global._ = current; return exports; };
|
||||
}()));
|
||||
}(this, (function () {
|
||||
// Underscore.js 1.13.7
|
||||
// Underscore.js 1.13.8
|
||||
// https://underscorejs.org
|
||||
// (c) 2009-2024 Jeremy Ashkenas, Julian Gonggrijp, and DocumentCloud and Investigative Reporters & Editors
|
||||
// (c) 2009-2026 Jeremy Ashkenas, Julian Gonggrijp, and DocumentCloud and Investigative Reporters & Editors
|
||||
// Underscore may be freely distributed under the MIT license.
|
||||
|
||||
// Current version.
|
||||
var VERSION = '1.13.7';
|
||||
var VERSION = '1.13.8';
|
||||
|
||||
// Establish the root object, `window` (`self`) in the browser, `global`
|
||||
// on the server, or `this` in some virtual machines. We use `self`
|
||||
@@ -357,131 +357,146 @@
|
||||
// We use this string twice, so give it a name for minification.
|
||||
var tagDataView = '[object DataView]';
|
||||
|
||||
// Internal recursive comparison function for `_.isEqual`.
|
||||
function eq(a, b, aStack, bStack) {
|
||||
// Identical objects are equal. `0 === -0`, but they aren't identical.
|
||||
// See the [Harmony `egal` proposal](https://wiki.ecmascript.org/doku.php?id=harmony:egal).
|
||||
if (a === b) return a !== 0 || 1 / a === 1 / b;
|
||||
// `null` or `undefined` only equal to itself (strict comparison).
|
||||
if (a == null || b == null) return false;
|
||||
// `NaN`s are equivalent, but non-reflexive.
|
||||
if (a !== a) return b !== b;
|
||||
// Exhaust primitive checks
|
||||
var type = typeof a;
|
||||
if (type !== 'function' && type !== 'object' && typeof b != 'object') return false;
|
||||
return deepEq(a, b, aStack, bStack);
|
||||
}
|
||||
// Perform a deep comparison to check if two objects are equal.
|
||||
function isEqual(a, b) {
|
||||
var todo = [{a: a, b: b}];
|
||||
// Initializing stacks of traversed objects for cycle detection.
|
||||
var aStack = [], bStack = [];
|
||||
|
||||
while (todo.length) {
|
||||
var frame = todo.pop();
|
||||
if (frame === true) {
|
||||
// Remove the first object from the stack of traversed objects.
|
||||
aStack.pop();
|
||||
bStack.pop();
|
||||
continue;
|
||||
}
|
||||
a = frame.a;
|
||||
b = frame.b;
|
||||
|
||||
// Identical objects are equal. `0 === -0`, but they aren't identical.
|
||||
// See the [Harmony `egal` proposal](https://wiki.ecmascript.org/doku.php?id=harmony:egal).
|
||||
if (a === b) {
|
||||
if (a !== 0 || 1 / a === 1 / b) continue;
|
||||
return false;
|
||||
}
|
||||
// `null` or `undefined` only equal to itself (strict comparison).
|
||||
if (a == null || b == null) return false;
|
||||
// `NaN`s are equivalent, but non-reflexive.
|
||||
if (a !== a) {
|
||||
if (b !== b) continue;
|
||||
return false;
|
||||
}
|
||||
// Exhaust primitive checks
|
||||
var type = typeof a;
|
||||
if (type !== 'function' && type !== 'object' && typeof b != 'object') return false;
|
||||
|
||||
// Internal recursive comparison function for `_.isEqual`.
|
||||
function deepEq(a, b, aStack, bStack) {
|
||||
// Unwrap any wrapped objects.
|
||||
if (a instanceof _$1) a = a._wrapped;
|
||||
if (b instanceof _$1) b = b._wrapped;
|
||||
// Compare `[[Class]]` names.
|
||||
var className = toString.call(a);
|
||||
if (className !== toString.call(b)) return false;
|
||||
// Work around a bug in IE 10 - Edge 13.
|
||||
if (hasDataViewBug && className == '[object Object]' && isDataView$1(a)) {
|
||||
if (!isDataView$1(b)) return false;
|
||||
className = tagDataView;
|
||||
}
|
||||
switch (className) {
|
||||
// These types are compared by value.
|
||||
// Unwrap any wrapped objects.
|
||||
if (a instanceof _$1) a = a._wrapped;
|
||||
if (b instanceof _$1) b = b._wrapped;
|
||||
// Compare `[[Class]]` names.
|
||||
var className = toString.call(a);
|
||||
if (className !== toString.call(b)) return false;
|
||||
// Work around a bug in IE 10 - Edge 13.
|
||||
if (hasDataViewBug && className == '[object Object]' && isDataView$1(a)) {
|
||||
if (!isDataView$1(b)) return false;
|
||||
className = tagDataView;
|
||||
}
|
||||
switch (className) {
|
||||
// These types are compared by value.
|
||||
case '[object RegExp]':
|
||||
// RegExps are coerced to strings for comparison (Note: '' + /a/i === '/a/i')
|
||||
case '[object String]':
|
||||
// Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is
|
||||
// equivalent to `new String("5")`.
|
||||
return '' + a === '' + b;
|
||||
if ('' + a === '' + b) continue;
|
||||
return false;
|
||||
case '[object Number]':
|
||||
// `NaN`s are equivalent, but non-reflexive.
|
||||
// Object(NaN) is equivalent to NaN.
|
||||
if (+a !== +a) return +b !== +b;
|
||||
// An `egal` comparison is performed for other numeric values.
|
||||
return +a === 0 ? 1 / +a === 1 / b : +a === +b;
|
||||
todo.push({a: +a, b: +b});
|
||||
continue;
|
||||
case '[object Date]':
|
||||
case '[object Boolean]':
|
||||
// Coerce dates and booleans to numeric primitive values. Dates are compared by their
|
||||
// millisecond representations. Note that invalid dates with millisecond representations
|
||||
// of `NaN` are not equivalent.
|
||||
return +a === +b;
|
||||
if (+a === +b) continue;
|
||||
return false;
|
||||
case '[object Symbol]':
|
||||
return SymbolProto.valueOf.call(a) === SymbolProto.valueOf.call(b);
|
||||
if (SymbolProto.valueOf.call(a) === SymbolProto.valueOf.call(b)) continue;
|
||||
return false;
|
||||
case '[object ArrayBuffer]':
|
||||
case tagDataView:
|
||||
// Coerce to typed array so we can fall through.
|
||||
return deepEq(toBufferView(a), toBufferView(b), aStack, bStack);
|
||||
}
|
||||
todo.push({a: toBufferView(a), b: toBufferView(b)});
|
||||
continue;
|
||||
}
|
||||
|
||||
var areArrays = className === '[object Array]';
|
||||
if (!areArrays && isTypedArray$1(a)) {
|
||||
var areArrays = className === '[object Array]';
|
||||
if (!areArrays && isTypedArray$1(a)) {
|
||||
var byteLength = getByteLength(a);
|
||||
if (byteLength !== getByteLength(b)) return false;
|
||||
if (a.buffer === b.buffer && a.byteOffset === b.byteOffset) return true;
|
||||
if (a.buffer === b.buffer && a.byteOffset === b.byteOffset) continue;
|
||||
areArrays = true;
|
||||
}
|
||||
if (!areArrays) {
|
||||
if (typeof a != 'object' || typeof b != 'object') return false;
|
||||
|
||||
// Objects with different constructors are not equivalent, but `Object`s or `Array`s
|
||||
// from different frames are.
|
||||
var aCtor = a.constructor, bCtor = b.constructor;
|
||||
if (aCtor !== bCtor && !(isFunction$1(aCtor) && aCtor instanceof aCtor &&
|
||||
isFunction$1(bCtor) && bCtor instanceof bCtor)
|
||||
&& ('constructor' in a && 'constructor' in b)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// Assume equality for cyclic structures. The algorithm for detecting cyclic
|
||||
// structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`.
|
||||
if (!areArrays) {
|
||||
if (typeof a != 'object' || typeof b != 'object') return false;
|
||||
|
||||
// Initializing stack of traversed objects.
|
||||
// It's done here since we only need them for objects and arrays comparison.
|
||||
aStack = aStack || [];
|
||||
bStack = bStack || [];
|
||||
var length = aStack.length;
|
||||
while (length--) {
|
||||
// Linear search. Performance is inversely proportional to the number of
|
||||
// unique nested structures.
|
||||
if (aStack[length] === a) return bStack[length] === b;
|
||||
}
|
||||
// Objects with different constructors are not equivalent, but `Object`s or `Array`s
|
||||
// from different frames are.
|
||||
var aCtor = a.constructor, bCtor = b.constructor;
|
||||
if (aCtor !== bCtor && !(isFunction$1(aCtor) && aCtor instanceof aCtor &&
|
||||
isFunction$1(bCtor) && bCtor instanceof bCtor)
|
||||
&& ('constructor' in a && 'constructor' in b)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Add the first object to the stack of traversed objects.
|
||||
aStack.push(a);
|
||||
bStack.push(b);
|
||||
// Assume equality for cyclic structures. The algorithm for detecting cyclic
|
||||
// structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`.
|
||||
|
||||
// Recursively compare objects and arrays.
|
||||
if (areArrays) {
|
||||
// Compare array lengths to determine if a deep comparison is necessary.
|
||||
length = a.length;
|
||||
if (length !== b.length) return false;
|
||||
// Deep compare the contents, ignoring non-numeric properties.
|
||||
var length = aStack.length;
|
||||
while (length--) {
|
||||
if (!eq(a[length], b[length], aStack, bStack)) return false;
|
||||
// Linear search. Performance is inversely proportional to the number of
|
||||
// unique nested structures.
|
||||
if (aStack[length] === a) {
|
||||
if (bStack[length] === b) break;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Deep compare objects.
|
||||
var _keys = keys(a), key;
|
||||
length = _keys.length;
|
||||
// Ensure that both objects contain the same number of properties before comparing deep equality.
|
||||
if (keys(b).length !== length) return false;
|
||||
while (length--) {
|
||||
// Deep compare each member
|
||||
key = _keys[length];
|
||||
if (!(has$1(b, key) && eq(a[key], b[key], aStack, bStack))) return false;
|
||||
if (length >= 0) continue;
|
||||
|
||||
// Add the first object to the stack of traversed objects.
|
||||
aStack.push(a);
|
||||
bStack.push(b);
|
||||
todo.push(true);
|
||||
|
||||
// Recursively compare objects and arrays.
|
||||
if (areArrays) {
|
||||
// Compare array lengths to determine if a deep comparison is necessary.
|
||||
length = a.length;
|
||||
if (length !== b.length) return false;
|
||||
// Deep compare the contents, ignoring non-numeric properties.
|
||||
while (length--) {
|
||||
todo.push({a: a[length], b: b[length]});
|
||||
}
|
||||
} else {
|
||||
// Deep compare objects.
|
||||
var _keys = keys(a), key;
|
||||
length = _keys.length;
|
||||
// Ensure that both objects contain the same number of properties before comparing deep equality.
|
||||
if (keys(b).length !== length) return false;
|
||||
while (length--) {
|
||||
// Deep compare each member
|
||||
key = _keys[length];
|
||||
if (!has$1(b, key)) return false;
|
||||
todo.push({a: a[key], b: b[key]});
|
||||
}
|
||||
}
|
||||
}
|
||||
// Remove the first object from the stack of traversed objects.
|
||||
aStack.pop();
|
||||
bStack.pop();
|
||||
return true;
|
||||
}
|
||||
|
||||
// Perform a deep comparison to check if two objects are equal.
|
||||
function isEqual(a, b) {
|
||||
return eq(a, b);
|
||||
}
|
||||
|
||||
// Retrieve all the enumerable property names of an object.
|
||||
function allKeys(obj) {
|
||||
if (!isObject(obj)) return [];
|
||||
@@ -1032,25 +1047,27 @@
|
||||
var isArrayLike = createSizePropertyCheck(getLength);
|
||||
|
||||
// Internal implementation of a recursive `flatten` function.
|
||||
function flatten$1(input, depth, strict, output) {
|
||||
output = output || [];
|
||||
if (!depth && depth !== 0) {
|
||||
depth = Infinity;
|
||||
} else if (depth <= 0) {
|
||||
return output.concat(input);
|
||||
}
|
||||
var idx = output.length;
|
||||
for (var i = 0, length = getLength(input); i < length; i++) {
|
||||
var value = input[i];
|
||||
if (isArrayLike(value) && (isArray(value) || isArguments$1(value))) {
|
||||
function flatten$1(input, depth, strict) {
|
||||
if (!depth && depth !== 0) depth = Infinity;
|
||||
var output = [], idx = 0, i = 0, length = getLength(input) || 0, stack = [];
|
||||
while (true) {
|
||||
if (i >= length) {
|
||||
if (!stack.length) break;
|
||||
var frame = stack.pop();
|
||||
i = frame.i;
|
||||
input = frame.v;
|
||||
length = getLength(input);
|
||||
continue;
|
||||
}
|
||||
var value = input[i++];
|
||||
if (stack.length >= depth) {
|
||||
output[idx++] = value;
|
||||
} else if (isArrayLike(value) && (isArray(value) || isArguments$1(value))) {
|
||||
// Flatten current level of array or arguments object.
|
||||
if (depth > 1) {
|
||||
flatten$1(value, depth - 1, strict, output);
|
||||
idx = output.length;
|
||||
} else {
|
||||
var j = 0, len = value.length;
|
||||
while (j < len) output[idx++] = value[j++];
|
||||
}
|
||||
stack.push({i: i, v: input});
|
||||
i = 0;
|
||||
input = value;
|
||||
length = getLength(input);
|
||||
} else if (!strict) {
|
||||
output[idx++] = value;
|
||||
}
|
||||
|
||||
@@ -3,9 +3,6 @@
|
||||
<h6 class="q-my-none q-mb-sm">Assets</h6>
|
||||
<div class="row q-col-gutter-md">
|
||||
<div class="col-12 col-md-3">
|
||||
<p>
|
||||
<span v-text="$t('max_asset_size_mb')"></span>
|
||||
</p>
|
||||
<q-input
|
||||
filled
|
||||
type="number"
|
||||
@@ -18,9 +15,6 @@
|
||||
</div>
|
||||
|
||||
<div class="col-12 col-md-9">
|
||||
<p>
|
||||
<span v-text="$t('assets_allowed_mime_types')"></span>
|
||||
</p>
|
||||
<q-input
|
||||
filled
|
||||
v-model.number="newAllowedAssetMimeType"
|
||||
@@ -56,11 +50,8 @@
|
||||
</div>
|
||||
<q-separator class="q-mb-lg q-mt-sm"></q-separator>
|
||||
<h6 class="q-my-none q-mb-sm">Thumbnails</h6>
|
||||
<div class="row q-col-gutter-md">
|
||||
<div class="col-12 col-md-3">
|
||||
<p>
|
||||
<span v-text="$t('thumbnail_width')"></span>
|
||||
</p>
|
||||
<div class="row q-col-gutter-md q-my-lg">
|
||||
<div class="col-12 col-md-4">
|
||||
<q-input
|
||||
filled
|
||||
type="number"
|
||||
@@ -71,10 +62,7 @@
|
||||
:hint="$t('thumbnail_width_desc')"
|
||||
></q-input>
|
||||
</div>
|
||||
<div class="col-12 col-md-3">
|
||||
<p>
|
||||
<span v-text="$t('thumbnail_height')"></span>
|
||||
</p>
|
||||
<div class="col-12 col-md-4">
|
||||
<q-input
|
||||
filled
|
||||
type="number"
|
||||
@@ -85,10 +73,7 @@
|
||||
:hint="$t('thumbnail_height_desc')"
|
||||
></q-input>
|
||||
</div>
|
||||
<div class="col-12 col-md-3">
|
||||
<p>
|
||||
<span v-text="$t('thumbnail_format')"></span>
|
||||
</p>
|
||||
<div class="col-12 col-md-4">
|
||||
<q-input
|
||||
filled
|
||||
v-model.number="formData.lnbits_asset_thumbnail_format"
|
||||
@@ -101,9 +86,6 @@
|
||||
<h6 class="q-my-none q-mb-sm">Users</h6>
|
||||
<div class="row q-col-gutter-md">
|
||||
<div class="col-12 col-md-3">
|
||||
<p>
|
||||
<span v-text="$t('max_assets_per_user')"></span>
|
||||
</p>
|
||||
<q-input
|
||||
filled
|
||||
type="number"
|
||||
@@ -115,9 +97,6 @@
|
||||
></q-input>
|
||||
</div>
|
||||
<div class="col-12 col-md-9">
|
||||
<p>
|
||||
<span v-text="$t('assets_no_limit_users')"></span>
|
||||
</p>
|
||||
<q-input
|
||||
filled
|
||||
v-model="newNoLimitUser"
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
</div>
|
||||
<q-separator class="q-mb-lg q-mt-sm"></q-separator>
|
||||
<div class="row">
|
||||
<div class="col-md-3 col-sm-12 q-pr-sm">
|
||||
<div class="col-md-6 col-sm-12 q-pr-sm">
|
||||
<q-item tag="label" v-ripple>
|
||||
<q-item-section avatar>
|
||||
<q-toggle
|
||||
@@ -62,7 +62,7 @@
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
</div>
|
||||
<div class="col-md-3 col-sm-12 q-pr-sm">
|
||||
<div class="col-md-6 col-sm-12 q-pr-sm">
|
||||
<q-item tag="label" v-ripple>
|
||||
<q-item-section avatar>
|
||||
<q-toggle
|
||||
@@ -83,7 +83,7 @@
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
</div>
|
||||
<div class="col-md-3 col-sm-12 q-pr-sm">
|
||||
<div class="col-md-6 col-sm-12 q-pr-sm">
|
||||
<q-item tag="label" v-ripple>
|
||||
<q-item-section avatar>
|
||||
<q-toggle
|
||||
@@ -104,7 +104,7 @@
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
</div>
|
||||
<div class="col-md-3 col-sm-12 q-pr-sm">
|
||||
<div class="col-md-6 col-sm-12 q-pr-sm">
|
||||
<q-item tag="label" v-ripple>
|
||||
<q-item-section avatar>
|
||||
<q-toggle
|
||||
@@ -129,7 +129,6 @@
|
||||
<q-separator class="q-mb-xl q-mt-sm"></q-separator>
|
||||
<div class="row q-mb-lg">
|
||||
<div class="col-md-6 col-sm-12 q-pr-sm">
|
||||
<p><span v-text="$t('audit_http_methods')"></span></p>
|
||||
<q-select
|
||||
filled
|
||||
v-model="formData.lnbits_audit_http_methods"
|
||||
@@ -148,7 +147,6 @@
|
||||
></q-select>
|
||||
</div>
|
||||
<div class="col-md-6 col-sm-12 q-pr-sm">
|
||||
<p><span v-text="$t('audit_resp_codes')"></span></p>
|
||||
<q-input
|
||||
class="q-mb-md"
|
||||
filled
|
||||
@@ -177,7 +175,6 @@
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6 col-sm-12 q-pr-sm">
|
||||
<p><span v-text="$t('audit_paths')"></span></p>
|
||||
<q-input
|
||||
class="q-mb-md"
|
||||
filled
|
||||
@@ -204,9 +201,6 @@
|
||||
<br />
|
||||
</div>
|
||||
<div class="col-md-6 col-sm-12">
|
||||
<p>
|
||||
<span v-text="$t('audit_paths_exclude')"></span>
|
||||
</p>
|
||||
<q-input
|
||||
class="q-mb-md"
|
||||
filled
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
</div>
|
||||
<div class="col-12 col-md-4">
|
||||
<q-input
|
||||
class="q-mb-md"
|
||||
filled
|
||||
v-model="formData.lnbits_exchange_history_refresh_interval_seconds"
|
||||
type="number"
|
||||
|
||||
@@ -137,7 +137,7 @@
|
||||
:hint="$t('extension_builder_manifest_url_hint')"
|
||||
></q-input>
|
||||
</div>
|
||||
<div class="col-12 col-md-6">
|
||||
<div class="col-12 col-md-6 q-pb-md">
|
||||
<p>
|
||||
<span v-text="$t('reviews_url')"></span>
|
||||
</p>
|
||||
|
||||
@@ -128,7 +128,7 @@
|
||||
</ul>
|
||||
</q-card-section>
|
||||
</q-expansion-item>
|
||||
<q-expansion-item :label="$t('service_fee')">
|
||||
<q-expansion-item :label="$t('service_fees')">
|
||||
<q-card-section>
|
||||
<div class="row">
|
||||
<div class="col-md-4 col-sm-12">
|
||||
@@ -140,7 +140,6 @@
|
||||
v-model="formData.stripe_limits.service_fee_percent"
|
||||
@update:model-value="formData.touch = null"
|
||||
:label="$t('service_fee_label')"
|
||||
:hint="$t('service_fee_hint')"
|
||||
></q-input>
|
||||
</div>
|
||||
<div class="col-md-4 col-sm-12">
|
||||
@@ -151,8 +150,7 @@
|
||||
min="0"
|
||||
v-model="formData.stripe_limits.service_max_fee_sats"
|
||||
@update:model-value="formData.touch = null"
|
||||
:label="$t('service_fee_max')"
|
||||
:hint="$t('service_fee_max_hint')"
|
||||
:label="$t('service_fee_max_label')"
|
||||
></q-input>
|
||||
</div>
|
||||
<div class="col-md-4 col-sm-12">
|
||||
|
||||
@@ -76,47 +76,75 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="row q-col-gutter-md">
|
||||
<div class="col-12 col-md-3">
|
||||
<p><span v-text="$t('fee_reserve')"></span></p>
|
||||
|
||||
<div class="col-12">
|
||||
<h6 class="q-my-none">
|
||||
<span v-text="$t('routing_fee_reserve_calculations')"></span>
|
||||
</h6>
|
||||
<p class="q-mt-sm q-mb-none">
|
||||
<span v-html="$t('routing_fee_reserve_calculations_desc')"></span>
|
||||
</p>
|
||||
</div>
|
||||
<div class="col-12 col-md-4">
|
||||
<p>
|
||||
<span v-text="$t('fee_reserve')"></span>
|
||||
<sup>
|
||||
<q-icon name="info" size="16px" class="q-ml-xs"></q-icon>
|
||||
<q-tooltip max-width="300px">
|
||||
<span v-html="$t('fee_reserve_min_hint')"></span>
|
||||
</q-tooltip>
|
||||
</sup>
|
||||
</p>
|
||||
<q-input
|
||||
type="number"
|
||||
filled
|
||||
v-model="formData.lnbits_reserve_fee_min"
|
||||
:label="$t('fee_reserve_msats')"
|
||||
:suffix="$t('millisats')"
|
||||
>
|
||||
</q-input>
|
||||
</div>
|
||||
<div class="col-12 col-md-3">
|
||||
<div class="col-12 col-md-4">
|
||||
<p>
|
||||
<span v-text="$t('fee_reserve_percent')"></span>
|
||||
<sup>
|
||||
<q-icon name="info" size="16px" class="q-ml-xs"></q-icon>
|
||||
<q-tooltip max-width="300px">
|
||||
<span v-html="$t('fee_reserve_percent_hint')"></span>
|
||||
</q-tooltip>
|
||||
</sup>
|
||||
</p>
|
||||
<q-input
|
||||
type="number"
|
||||
filled
|
||||
name="lnbits_reserve_fee_percent"
|
||||
v-model="formData.lnbits_reserve_fee_percent"
|
||||
:label="$t('reserve_fee_in_percent')"
|
||||
step="0.1"
|
||||
suffix="%"
|
||||
></q-input>
|
||||
</div>
|
||||
<div class="col-12 col-md-3">
|
||||
</div>
|
||||
<div class="row q-col-gutter-md q-mt-sm">
|
||||
<div class="col-12">
|
||||
<h6 class="q-my-none">
|
||||
<span v-text="$t('payment_timeouts')"></span>
|
||||
</h6>
|
||||
</div>
|
||||
<div class="col-12 col-md-4">
|
||||
<p><span v-text="$t('invoice_expiry')"></span></p>
|
||||
<q-input
|
||||
filled
|
||||
v-model.number="formData.lightning_invoice_expiry"
|
||||
type="number"
|
||||
:label="$t('invoice_expiry_label')"
|
||||
:suffix="$t('seconds')"
|
||||
mask="#######"
|
||||
>
|
||||
</q-input>
|
||||
</div>
|
||||
<div class="col-12 col-md-3">
|
||||
<div class="col-12 col-md-4">
|
||||
<p>
|
||||
<span v-text="$t('payment_wait_time')"></span>
|
||||
<sup>
|
||||
<q-icon name="info" size="16px" class="q-ml-xs"></q-icon>
|
||||
<q-tooltip max-width="150px">
|
||||
<q-tooltip max-width="300px">
|
||||
<span v-text="$t('payment_wait_time_tooltip')"></span>
|
||||
</q-tooltip>
|
||||
</sup>
|
||||
@@ -126,8 +154,8 @@
|
||||
filled
|
||||
name="lnbits_funding_source_pay_invoice_wait_seconds"
|
||||
v-model="formData.lnbits_funding_source_pay_invoice_wait_seconds"
|
||||
:label="$t('payment_wait_time')"
|
||||
:hint="$t('payment_wait_time_desc')"
|
||||
:suffix="$t('seconds')"
|
||||
step="1"
|
||||
min="0"
|
||||
></q-input>
|
||||
@@ -165,6 +193,11 @@
|
||||
<h6 class="q-mt-lg q-mb-sm">
|
||||
<p v-text="$t('watchdog')"></p>
|
||||
</h6>
|
||||
<div class="row q-col-gutter-md">
|
||||
<div class="col-12">
|
||||
<p v-text="$t('watchdog_introduction')"></p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row q-col-gutter-md">
|
||||
<div class="col-12 col-md-6">
|
||||
<q-item tag="label" v-ripple>
|
||||
@@ -239,6 +272,7 @@
|
||||
<q-input
|
||||
filled
|
||||
v-model="formData.lnbits_watchdog_delta"
|
||||
:suffix="$t('sats')"
|
||||
type="number"
|
||||
/>
|
||||
</q-item-section>
|
||||
|
||||
@@ -12,11 +12,14 @@
|
||||
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<p>Active Funding<small> (Requires server restart)</small></p>
|
||||
<p>
|
||||
<span v-text="$t('funding_source')"></span>
|
||||
<small><span v-text="$t('requires_server_restart')"></span></small>
|
||||
</p>
|
||||
<q-select
|
||||
filled
|
||||
v-model="formData.lnbits_backend_wallet_class"
|
||||
hint="Select the active funding wallet"
|
||||
:hint="$t('funding_source_info')"
|
||||
:options="sortedAllowedFundingSources"
|
||||
:option-label="item => getFundingSourceLabel(item)"
|
||||
></q-select>
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
<template id="lnbits-admin-security">
|
||||
<q-card-section class="q-pa-none">
|
||||
<h6 class="q-my-none">
|
||||
<h6 class="q-my-none q-mb-sm">
|
||||
<span v-text="$t('server_management')"></span>
|
||||
</h6>
|
||||
<div class="row">
|
||||
<div class="col-12 col-md-6">
|
||||
<p><span v-text="$t('base_url')"></span></p>
|
||||
<q-input
|
||||
filled
|
||||
v-model.number="formData.lnbits_baseurl"
|
||||
@@ -17,7 +16,7 @@
|
||||
<h6 class="q-my-none q-mb-sm">
|
||||
<span v-text="$t('authentication')"></span>
|
||||
</h6>
|
||||
<div class="row q-col-gutter-sm">
|
||||
<div class="row q-col-gutter-sm q-mb-md">
|
||||
<div class="col-12 col-md-6">
|
||||
<q-input
|
||||
filled
|
||||
@@ -305,6 +304,7 @@
|
||||
type="number"
|
||||
v-model.number="formData.lnbits_rate_limit_no"
|
||||
:label="$t('number_of_requests')"
|
||||
:hint="$t('number_of_requests_hint')"
|
||||
></q-input>
|
||||
</div>
|
||||
<div class="col-12 col-md-6">
|
||||
|
||||
@@ -38,14 +38,11 @@
|
||||
</div>
|
||||
|
||||
<q-separator class="q-mb-lg q-mt-sm"></q-separator>
|
||||
<h6 class="q-my-none">
|
||||
<h6 class="q-my-none q-mb-sm">
|
||||
<span v-text="$t('payments')"></span>
|
||||
</h6>
|
||||
<div class="row q-col-gutter-md">
|
||||
<div class="col-12 col-md-3">
|
||||
<p>
|
||||
<span v-text="$t('max_outgoing_payment_amount')"></span>
|
||||
</p>
|
||||
<div class="col-12 col-md-4">
|
||||
<q-input
|
||||
filled
|
||||
type="number"
|
||||
@@ -57,10 +54,7 @@
|
||||
></q-input>
|
||||
</div>
|
||||
|
||||
<div class="col-12 col-md-3">
|
||||
<p>
|
||||
<span v-text="$t('max_incoming_payment_amount')"></span>
|
||||
</p>
|
||||
<div class="col-12 col-md-4">
|
||||
<q-input
|
||||
filled
|
||||
type="number"
|
||||
@@ -75,7 +69,7 @@
|
||||
</div>
|
||||
|
||||
<q-separator class="q-mb-lg q-mt-sm"></q-separator>
|
||||
<h6 class="q-my-none">
|
||||
<h6 class="q-my-none q-mb-sm">
|
||||
<span v-text="$t('wallet_limiter')"></span>
|
||||
</h6>
|
||||
<div class="row q-col-gutter-md">
|
||||
@@ -113,35 +107,32 @@
|
||||
</div>
|
||||
|
||||
<q-separator class="q-mb-lg q-mt-sm"></q-separator>
|
||||
<h6 class="q-my-none">
|
||||
<span v-text="$t('service_fee')"></span>
|
||||
<h6 class="q-my-none q-mb-sm">
|
||||
<span v-text="$t('service_fees')"></span>
|
||||
</h6>
|
||||
<div class="row q-col-gutter-md">
|
||||
<div class="col-12 col-md-6">
|
||||
<p><span v-text="$t('service_fee')"></span></p>
|
||||
<div class="col-12 col-md-4">
|
||||
<q-input
|
||||
filled
|
||||
type="number"
|
||||
v-model.number="formData.lnbits_service_fee"
|
||||
:label="$t('service_fee_label')"
|
||||
step="0.1"
|
||||
:hint="$t('service_fee_hint')"
|
||||
:suffix="'%'"
|
||||
></q-input>
|
||||
<br />
|
||||
</div>
|
||||
<div class="col-12 col-md-6">
|
||||
<p><span v-text="$t('service_fee_max')"></span></p>
|
||||
<div class="col-12 col-md-4">
|
||||
<q-input
|
||||
filled
|
||||
type="number"
|
||||
v-model.number="formData.lnbits_service_fee_max"
|
||||
:label="$t('service_fee_max_label')"
|
||||
:hint="$t('service_fee_max_hint')"
|
||||
:suffix="$t('sats')"
|
||||
></q-input>
|
||||
<br />
|
||||
</div>
|
||||
<div class="col-12 col-md-6">
|
||||
<p><span v-text="$t('fee_wallet')"></span></p>
|
||||
<q-input
|
||||
filled
|
||||
v-model="formData.lnbits_service_fee_wallet"
|
||||
@@ -151,16 +142,9 @@
|
||||
<br />
|
||||
</div>
|
||||
<div class="col-12 col-md-6">
|
||||
<p>
|
||||
<span v-text="$t('disable_fee_internal')"></span>
|
||||
</p>
|
||||
<q-item tag="label" v-ripple>
|
||||
<q-item-section>
|
||||
<q-item-label v-text="$t('disable_fee')"></q-item-label>
|
||||
<q-item-label
|
||||
caption
|
||||
v-text="$t('disable_fee_internal_desc')"
|
||||
></q-item-label>
|
||||
</q-item-section>
|
||||
<q-item-section avatar>
|
||||
<q-toggle
|
||||
|
||||
@@ -6,8 +6,7 @@
|
||||
<br />
|
||||
<div>
|
||||
<div class="row q-col-gutter-md">
|
||||
<div class="col-12 col-md-5">
|
||||
<p><span v-text="$t('ui_site_title')"></span></p>
|
||||
<div class="col-12 col-md-6">
|
||||
<q-input
|
||||
filled
|
||||
type="text"
|
||||
@@ -18,8 +17,7 @@
|
||||
></q-input>
|
||||
<br />
|
||||
</div>
|
||||
<div class="col-12 col-md-5">
|
||||
<p><span v-text="$t('ui_site_tagline')"></span></p>
|
||||
<div class="col-12 col-md-6">
|
||||
<q-input
|
||||
filled
|
||||
type="text"
|
||||
@@ -28,7 +26,9 @@
|
||||
></q-input>
|
||||
<br />
|
||||
</div>
|
||||
<div class="col-12 col-md-2 q-mt-xl">
|
||||
</div>
|
||||
<div class="row q-col-gutter-md">
|
||||
<div class="col-12 col-md-12">
|
||||
<q-toggle
|
||||
:tip="$t('ui_toggle_elements_tip')"
|
||||
v-model="formData.lnbits_show_home_page_elements"
|
||||
@@ -40,78 +40,66 @@
|
||||
></q-toggle>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<p>
|
||||
<span v-text="$t('ui_site_description')"></span>
|
||||
</p>
|
||||
<q-input
|
||||
v-model="formData.lnbits_site_description"
|
||||
filled
|
||||
type="textarea"
|
||||
:hint="$t('ui_site_description_hint')"
|
||||
/>
|
||||
</div>
|
||||
<br />
|
||||
<div class="row q-col-gutter-md">
|
||||
<div class="col-12">
|
||||
<q-input
|
||||
v-model="formData.lnbits_site_description"
|
||||
filled
|
||||
type="textarea"
|
||||
:label="$t('ui_site_description')"
|
||||
:hint="$t('ui_site_description_hint')"
|
||||
/>
|
||||
</div>
|
||||
<div class="col-12 col-md-4">
|
||||
<p>
|
||||
<span v-text="$t('ui_default_wallet_name')"></span>
|
||||
</p>
|
||||
<q-input
|
||||
filled
|
||||
type="text"
|
||||
v-model="formData.lnbits_default_wallet_name"
|
||||
:label="$t('lnbits_wallet')"
|
||||
:label="$t('ui_default_wallet_name')"
|
||||
></q-input>
|
||||
</div>
|
||||
<div class="col-12 col-md-4">
|
||||
<p><span v-text="$t('ui_qr_code_logo')"></span></p>
|
||||
<q-input
|
||||
filled
|
||||
type="text"
|
||||
v-model="formData.lnbits_qr_logo"
|
||||
label="https://example.com/image.svg"
|
||||
:label="$t('ui_qr_code_logo')"
|
||||
:hint="$t('ui_qr_code_logo_hint')"
|
||||
></q-input>
|
||||
</div>
|
||||
<div class="col-12 col-md-4">
|
||||
<p><span v-text="$t('ui_apple_touch_icon')"></span></p>
|
||||
<q-input
|
||||
filled
|
||||
type="text"
|
||||
v-model="formData.lnbits_apple_touch_icon"
|
||||
label="https://example.com/image.png"
|
||||
:label="$t('ui_apple_touch_icon')"
|
||||
:hint="$t('ui_apple_touch_icon_hint')"
|
||||
></q-input>
|
||||
</div>
|
||||
</div>
|
||||
<br />
|
||||
<div class="row q-col-gutter-md">
|
||||
<div class="col-12 col-md-12">
|
||||
<p><span v-text="$t('wallet_featured_button_title')"></span></p>
|
||||
</div>
|
||||
<div class="col-12 col-md-4">
|
||||
<p>
|
||||
<span v-text="$t('wallet_featured_button_label')"></span>
|
||||
</p>
|
||||
<q-input
|
||||
filled
|
||||
type="text"
|
||||
v-model="formData.lnbits_wallet_featured_button_label"
|
||||
label="Loop to Onchain"
|
||||
:label="$t('wallet_featured_button_label')"
|
||||
:hint="$t('wallet_featured_button_label_hint')"
|
||||
></q-input>
|
||||
</div>
|
||||
<div class="col-12 col-md-4">
|
||||
<p><span v-text="$t('wallet_featured_button_url')"></span></p>
|
||||
<q-input
|
||||
filled
|
||||
type="text"
|
||||
v-model="formData.lnbits_wallet_featured_button_url"
|
||||
label="/boltz"
|
||||
:label="$t('wallet_featured_button_url')"
|
||||
:hint="$t('wallet_featured_button_url_hint')"
|
||||
></q-input>
|
||||
</div>
|
||||
<div class="col-12 col-md-4">
|
||||
<p><span v-text="$t('wallet_featured_button_icon')"></span></p>
|
||||
<q-input
|
||||
filled
|
||||
type="text"
|
||||
@@ -121,21 +109,27 @@
|
||||
></q-input>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row q-col-gutter-md q-mt-md">
|
||||
<div class="col-12 col-md-6">
|
||||
<p><span v-text="$t('ui_custom_badge')"></span></p>
|
||||
<div class="col-12 col-md-12">
|
||||
<h6 class="q-my-sm">
|
||||
<span v-text="$t('ui_custom_badge_title')"></span>
|
||||
</h6>
|
||||
<p class="q-mb-none">
|
||||
<span v-text="$t('ui_custom_badge_desc')"></span>
|
||||
</p>
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<div class="row q-col-gutter-md">
|
||||
<div class="col-12 col-md-8">
|
||||
<div class="col-12 col-md-6">
|
||||
<q-input
|
||||
filled
|
||||
type="text"
|
||||
tip="Custom Badge"
|
||||
v-model.trim="formData.lnbits_custom_badge"
|
||||
:label="$t('ui_custom_badge_label')"
|
||||
:label="$t('ui_custom_badge')"
|
||||
></q-input>
|
||||
</div>
|
||||
<div class="col-12 col-md-4">
|
||||
<div class="col-12 col-md-6">
|
||||
<q-select
|
||||
filled
|
||||
v-model="formData.lnbits_custom_badge_color"
|
||||
@@ -145,8 +139,8 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 col-md-6">
|
||||
<p><span v-text="$t('ui_custom_image')"></span></p>
|
||||
<div class="col-12">
|
||||
<h6 class="q-my-sm"><span v-text="$t('ui_custom_image')"></span></h6>
|
||||
<q-input
|
||||
filled
|
||||
type="text"
|
||||
@@ -157,10 +151,8 @@
|
||||
></q-input>
|
||||
</div>
|
||||
</div>
|
||||
<br />
|
||||
<div class="row q-col-gutter-md">
|
||||
<div class="col-12 col-md-6">
|
||||
<p><span v-text="$t('themes')"></span></p>
|
||||
<q-select
|
||||
filled
|
||||
v-model="formData.lnbits_theme_options"
|
||||
@@ -172,41 +164,26 @@
|
||||
<br />
|
||||
</div>
|
||||
<div class="col-12 col-md-6">
|
||||
<p><span v-text="$t('custom_logo')"></span></p>
|
||||
<q-input
|
||||
filled
|
||||
type="text"
|
||||
v-model="formData.lnbits_custom_logo"
|
||||
label="https://example.com/image.png"
|
||||
:label="$t('custom_logo')"
|
||||
:hint="$t('custom_logo_hint')"
|
||||
></q-input>
|
||||
<br />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row q-col-gutter-md">
|
||||
<div class="col-12 col-md-6">
|
||||
<p><span v-text="$t('ad_space_title')"></span></p>
|
||||
<q-input
|
||||
filled
|
||||
type="text"
|
||||
v-model="formData.lnbits_ad_space_title"
|
||||
:label="$t('ad_space_title_label')"
|
||||
></q-input>
|
||||
<br />
|
||||
<div class="col-12 col-md-12">
|
||||
<h6 class="q-my-sm">
|
||||
<span v-text="$t('ad_space_section_title')"></span>
|
||||
</h6>
|
||||
<p class="q-my-none">
|
||||
<span v-text="$t('ad_space_section_desc')"></span>
|
||||
</p>
|
||||
</div>
|
||||
<div class="col-12 col-md-6">
|
||||
<p><span v-text="$t('ad_slots')"></span></p>
|
||||
<q-input
|
||||
class="q-mb-md"
|
||||
filled
|
||||
v-model="formData.lnbits_ad_space"
|
||||
type="text"
|
||||
:label="$t('ad_slots_label')"
|
||||
:hint="$t('ad_slots_hint')"
|
||||
><q-tooltip>
|
||||
format {url};{img-light};{img-dark},{url};{img-light};{img-dark}"
|
||||
</q-tooltip>
|
||||
</q-input>
|
||||
<div class="col-12 col-md-12">
|
||||
<q-toggle
|
||||
v-model="formData.lnbits_ad_space_enabled"
|
||||
:label="
|
||||
@@ -215,8 +192,30 @@
|
||||
: $t('ads_disabled')
|
||||
"
|
||||
/>
|
||||
</div>
|
||||
<div class="col-12 col-md-6">
|
||||
<q-input
|
||||
filled
|
||||
type="text"
|
||||
v-model="formData.lnbits_ad_space_title"
|
||||
:label="$t('ad_space_title')"
|
||||
:hint="$t('ad_space_title_hint')"
|
||||
></q-input>
|
||||
<br />
|
||||
</div>
|
||||
<div class="col-12 col-md-6">
|
||||
<q-input
|
||||
class="q-mb-md"
|
||||
filled
|
||||
v-model="formData.lnbits_ad_space"
|
||||
type="text"
|
||||
:label="$t('ad_slots')"
|
||||
:hint="$t('ad_slots_hint')"
|
||||
><q-tooltip>
|
||||
format {url};{img-light};{img-dark},{url};{img-light};{img-dark}"
|
||||
</q-tooltip>
|
||||
</q-input>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row q-col-gutter-md q-my-md">
|
||||
<div class="col-12" v-text="$t('ui_default_theme')"></div>
|
||||
|
||||
@@ -143,6 +143,9 @@ class SparkL2Wallet(Wallet):
|
||||
async def pay_invoice(self, bolt11: str, fee_limit_msat: int) -> PaymentResponse:
|
||||
try:
|
||||
max_fee_sats = (int(fee_limit_msat) + 999) // 1000
|
||||
logger.info(
|
||||
f"Paying invoice via Spark sidecar with max fee {max_fee_sats} sats."
|
||||
)
|
||||
|
||||
payment_hash = None
|
||||
try:
|
||||
|
||||
Generated
+8
-7
@@ -13,7 +13,7 @@
|
||||
"qrcode.vue": "^3.6.0",
|
||||
"quasar": "2.18.6",
|
||||
"showdown": "^2.1.0",
|
||||
"underscore": "^1.13.7",
|
||||
"underscore": "^1.13.8",
|
||||
"vue": "3.5.25",
|
||||
"vue-i18n": "^11.2.2",
|
||||
"vue-qrcode-reader": "^5.7.3",
|
||||
@@ -1260,9 +1260,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/immutable": {
|
||||
"version": "5.1.4",
|
||||
"resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.4.tgz",
|
||||
"integrity": "sha512-p6u1bG3YSnINT5RQmx/yRZBpenIl30kVxkTLDyHLIMk0gict704Q9n+thfDI7lTRm9vXdDYutVzXhzcThxTnXA==",
|
||||
"version": "5.1.5",
|
||||
"resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.5.tgz",
|
||||
"integrity": "sha512-t7xcm2siw+hlUM68I+UEOK+z84RzmN59as9DZ7P1l0994DKUWV7UXBMQZVxaoMSRQ+PBZbHCOoBt7a2wxOMt+A==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
@@ -1722,9 +1722,10 @@
|
||||
}
|
||||
},
|
||||
"node_modules/underscore": {
|
||||
"version": "1.13.7",
|
||||
"resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.7.tgz",
|
||||
"integrity": "sha512-GMXzWtsc57XAtguZgaQViUOzs0KTkk8ojr3/xAxXLITqf/3EMwxC0inyETfDFjH/Krbhuep0HNbbjI9i/q3F3g=="
|
||||
"version": "1.13.8",
|
||||
"resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.8.tgz",
|
||||
"integrity": "sha512-DXtD3ZtEQzc7M8m4cXotyHR+FAS18C64asBYY5vqZexfYryNNnDc02W4hKg3rdQuqOYas1jkseX0+nZXjTXnvQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/vue": {
|
||||
"version": "3.5.25",
|
||||
|
||||
+1
-1
@@ -28,7 +28,7 @@
|
||||
"qrcode.vue": "^3.6.0",
|
||||
"quasar": "2.18.6",
|
||||
"showdown": "^2.1.0",
|
||||
"underscore": "^1.13.7",
|
||||
"underscore": "^1.13.8",
|
||||
"vue": "3.5.25",
|
||||
"vue-i18n": "^11.2.2",
|
||||
"vue-qrcode-reader": "^5.7.3",
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
[project]
|
||||
name = "lnbits"
|
||||
version = "1.5.1-rc1"
|
||||
version = "1.5.2"
|
||||
requires-python = ">=3.10,<3.13"
|
||||
description = "LNbits, free and open-source Lightning wallet and accounts system."
|
||||
authors = [{ name = "Alan Bits", email = "alan@lnbits.com" }]
|
||||
|
||||
@@ -6,10 +6,6 @@ from pydantic import BaseModel
|
||||
from lnbits.wallets import get_funding_source, set_funding_source
|
||||
|
||||
|
||||
class FakeError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class DbTestModel(BaseModel):
|
||||
id: int
|
||||
name: str
|
||||
|
||||
@@ -2,6 +2,7 @@ import asyncio
|
||||
import hashlib
|
||||
|
||||
import pytest
|
||||
from pytest_mock.plugin import MockerFixture
|
||||
|
||||
from lnbits import bolt11
|
||||
from lnbits.core.crud import get_standalone_payment, update_payment
|
||||
@@ -18,7 +19,7 @@ from lnbits.exceptions import PaymentError
|
||||
from lnbits.tasks import create_task, wait_for_paid_invoices
|
||||
from lnbits.wallets import get_funding_source
|
||||
|
||||
from ..helpers import FakeError, is_fake, is_regtest
|
||||
from ..helpers import is_fake, is_regtest
|
||||
from .helpers import (
|
||||
cancel_invoice,
|
||||
get_real_invoice,
|
||||
@@ -138,7 +139,9 @@ async def test_pay_real_invoice_mainnet(
|
||||
|
||||
@pytest.mark.anyio
|
||||
@pytest.mark.skipif(is_fake, reason="this only works in regtest")
|
||||
async def test_create_real_invoice(client, adminkey_headers_from, inkey_headers_from):
|
||||
async def test_create_real_invoice(
|
||||
client, adminkey_headers_from, inkey_headers_from, mocker: MockerFixture
|
||||
):
|
||||
prev_balance = await get_node_balance_sats()
|
||||
create_invoice = CreateInvoice(out=False, amount=1000, memo="test")
|
||||
response = await client.post(
|
||||
@@ -156,34 +159,32 @@ async def test_create_real_invoice(client, adminkey_headers_from, inkey_headers_
|
||||
payment_status = response.json()
|
||||
assert not payment_status["paid"]
|
||||
|
||||
async def on_paid(payment: Payment):
|
||||
on_paid_mock = mocker.AsyncMock()
|
||||
create_task(wait_for_paid_invoices("test_create_invoice", on_paid_mock)())
|
||||
|
||||
assert payment.payment_hash == invoice["payment_hash"]
|
||||
assert payment.checking_id == invoice["checking_id"]
|
||||
|
||||
response = await client.get(
|
||||
f'/api/v1/payments/{invoice["payment_hash"]}', headers=inkey_headers_from
|
||||
)
|
||||
assert response.status_code < 300
|
||||
payment_status = response.json()
|
||||
assert payment_status["paid"]
|
||||
|
||||
await asyncio.sleep(1)
|
||||
balance = await get_node_balance_sats()
|
||||
fee = abs(payment_status.get("details", {}).get("fee", 0) // 1000)
|
||||
assert balance - prev_balance == create_invoice.amount - fee
|
||||
|
||||
assert payment_status.get("preimage") is not None
|
||||
|
||||
# exit out of infinite loop
|
||||
raise FakeError()
|
||||
|
||||
task = create_task(wait_for_paid_invoices("test_create_invoice", on_paid)())
|
||||
pay_real_invoice(invoice["bolt11"])
|
||||
|
||||
# wait for the task to exit
|
||||
with pytest.raises(FakeError):
|
||||
await task
|
||||
await asyncio.sleep(1)
|
||||
|
||||
assert on_paid_mock.call_count == 1
|
||||
payment = on_paid_mock.call_args_list[0][0][0]
|
||||
|
||||
assert payment.payment_hash == invoice["payment_hash"]
|
||||
assert payment.checking_id == invoice["checking_id"]
|
||||
|
||||
response = await client.get(
|
||||
f'/api/v1/payments/{invoice["payment_hash"]}', headers=inkey_headers_from
|
||||
)
|
||||
assert response.status_code < 300
|
||||
payment_status = response.json()
|
||||
assert payment_status["paid"]
|
||||
|
||||
await asyncio.sleep(1)
|
||||
balance = await get_node_balance_sats()
|
||||
fee = abs(payment_status.get("details", {}).get("fee", 0) // 1000)
|
||||
assert balance - prev_balance == create_invoice.amount - fee
|
||||
|
||||
assert payment_status.get("preimage") is not None
|
||||
|
||||
|
||||
@pytest.mark.anyio
|
||||
@@ -367,7 +368,7 @@ async def test_pay_hold_invoice_check_pending_and_fail_cancel_payment_task_in_me
|
||||
@pytest.mark.anyio
|
||||
@pytest.mark.skipif(is_fake, reason="this only works in regtest")
|
||||
async def test_receive_real_invoice_set_pending_and_check_state(
|
||||
client, adminkey_headers_from, inkey_headers_from
|
||||
client, adminkey_headers_from, inkey_headers_from, mocker: MockerFixture
|
||||
):
|
||||
"""
|
||||
1. We create a real invoice
|
||||
@@ -391,39 +392,36 @@ async def test_receive_real_invoice_set_pending_and_check_state(
|
||||
payment_status = response.json()
|
||||
assert not payment_status["paid"]
|
||||
|
||||
async def on_paid(payment: Payment):
|
||||
on_paid_mock = mocker.AsyncMock()
|
||||
create_task(wait_for_paid_invoices("test_create_invoice", on_paid_mock)())
|
||||
|
||||
assert payment.payment_hash == invoice["payment_hash"]
|
||||
assert payment.checking_id == invoice["checking_id"]
|
||||
|
||||
response = await client.get(
|
||||
f'/api/v1/payments/{invoice["payment_hash"]}', headers=inkey_headers_from
|
||||
)
|
||||
assert response.status_code < 300
|
||||
payment_status = response.json()
|
||||
assert payment_status["paid"]
|
||||
|
||||
assert payment
|
||||
|
||||
# set the incoming invoice to pending
|
||||
payment.status = PaymentState.PENDING
|
||||
await update_payment(payment)
|
||||
|
||||
payment_pending = await get_standalone_payment(
|
||||
invoice["payment_hash"], incoming=True
|
||||
)
|
||||
assert payment_pending
|
||||
assert payment_pending.success is False
|
||||
assert payment_pending.failed is False
|
||||
|
||||
# exit out of infinite loop
|
||||
raise FakeError()
|
||||
|
||||
task = create_task(wait_for_paid_invoices("test_create_invoice", on_paid)())
|
||||
pay_real_invoice(invoice["bolt11"])
|
||||
|
||||
with pytest.raises(FakeError):
|
||||
await task
|
||||
await asyncio.sleep(1)
|
||||
|
||||
assert on_paid_mock.call_count == 1
|
||||
payment = on_paid_mock.call_args_list[0][0][0]
|
||||
|
||||
assert payment.payment_hash == invoice["payment_hash"]
|
||||
assert payment.checking_id == invoice["checking_id"]
|
||||
|
||||
response = await client.get(
|
||||
f'/api/v1/payments/{invoice["payment_hash"]}', headers=inkey_headers_from
|
||||
)
|
||||
assert response.status_code < 300
|
||||
payment_status = response.json()
|
||||
assert payment_status["paid"]
|
||||
|
||||
# set the incoming invoice to pending
|
||||
payment.status = PaymentState.PENDING
|
||||
await update_payment(payment)
|
||||
|
||||
payment_pending = await get_standalone_payment(
|
||||
invoice["payment_hash"], incoming=True
|
||||
)
|
||||
assert payment_pending
|
||||
assert payment_pending.success is False
|
||||
assert payment_pending.failed is False
|
||||
|
||||
|
||||
@pytest.mark.anyio
|
||||
|
||||
@@ -10,16 +10,12 @@ from pytest_mock.plugin import MockerFixture
|
||||
|
||||
from lnbits.core.crud import create_wallet, get_standalone_payment, get_wallet
|
||||
from lnbits.core.crud.payments import get_payment, get_payments_paginated
|
||||
from lnbits.core.models import Payment, PaymentState, Wallet
|
||||
from lnbits.core.models import PaymentState, Wallet
|
||||
from lnbits.core.services import create_invoice, create_user_account, pay_invoice
|
||||
from lnbits.core.services.payments import update_wallet_balance
|
||||
from lnbits.exceptions import InvoiceError, PaymentError
|
||||
from lnbits.settings import Settings
|
||||
from lnbits.tasks import (
|
||||
create_permanent_task,
|
||||
internal_invoice_listener,
|
||||
register_invoice_listener,
|
||||
)
|
||||
from lnbits.tasks import create_task, wait_for_paid_invoices
|
||||
from lnbits.wallets.base import PaymentResponse
|
||||
from lnbits.wallets.fake import FakeWallet
|
||||
|
||||
@@ -230,13 +226,13 @@ async def test_pay_for_extension(to_wallet: Wallet, settings: Settings):
|
||||
|
||||
|
||||
@pytest.mark.anyio
|
||||
async def test_notification_for_internal_payment(to_wallet: Wallet):
|
||||
async def test_notification_for_internal_payment(
|
||||
to_wallet: Wallet, mocker: MockerFixture
|
||||
):
|
||||
test_name = "test_notification_for_internal_payment"
|
||||
|
||||
create_permanent_task(internal_invoice_listener)
|
||||
invoice_queue: asyncio.Queue = asyncio.Queue()
|
||||
register_invoice_listener(invoice_queue, test_name)
|
||||
|
||||
on_paid_mock = mocker.AsyncMock()
|
||||
create_task(wait_for_paid_invoices(test_name, on_paid_mock)())
|
||||
payment = await create_invoice(
|
||||
wallet_id=to_wallet.id,
|
||||
amount=123,
|
||||
@@ -248,17 +244,15 @@ async def test_notification_for_internal_payment(to_wallet: Wallet):
|
||||
)
|
||||
await asyncio.sleep(1)
|
||||
|
||||
while True:
|
||||
_payment: Payment = invoice_queue.get_nowait() # raises if queue empty
|
||||
assert _payment
|
||||
if _payment.memo == test_name:
|
||||
assert _payment.status == PaymentState.SUCCESS.value
|
||||
assert _payment.bolt11 == payment.bolt11
|
||||
assert _payment.amount == 123_000
|
||||
updated_payment = await get_payment(_payment.checking_id)
|
||||
assert updated_payment.webhook_status == "404"
|
||||
assert on_paid_mock.call_count == 1
|
||||
_payment = on_paid_mock.call_args_list[0][0][0]
|
||||
|
||||
break # we found our payment, success
|
||||
assert _payment.memo == test_name
|
||||
assert _payment.status == PaymentState.SUCCESS.value
|
||||
assert _payment.bolt11 == payment.bolt11
|
||||
assert _payment.amount == 123_000
|
||||
updated_payment = await get_payment(_payment.checking_id)
|
||||
assert updated_payment.webhook_status == "404"
|
||||
|
||||
|
||||
@pytest.mark.anyio
|
||||
|
||||
+24
-2
@@ -1,5 +1,27 @@
|
||||
# 1. Always check the results of the procedure
|
||||
# 2. Always run "npx prettier -w lnbits/static/i18n/XX.js" to reformat the result
|
||||
"""_summary_
|
||||
The script syncs missing translation keys from en.js into another language file
|
||||
using GPT-4o.
|
||||
|
||||
What it does:
|
||||
1. Loads en.js and the target language file (e.g. de.js)
|
||||
2. Finds keys present in en.js but missing from the target
|
||||
3. For each missing key, calls GPT-4o to translate the English string
|
||||
4. Preserves %{variable} placeholders verbatim — skips the translation if they get
|
||||
mangled
|
||||
5. Writes the updated language file back, maintaining key order from en.js
|
||||
6. If no keys are missing, it instead checks that %{variable} placeholders match
|
||||
between English and the target
|
||||
|
||||
1. Always check the results of the procedure
|
||||
2. Always run "npx prettier -w lnbits/static/i18n/XX.js" to format the result
|
||||
|
||||
Usage:
|
||||
export OPENAI_API_KEY=sk-...
|
||||
python3 tools/i18n-ai-tool.py de
|
||||
npx prettier -w lnbits/static/i18n/de.js
|
||||
Returns:
|
||||
_type_: _description_
|
||||
"""
|
||||
|
||||
import os
|
||||
import re
|
||||
|
||||
@@ -1247,7 +1247,7 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "lnbits"
|
||||
version = "1.5.1rc1"
|
||||
version = "1.5.2"
|
||||
source = { editable = "." }
|
||||
dependencies = [
|
||||
{ name = "aiosqlite" },
|
||||
@@ -2537,21 +2537,19 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "tornado"
|
||||
version = "6.5.2"
|
||||
version = "6.5.5"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/09/ce/1eb500eae19f4648281bb2186927bb062d2438c2e5093d1360391afd2f90/tornado-6.5.2.tar.gz", hash = "sha256:ab53c8f9a0fa351e2c0741284e06c7a45da86afb544133201c5cc8578eb076a0", size = 510821, upload-time = "2025-08-08T18:27:00.78Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/f8/f1/3173dfa4a18db4a9b03e5d55325559dab51ee653763bb8745a75af491286/tornado-6.5.5.tar.gz", hash = "sha256:192b8f3ea91bd7f1f50c06955416ed76c6b72f96779b962f07f911b91e8d30e9", size = 516006, upload-time = "2026-03-10T21:31:02.067Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/f6/48/6a7529df2c9cc12efd2e8f5dd219516184d703b34c06786809670df5b3bd/tornado-6.5.2-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:2436822940d37cde62771cff8774f4f00b3c8024fe482e16ca8387b8a2724db6", size = 442563, upload-time = "2025-08-08T18:26:42.945Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f2/b5/9b575a0ed3e50b00c40b08cbce82eb618229091d09f6d14bce80fc01cb0b/tornado-6.5.2-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:583a52c7aa94ee046854ba81d9ebb6c81ec0fd30386d96f7640c96dad45a03ef", size = 440729, upload-time = "2025-08-08T18:26:44.473Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/1b/4e/619174f52b120efcf23633c817fd3fed867c30bff785e2cd5a53a70e483c/tornado-6.5.2-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b0fe179f28d597deab2842b86ed4060deec7388f1fd9c1b4a41adf8af058907e", size = 444295, upload-time = "2025-08-08T18:26:46.021Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/95/fa/87b41709552bbd393c85dd18e4e3499dcd8983f66e7972926db8d96aa065/tornado-6.5.2-cp39-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b186e85d1e3536d69583d2298423744740986018e393d0321df7340e71898882", size = 443644, upload-time = "2025-08-08T18:26:47.625Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f9/41/fb15f06e33d7430ca89420283a8762a4e6b8025b800ea51796ab5e6d9559/tornado-6.5.2-cp39-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e792706668c87709709c18b353da1f7662317b563ff69f00bab83595940c7108", size = 443878, upload-time = "2025-08-08T18:26:50.599Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/11/92/fe6d57da897776ad2e01e279170ea8ae726755b045fe5ac73b75357a5a3f/tornado-6.5.2-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:06ceb1300fd70cb20e43b1ad8aaee0266e69e7ced38fa910ad2e03285009ce7c", size = 444549, upload-time = "2025-08-08T18:26:51.864Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/9b/02/c8f4f6c9204526daf3d760f4aa555a7a33ad0e60843eac025ccfd6ff4a93/tornado-6.5.2-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:74db443e0f5251be86cbf37929f84d8c20c27a355dd452a5cfa2aada0d001ec4", size = 443973, upload-time = "2025-08-08T18:26:53.625Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ae/2d/f5f5707b655ce2317190183868cd0f6822a1121b4baeae509ceb9590d0bd/tornado-6.5.2-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:b5e735ab2889d7ed33b32a459cac490eda71a1ba6857b0118de476ab6c366c04", size = 443954, upload-time = "2025-08-08T18:26:55.072Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e8/59/593bd0f40f7355806bf6573b47b8c22f8e1374c9b6fd03114bd6b7a3dcfd/tornado-6.5.2-cp39-abi3-win32.whl", hash = "sha256:c6f29e94d9b37a95013bb669616352ddb82e3bfe8326fccee50583caebc8a5f0", size = 445023, upload-time = "2025-08-08T18:26:56.677Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c7/2a/f609b420c2f564a748a2d80ebfb2ee02a73ca80223af712fca591386cafb/tornado-6.5.2-cp39-abi3-win_amd64.whl", hash = "sha256:e56a5af51cc30dd2cae649429af65ca2f6571da29504a07995175df14c18f35f", size = 445427, upload-time = "2025-08-08T18:26:57.91Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/5e/4f/e1f65e8f8c76d73658b33d33b81eed4322fb5085350e4328d5c956f0c8f9/tornado-6.5.2-cp39-abi3-win_arm64.whl", hash = "sha256:d6c33dc3672e3a1f3618eb63b7ef4683a7688e7b9e6e8f0d9aa5726360a004af", size = 444456, upload-time = "2025-08-08T18:26:59.207Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/59/8c/77f5097695f4dd8255ecbd08b2a1ed8ba8b953d337804dd7080f199e12bf/tornado-6.5.5-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:487dc9cc380e29f58c7ab88f9e27cdeef04b2140862e5076a66fb6bb68bb1bfa", size = 445983, upload-time = "2026-03-10T21:30:44.28Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ab/5e/7625b76cd10f98f1516c36ce0346de62061156352353ef2da44e5c21523c/tornado-6.5.5-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:65a7f1d46d4bb41df1ac99f5fcb685fb25c7e61613742d5108b010975a9a6521", size = 444246, upload-time = "2026-03-10T21:30:46.571Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b2/04/7b5705d5b3c0fab088f434f9c83edac1573830ca49ccf29fb83bf7178eec/tornado-6.5.5-cp39-abi3-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:e74c92e8e65086b338fd56333fb9a68b9f6f2fe7ad532645a290a464bcf46be5", size = 447229, upload-time = "2026-03-10T21:30:48.273Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/34/01/74e034a30ef59afb4097ef8659515e96a39d910b712a89af76f5e4e1f93c/tornado-6.5.5-cp39-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:435319e9e340276428bbdb4e7fa732c2d399386d1de5686cb331ec8eee754f07", size = 448192, upload-time = "2026-03-10T21:30:51.22Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/be/00/fe9e02c5a96429fce1a1d15a517f5d8444f9c412e0bb9eadfbe3b0fc55bf/tornado-6.5.5-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:3f54aa540bdbfee7b9eb268ead60e7d199de5021facd276819c193c0fb28ea4e", size = 448039, upload-time = "2026-03-10T21:30:53.52Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/82/9e/656ee4cec0398b1d18d0f1eb6372c41c6b889722641d84948351ae19556d/tornado-6.5.5-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:36abed1754faeb80fbd6e64db2758091e1320f6bba74a4cf8c09cd18ccce8aca", size = 447445, upload-time = "2026-03-10T21:30:55.541Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/5a/76/4921c00511f88af86a33de770d64141170f1cfd9c00311aea689949e274e/tornado-6.5.5-cp39-abi3-win32.whl", hash = "sha256:dd3eafaaeec1c7f2f8fdcd5f964e8907ad788fe8a5a32c4426fbbdda621223b7", size = 448582, upload-time = "2026-03-10T21:30:57.142Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/2c/23/f6c6112a04d28eed765e374435fb1a9198f73e1ec4b4024184f21faeb1ad/tornado-6.5.5-cp39-abi3-win_amd64.whl", hash = "sha256:6443a794ba961a9f619b1ae926a2e900ac20c34483eea67be4ed8f1e58d3ef7b", size = 448990, upload-time = "2026-03-10T21:30:58.857Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b7/c8/876602cbc96469911f0939f703453c1157b0c826ecb05bdd32e023397d4e/tornado-6.5.5-cp39-abi3-win_arm64.whl", hash = "sha256:2c9a876e094109333f888539ddb2de4361743e5d21eece20688e3e351e4990a6", size = 448016, upload-time = "2026-03-10T21:31:00.43Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2769,14 +2767,14 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "werkzeug"
|
||||
version = "3.1.5"
|
||||
version = "3.1.6"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "markupsafe" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/5a/70/1469ef1d3542ae7c2c7b72bd5e3a4e6ee69d7978fa8a3af05a38eca5becf/werkzeug-3.1.5.tar.gz", hash = "sha256:6a548b0e88955dd07ccb25539d7d0cc97417ee9e179677d22c7041c8f078ce67", size = 864754, upload-time = "2026-01-08T17:49:23.247Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/61/f1/ee81806690a87dab5f5653c1f146c92bc066d7f4cebc603ef88eb9e13957/werkzeug-3.1.6.tar.gz", hash = "sha256:210c6bede5a420a913956b4791a7f4d6843a43b6fcee4dfa08a65e93007d0d25", size = 864736, upload-time = "2026-02-19T15:17:18.884Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/ad/e4/8d97cca767bcc1be76d16fb76951608305561c6e056811587f36cb1316a8/werkzeug-3.1.5-py3-none-any.whl", hash = "sha256:5111e36e91086ece91f93268bb39b4a35c1e6f1feac762c9c822ded0a4e322dc", size = 225025, upload-time = "2026-01-08T17:49:21.859Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/4d/ec/d58832f89ede95652fd01f4f24236af7d32b70cab2196dfcc2d2fd13c5c2/werkzeug-3.1.6-py3-none-any.whl", hash = "sha256:7ddf3357bb9564e407607f988f683d72038551200c704012bb9a4c523d42f131", size = 225166, upload-time = "2026-02-19T15:17:17.475Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
||||
Reference in New Issue
Block a user