This commit is contained in:
Arc
2026-02-25 22:24:22 +00:00
parent 0fb2334181
commit 2e71830817
8 changed files with 4 additions and 252 deletions
-4
View File
@@ -70,10 +70,6 @@ FORWARDED_ALLOW_IPS="*"
# Inside this directory the `extensions` and `upgrades` sub-directories will be created.
# LNBITS_EXTENSIONS_PATH="/path/to/some/dir"
# === WASM Extensions Sandbox Limits ===
# LNBITS_WASM_TIMEOUT_SECONDS=3.0
# LNBITS_WASM_MAX_MODULE_BYTES=1000000
# LNBITS_WASM_MAX_DB_OPS_PER_MIN=120
# ID of the super user. The user ID must exist.
# SUPER_USER=""
-67
View File
@@ -1,67 +0,0 @@
---
layout: default
parent: For developers
title: Agent Guide - Python Extensions
nav_order: 4
---
# Agent Guide - Python Extensions
This guide is for AI agents or developers using AI to build **traditional (Python) LNbits extensions**. It defines what to change, what not to change, and the expected structure.
## Hard Rules (Non-Negotiable)
- Do **not** change core LNbits files.
- Only edit files inside your extension folder.
- Do **not** add new Python dependencies unless explicitly approved.
## Extension Folder Layout (Python)
Your extension lives under:
```
lnbits/extensions/<ext_id>/
```
Typical files to edit:
- `views.py` (HTML routes)
- `views_api.py` (API routes)
- `crud.py` / `models.py` (storage logic + models)
- `migrations.py` (DB schema)
- `templates/<ext_id>/` (HTML)
- `static/` (JS/CSS/images)
- `config.json`, `manifest.json`, `README.md`
## What You Can Do
Python extensions can:
- Define their own database schema via `migrations.py`
- Run long-running background tasks via `*_start()` and `*_stop()` hooks
- Access LNbits internal services directly in Python
- Expose custom API routes under `/<ext_id>/api/v1/...`
## What You Must Not Do
- Do not modify core services or routes.
- Do not patch LNbits internals for your extension.
- Avoid direct DB access outside your own schema.
## Background Tasks
Implement background tasks by exposing:
```
def <ext_id>_start():
def <ext_id>_stop():
```
Use `register_invoice_listener` or `wait_for_paid_invoices` if you need to react to payments.
## Testing Checklist
- Extension loads without errors.
- Migrations apply cleanly.
- Routes are registered under `/<ext_id>/...`.
- Background tasks start/stop cleanly.
-174
View File
@@ -1,174 +0,0 @@
---
layout: default
parent: For developers
title: Agent Guide - WASM Extensions
nav_order: 3
---
# Agent Guide - WASM Extensions
This guide is written for AI agents or developers using AI to build LNbits WASM extensions. It describes what to change, what not to change, and the available capabilities/limits.
## Hard Rules (Non-Negotiable)
- Do **not** change core LNbits files. Only edit files inside your extension folder.
- Do **not** add new Python dependencies.
- Do **not** rely on long-running WASM processes. WASM runs per-call with timeouts.
## Extension Folder Layout (WASM)
Your extension lives under:
```
lnbits/extensions/<ext_id>/
```
You should only edit files under this folder, typically:
- `config.json` (metadata, permissions, tags, public handlers)
- `wasm/` (your `module.wasm` or `module.wat`)
- `static/` (frontend assets)
- `templates/` (HTML pages)
- `manifest.json`, `README.md`, `description.md` (docs and metadata)
## Required Config Fields
In `config.json`:
- `id` / `name`
- `extension_type: "wasm"`
- `permissions` (required API permissions)
- `public_wasm_functions` (handlers callable from public routes)
- `public_kv_keys` (publicly readable KV keys)
- `payment_tags` (list of tags the user may grant for watcher access)
Example:
```json
{
"id": "myext",
"name": "MyExt",
"extension_type": "wasm",
"permissions": [
{"id": "ext.db.read_write", "label": "DB access", "description": "..."},
{
"id": "api.POST:/api/v1/payments",
"label": "Create invoices",
"description": "..."
},
{
"id": "ext.payments.watch",
"label": "Watch payments",
"description": "..."
},
{
"id": "ext.tasks.schedule",
"label": "Schedule tasks",
"description": "..."
},
{"id": "ext.db.sql", "label": "SQL access", "description": "..."}
],
"public_wasm_functions": [
"public_create_invoice",
"on_tag_payment",
"on_schedule"
],
"public_kv_keys": ["public_lists", "public_tasks"],
"payment_tags": ["coinflip", "myext"]
}
```
## What the WASM Host Can Do
WASM runs in a short-lived subprocess. It can:
- Read/write extension KV (`/api/v1/kv/*`)
- Read/write secret KV (`/api/v1/secret/*`)
- Call internal LNbits endpoints (only if declared + granted)
- Publish websockets (`ws_publish`)
- Run backend tag watchers and scheduled handlers (server-side triggers)
## Permissions Model
Your extension can only call or access what is declared and granted:
- `api.METHOD:/path` for internal endpoints (core or other extensions)
- `ext.db.read_write` for KV access
- `ext.payments.watch` for payment watchers
- `ext.tasks.schedule` for scheduled jobs
- `ext.db.sql` for SQL interface
If the endpoint doesnt exist, permissions wont save.
## Tag Watchers (Backend)
You can register tag watchers:
```
POST /<ext_id>/api/v1/watch_tag
{
"tag": "coinflip",
"wallet_id": "<wallet-id>",
"handler": "on_tag_payment",
"store_key": "tag:coinflip:last_payment"
}
```
Constraints:
- Tag must be in `payment_tags` and granted by the user.
- Watchers are persisted and restored on restart.
## Scheduled Tasks (Backend)
You can schedule periodic handlers:
```
POST /<ext_id>/api/v1/schedule
{
"interval_seconds": 30,
"handler": "on_schedule",
"store_key": "schedule:last_run"
}
```
Constraints:
- Requires `ext.tasks.schedule` permission.
- Minimum interval is 5 seconds.
- Stored in extension KV and restored on restart.
## SQL Interface (Limited)
You can run SQL within your extension schema:
- `/api/v1/sql/query` (SELECT only)
- `/api/v1/sql/exec` (limited DDL/DML)
Rules:
- Single statement only
- No `PRAGMA`, no `sqlite_master`
- No cross-schema access
## Public Pages (No Keys)
Public pages must not depend on `window.g` or wallet keys.
They can call:
- `/{ext_id}/api/v1/public/kv/{key}`
- `/{ext_id}/api/v1/public/call/{handler}`
## What Not To Do
- Do not write to core routes or override existing LNbits paths.
- Do not add background threads; use watchers or scheduler instead.
- Do not assume the WASM process persists.
## Testing Checklist
- Permissions show correctly in the extensions UI.
- Public handlers are in `public_wasm_functions`.
- Public KV keys are explicitly listed.
- Tag watchers only use allowed tags.
- Scheduled handlers run and update KV as expected.
+1 -1
View File
@@ -1 +1 @@
from lnbits.extensions.wasm.wasm_host import * # noqa: F403
from lnbits.extensions.wasm.wasm_host import * # noqa: F401,F403
+1 -1
View File
@@ -1 +1 @@
from lnbits.extensions.wasm.wasm_host.extension_host import * # noqa: F403
from lnbits.extensions.wasm.wasm_host.extension_host import * # noqa: F401,F403
+1 -1
View File
@@ -1 +1 @@
from lnbits.extensions.wasm.wasm_host.runner import * # noqa: F403
from lnbits.extensions.wasm.wasm_host.runner import * # noqa: F401,F403
+1 -1
View File
@@ -1 +1 @@
from lnbits.extensions.wasm.wasm_host.service import * # noqa: F403
from lnbits.extensions.wasm.wasm_host.service import * # noqa: F401,F403
-3
View File
@@ -75,9 +75,6 @@ class ExtensionsSettings(LNbitsSettings):
lnbits_extensions_builder_manifest_url: str = Field(
default="https://raw.githubusercontent.com/lnbits/extension_builder_stub/refs/heads/main/manifest.json"
)
lnbits_wasm_timeout_seconds: float = Field(default=3.0, ge=0.1)
lnbits_wasm_max_module_bytes: int = Field(default=1_000_000, ge=0)
lnbits_wasm_max_db_ops_per_min: int = Field(default=120, ge=0)
@property
def extension_builder_working_dir_path(self) -> Path: