clean
This commit is contained in:
@@ -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=""
|
||||
|
||||
@@ -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.
|
||||
@@ -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 doesn’t exist, permissions won’t 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 @@
|
||||
from lnbits.extensions.wasm.wasm_host import * # noqa: F403
|
||||
from lnbits.extensions.wasm.wasm_host import * # noqa: F401,F403
|
||||
|
||||
@@ -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 @@
|
||||
from lnbits.extensions.wasm.wasm_host.runner import * # noqa: F403
|
||||
from lnbits.extensions.wasm.wasm_host.runner import * # noqa: F401,F403
|
||||
|
||||
@@ -1 +1 @@
|
||||
from lnbits.extensions.wasm.wasm_host.service import * # noqa: F403
|
||||
from lnbits.extensions.wasm.wasm_host.service import * # noqa: F401,F403
|
||||
|
||||
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user