Compare commits
4
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8f10c40943 | ||
|
|
3f01c91e3e | ||
|
|
ba5005fc44 | ||
|
|
2329770acd |
@@ -1,79 +0,0 @@
|
|||||||
# Feature Spec: [FEAT-XXX] - Short Descriptive Title
|
|
||||||
|
|
||||||
**Milestone:** [e.g. MVP Core / Performance & Polish / Extension Framework]
|
|
||||||
**Priority:** Must-have / Should-have / Nice-to-have
|
|
||||||
**Spec Owner:** [Your Name / AI Agent Name]
|
|
||||||
**Status:** Draft → Under Review → Approved → Implemented → Verified
|
|
||||||
|
|
||||||
## 1. Purpose & User Story
|
|
||||||
|
|
||||||
As a [user type], I want [goal] so that [benefit].
|
|
||||||
|
|
||||||
_(One clear sentence. Keep it concise.)_
|
|
||||||
|
|
||||||
## 2. Functional Requirements
|
|
||||||
|
|
||||||
- [ ] REQ-1: [Clear, testable description]
|
|
||||||
- [ ] REQ-2: ...
|
|
||||||
- [ ] REQ-3: ...
|
|
||||||
|
|
||||||
_(List what the feature must do. Make each item verifiable.)_
|
|
||||||
|
|
||||||
## 3. Non-Functional Requirements
|
|
||||||
|
|
||||||
- **Performance:** [e.g. Latency < 800ms at p95, max 5k tokens, etc.]
|
|
||||||
- **Security / Safety:** [e.g. Input validation, no raw errors to user, etc.]
|
|
||||||
- **Compatibility:** [e.g. Works with all existing wallet backends, no breaking changes for extensions]
|
|
||||||
- **UI/UX:** [e.g. Follows existing Quasar/Vue patterns in wallet.js]
|
|
||||||
- **Other:** [cost, scalability, accessibility, etc.]
|
|
||||||
|
|
||||||
## 4. Technical Approach (Optional – recommended for complex features)
|
|
||||||
|
|
||||||
- Proposed solution: [e.g. Extend existing CRUD in lnbits/core/, new extension, middleware change, etc.]
|
|
||||||
- Key files to modify: [list expected files]
|
|
||||||
- New dependencies: [none / specific package + version]
|
|
||||||
- Migration / Database changes: [yes/no + description]
|
|
||||||
|
|
||||||
## 5. Success Criteria & Verification
|
|
||||||
|
|
||||||
**Must pass all of these to be accepted:**
|
|
||||||
|
|
||||||
- [ ] All functional requirements (REQ-\*) implemented and tested
|
|
||||||
- [ ] Non-functional requirements met (performance, security, etc.)
|
|
||||||
- [ ] Relevant tests pass: `make test-unit`, `make test-api`, `make test-regtest` (as applicable)
|
|
||||||
- [ ] `make check` passes (ruff, mypy, pyright, prettier, checkbundle)
|
|
||||||
- [ ] Constitution compliance: All changes respect CONSTITUTION.md
|
|
||||||
- [ ] Backward compatibility: No breakage for existing extensions or wallet backends
|
|
||||||
- [ ] Documentation updated (if applicable: README, OpenAPI, inline comments)
|
|
||||||
|
|
||||||
**Additional Tests / Edge Cases:**
|
|
||||||
|
|
||||||
- [ ] Test invalid inputs / error paths
|
|
||||||
- [ ] Test with FakeWallet and at least one real backend
|
|
||||||
- [ ] Test with multiple extensions installed
|
|
||||||
|
|
||||||
## 6. Safety & Risk Assessment
|
|
||||||
|
|
||||||
- Potential risks: [e.g. Payment flow impact, key exposure, extension conflicts]
|
|
||||||
- Mitigation: [how addressed]
|
|
||||||
- Security review needed: [yes/no]
|
|
||||||
|
|
||||||
## 7. Implementation Notes (for AI / Developer)
|
|
||||||
|
|
||||||
- Style to match: Existing code patterns in `lnbits/core/` and `wallet.js`
|
|
||||||
- Surgical changes only (per AGENTS.md)
|
|
||||||
- Any known gotchas or dependencies on other features:
|
|
||||||
|
|
||||||
## 8. Acceptance Checklist (Sign-off)
|
|
||||||
|
|
||||||
- [ ] Spec reviewed and approved by project owner
|
|
||||||
- [ ] Implementation completed
|
|
||||||
- [ ] Verification steps passed
|
|
||||||
- [ ] PR created with link to this spec
|
|
||||||
- [ ] Constitution & AGENTS.md compliance confirmed
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**Created:** [Date]
|
|
||||||
**Last Updated:** [Date]
|
|
||||||
**Approved By:** [Name / "Approved"]
|
|
||||||
@@ -1,122 +0,0 @@
|
|||||||
# AGENTS.md - Instructions for All AI Coding Agents
|
|
||||||
|
|
||||||
This file is the **master instruction manual** for any AI agent (Grok, Claude, Cursor, Aider, etc.) working on LNbits.
|
|
||||||
|
|
||||||
## 1. Core Rule (Never Break This)
|
|
||||||
|
|
||||||
**You MUST read and strictly follow `CONSTITUTION.md` before doing any planning, coding, refactoring, or suggesting changes.**
|
|
||||||
|
|
||||||
- Every single change, feature, extension, or fix **must comply** with the Constitution.
|
|
||||||
- If you detect a violation (in new code or existing code), you **must** flag it immediately and propose a fix or ask for clarification.
|
|
||||||
- Constitution > any other instruction (including this file, user prompts, or previous conversations).
|
|
||||||
|
|
||||||
## 2. Mandatory Development Workflow
|
|
||||||
|
|
||||||
For **any non-trivial task** (new feature, bug fix, refactor, extension change):
|
|
||||||
|
|
||||||
1. **Constitution Check** – Re-read relevant sections of `CONSTITUTION.md`
|
|
||||||
2. **Feature Spec Check** – If a spec exists in `.specify/`, follow it exactly. If none exists, ask the user for clarification or propose a minimal spec.
|
|
||||||
3. **Think Step-by-Step** – Follow the "Think Before Coding" and "Simplicity First" guidelines below.
|
|
||||||
4. **Surgical Changes** – Only touch what is necessary.
|
|
||||||
5. **Implement**
|
|
||||||
6. **Verify** – Run relevant tests (`make test-unit`, `make test-api`, etc.), `make check`, and confirm compliance.
|
|
||||||
7. **Report** – Always include a clear summary.
|
|
||||||
|
|
||||||
Use the following response format:
|
|
||||||
|
|
||||||
```markdown
|
|
||||||
## Constitution & Spec Compliance
|
|
||||||
|
|
||||||
- Relevant Constitution sections checked: [list or quote key rules]
|
|
||||||
- Feature Spec followed: [yes / no / proposed]
|
|
||||||
|
|
||||||
## Assumptions & Plan
|
|
||||||
|
|
||||||
- Assumptions: ...
|
|
||||||
- Plan:
|
|
||||||
1. ...
|
|
||||||
2. ...
|
|
||||||
- Tradeoffs considered: ...
|
|
||||||
|
|
||||||
## Changes Made
|
|
||||||
|
|
||||||
- Files changed: ...
|
|
||||||
- Summary of modifications:
|
|
||||||
|
|
||||||
## Verification
|
|
||||||
|
|
||||||
- [ ] Passes `make check`
|
|
||||||
- [ ] Relevant tests pass (`make test-xxx`)
|
|
||||||
- [ ] Complies with Constitution
|
|
||||||
- [ ] Surgical & minimal (no unrelated changes)
|
|
||||||
```
|
|
||||||
|
|
||||||
## 3. Behavioral Guidelines (Merged & Project-Specific)
|
|
||||||
|
|
||||||
**Think Before Coding**
|
|
||||||
|
|
||||||
- Don't assume. Don't hide confusion. Surface tradeoffs.
|
|
||||||
- State assumptions explicitly. If uncertain, ask.
|
|
||||||
- If multiple interpretations exist, present them — don't pick silently.
|
|
||||||
- If something is unclear (especially regarding wallets, extensions, or funding sources), stop and ask.
|
|
||||||
|
|
||||||
**Simplicity First**
|
|
||||||
|
|
||||||
- Minimum code that solves the problem. Nothing speculative.
|
|
||||||
- No features beyond what was asked.
|
|
||||||
- No abstractions for single-use code.
|
|
||||||
- Respect LNbits' lean core philosophy: new functionality should preferably go into an **extension** unless it truly belongs in core.
|
|
||||||
|
|
||||||
**Surgical Changes**
|
|
||||||
|
|
||||||
- Touch only what you must. Clean up only your own mess.
|
|
||||||
- Match existing style (Python: Black + Ruff rules; JS: Prettier).
|
|
||||||
- Do not "improve" or refactor adjacent code unless explicitly asked.
|
|
||||||
- When editing, remove only imports/variables/functions made unused **by your changes**.
|
|
||||||
- Never delete pre-existing dead code unless instructed.
|
|
||||||
|
|
||||||
**Goal-Driven Execution**
|
|
||||||
|
|
||||||
- Transform tasks into verifiable goals.
|
|
||||||
- For tests: Write or update tests first when fixing bugs or adding behavior.
|
|
||||||
- Always consider impact on existing extensions and multiple wallet backends (LND, CLN, Boltz, VoidWallet, etc.).
|
|
||||||
|
|
||||||
## 4. LNbits-Specific Rules
|
|
||||||
|
|
||||||
- **Extensions First**: Core should remain lean. Prefer implementing new features as extensions unless they are fundamental to wallets, security, or the API.
|
|
||||||
- **Testing**: Use `FakeWallet` for unit/API tests. Regtest tests for full Lightning flows. Never break existing test targets in the Makefile.
|
|
||||||
- **Dependencies**: Never add new dependencies without updating `pyproject.toml` and getting approval.
|
|
||||||
- **Frontend**: JS/Vue code (e.g. `wallet.js`) must follow existing patterns and pass `make checkbundle` when static files are affected.
|
|
||||||
- **Database / Migrations**: Do not make raw SQL changes. Use existing CRUD/services and migration tooling.
|
|
||||||
- **Security**: Be extremely cautious with anything touching payments, keys, LNURL, Bolt11, or admin routes.
|
|
||||||
- **Tools**: Use `uv run` for all commands. Prefer Makefile targets (`make format`, `make check`, `make test-xxx`).
|
|
||||||
- **Generated Files**: Never modify gRPC files or other generated code.
|
|
||||||
|
|
||||||
## 5. Forbidden Behaviors
|
|
||||||
|
|
||||||
- Ignoring Constitution rules to "be helpful"
|
|
||||||
- Large refactors without a spec or explicit request
|
|
||||||
- Adding features "for future use"
|
|
||||||
- Breaking backward compatibility for extensions or existing wallet backends
|
|
||||||
- Committing code that fails `make check` or relevant tests
|
|
||||||
- Exposing raw errors/stack traces to users
|
|
||||||
- Using synchronous code in hot async paths without justification
|
|
||||||
|
|
||||||
## 6. How to Handle This File + Constitution
|
|
||||||
|
|
||||||
When the user gives you a task, start your response with:
|
|
||||||
|
|
||||||
> Following LNbits CONSTITUTION.md and AGENTS.md...
|
|
||||||
|
|
||||||
Then proceed with the structured format above.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**These guidelines are working if:**
|
|
||||||
|
|
||||||
- Fewer unnecessary changes appear in diffs
|
|
||||||
- Clarifying questions come **before** implementation
|
|
||||||
- All changes respect the lean, extension-first, security-first nature of LNbits
|
|
||||||
- Tests and `make check` continue to pass
|
|
||||||
|
|
||||||
Last Updated: April 2026
|
|
||||||
-136
@@ -1,136 +0,0 @@
|
|||||||
# CONSTITUTION.md
|
|
||||||
|
|
||||||
This is the immutable constitution of the LNbits project.
|
|
||||||
Every feature spec, code change, refactor, extension, or decision by humans or AI agents **must comply** with this document.
|
|
||||||
Changes to this file require explicit approval from the project owner/maintainers.
|
|
||||||
|
|
||||||
## 1. Project Overview
|
|
||||||
|
|
||||||
**Project Name:** LNbits
|
|
||||||
**Core Purpose:** Free and open-source Lightning wallet and accounts system. A lightweight Python server that sits on top of any Lightning funding source, providing safe isolated wallets, a clean REST API, and a powerful extension system for adding features rapidly.
|
|
||||||
**Target Users:** Individuals, communities, merchants, developers, and enterprises building on Bitcoin/Lightning (self-hosted or as part of larger stacks).
|
|
||||||
**High-Level Success Criteria:**
|
|
||||||
|
|
||||||
- Reliable multi-wallet Lightning accounting with any backend (20+ supported funding sources)
|
|
||||||
- Secure, extensible via 60+ extensions without bloating core
|
|
||||||
- High code quality, test coverage, and backward compatibility for extensions
|
|
||||||
- Production-ready performance and security for real Bitcoin value
|
|
||||||
|
|
||||||
**Version:** 1.5.4
|
|
||||||
|
|
||||||
## 2. Technology Stack (Strict)
|
|
||||||
|
|
||||||
- **Language:** Python >=3.10, <3.13 (strictly enforced via `pyproject.toml`)
|
|
||||||
- **Framework:** FastAPI + Starlette (backend API)
|
|
||||||
- **Frontend:** Vue.js + Quasar framework, with bundled static assets
|
|
||||||
- **Database:** SQLite (aiosqlite) by default, PostgreSQL (asyncpg/psycopg2) supported via `LNBITS_DATABASE_URL`
|
|
||||||
- **Async Runtime:** uvloop preferred
|
|
||||||
- **Dependency Management:** uv + pyproject.toml (Hatchling build backend). Use `uv run` for all commands.
|
|
||||||
- **Wallet Backends:** Abstracted via `lnbits.wallets` – support for LND, Core Lightning, Phoenixd, Boltz, Breez SDK, Liquid, VoidWallet fallback, etc. New backends must follow existing abstraction.
|
|
||||||
- **Other Key Libs:** SQLAlchemy, Pydantic (v1), Loguru, Jinja2, LNURL, Bolt11, etc. (see `pyproject.toml` for pinned versions)
|
|
||||||
- **Build/Frontend Tools:** npm for bundling (Quasar/Vue), Prettier for JS/CSS (check Makefile targets)
|
|
||||||
|
|
||||||
**Forbidden:**
|
|
||||||
|
|
||||||
- Adding new top-level dependencies without updating `pyproject.toml` **and** team approval
|
|
||||||
- Using synchronous blocking calls in async paths (except where explicitly justified)
|
|
||||||
- Direct database queries outside of CRUD layers or core services
|
|
||||||
- Modifying generated files (e.g., gRPC files in wallets/boltz_grpc_files or lnd_grpc_files)
|
|
||||||
|
|
||||||
## 3. Architecture & Code Organization (Mandatory Rules)
|
|
||||||
|
|
||||||
- **Core Principle:** Modular monolith with heavy emphasis on **extensions**. All non-core features must live in extensions (installed via `lnbits/extensions`). Core stays lean.
|
|
||||||
- **Backend Structure:**
|
|
||||||
- `lnbits/core/` for core models, CRUD, services, routers, tasks
|
|
||||||
- `lnbits/wallets/` for funding source abstractions
|
|
||||||
- `lnbits/extensions/` for installed/upgradeable extensions (do not commit large extensions to core repo)
|
|
||||||
- `lnbits/static/` for bundled frontend assets (managed via npm bundle)
|
|
||||||
- **Key Rules:**
|
|
||||||
- Use dependency injection and FastAPI routers properly
|
|
||||||
- Extensions register routes/tasks via `register_ext_routes` / `register_ext_tasks`
|
|
||||||
- Database migrations handled centrally (extension-specific migrations)
|
|
||||||
- All new endpoints must be under proper versioning/prefixing where applicable
|
|
||||||
- Frontend: Vue 2/Quasar components in `wallet.js` style (or updated) – keep reactive, use LNbits.utils helpers
|
|
||||||
- No circular imports; respect existing middleware order (e.g., InstalledExtensionMiddleware before ExtensionsRedirectMiddleware)
|
|
||||||
|
|
||||||
**Exclusions** (do not lint/format these):
|
|
||||||
|
|
||||||
- `lnbits/extensions/`, `lnbits/upgrades/`, generated gRPC files, static/vendor bundles
|
|
||||||
|
|
||||||
## 4. Code Quality & Style
|
|
||||||
|
|
||||||
- **Formatting & Linting:**
|
|
||||||
- Python: Black (line-length 88), Ruff (with selected rules: F, E, W, I, A, C, N, UP, RUF, B, S), MyPy (strict where possible), Pyright
|
|
||||||
- JS/Frontend: Prettier
|
|
||||||
- Run via Makefile: `make format` and `make check`
|
|
||||||
- **Type Checking:** MyPy + Pyright enforced on `lnbits/`, `tests/`, `tools/`
|
|
||||||
- **Testing Requirements:**
|
|
||||||
- Unit, API, wallet, and regtest tests via pytest (see Makefile targets)
|
|
||||||
- New core code or critical paths: high coverage expected (`--cov=lnbits`)
|
|
||||||
- Extensions should include their own tests where possible
|
|
||||||
- **Error Handling & Logging:** Use Loguru with structured context. Never expose raw stack traces to end users. Graceful fallbacks (e.g., VoidWallet on funding source failure).
|
|
||||||
- **Pre-commit:** Strongly recommended (`make install-pre-commit-hook`)
|
|
||||||
- **Bundle Integrity:** Frontend bundles must pass `make checkbundle` before commits affecting static files.
|
|
||||||
|
|
||||||
## 5. AI / LLM Usage Standards (if any agents or future AI features are added)
|
|
||||||
|
|
||||||
- Any new AI-powered features (e.g., via extensions) must use structured outputs (Pydantic/JSON mode)
|
|
||||||
- Store prompts/templates versioned in the extension
|
|
||||||
- Prefer deterministic behavior for financial/security paths (low temperature)
|
|
||||||
- All AI outputs involving value/money must be validated server-side
|
|
||||||
- Safety: Never allow untrusted model output to influence payments, wallet balances, or admin actions without guardrails
|
|
||||||
|
|
||||||
## 6. Safety, Security & Ethics
|
|
||||||
|
|
||||||
- **Critical:** Handle real Bitcoin/Lightning value → security-first mindset
|
|
||||||
- Per-wallet isolation with separate admin/invoice/read keys
|
|
||||||
- Rate limiting (SlowAPI) and IP blocking middleware mandatory
|
|
||||||
- Sanitize all user inputs; validate LNURL, Bolt11, etc.
|
|
||||||
- PII: Minimal collection; respect privacy (no unnecessary logging of sensitive data)
|
|
||||||
- Funding source failures: Graceful degradation to VoidWallet + clear logging
|
|
||||||
- Extensions: Hash-verified installs for vetted extensions; careful with custom extension paths
|
|
||||||
- Audit logging via AuditMiddleware
|
|
||||||
- Forbidden: Hard-coded secrets, insecure subprocess calls without review, SQL injection risks (use SQLAlchemy properly)
|
|
||||||
|
|
||||||
## 7. Performance & Cost Budgets
|
|
||||||
|
|
||||||
- Keep core lightweight – extensions handle heavy features
|
|
||||||
- Async-first (uvloop, asyncpg/aiosqlite)
|
|
||||||
- Reasonable retry logic for funding source connections (see `check_funding_source`)
|
|
||||||
- Frontend: Optimized bundles (checkbundle enforced)
|
|
||||||
- No unnecessary blocking operations in request paths
|
|
||||||
|
|
||||||
## 8. Development Workflow (Spec-Driven where possible)
|
|
||||||
|
|
||||||
- **All significant changes** should follow Spec-Driven Development:
|
|
||||||
- Create/update Feature Spec in `.specify/` folder (or equivalent)
|
|
||||||
- Reference this Constitution in every spec and PR
|
|
||||||
- Use Makefile targets for format/check/test
|
|
||||||
- Tests run with `FakeWallet` by default for unit/API; regtest for full flows
|
|
||||||
- PRs must:
|
|
||||||
- Pass `make check` and relevant tests
|
|
||||||
- Include Constitution compliance notes (via AGENTS.md/CLAUDE.md)
|
|
||||||
- Not break existing extensions or wallet backends
|
|
||||||
- Branching: Protect main; use feature branches
|
|
||||||
- Extensions: Develop separately; core repo focuses on framework stability
|
|
||||||
|
|
||||||
## 9. Decision Hierarchy (What Takes Precedence)
|
|
||||||
|
|
||||||
1. This Constitution
|
|
||||||
2. Approved Feature Spec / Milestone
|
|
||||||
3. Existing tests and backward compatibility (especially for extensions and wallet backends)
|
|
||||||
4. Project maintainers / owner decision
|
|
||||||
5. Everything else (including helpful AI suggestions)
|
|
||||||
|
|
||||||
If conflict: Stop, document the issue, and seek clarification from maintainers.
|
|
||||||
|
|
||||||
## 10. Amendment Process
|
|
||||||
|
|
||||||
- This Constitution can only be changed with explicit approval from project maintainers.
|
|
||||||
- All changes must be dated, versioned, and reflected in `AGENTS.md`.
|
|
||||||
- Minor clarifications can be proposed via PR with justification.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**Last Updated:** April 2026 (based on v1.5.4)
|
|
||||||
**Owner/Maintainers Approval:** LNbits Team
|
|
||||||
@@ -5,7 +5,7 @@
|
|||||||
</picture>
|
</picture>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
 [![license-badge]](LICENSE) [![docs-badge]][docs]  [](https://extensions.lnbits.com/) [](https://shop.lnbits.com/) [<img src="https://img.shields.io/badge/community_chat-Telegram-24A1DE">](https://t.me/lnbits)
|
 [![license-badge]](LICENSE) [![docs-badge]][docs]  [](https://extensions.lnbits.com/) [](https://shop.lnbits.com/) [<img src="https://img.shields.io/badge/community_chat-Telegram-24A1DE">](https://t.me/lnbits) [<img src="https://img.shields.io/badge/supported_by-%3E__OpenSats-f97316">](https://opensats.org)
|
||||||
<img alt="lnbits_head" src="docs/assets/header.jpg" />
|
<img alt="lnbits_head" src="docs/assets/header.jpg" />
|
||||||
[](https://demo.lnbits.com/tipjar/DwaUiE4kBX6mUW6pj3X5Kg)
|
[](https://demo.lnbits.com/tipjar/DwaUiE4kBX6mUW6pj3X5Kg)
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ nav_order: 1
|
|||||||

|

|
||||||

|

|
||||||
[<img src="https://img.shields.io/badge/community_chat-Telegram-24A1DE">](https://t.me/lnbits)
|
[<img src="https://img.shields.io/badge/community_chat-Telegram-24A1DE">](https://t.me/lnbits)
|
||||||
|
[<img src="https://img.shields.io/badge/supported_by-%3E__OpenSats-f97316">](https://opensats.org)
|
||||||
|
|
||||||
# LNBits Admin UI
|
# LNBits Admin UI
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ nav_order: 1
|
|||||||

|

|
||||||

|

|
||||||
[<img src="https://img.shields.io/badge/community_chat-Telegram-24A1DE">](https://t.me/lnbits)
|
[<img src="https://img.shields.io/badge/community_chat-Telegram-24A1DE">](https://t.me/lnbits)
|
||||||
|
[<img src="https://img.shields.io/badge/supported_by-%3E__OpenSats-f97316">](https://opensats.org)
|
||||||
|
|
||||||
# Backend Wallet Comparison Table
|
# Backend Wallet Comparison Table
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ nav_order: 1
|
|||||||
</picture>
|
</picture>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
   [](https://extensions.lnbits.com/) [<img src="https://img.shields.io/badge/community_chat-Telegram-24A1DE">](https://t.me/lnbits)
|
   [](https://extensions.lnbits.com/) [<img src="https://img.shields.io/badge/community_chat-Telegram-24A1DE">](https://t.me/lnbits) <img src="https://img.shields.io/badge/supported_by-%3E__OpenSats-f97316">
|
||||||
|
|
||||||
# Basic installation
|
# Basic installation
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ nav_order: 1
|
|||||||

|

|
||||||

|

|
||||||
[<img src="https://img.shields.io/badge/community_chat-Telegram-24A1DE">](https://t.me/lnbits)
|
[<img src="https://img.shields.io/badge/community_chat-Telegram-24A1DE">](https://t.me/lnbits)
|
||||||
|
[<img src="https://img.shields.io/badge/supported_by-%3E__OpenSats-f97316">](https://opensats.org)
|
||||||
|
|
||||||
# LNbits Super User (SU)
|
# LNbits Super User (SU)
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ nav_order: 1
|
|||||||

|

|
||||||

|

|
||||||
[<img src="https://img.shields.io/badge/community_chat-Telegram-24A1DE">](https://t.me/lnbits)
|
[<img src="https://img.shields.io/badge/community_chat-Telegram-24A1DE">](https://t.me/lnbits)
|
||||||
|
[<img src="https://img.shields.io/badge/supported_by-%3E__OpenSats-f97316">](https://opensats.org)
|
||||||
|
|
||||||
# LNbits Roles: A Quick Overview
|
# LNbits Roles: A Quick Overview
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ nav_order: 3
|
|||||||

|

|
||||||

|

|
||||||
[<img src="https://img.shields.io/badge/community_chat-Telegram-24A1DE">](https://t.me/lnbits)
|
[<img src="https://img.shields.io/badge/community_chat-Telegram-24A1DE">](https://t.me/lnbits)
|
||||||
|
[<img src="https://img.shields.io/badge/supported_by-%3E__OpenSats-f97316">](https://opensats.org)
|
||||||
|
|
||||||
# Backend wallets
|
# Backend wallets
|
||||||
|
|
||||||
|
|||||||
+2
-4
@@ -35,7 +35,7 @@ if settings.lnbits_database_url:
|
|||||||
else:
|
else:
|
||||||
if not database_uri.startswith("postgres://"):
|
if not database_uri.startswith("postgres://"):
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
"Please use the 'postgres://...' format for the database URL."
|
"Please use the 'postgres://...' " "format for the database URL."
|
||||||
)
|
)
|
||||||
DB_TYPE = POSTGRES
|
DB_TYPE = POSTGRES
|
||||||
|
|
||||||
@@ -560,9 +560,7 @@ class Filters(BaseModel, Generic[TFilterModel]):
|
|||||||
|
|
||||||
def pagination(self) -> str:
|
def pagination(self) -> str:
|
||||||
stmt = ""
|
stmt = ""
|
||||||
if self.limit == 0:
|
self.limit = self.limit or 10
|
||||||
self.limit = 1000
|
|
||||||
self.limit = 10 if self.limit is None else self.limit
|
|
||||||
stmt += f"LIMIT {min(1000, self.limit)} "
|
stmt += f"LIMIT {min(1000, self.limit)} "
|
||||||
if self.offset:
|
if self.offset:
|
||||||
stmt += f"OFFSET {self.offset}"
|
stmt += f"OFFSET {self.offset}"
|
||||||
|
|||||||
+1
-1
@@ -284,7 +284,7 @@ class ThemesSettings(LNbitsSettings):
|
|||||||
lnbits_custom_image: str | None = Field(default="/static/images/logos/lnbits.svg")
|
lnbits_custom_image: str | None = Field(default="/static/images/logos/lnbits.svg")
|
||||||
lnbits_ad_space_title: str = Field(default="Supported by")
|
lnbits_ad_space_title: str = Field(default="Supported by")
|
||||||
lnbits_ad_space: str = Field(
|
lnbits_ad_space: str = Field(
|
||||||
default="https://shop.lnbits.com/;/static/images/bitcoin-shop-banner.png;/static/images/bitcoin-shop-banner.png,https://affil.trezor.io/aff_c?offer_id=169&aff_id=33845;/static/images/bitcoin-hardware-wallet.png;/static/images/bitcoin-hardware-wallet.png,https://firefish.io/?ref=lnbits;/static/images/firefish.png;/static/images/firefish.png"
|
default="https://shop.lnbits.com/;/static/images/bitcoin-shop-banner.png;/static/images/bitcoin-shop-banner.png,https://affil.trezor.io/aff_c?offer_id=169&aff_id=33845;/static/images/bitcoin-hardware-wallet.png;/static/images/bitcoin-hardware-wallet.png,https://firefish.io/?ref=lnbits;/static/images/firefish.png;/static/images/firefish.png,https://opensats.org/;/static/images/open-sats.png;/static/images/open-sats.png"
|
||||||
) # sneaky sneaky
|
) # sneaky sneaky
|
||||||
lnbits_ad_space_enabled: bool = Field(default=False)
|
lnbits_ad_space_enabled: bool = Field(default=False)
|
||||||
lnbits_allowed_currencies: list[str] = Field(default=[])
|
lnbits_allowed_currencies: list[str] = Field(default=[])
|
||||||
|
|||||||
+1
-1
File diff suppressed because one or more lines are too long
Binary file not shown.
|
After Width: | Height: | Size: 16 KiB |
@@ -21,10 +21,7 @@ window.app.component('lnbits-qrcode-lnurl', {
|
|||||||
if (this.tab == 'bech32') {
|
if (this.tab == 'bech32') {
|
||||||
const bytes = new TextEncoder().encode(this.url)
|
const bytes = new TextEncoder().encode(this.url)
|
||||||
const bech32 = NostrTools.nip19.encodeBytes('lnurl', bytes)
|
const bech32 = NostrTools.nip19.encodeBytes('lnurl', bytes)
|
||||||
this.lnurl =
|
this.lnurl = `lightning:${bech32.toUpperCase()}`
|
||||||
this.prefix == 'lnurlw'
|
|
||||||
? `${new URL(this.url).origin}/?lightning=${bech32.toUpperCase()}`
|
|
||||||
: `lightning:${bech32.toUpperCase()}`
|
|
||||||
} else if (this.tab == 'lud17') {
|
} else if (this.tab == 'lud17') {
|
||||||
if (this.url.startsWith('http://')) {
|
if (this.url.startsWith('http://')) {
|
||||||
this.lnurl = this.url.replace('http://', this.prefix + '://')
|
this.lnurl = this.url.replace('http://', this.prefix + '://')
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ window.PageHome = {
|
|||||||
return (
|
return (
|
||||||
this.lnurl !== '' &&
|
this.lnurl !== '' &&
|
||||||
this.g.settings.allowRegister &&
|
this.g.settings.allowRegister &&
|
||||||
this.g.settings.authMethods.includes('user-id-only')
|
'user-id-only' in this.g.settings.authMethods
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
formatDescription() {
|
formatDescription() {
|
||||||
|
|||||||
@@ -1,32 +1,7 @@
|
|||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from lnbits.db import Filters
|
|
||||||
from tests.helpers import DbTestModel
|
from tests.helpers import DbTestModel
|
||||||
|
|
||||||
TEST_DB_FETCH_PAGE_ROWS: tuple[dict[str, str], ...] = (
|
|
||||||
{"id": "1", "name": "Alice", "value": "foo"},
|
|
||||||
{"id": "2", "name": "Bob", "value": "bar"},
|
|
||||||
{"id": "3", "name": "Carol", "value": "bar"},
|
|
||||||
{"id": "4", "name": "Dave", "value": "bar"},
|
|
||||||
{"id": "5", "name": "Dave", "value": "foo"},
|
|
||||||
{"id": "6", "name": "Eve", "value": "foo"},
|
|
||||||
{"id": "7", "name": "Frank", "value": "bar"},
|
|
||||||
{"id": "8", "name": "Grace", "value": "foo"},
|
|
||||||
{"id": "9", "name": "Heidi", "value": "bar"},
|
|
||||||
{"id": "10", "name": "Ivan", "value": "foo"},
|
|
||||||
{"id": "11", "name": "Judy", "value": "bar"},
|
|
||||||
{"id": "12", "name": "Mallory", "value": "foo"},
|
|
||||||
{"id": "13", "name": "Niaj", "value": "bar"},
|
|
||||||
{"id": "14", "name": "Olivia", "value": "foo"},
|
|
||||||
{"id": "15", "name": "Peggy", "value": "bar"},
|
|
||||||
{"id": "16", "name": "Rupert", "value": "foo"},
|
|
||||||
{"id": "17", "name": "Sybil", "value": "bar"},
|
|
||||||
{"id": "18", "name": "Trent", "value": "foo"},
|
|
||||||
{"id": "19", "name": "Victor", "value": "bar"},
|
|
||||||
{"id": "20", "name": "Walter", "value": "foo"},
|
|
||||||
{"id": "21", "name": "Zoe", "value": "bar"},
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope="session")
|
@pytest.fixture(scope="session")
|
||||||
async def fetch_page(db):
|
async def fetch_page(db):
|
||||||
@@ -38,14 +13,14 @@ async def fetch_page(db):
|
|||||||
name TEXT NOT NULL
|
name TEXT NOT NULL
|
||||||
)
|
)
|
||||||
""")
|
""")
|
||||||
for row in TEST_DB_FETCH_PAGE_ROWS:
|
await db.execute("""
|
||||||
await db.execute(
|
INSERT INTO test_db_fetch_page (id, name, value) VALUES
|
||||||
"""
|
('1', 'Alice', 'foo'),
|
||||||
INSERT INTO test_db_fetch_page (id, name, value)
|
('2', 'Bob', 'bar'),
|
||||||
VALUES (:id, :name, :value)
|
('3', 'Carol', 'bar'),
|
||||||
""",
|
('4', 'Dave', 'bar'),
|
||||||
row,
|
('5', 'Dave', 'foo')
|
||||||
)
|
""")
|
||||||
yield
|
yield
|
||||||
await db.execute("DROP TABLE test_db_fetch_page")
|
await db.execute("DROP TABLE test_db_fetch_page")
|
||||||
|
|
||||||
@@ -58,35 +33,8 @@ async def test_db_fetch_page_simple(fetch_page, db):
|
|||||||
)
|
)
|
||||||
|
|
||||||
assert row
|
assert row
|
||||||
assert row.total == len(TEST_DB_FETCH_PAGE_ROWS)
|
assert row.total == 5
|
||||||
assert len(row.data) == Filters().limit
|
assert len(row.data) == 5
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.anyio
|
|
||||||
async def test_db_fetch_page_limit_zero_returns_all(fetch_page, db):
|
|
||||||
row = await db.fetch_page(
|
|
||||||
query="select * from test_db_fetch_page",
|
|
||||||
filters=Filters(limit=0),
|
|
||||||
model=DbTestModel,
|
|
||||||
)
|
|
||||||
|
|
||||||
assert row
|
|
||||||
assert row.total == len(TEST_DB_FETCH_PAGE_ROWS)
|
|
||||||
assert len(row.data) == len(TEST_DB_FETCH_PAGE_ROWS)
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.anyio
|
|
||||||
async def test_db_fetch_page_limit(fetch_page, db):
|
|
||||||
limit = 5
|
|
||||||
row = await db.fetch_page(
|
|
||||||
query="select * from test_db_fetch_page",
|
|
||||||
filters=Filters(limit=limit),
|
|
||||||
model=DbTestModel,
|
|
||||||
)
|
|
||||||
|
|
||||||
assert row
|
|
||||||
assert row.total == len(TEST_DB_FETCH_PAGE_ROWS)
|
|
||||||
assert len(row.data) == limit
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.anyio
|
@pytest.mark.anyio
|
||||||
@@ -97,7 +45,7 @@ async def test_db_fetch_page_group_by(fetch_page, db):
|
|||||||
group_by=["name"],
|
group_by=["name"],
|
||||||
)
|
)
|
||||||
assert row
|
assert row
|
||||||
assert row.total == len({test_row["name"] for test_row in TEST_DB_FETCH_PAGE_ROWS})
|
assert row.total == 4
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.anyio
|
@pytest.mark.anyio
|
||||||
@@ -108,9 +56,7 @@ async def test_db_fetch_page_group_by_multiple(fetch_page, db):
|
|||||||
group_by=["value", "name"],
|
group_by=["value", "name"],
|
||||||
)
|
)
|
||||||
assert row
|
assert row
|
||||||
assert row.total == len(
|
assert row.total == 5
|
||||||
{(test_row["value"], test_row["name"]) for test_row in TEST_DB_FETCH_PAGE_ROWS}
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.anyio
|
@pytest.mark.anyio
|
||||||
|
|||||||
Reference in New Issue
Block a user