diff --git a/doc/gatekeeper-api.json b/doc/gatekeeper-api.json index 5d5d7f56..8efc97b7 100644 --- a/doc/gatekeeper-api.json +++ b/doc/gatekeeper-api.json @@ -23,16 +23,24 @@ } } }, - "/version": { + "/api/v1/version": { "get": { "summary": "Retrieve the API version", "responses": { "200": { - "description": "The API version string.", + "description": "The API version and commit hash.", "content": { "application/json": { "schema": { - "type": "string" + "type": "object", + "properties": { + "version": { + "type": "string" + }, + "commit": { + "type": "string" + } + } } } } diff --git a/doc/keymaster-api.json b/doc/keymaster-api.json index e44ecd23..1c427101 100644 --- a/doc/keymaster-api.json +++ b/doc/keymaster-api.json @@ -44,6 +44,31 @@ } } }, + "/api/v1/version": { + "get": { + "summary": "Retrieve the API version", + "responses": { + "200": { + "description": "The API version and commit hash.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "version": { + "type": "string" + }, + "commit": { + "type": "string" + } + } + } + } + } + } + } + } + }, "/registries": { "get": { "summary": "List the available registries.", @@ -2073,6 +2098,232 @@ } } }, + "/lightning": { + "post": { + "summary": "Create a Lightning wallet for the current identity.", + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Optional identity name or DID." + } + } + } + } + } + }, + "responses": { + "200": { + "description": "Lightning wallet configuration." + }, + "400": { + "description": "Error creating Lightning wallet." + } + } + }, + "delete": { + "summary": "Remove Lightning wallet from the current identity.", + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Optional identity name or DID." + } + } + } + } + } + }, + "responses": { + "200": { + "description": "Success." + }, + "400": { + "description": "Error removing Lightning wallet." + } + } + } + }, + "/lightning/balance": { + "post": { + "summary": "Get Lightning wallet balance for the current identity.", + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Optional identity name or DID." + } + } + } + } + } + }, + "responses": { + "200": { + "description": "Balance in sats." + }, + "400": { + "description": "Error getting balance." + } + } + } + }, + "/lightning/invoice": { + "post": { + "summary": "Create a Lightning invoice to receive sats.", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "amount", + "memo" + ], + "properties": { + "amount": { + "type": "number", + "description": "Amount in sats." + }, + "memo": { + "type": "string", + "description": "Invoice description." + }, + "id": { + "type": "string", + "description": "Optional identity name or DID." + } + } + } + } + } + }, + "responses": { + "200": { + "description": "Lightning invoice." + }, + "400": { + "description": "Error creating invoice." + } + } + } + }, + "/lightning/pay": { + "post": { + "summary": "Pay a Lightning invoice.", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "bolt11" + ], + "properties": { + "bolt11": { + "type": "string", + "description": "BOLT11 invoice string." + }, + "id": { + "type": "string", + "description": "Optional identity name or DID." + } + } + } + } + } + }, + "responses": { + "200": { + "description": "Payment result." + }, + "400": { + "description": "Error paying invoice." + } + } + } + }, + "/lightning/payment": { + "post": { + "summary": "Check status of a Lightning payment.", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "paymentHash" + ], + "properties": { + "paymentHash": { + "type": "string", + "description": "Payment hash to check." + }, + "id": { + "type": "string", + "description": "Optional identity name or DID." + } + } + } + } + } + }, + "responses": { + "200": { + "description": "Payment status." + }, + "400": { + "description": "Error checking payment." + } + } + } + }, + "/lightning/decode": { + "post": { + "summary": "Decode a Lightning BOLT11 invoice.", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "bolt11": { + "type": "string" + } + } + } + } + } + }, + "responses": { + "200": { + "description": "Decoded invoice details." + }, + "400": { + "description": "Error decoding invoice." + } + } + } + }, "/challenge": { "get": { "summary": "Create a default challenge DID with no parameters.", diff --git a/package-lock.json b/package-lock.json index 7c85ab33..275a2850 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3830,9 +3830,9 @@ } }, "node_modules/@ioredis/commands": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@ioredis/commands/-/commands-1.5.0.tgz", - "integrity": "sha512-eUgLqrMf8nJkZxT24JvVRrQya1vZkQh8BBeYNwGDqa5I0VUi8ACx7uFvAaLxintokpTenkK6DASvo/bvNbBGow==", + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@ioredis/commands/-/commands-1.5.1.tgz", + "integrity": "sha512-JH8ZL/ywcJyR9MmJ5BNqZllXNZQqQbnVZOqpPQqE1vHiFgAw4NHbvE0FOduNU8IX9babitBT46571OnPTT0Zcw==", "license": "MIT" }, "node_modules/@ipld/dag-cbor": { @@ -4453,9 +4453,9 @@ "license": "MIT" }, "node_modules/@lerna/create": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/@lerna/create/-/create-9.0.4.tgz", - "integrity": "sha512-WxedGD98G8/a6HztCXNWquaM0x17oSvfvuqDsLxNNX1qXGyrzmMUmd1mQikF/47uy80X6qyWdaRtaAHlwkvEUA==", + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/@lerna/create/-/create-9.0.5.tgz", + "integrity": "sha512-Gwd6ooSqXMdkdhiCGvHAfLRstj7W3ttr72WQB3Jf9HPP1A6mWtw0O80D0X+T/2hakqfe7lNLuKrEid4f7C0qbg==", "dev": true, "license": "MIT", "dependencies": { @@ -4492,7 +4492,7 @@ "load-json-file": "6.2.0", "make-dir": "4.0.0", "make-fetch-happen": "15.0.2", - "minimatch": "3.0.5", + "minimatch": "3.1.4", "multimatch": "5.0.0", "npm-package-arg": "13.0.1", "npm-packlist": "10.0.3", @@ -4513,7 +4513,7 @@ "slash": "^3.0.0", "ssri": "12.0.0", "string-width": "^4.2.3", - "tar": "7.5.7", + "tar": "7.5.8", "temp-dir": "1.0.0", "through": "2.3.8", "tinyglobby": "0.2.12", @@ -4629,9 +4629,9 @@ } }, "node_modules/@lerna/create/node_modules/glob/node_modules/brace-expansion": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.3.tgz", - "integrity": "sha512-fy6KJm2RawA5RcHkLa1z/ScpBeA762UF9KmZQxwIbDtRJrgLzM10depAiEQ+CXYcoiqW1/m96OAAoke2nE9EeA==", + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz", + "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==", "dev": true, "license": "MIT", "dependencies": { @@ -4675,9 +4675,9 @@ } }, "node_modules/@lerna/create/node_modules/minimatch": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.5.tgz", - "integrity": "sha512-tUpxzX0VAzJHjLu0xUfFv1gwVp9ba3IOuRAVH2EGuRW8a5emA2FlACLqiT/lDVtS1W+TGNwqz3sWaNyLgDJWuw==", + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.4.tgz", + "integrity": "sha512-twmL+S8+7yIsE9wsqgzU3E8/LumN3M3QELrBZ20OdmQ9jB2JvW5oZtBEmft84k/Gs5CG9mqtWc6Y9vW+JEzGxw==", "dev": true, "license": "ISC", "dependencies": { @@ -5823,9 +5823,9 @@ } }, "node_modules/@npmcli/arborist/node_modules/brace-expansion": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.3.tgz", - "integrity": "sha512-fy6KJm2RawA5RcHkLa1z/ScpBeA762UF9KmZQxwIbDtRJrgLzM10depAiEQ+CXYcoiqW1/m96OAAoke2nE9EeA==", + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz", + "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==", "dev": true, "license": "MIT", "dependencies": { @@ -6138,9 +6138,9 @@ } }, "node_modules/@npmcli/map-workspaces/node_modules/brace-expansion": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.3.tgz", - "integrity": "sha512-fy6KJm2RawA5RcHkLa1z/ScpBeA762UF9KmZQxwIbDtRJrgLzM10depAiEQ+CXYcoiqW1/m96OAAoke2nE9EeA==", + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz", + "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==", "dev": true, "license": "MIT", "dependencies": { @@ -6289,9 +6289,9 @@ } }, "node_modules/@npmcli/package-json/node_modules/brace-expansion": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.3.tgz", - "integrity": "sha512-fy6KJm2RawA5RcHkLa1z/ScpBeA762UF9KmZQxwIbDtRJrgLzM10depAiEQ+CXYcoiqW1/m96OAAoke2nE9EeA==", + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz", + "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==", "dev": true, "license": "MIT", "dependencies": { @@ -6521,9 +6521,9 @@ } }, "node_modules/@nx/devkit/node_modules/brace-expansion": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.3.tgz", - "integrity": "sha512-fy6KJm2RawA5RcHkLa1z/ScpBeA762UF9KmZQxwIbDtRJrgLzM10depAiEQ+CXYcoiqW1/m96OAAoke2nE9EeA==", + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz", + "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==", "dev": true, "license": "MIT", "dependencies": { @@ -7078,9 +7078,9 @@ } }, "node_modules/@react-native/assets-registry": { - "version": "0.84.0", - "resolved": "https://registry.npmjs.org/@react-native/assets-registry/-/assets-registry-0.84.0.tgz", - "integrity": "sha512-YiU9h1IN0pvvZsHbd03MaD7mE2q+ySaKMlE9tWK+3iiwtbEaMQOsMUuSJ1er2LU6ERMWfhfvCYgWpKRGOMeN8A==", + "version": "0.84.1", + "resolved": "https://registry.npmjs.org/@react-native/assets-registry/-/assets-registry-0.84.1.tgz", + "integrity": "sha512-lAJ6PDZv95FdT9s9uhc9ivhikW1Zwh4j9XdXM7J2l4oUA3t37qfoBmTSDLuPyE3Bi+Xtwa11hJm0BUTT2sc/gg==", "license": "MIT", "peer": true, "engines": { @@ -7088,9 +7088,9 @@ } }, "node_modules/@react-native/codegen": { - "version": "0.84.0", - "resolved": "https://registry.npmjs.org/@react-native/codegen/-/codegen-0.84.0.tgz", - "integrity": "sha512-TcTAO58JigCw9onYTrbE2yK2js5YNgqbmnpYyq9oXz2mofbX7JcK53kIi7fhqyJhie8RkY+X85zSOTWNs6S3CA==", + "version": "0.84.1", + "resolved": "https://registry.npmjs.org/@react-native/codegen/-/codegen-0.84.1.tgz", + "integrity": "sha512-n1RIU0QAavgCg1uC5+s53arL7/mpM+16IBhJ3nCFSd/iK5tUmCwxQDcIDC703fuXfpub/ZygeSjVN8bcOWn0gA==", "license": "MIT", "peer": true, "dependencies": { @@ -7158,13 +7158,13 @@ } }, "node_modules/@react-native/community-cli-plugin": { - "version": "0.84.0", - "resolved": "https://registry.npmjs.org/@react-native/community-cli-plugin/-/community-cli-plugin-0.84.0.tgz", - "integrity": "sha512-uYoLBHnAzod4E5dA5rPPQeny2A5RD0PiIJQ4r+2F7cvA+5bZ8+znxw4TdaSiEk8uhN+clffI4d2bl9V4+xEK+Q==", + "version": "0.84.1", + "resolved": "https://registry.npmjs.org/@react-native/community-cli-plugin/-/community-cli-plugin-0.84.1.tgz", + "integrity": "sha512-f6a+mJEJ6Joxlt/050TqYUr7uRRbeKnz8lnpL7JajhpsgZLEbkJRjH8HY5QiLcRdUwWFtizml4V+vcO3P4RxoQ==", "license": "MIT", "peer": true, "dependencies": { - "@react-native/dev-middleware": "0.84.0", + "@react-native/dev-middleware": "0.84.1", "debug": "^4.4.0", "invariant": "^2.2.4", "metro": "^0.83.3", @@ -7202,9 +7202,9 @@ } }, "node_modules/@react-native/debugger-frontend": { - "version": "0.84.0", - "resolved": "https://registry.npmjs.org/@react-native/debugger-frontend/-/debugger-frontend-0.84.0.tgz", - "integrity": "sha512-n7JKYVDCbA2aj8/5/OD1IK7nuiAYj5l/Z6yhGf7GG4EGaeQdthqdb0LZbseaRPyZK/7tLfdnLdqlqdTQC6/UTQ==", + "version": "0.84.1", + "resolved": "https://registry.npmjs.org/@react-native/debugger-frontend/-/debugger-frontend-0.84.1.tgz", + "integrity": "sha512-rUU/Pyh3R5zT0WkVgB+yA6VwOp7HM5Hz4NYE97ajFS07OUIcv8JzBL3MXVdSSjLfldfqOuPEuKUaZcAOwPgabw==", "license": "BSD-3-Clause", "peer": true, "engines": { @@ -7212,9 +7212,9 @@ } }, "node_modules/@react-native/debugger-shell": { - "version": "0.84.0", - "resolved": "https://registry.npmjs.org/@react-native/debugger-shell/-/debugger-shell-0.84.0.tgz", - "integrity": "sha512-5t/NvQLYk/d0kWlGOMNobkjfimqBc+/LYRmSOkgKm+pyOhxjygCLSnRjAUkeRALSZ8h6MKGTz1Wc4pbmJr7T0Q==", + "version": "0.84.1", + "resolved": "https://registry.npmjs.org/@react-native/debugger-shell/-/debugger-shell-0.84.1.tgz", + "integrity": "sha512-LIGhh4q4ette3yW5OzmukNMYwmINYrRGDZqKyTYc/VZyNpblZPw72coXVHXdfpPT6+YlxHqXzn3UjFZpNODGCQ==", "license": "MIT", "peer": true, "dependencies": { @@ -7227,15 +7227,15 @@ } }, "node_modules/@react-native/dev-middleware": { - "version": "0.84.0", - "resolved": "https://registry.npmjs.org/@react-native/dev-middleware/-/dev-middleware-0.84.0.tgz", - "integrity": "sha512-c0o7YW39AUI1FSLV/TFSszr87kQGmaePAQK0ygIRnwZ2fAGDnQ5Iu/tk3u9O5lVH6nTjfAwTKJ3El9YeEWDeEQ==", + "version": "0.84.1", + "resolved": "https://registry.npmjs.org/@react-native/dev-middleware/-/dev-middleware-0.84.1.tgz", + "integrity": "sha512-Z83ra+Gk6ElAhH3XRrv3vwbwCPTb04sPPlNpotxcFZb5LtRQZwT91ZQEXw3GOJCVIFp9EQ/gj8AQbVvtHKOUlQ==", "license": "MIT", "peer": true, "dependencies": { "@isaacs/ttlcache": "^1.4.1", - "@react-native/debugger-frontend": "0.84.0", - "@react-native/debugger-shell": "0.84.0", + "@react-native/debugger-frontend": "0.84.1", + "@react-native/debugger-shell": "0.84.1", "chrome-launcher": "^0.15.2", "chromium-edge-launcher": "^0.2.0", "connect": "^3.6.5", @@ -7290,9 +7290,9 @@ } }, "node_modules/@react-native/gradle-plugin": { - "version": "0.84.0", - "resolved": "https://registry.npmjs.org/@react-native/gradle-plugin/-/gradle-plugin-0.84.0.tgz", - "integrity": "sha512-j8g/I4Z+SAdh2NXOVng4rmfYgPoeJBZwAKoGPpSe/wB/9XDLh9IRGUTg8dGS5BWUy2471xBUoGZPwHb6QMJmVw==", + "version": "0.84.1", + "resolved": "https://registry.npmjs.org/@react-native/gradle-plugin/-/gradle-plugin-0.84.1.tgz", + "integrity": "sha512-7uVlPBE3uluRNRX4MW7PUJIO1LDBTpAqStKHU7LHH+GRrdZbHsWtOEAX8PiY4GFfBEvG8hEjiuTOqAxMjV+hDg==", "license": "MIT", "peer": true, "engines": { @@ -7300,9 +7300,9 @@ } }, "node_modules/@react-native/js-polyfills": { - "version": "0.84.0", - "resolved": "https://registry.npmjs.org/@react-native/js-polyfills/-/js-polyfills-0.84.0.tgz", - "integrity": "sha512-xaxmzYWLgHH+2uAZQ0owEkDE58hOTWmuBKD/Gl+cDFD3mFfSK4lZpin/3hiXtE5LB4BwgqICsPN07zCAqx6Fpg==", + "version": "0.84.1", + "resolved": "https://registry.npmjs.org/@react-native/js-polyfills/-/js-polyfills-0.84.1.tgz", + "integrity": "sha512-UsTe2AbUugsfyI7XIHMQq4E7xeC8a6GrYwuK+NohMMMJMxmyM3JkzIk+GB9e2il6ScEQNMJNaj+q+i5za8itxQ==", "license": "MIT", "peer": true, "engines": { @@ -7310,16 +7310,16 @@ } }, "node_modules/@react-native/normalize-colors": { - "version": "0.84.0", - "resolved": "https://registry.npmjs.org/@react-native/normalize-colors/-/normalize-colors-0.84.0.tgz", - "integrity": "sha512-7JgZyWtQ9Sz4qZvCTsURUtuv8/niEZ/iCorp7eExc3GgpBWNazPumieiUoWPdgRKofU0Bqpr2/dJevEn2hrlwA==", + "version": "0.84.1", + "resolved": "https://registry.npmjs.org/@react-native/normalize-colors/-/normalize-colors-0.84.1.tgz", + "integrity": "sha512-/UPaQ4jl95soXnLDEJ6Cs6lnRXhwbxtT4KbZz+AFDees7prMV2NOLcHfCnzmTabf5Y3oxENMVBL666n4GMLcTA==", "license": "MIT", "peer": true }, "node_modules/@react-native/virtualized-lists": { - "version": "0.84.0", - "resolved": "https://registry.npmjs.org/@react-native/virtualized-lists/-/virtualized-lists-0.84.0.tgz", - "integrity": "sha512-ugwSj0Gb4MYrcm8uQrQw8qHPx5RKGDLuZRAP/AuwneFizHx8YCLBEFbOYRGWgxHBRtkJ70D1o+jpIx3CK3p5lw==", + "version": "0.84.1", + "resolved": "https://registry.npmjs.org/@react-native/virtualized-lists/-/virtualized-lists-0.84.1.tgz", + "integrity": "sha512-sJoDunzhci8ZsqxlUiKoLut4xQeQcmbIgvDHGQKeBz6uEq9HgU+hCWOijMRr6sLP0slQVfBAza34Rq7IbXZZOA==", "license": "MIT", "peer": true, "dependencies": { @@ -7869,6 +7869,18 @@ "dev": true, "license": "MIT" }, + "node_modules/@scure/base": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.1.tgz", + "integrity": "sha512-ZxOhsSyxYwLJj3pLZCefNitxsj093tb2vq90mp2txoYeBqbcjDjqFhyM8eUjq/uFm6zJ+mUuqxlS2FkuSY1MTA==", + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "license": "MIT" + }, "node_modules/@sigstore/bundle": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/@sigstore/bundle/-/bundle-4.0.0.tgz", @@ -8026,6 +8038,19 @@ "node": "^20.17.0 || >=22.9.0" } }, + "node_modules/@simple-libs/stream-utils": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@simple-libs/stream-utils/-/stream-utils-1.2.0.tgz", + "integrity": "sha512-KxXvfapcixpz6rVEB6HPjOUZT22yN6v0vI0urQSk1L8MlEWPDFCZkhw2xmkyoTGYeFw7tWTZd7e3lVzRZRN/EA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://ko-fi.com/dangreen" + } + }, "node_modules/@sinclair/typebox": { "version": "0.27.10", "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.10.tgz", @@ -8130,9 +8155,9 @@ } }, "node_modules/@tufjs/models/node_modules/brace-expansion": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.3.tgz", - "integrity": "sha512-fy6KJm2RawA5RcHkLa1z/ScpBeA762UF9KmZQxwIbDtRJrgLzM10depAiEQ+CXYcoiqW1/m96OAAoke2nE9EeA==", + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz", + "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==", "dev": true, "license": "MIT", "dependencies": { @@ -9413,9 +9438,9 @@ } }, "node_modules/axios": { - "version": "1.13.5", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.5.tgz", - "integrity": "sha512-cz4ur7Vb0xS4/KUN0tPWe44eqxrIu31me+fbang3ijiNscE129POzipJJA6zniq2C/Z6sJCjMimjS8Lc/GAs8Q==", + "version": "1.13.6", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.6.tgz", + "integrity": "sha512-ChTCHMouEe2kn713WHbQGcuYrr6fXTBiu460OTwWrWob16g1bXn4vtz07Ope7ewMozJAnEquLk5lWQWtBig9DQ==", "license": "MIT", "dependencies": { "follow-redirects": "^1.15.11", @@ -10097,9 +10122,9 @@ } }, "node_modules/cacache/node_modules/brace-expansion": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.3.tgz", - "integrity": "sha512-fy6KJm2RawA5RcHkLa1z/ScpBeA762UF9KmZQxwIbDtRJrgLzM10depAiEQ+CXYcoiqW1/m96OAAoke2nE9EeA==", + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz", + "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==", "dev": true, "license": "MIT", "dependencies": { @@ -10284,9 +10309,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001774", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001774.tgz", - "integrity": "sha512-DDdwPGz99nmIEv216hKSgLD+D4ikHQHjBC/seF98N9CPqRX4M5mSxT9eTV6oyisnJcuzxtZy4n17yKKQYmYQOA==", + "version": "1.0.30001775", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001775.tgz", + "integrity": "sha512-s3Qv7Lht9zbVKE9XoTyRG6wVDCKdtOFIjBGg3+Yhn6JaytuNKPIjBMTMIY1AnOH3seL5mvF+x33oGAyK3hVt3A==", "funding": [ { "type": "opencollective", @@ -10754,9 +10779,9 @@ "license": "ISC" }, "node_modules/conventional-changelog-angular": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-8.1.0.tgz", - "integrity": "sha512-GGf2Nipn1RUCAktxuVauVr1e3r8QrLP/B0lEUsFktmGqc3ddbQkhoJZHJctVU829U1c6mTSWftrVOCHaL85Q3w==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-8.2.0.tgz", + "integrity": "sha512-4YB1zEXqB17oBI8yRsAs1T+ZhbdsOgJqkl6Trz+GXt/eKf1e4jnA0oW+sOd9BEENzEViuNW0DNoFFjSf3CeC5Q==", "dev": true, "license": "ISC", "dependencies": { @@ -10767,9 +10792,9 @@ } }, "node_modules/conventional-changelog-conventionalcommits": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-9.1.0.tgz", - "integrity": "sha512-MnbEysR8wWa8dAEvbj5xcBgJKQlX/m0lhS8DsyAAWDHdfs2faDJxTgzRYlRYpXSe7UiKrIIlB4TrBKU9q9DgkA==", + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-9.2.0.tgz", + "integrity": "sha512-fCf+ODjseueTV09wVBoC0HXLi3OyuBJ+HfE3L63Khxqnr99f9nUcnQh3a15lCWHlGLihyZShW/mVVkBagr9JvQ==", "dev": true, "license": "ISC", "dependencies": { @@ -10849,6 +10874,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/git-raw-commits/-/git-raw-commits-3.0.0.tgz", "integrity": "sha512-b5OHmZ3vAgGrDn/X0kS+9qCfNKWe4K/jFnhwzVWWg0/k5eLa3060tZShrRg8Dja5kPc+YjS0Gc6y7cRr44Lpjw==", + "deprecated": "This package is no longer maintained. For the JavaScript API, please use @conventional-changelog/git-client instead.", "dev": true, "license": "MIT", "dependencies": { @@ -11297,12 +11323,13 @@ } }, "node_modules/conventional-commits-parser": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-6.2.1.tgz", - "integrity": "sha512-20pyHgnO40rvfI0NGF/xiEoFMkXDtkF8FwHvk5BokoFoCuTQRI8vrNCNFWUOfuolKJMm1tPCHc8GgYEtr1XRNA==", + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-6.3.0.tgz", + "integrity": "sha512-RfOq/Cqy9xV9bOA8N+ZH6DlrDR+5S3Mi0B5kACEjESpE+AviIpAptx9a9cFpWCCvgRtWT+0BbUw+e1BZfts9jg==", "dev": true, "license": "MIT", "dependencies": { + "@simple-libs/stream-utils": "^1.2.0", "meow": "^13.0.0" }, "bin": { @@ -11381,6 +11408,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/git-raw-commits/-/git-raw-commits-3.0.0.tgz", "integrity": "sha512-b5OHmZ3vAgGrDn/X0kS+9qCfNKWe4K/jFnhwzVWWg0/k5eLa3060tZShrRg8Dja5kPc+YjS0Gc6y7cRr44Lpjw==", + "deprecated": "This package is no longer maintained. For the JavaScript API, please use @conventional-changelog/git-client instead.", "dev": true, "license": "MIT", "dependencies": { @@ -11913,9 +11941,9 @@ } }, "node_modules/dedent": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.7.1.tgz", - "integrity": "sha512-9JmrhGZpOlEgOLdQgSm0zxFaYoQon408V1v49aqTWuXENVlnCuY9JBZcXZiCsZQWDjTm5Qf/nIvAy77mXDAjEg==", + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.7.2.tgz", + "integrity": "sha512-WzMx3mW98SN+zn3hgemf4OzdmyNhhhKz5Ay0pUfQiMQ3e1g+xmTJWp/pKdwKVXhdSkAEGIIzqeuWrL3mV/AXbA==", "dev": true, "license": "MIT", "peerDependencies": { @@ -12862,14 +12890,11 @@ } }, "node_modules/eslint-plugin-only-warn": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-only-warn/-/eslint-plugin-only-warn-1.1.0.tgz", - "integrity": "sha512-2tktqUAT+Q3hCAU0iSf4xAN1k9zOpjK5WO8104mB0rT/dGhOa09582HN5HlbxNbPRZ0THV7nLGvzugcNOSjzfA==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-only-warn/-/eslint-plugin-only-warn-1.2.1.tgz", + "integrity": "sha512-j37hwfaQDEOfkZ1Dpvu/HnWLavlzQxQxfbrU/9Jb4R9qzrE1eTYuRJyrxq7LzLRI8miG5FOV6veoUVhx7AI84w==", "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } + "license": "MIT" }, "node_modules/eslint-plugin-react": { "version": "7.37.5", @@ -14023,6 +14048,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/git-raw-commits/-/git-raw-commits-4.0.0.tgz", "integrity": "sha512-ICsMM1Wk8xSGMowkOmPrzo2Fgmfo4bMHLNX6ytHjajRJUqvHOw/TFapQ+QG75c3X/tTDDhOSRPGC52dDbNM8FQ==", + "deprecated": "This package is no longer maintained. For the JavaScript API, please use @conventional-changelog/git-client instead.", "dev": true, "license": "MIT", "dependencies": { @@ -14078,6 +14104,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/git-semver-tags/-/git-semver-tags-5.0.1.tgz", "integrity": "sha512-hIvOeZwRbQ+7YEUmCkHqo8FOLQZCEn18yevLHADlFPZY02KJGsu5FZt9YW/lybfK2uhWFI7Qg/07LekJiTv7iA==", + "deprecated": "This package is no longer maintained. For the JavaScript API, please use @conventional-changelog/git-client instead.", "dev": true, "license": "MIT", "dependencies": { @@ -14759,9 +14786,9 @@ } }, "node_modules/hermes-compiler": { - "version": "250829098.0.7", - "resolved": "https://registry.npmjs.org/hermes-compiler/-/hermes-compiler-250829098.0.7.tgz", - "integrity": "sha512-8QOmg1VjAWv8poFVslJDY8qkvjTy/UiO3R/hyGoC0IAchLzBdS9/TmAvI9cN1F3yLTEjimAIQQtUslpBMPXVVg==", + "version": "250829098.0.9", + "resolved": "https://registry.npmjs.org/hermes-compiler/-/hermes-compiler-250829098.0.9.tgz", + "integrity": "sha512-hZ5O7PDz1vQ99TS7HD3FJ9zVynfU1y+VWId6U1Pldvd8hmAYrNec/XLPYJKD3dLOW6NXak6aAQAuMuSo3ji0tQ==", "license": "MIT", "peer": true }, @@ -15003,9 +15030,9 @@ } }, "node_modules/ignore-walk/node_modules/brace-expansion": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.3.tgz", - "integrity": "sha512-fy6KJm2RawA5RcHkLa1z/ScpBeA762UF9KmZQxwIbDtRJrgLzM10depAiEQ+CXYcoiqW1/m96OAAoke2nE9EeA==", + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz", + "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==", "dev": true, "license": "MIT", "dependencies": { @@ -15269,12 +15296,12 @@ } }, "node_modules/ioredis": { - "version": "5.9.3", - "resolved": "https://registry.npmjs.org/ioredis/-/ioredis-5.9.3.tgz", - "integrity": "sha512-VI5tMCdeoxZWU5vjHWsiE/Su76JGhBvWF1MJnV9ZtGltHk9BmD48oDq8Tj8haZ85aceXZMxLNDQZRVo5QKNgXA==", + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/ioredis/-/ioredis-5.10.0.tgz", + "integrity": "sha512-HVBe9OFuqs+Z6n64q09PQvP1/R4Bm+30PAyyD4wIEqssh3v9L21QjCVk4kRLucMBcDokJTcLjsGeVRlq/nH6DA==", "license": "MIT", "dependencies": { - "@ioredis/commands": "1.5.0", + "@ioredis/commands": "1.5.1", "cluster-key-slot": "^1.1.0", "debug": "^4.3.4", "denque": "^2.1.0", @@ -17522,13 +17549,13 @@ } }, "node_modules/lerna": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/lerna/-/lerna-9.0.4.tgz", - "integrity": "sha512-wKy9TOkkdCWPWET0R5o7mh7J0KuNNjxE0g+qTruNAt5ffWwy54wfWiJtWyDSMOrcGDt6gtisDBTKniOqK/sJvw==", + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/lerna/-/lerna-9.0.5.tgz", + "integrity": "sha512-LtwZu2wINHlKpjRCxrEdK3QopyeUpFuUS4v6uzLYdg/uxnAKqDHrGY/mDPxdxDR3YAXJzpWXBdz49AHNIKZaSg==", "dev": true, "license": "MIT", "dependencies": { - "@lerna/create": "9.0.4", + "@lerna/create": "9.0.5", "@npmcli/arborist": "9.1.6", "@npmcli/package-json": "7.0.2", "@npmcli/run-script": "10.0.3", @@ -17568,7 +17595,7 @@ "load-json-file": "6.2.0", "make-dir": "4.0.0", "make-fetch-happen": "15.0.2", - "minimatch": "3.0.5", + "minimatch": "3.1.4", "multimatch": "5.0.0", "npm-package-arg": "13.0.1", "npm-packlist": "10.0.3", @@ -17591,7 +17618,7 @@ "slash": "3.0.0", "ssri": "12.0.0", "string-width": "^4.2.3", - "tar": "7.5.7", + "tar": "7.5.8", "temp-dir": "1.0.0", "through": "2.3.8", "tinyglobby": "0.2.12", @@ -17744,9 +17771,9 @@ } }, "node_modules/lerna/node_modules/glob/node_modules/brace-expansion": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.3.tgz", - "integrity": "sha512-fy6KJm2RawA5RcHkLa1z/ScpBeA762UF9KmZQxwIbDtRJrgLzM10depAiEQ+CXYcoiqW1/m96OAAoke2nE9EeA==", + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz", + "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==", "dev": true, "license": "MIT", "dependencies": { @@ -17843,9 +17870,9 @@ } }, "node_modules/lerna/node_modules/minimatch": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.5.tgz", - "integrity": "sha512-tUpxzX0VAzJHjLu0xUfFv1gwVp9ba3IOuRAVH2EGuRW8a5emA2FlACLqiT/lDVtS1W+TGNwqz3sWaNyLgDJWuw==", + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.4.tgz", + "integrity": "sha512-twmL+S8+7yIsE9wsqgzU3E8/LumN3M3QELrBZ20OdmQ9jB2JvW5oZtBEmft84k/Gs5CG9mqtWc6Y9vW+JEzGxw==", "dev": true, "license": "ISC", "dependencies": { @@ -18065,6 +18092,15 @@ "uint8arrays": "^5.1.0" } }, + "node_modules/light-bolt11-decoder": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/light-bolt11-decoder/-/light-bolt11-decoder-3.2.0.tgz", + "integrity": "sha512-3QEofgiBOP4Ehs9BI+RkZdXZNtSys0nsJ6fyGeSiAGCBsMwHGUDS/JQlY/sTnWs91A2Nh0S9XXfA8Sy9g6QpuQ==", + "license": "MIT", + "dependencies": { + "@scure/base": "1.1.1" + } + }, "node_modules/lighthouse-logger": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/lighthouse-logger/-/lighthouse-logger-1.4.2.tgz", @@ -18482,9 +18518,9 @@ } }, "node_modules/metro": { - "version": "0.83.4", - "resolved": "https://registry.npmjs.org/metro/-/metro-0.83.4.tgz", - "integrity": "sha512-eBkAtcob+YmvSLL+/rsFiK8dHNfDbQA2/pi0lnxg3E6LLtUpwDfdGJ9WBWXkj0PVeOhoWQyj9Rt7s/+6k/GXuA==", + "version": "0.83.5", + "resolved": "https://registry.npmjs.org/metro/-/metro-0.83.5.tgz", + "integrity": "sha512-BgsXevY1MBac/3ZYv/RfNFf/4iuW9X7f4H8ZNkiH+r667HD9sVujxcmu4jvEzGCAm4/WyKdZCuyhAcyhTHOucQ==", "license": "MIT", "peer": true, "dependencies": { @@ -18509,18 +18545,18 @@ "jest-worker": "^29.7.0", "jsc-safe-url": "^0.2.2", "lodash.throttle": "^4.1.1", - "metro-babel-transformer": "0.83.4", - "metro-cache": "0.83.4", - "metro-cache-key": "0.83.4", - "metro-config": "0.83.4", - "metro-core": "0.83.4", - "metro-file-map": "0.83.4", - "metro-resolver": "0.83.4", - "metro-runtime": "0.83.4", - "metro-source-map": "0.83.4", - "metro-symbolicate": "0.83.4", - "metro-transform-plugins": "0.83.4", - "metro-transform-worker": "0.83.4", + "metro-babel-transformer": "0.83.5", + "metro-cache": "0.83.5", + "metro-cache-key": "0.83.5", + "metro-config": "0.83.5", + "metro-core": "0.83.5", + "metro-file-map": "0.83.5", + "metro-resolver": "0.83.5", + "metro-runtime": "0.83.5", + "metro-source-map": "0.83.5", + "metro-symbolicate": "0.83.5", + "metro-transform-plugins": "0.83.5", + "metro-transform-worker": "0.83.5", "mime-types": "^3.0.1", "nullthrows": "^1.1.1", "serialize-error": "^2.1.0", @@ -18537,9 +18573,9 @@ } }, "node_modules/metro-babel-transformer": { - "version": "0.83.4", - "resolved": "https://registry.npmjs.org/metro-babel-transformer/-/metro-babel-transformer-0.83.4.tgz", - "integrity": "sha512-xfNtsYIigybqm9xVL3ygTYYNFyYTMf2lGg/Wt+znVGtwcjXoRPG80WlL5SS09ZjYVei3MoE920i7MNr7ukSULA==", + "version": "0.83.5", + "resolved": "https://registry.npmjs.org/metro-babel-transformer/-/metro-babel-transformer-0.83.5.tgz", + "integrity": "sha512-d9FfmgUEVejTiSb7bkQeLRGl6aeno2UpuPm3bo3rCYwxewj03ymvOn8s8vnS4fBqAPQ+cE9iQM40wh7nGXR+eA==", "license": "MIT", "peer": true, "dependencies": { @@ -18570,25 +18606,25 @@ } }, "node_modules/metro-cache": { - "version": "0.83.4", - "resolved": "https://registry.npmjs.org/metro-cache/-/metro-cache-0.83.4.tgz", - "integrity": "sha512-Pm6CiksVms0cZNDDe/nFzYr1xpXzJLOSwvOjl4b3cYtXxEFllEjD6EeBgoQK5C8yk7U54PcuRaUAFSvJ+eCKbg==", + "version": "0.83.5", + "resolved": "https://registry.npmjs.org/metro-cache/-/metro-cache-0.83.5.tgz", + "integrity": "sha512-oH+s4U+IfZyg8J42bne2Skc90rcuESIYf86dYittcdWQtPfcaFXWpByPyTuWk3rR1Zz3Eh5HOrcVImfEhhJLng==", "license": "MIT", "peer": true, "dependencies": { "exponential-backoff": "^3.1.1", "flow-enums-runtime": "^0.0.6", "https-proxy-agent": "^7.0.5", - "metro-core": "0.83.4" + "metro-core": "0.83.5" }, "engines": { "node": ">=20.19.4" } }, "node_modules/metro-cache-key": { - "version": "0.83.4", - "resolved": "https://registry.npmjs.org/metro-cache-key/-/metro-cache-key-0.83.4.tgz", - "integrity": "sha512-Y8E6mm1alkYIRzmfkOdrwXMzJ4HKANYiZE7J2d3iYTwmnLIQG+aoIpvla+bo6LRxH1Gm3qjEiOl+LbxvPCzIug==", + "version": "0.83.5", + "resolved": "https://registry.npmjs.org/metro-cache-key/-/metro-cache-key-0.83.5.tgz", + "integrity": "sha512-Ycl8PBajB7bhbAI7Rt0xEyiF8oJ0RWX8EKkolV1KfCUlC++V/GStMSGpPLwnnBZXZWkCC5edBPzv1Hz1Yi0Euw==", "license": "MIT", "peer": true, "dependencies": { @@ -18599,19 +18635,19 @@ } }, "node_modules/metro-config": { - "version": "0.83.4", - "resolved": "https://registry.npmjs.org/metro-config/-/metro-config-0.83.4.tgz", - "integrity": "sha512-ydOgMNI9aT8l2LOTOugt1FvC7getPKG9uJo9Vclg9/RWJxbwkBF/FMBm6w5gH8NwJokSmQrbNkojXPn7nm0kGw==", + "version": "0.83.5", + "resolved": "https://registry.npmjs.org/metro-config/-/metro-config-0.83.5.tgz", + "integrity": "sha512-JQ/PAASXH7yczgV6OCUSRhZYME+NU8NYjI2RcaG5ga4QfQ3T/XdiLzpSb3awWZYlDCcQb36l4Vl7i0Zw7/Tf9w==", "license": "MIT", "peer": true, "dependencies": { "connect": "^3.6.5", "flow-enums-runtime": "^0.0.6", "jest-validate": "^29.7.0", - "metro": "0.83.4", - "metro-cache": "0.83.4", - "metro-core": "0.83.4", - "metro-runtime": "0.83.4", + "metro": "0.83.5", + "metro-cache": "0.83.5", + "metro-core": "0.83.5", + "metro-runtime": "0.83.5", "yaml": "^2.6.1" }, "engines": { @@ -18619,24 +18655,24 @@ } }, "node_modules/metro-core": { - "version": "0.83.4", - "resolved": "https://registry.npmjs.org/metro-core/-/metro-core-0.83.4.tgz", - "integrity": "sha512-EE+j/imryd3og/6Ly9usku9vcTLQr2o4IDax/izsr6b0HRqZK9k6f5SZkGkOPqnsACLq6csPCx+2JsgF9DkVbw==", + "version": "0.83.5", + "resolved": "https://registry.npmjs.org/metro-core/-/metro-core-0.83.5.tgz", + "integrity": "sha512-YcVcLCrf0ed4mdLa82Qob0VxYqfhmlRxUS8+TO4gosZo/gLwSvtdeOjc/Vt0pe/lvMNrBap9LlmvZM8FIsMgJQ==", "license": "MIT", "peer": true, "dependencies": { "flow-enums-runtime": "^0.0.6", "lodash.throttle": "^4.1.1", - "metro-resolver": "0.83.4" + "metro-resolver": "0.83.5" }, "engines": { "node": ">=20.19.4" } }, "node_modules/metro-file-map": { - "version": "0.83.4", - "resolved": "https://registry.npmjs.org/metro-file-map/-/metro-file-map-0.83.4.tgz", - "integrity": "sha512-RSZLpGQhW9topefjJ9dp77Ff7BP88b17sb/YjxLHC1/H0lJVYYC9Cgqua21Vxe4RUJK2z64hw72g+ySLGTCawA==", + "version": "0.83.5", + "resolved": "https://registry.npmjs.org/metro-file-map/-/metro-file-map-0.83.5.tgz", + "integrity": "sha512-ZEt8s3a1cnYbn40nyCD+CsZdYSlwtFh2kFym4lo+uvfM+UMMH+r/BsrC6rbNClSrt+B7rU9T+Te/sh/NL8ZZKQ==", "license": "MIT", "peer": true, "dependencies": { @@ -18655,9 +18691,9 @@ } }, "node_modules/metro-minify-terser": { - "version": "0.83.4", - "resolved": "https://registry.npmjs.org/metro-minify-terser/-/metro-minify-terser-0.83.4.tgz", - "integrity": "sha512-KmZnpxfj0nPIRkbBNTc6xul5f5GPvWL5kQ1UkisB7qFkgh6+UiJG+L4ukJ2sK7St6+8Za/Cb68MUEYkUouIYcQ==", + "version": "0.83.5", + "resolved": "https://registry.npmjs.org/metro-minify-terser/-/metro-minify-terser-0.83.5.tgz", + "integrity": "sha512-Toe4Md1wS1PBqbvB0cFxBzKEVyyuYTUb0sgifAZh/mSvLH84qA1NAWik9sISWatzvfWf3rOGoUoO5E3f193a3Q==", "license": "MIT", "peer": true, "dependencies": { @@ -18669,9 +18705,9 @@ } }, "node_modules/metro-resolver": { - "version": "0.83.4", - "resolved": "https://registry.npmjs.org/metro-resolver/-/metro-resolver-0.83.4.tgz", - "integrity": "sha512-drWdylyNqgdaJufz0GjU/ielv2hjcc6piegjjJwKn8l7A/72aLQpUpOHtP+GMR+kOqhSsD4MchhJ6PSANvlSEw==", + "version": "0.83.5", + "resolved": "https://registry.npmjs.org/metro-resolver/-/metro-resolver-0.83.5.tgz", + "integrity": "sha512-7p3GtzVUpbAweJeCcUJihJeOQl1bDuimO5ueo1K0BUpUtR41q5EilbQ3klt16UTPPMpA+tISWBtsrqU556mY1A==", "license": "MIT", "peer": true, "dependencies": { @@ -18682,9 +18718,9 @@ } }, "node_modules/metro-runtime": { - "version": "0.83.4", - "resolved": "https://registry.npmjs.org/metro-runtime/-/metro-runtime-0.83.4.tgz", - "integrity": "sha512-sWj9KN311yG22Zv0kVbAp9dorB9HtTThvQKsAn6PLxrVrz+1UBsLrQSxjE/s4PtzDi1HABC648jo4K9Euz/5jw==", + "version": "0.83.5", + "resolved": "https://registry.npmjs.org/metro-runtime/-/metro-runtime-0.83.5.tgz", + "integrity": "sha512-f+b3ue9AWTVlZe2Xrki6TAoFtKIqw30jwfk7GQ1rDUBQaE0ZQ+NkiMEtb9uwH7uAjJ87U7Tdx1Jg1OJqUfEVlA==", "license": "MIT", "peer": true, "dependencies": { @@ -18696,9 +18732,9 @@ } }, "node_modules/metro-source-map": { - "version": "0.83.4", - "resolved": "https://registry.npmjs.org/metro-source-map/-/metro-source-map-0.83.4.tgz", - "integrity": "sha512-pPbmQwS0zgU+/0u5KPkuvlsQP0V+WYQ9qNshqupIL720QRH0vS3QR25IVVtbunofEDJchI11Q4QtIbmUyhpOBw==", + "version": "0.83.5", + "resolved": "https://registry.npmjs.org/metro-source-map/-/metro-source-map-0.83.5.tgz", + "integrity": "sha512-VT9bb2KO2/4tWY9Z2yeZqTUao7CicKAOps9LUg2aQzsz+04QyuXL3qgf1cLUVRjA/D6G5u1RJAlN1w9VNHtODQ==", "license": "MIT", "peer": true, "dependencies": { @@ -18706,9 +18742,9 @@ "@babel/types": "^7.29.0", "flow-enums-runtime": "^0.0.6", "invariant": "^2.2.4", - "metro-symbolicate": "0.83.4", + "metro-symbolicate": "0.83.5", "nullthrows": "^1.1.1", - "ob1": "0.83.4", + "ob1": "0.83.5", "source-map": "^0.5.6", "vlq": "^1.0.0" }, @@ -18727,15 +18763,15 @@ } }, "node_modules/metro-symbolicate": { - "version": "0.83.4", - "resolved": "https://registry.npmjs.org/metro-symbolicate/-/metro-symbolicate-0.83.4.tgz", - "integrity": "sha512-clyWAXDgkDHPwvldl95pcLTrJIqUj9GbZayL8tfeUs69ilsIUBpVym2lRd/8l3/8PIHCInxL868NvD2Y7OqKXg==", + "version": "0.83.5", + "resolved": "https://registry.npmjs.org/metro-symbolicate/-/metro-symbolicate-0.83.5.tgz", + "integrity": "sha512-EMIkrjNRz/hF+p0RDdxoE60+dkaTLPN3vaaGkFmX5lvFdO6HPfHA/Ywznzkev+za0VhPQ5KSdz49/MALBRteHA==", "license": "MIT", "peer": true, "dependencies": { "flow-enums-runtime": "^0.0.6", "invariant": "^2.2.4", - "metro-source-map": "0.83.4", + "metro-source-map": "0.83.5", "nullthrows": "^1.1.1", "source-map": "^0.5.6", "vlq": "^1.0.0" @@ -18758,9 +18794,9 @@ } }, "node_modules/metro-transform-plugins": { - "version": "0.83.4", - "resolved": "https://registry.npmjs.org/metro-transform-plugins/-/metro-transform-plugins-0.83.4.tgz", - "integrity": "sha512-c0ROVcyvdaGPUFIg2N5nEQF4xbsqB2p1PPPhVvK1d/Y7ZhBAFiwQ75so0SJok32q+I++lc/hq7IdPCp2frPGQg==", + "version": "0.83.5", + "resolved": "https://registry.npmjs.org/metro-transform-plugins/-/metro-transform-plugins-0.83.5.tgz", + "integrity": "sha512-KxYKzZL+lt3Os5H2nx7YkbkWVduLZL5kPrE/Yq+Prm/DE1VLhpfnO6HtPs8vimYFKOa58ncl60GpoX0h7Wm0Vw==", "license": "MIT", "peer": true, "dependencies": { @@ -18776,9 +18812,9 @@ } }, "node_modules/metro-transform-worker": { - "version": "0.83.4", - "resolved": "https://registry.npmjs.org/metro-transform-worker/-/metro-transform-worker-0.83.4.tgz", - "integrity": "sha512-6I81IZLeU/0ww7OBgCPALFl0OE0FQwvIuKCtuViSiKufmislF7kVr7IHH9GYtQuZcnualQ82gYeQ11KzZQTouw==", + "version": "0.83.5", + "resolved": "https://registry.npmjs.org/metro-transform-worker/-/metro-transform-worker-0.83.5.tgz", + "integrity": "sha512-8N4pjkNXc6ytlP9oAM6MwqkvUepNSW39LKYl9NjUMpRDazBQ7oBpQDc8Sz4aI8jnH6AGhF7s1m/ayxkN1t04yA==", "license": "MIT", "peer": true, "dependencies": { @@ -18787,13 +18823,13 @@ "@babel/parser": "^7.29.0", "@babel/types": "^7.29.0", "flow-enums-runtime": "^0.0.6", - "metro": "0.83.4", - "metro-babel-transformer": "0.83.4", - "metro-cache": "0.83.4", - "metro-cache-key": "0.83.4", - "metro-minify-terser": "0.83.4", - "metro-source-map": "0.83.4", - "metro-transform-plugins": "0.83.4", + "metro": "0.83.5", + "metro-babel-transformer": "0.83.5", + "metro-cache": "0.83.5", + "metro-cache-key": "0.83.5", + "metro-minify-terser": "0.83.5", + "metro-source-map": "0.83.5", + "metro-transform-plugins": "0.83.5", "nullthrows": "^1.1.1" }, "engines": { @@ -20076,9 +20112,9 @@ } }, "node_modules/nx/node_modules/brace-expansion": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.3.tgz", - "integrity": "sha512-fy6KJm2RawA5RcHkLa1z/ScpBeA762UF9KmZQxwIbDtRJrgLzM10depAiEQ+CXYcoiqW1/m96OAAoke2nE9EeA==", + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz", + "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==", "dev": true, "license": "MIT", "dependencies": { @@ -20184,9 +20220,9 @@ } }, "node_modules/ob1": { - "version": "0.83.4", - "resolved": "https://registry.npmjs.org/ob1/-/ob1-0.83.4.tgz", - "integrity": "sha512-9JiflaRKCkxKzH8uuZlax72cHzZ8iFLsNIORFOAKDgZUOfvfwYWOVS0ezGLzPp/yEhVktD+PTTImC0AAehSOBw==", + "version": "0.83.5", + "resolved": "https://registry.npmjs.org/ob1/-/ob1-0.83.5.tgz", + "integrity": "sha512-vNKPYC8L5ycVANANpF/S+WZHpfnRWKx/F3AYP4QMn6ZJTh+l2HOrId0clNkEmua58NB9vmI9Qh7YOoV/4folYg==", "license": "MIT", "peer": true, "dependencies": { @@ -21417,9 +21453,9 @@ "license": "MIT" }, "node_modules/pump": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.3.tgz", - "integrity": "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.4.tgz", + "integrity": "sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==", "license": "MIT", "dependencies": { "end-of-stream": "^1.1.0", @@ -21667,20 +21703,20 @@ "license": "MIT" }, "node_modules/react-native": { - "version": "0.84.0", - "resolved": "https://registry.npmjs.org/react-native/-/react-native-0.84.0.tgz", - "integrity": "sha512-CcBfucLDHz8MAjQx9kFXasYtpcn8zP1YapUgGtAy0psRZTLShwF9yeh5+ErSgEK2gXV1CCSz7hqCZqx1eMyBLA==", + "version": "0.84.1", + "resolved": "https://registry.npmjs.org/react-native/-/react-native-0.84.1.tgz", + "integrity": "sha512-0PjxOyXRu3tZ8EobabxSukvhKje2HJbsZikR0U+pvS0pYZza2hXKjcSBiBdFN4h9D0S3v6a8kkrDK6WTRKMwzg==", "license": "MIT", "peer": true, "dependencies": { "@jest/create-cache-key-function": "^29.7.0", - "@react-native/assets-registry": "0.84.0", - "@react-native/codegen": "0.84.0", - "@react-native/community-cli-plugin": "0.84.0", - "@react-native/gradle-plugin": "0.84.0", - "@react-native/js-polyfills": "0.84.0", - "@react-native/normalize-colors": "0.84.0", - "@react-native/virtualized-lists": "0.84.0", + "@react-native/assets-registry": "0.84.1", + "@react-native/codegen": "0.84.1", + "@react-native/community-cli-plugin": "0.84.1", + "@react-native/gradle-plugin": "0.84.1", + "@react-native/js-polyfills": "0.84.1", + "@react-native/normalize-colors": "0.84.1", + "@react-native/virtualized-lists": "0.84.1", "abort-controller": "^3.0.0", "anser": "^1.4.9", "ansi-regex": "^5.0.0", @@ -21689,7 +21725,7 @@ "base64-js": "^1.5.1", "commander": "^12.0.0", "flow-enums-runtime": "^0.0.6", - "hermes-compiler": "250829098.0.7", + "hermes-compiler": "250829098.0.9", "invariant": "^2.2.4", "jest-environment-node": "^29.7.0", "memoize-one": "^5.0.0", @@ -22596,9 +22632,9 @@ } }, "node_modules/sax": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.4.tgz", - "integrity": "sha512-1n3r/tGXO6b6VXMdFT54SHzT9ytu9yr7TaELowdYpMqY/Ao7EnlQGmAQ1+RatX7Tkkdm6hONI2owqNx2aZj5Sw==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.5.0.tgz", + "integrity": "sha512-21IYA3Q5cQf089Z6tgaUTr7lDAyzoTPx5HRtbhsME8Udispad8dC/+sziTNugOEx54ilvatQ9YCzl4KQLPcRHA==", "license": "BlueOak-1.0.0", "engines": { "node": ">=11.0.0" @@ -24120,10 +24156,9 @@ } }, "node_modules/tar": { - "version": "7.5.7", - "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.7.tgz", - "integrity": "sha512-fov56fJiRuThVFXD6o6/Q354S7pnWMJIVlDBYijsTNx6jKSE4pvrDTs6lUnmGvNyfJwFQQwWy3owKz1ucIhveQ==", - "deprecated": "Old versions of tar are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "version": "7.5.8", + "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.8.tgz", + "integrity": "sha512-SYkBtK99u0yXa+IWL0JRzzcl7RxNpvX/U08Z+8DKnysfno7M+uExnTZH8K+VGgShf2qFPKtbNr9QBl8n7WBP6Q==", "dev": true, "license": "BlueOak-1.0.0", "dependencies": { @@ -25921,6 +25956,7 @@ "file-type": "^21.0.0", "image-size": "^2.0.1", "ioredis": "^5.4.1", + "light-bolt11-decoder": "^3.2.0", "mongodb": "^6.5.0", "sqlite": "^5.1.1", "sqlite3": "^5.1.7" diff --git a/packages/gatekeeper/src/drawbridge-client.ts b/packages/gatekeeper/src/drawbridge-client.ts index a1aeae29..0e3de813 100644 --- a/packages/gatekeeper/src/drawbridge-client.ts +++ b/packages/gatekeeper/src/drawbridge-client.ts @@ -12,7 +12,7 @@ import GatekeeperClient from './gatekeeper-client.js'; function throwError(error: any): never { if (error.response) { if (error.response.status === 404) { - throw { type: 'Lightning service unavailable', error: 'Server does not support Lightning' }; + throw new Error('Lightning service unavailable: Server does not support Lightning'); } throw error.response.data; } diff --git a/packages/keymaster/package.json b/packages/keymaster/package.json index 0ff97b36..bd179c93 100644 --- a/packages/keymaster/package.json +++ b/packages/keymaster/package.json @@ -150,6 +150,7 @@ "file-type": "^21.0.0", "image-size": "^2.0.1", "ioredis": "^5.4.1", + "light-bolt11-decoder": "^3.2.0", "mongodb": "^6.5.0", "sqlite": "^5.1.1", "sqlite3": "^5.1.7" diff --git a/packages/keymaster/src/cli.ts b/packages/keymaster/src/cli.ts index f13a3832..7a2adb07 100644 --- a/packages/keymaster/src/cli.ts +++ b/packages/keymaster/src/cli.ts @@ -837,6 +837,19 @@ program } }); +program + .command('lightning-decode ') + .description('Decode a Lightning BOLT11 invoice') + .action(async (bolt11) => { + try { + const info = await keymaster.decodeLightningInvoice(bolt11); + console.log(JSON.stringify(info, null, 4)); + } + catch (error: any) { + console.error(error.error || error.message || error); + } + }); + program .command('lightning-invoice [id]') .description('Create a Lightning invoice to receive sats') diff --git a/packages/keymaster/src/keymaster-client.ts b/packages/keymaster/src/keymaster-client.ts index 51e8a33c..38c86b41 100644 --- a/packages/keymaster/src/keymaster-client.ts +++ b/packages/keymaster/src/keymaster-client.ts @@ -26,6 +26,7 @@ import { LightningInvoice, LightningPayment, LightningPaymentStatus, + DecodedLightningInvoice, NostrKeys, NostrEvent, NoticeMessage, @@ -541,6 +542,16 @@ export default class KeymasterClient implements KeymasterInterface { } } + async decodeLightningInvoice(bolt11: string): Promise { + try { + const response = await this.axios.post(`${this.API}/lightning/decode`, { bolt11 }); + return response.data; + } + catch (error) { + throwError(error); + } + } + async resolveDID( id: string, options?: ResolveDIDOptions diff --git a/packages/keymaster/src/keymaster.ts b/packages/keymaster/src/keymaster.ts index 4701c41b..55828f57 100644 --- a/packages/keymaster/src/keymaster.ts +++ b/packages/keymaster/src/keymaster.ts @@ -1,5 +1,6 @@ import { imageSize } from 'image-size'; import { fileTypeFromBuffer } from 'file-type'; +import { decode as decodeBolt11 } from 'light-bolt11-decoder'; import { base64url } from 'multiformats/bases/base64'; import { InvalidDIDError, @@ -47,6 +48,7 @@ import { LightningInvoice, LightningPayment, LightningPaymentStatus, + DecodedLightningInvoice, NostrKeys, NostrEvent, NoticeMessage, @@ -1863,6 +1865,47 @@ export default class Keymaster implements KeymasterInterface { }; } + async decodeLightningInvoice(bolt11: string): Promise { + if (!bolt11) { + throw new InvalidParameterError('bolt11'); + } + + const decoded = decodeBolt11(bolt11); + const info: DecodedLightningInvoice = {}; + + let timestamp: number | undefined; + + for (const section of decoded.sections) { + switch (section.name) { + case 'amount': + info.amount = `${parseInt(section.value) / 1000} sats`; + break; + case 'description': + info.description = section.value; + break; + case 'timestamp': + timestamp = section.value; + info.created = new Date(section.value * 1000).toISOString(); + break; + case 'expiry': + info.expiry = `${section.value} seconds`; + break; + case 'payment_hash': + info.payment_hash = section.value; + break; + case 'coin_network': + info.network = section.value?.bech32; + break; + } + } + + if (timestamp !== undefined && decoded.expiry !== undefined) { + info.expires = new Date((timestamp + decoded.expiry) * 1000).toISOString(); + } + + return info; + } + async testAgent(id: string): Promise { const doc = await this.resolveDID(id); return doc.didDocumentRegistration?.type === 'agent'; diff --git a/packages/keymaster/src/types.ts b/packages/keymaster/src/types.ts index 9f0330bd..5db657c5 100644 --- a/packages/keymaster/src/types.ts +++ b/packages/keymaster/src/types.ts @@ -248,6 +248,16 @@ export type { LightningPaymentStatus, } from '@didcid/gatekeeper/types'; +export interface DecodedLightningInvoice { + amount?: string; + description?: string; + created?: string; + expiry?: string; + expires?: string; + payment_hash?: string; + network?: string; +} + export interface KeymasterOptions { passphrase: string; gatekeeper: GatekeeperInterface; @@ -355,6 +365,7 @@ export interface KeymasterInterface { createLightningInvoice(amount: number, memo: string, id?: string): Promise; payLightningInvoice(bolt11: string, id?: string): Promise; checkLightningPayment(paymentHash: string, id?: string): Promise; + decodeLightningInvoice(bolt11: string): Promise; // DIDs resolveDID(did: string, options?: ResolveDIDOptions): Promise; diff --git a/python/keymaster_sdk/src/keymaster_sdk/__init__.py b/python/keymaster_sdk/src/keymaster_sdk/__init__.py index 38ba1b43..ea920689 100644 --- a/python/keymaster_sdk/src/keymaster_sdk/__init__.py +++ b/python/keymaster_sdk/src/keymaster_sdk/__init__.py @@ -2,6 +2,9 @@ accept_credential, add_dmail_attachment, add_group_member, + add_lightning, + add_nostr, + add_poll_voter, add_vault_item, add_vault_member, add_alias, @@ -9,24 +12,32 @@ backup_id, backup_wallet, bind_credential, + change_passphrase, + check_lightning_payment, check_wallet, + clone_asset, + create_asset, create_dmail, create_file, create_id, create_image, create_challenge, create_group, + create_lightning_invoice, create_vault, create_notice, create_poll, create_response, create_schema, create_template, + decode_lightning_invoice, decrypt_json, decrypt_message, decrypt_mnemonic, encrypt_json, encrypt_message, + export_encrypted_wallet, + export_nsec, file_dmail, fix_wallet, get_credential, @@ -35,14 +46,18 @@ get_dmail_message, get_file, get_group, + get_ipfs_data, + get_lightning_balance, get_vault, get_vault_item, get_image, + get_poll, get_schema, import_dmail, is_ready, issue_credential, KeymasterError, + list_assets, list_credentials, list_dmail, list_dmail_attachments, @@ -52,10 +67,14 @@ list_ids, list_issued, list_aliases, + list_poll_voters, + list_polls, list_registries, list_schemas, load_wallet, + merge_data, new_wallet, + pay_lightning_invoice, poll_template, publish_credential, publish_poll, @@ -66,29 +85,39 @@ remove_dmail, remove_dmail_attachment, remove_group_member, + remove_lightning, + remove_nostr, + remove_poll_voter, remove_vault_item, remove_vault_member, remove_alias, remove_id, resolve_asset, resolve_did, + rename_id, revoke_credential, revoke_did, rotate_keys, + send_ballot, send_credential, send_dmail, + send_poll, set_current_id, set_schema, set_api_key, set_url, save_wallet, + sign_nostr_event, test_agent, test_file, test_group, test_vault, test_image, + test_poll, test_schema, + transfer_asset, update_credential, + update_did, update_dmail, update_file, update_image, @@ -98,6 +127,7 @@ unpublish_poll, verify_response, verify_proof, + view_ballot, view_poll, vote_poll, ) diff --git a/python/keymaster_sdk/src/keymaster_sdk/keymaster_sdk.py b/python/keymaster_sdk/src/keymaster_sdk/keymaster_sdk.py index 4713e507..fd7167b7 100644 --- a/python/keymaster_sdk/src/keymaster_sdk/keymaster_sdk.py +++ b/python/keymaster_sdk/src/keymaster_sdk/keymaster_sdk.py @@ -911,3 +911,224 @@ def get_file(identifier): def test_file(identifier): response = proxy_request("POST", f"{_keymaster_api}/files/{identifier}/test") return response["test"] + + +# Wallet extras + +def change_passphrase(passphrase): + response = proxy_request( + "POST", + f"{_keymaster_api}/wallet/passphrase", + json={"passphrase": passphrase}, + ) + return response["ok"] + + +def export_encrypted_wallet(): + response = proxy_request("GET", f"{_keymaster_api}/export/wallet/encrypted") + return response["wallet"] + + +# DID updates + +def update_did(identifier, doc): + response = proxy_request( + "PUT", + f"{_keymaster_api}/did/{identifier}", + json={"doc": doc}, + ) + return response["ok"] + + +# Asset management + +def create_asset(data, options=None): + if options is None: + options = {} + response = proxy_request( + "POST", + f"{_keymaster_api}/assets", + json={"data": data, "options": options}, + ) + return response["did"] + + +def list_assets(): + response = proxy_request("GET", f"{_keymaster_api}/assets") + return response["assets"] + + +def clone_asset(identifier, options=None): + if options is None: + options = {} + response = proxy_request( + "POST", + f"{_keymaster_api}/assets/{identifier}/clone", + json={"options": options}, + ) + return response["did"] + + +def merge_data(identifier, data): + response = proxy_request( + "PUT", + f"{_keymaster_api}/assets/{identifier}", + json={"data": data}, + ) + return response["ok"] + + +def transfer_asset(identifier, controller): + response = proxy_request( + "POST", + f"{_keymaster_api}/assets/{identifier}/transfer", + json={"controller": controller}, + ) + return response["ok"] + + +# Poll extras + +def send_poll(poll): + response = proxy_request("POST", f"{_keymaster_api}/polls/{poll}/send") + return response["did"] + + +def send_ballot(ballot, poll): + response = proxy_request( + "POST", + f"{_keymaster_api}/polls/ballot/send", + json={"ballot": ballot, "poll": poll}, + ) + return response["did"] + + +def view_ballot(did): + response = proxy_request("GET", f"{_keymaster_api}/polls/ballot/{did}") + return response["ballot"] + + +def add_poll_voter(poll, member_id): + response = proxy_request( + "POST", + f"{_keymaster_api}/polls/{poll}/voters", + json={"memberId": member_id}, + ) + return response["ok"] + + +def remove_poll_voter(poll, voter): + safe = requests.utils.quote(str(voter), safe="") + response = proxy_request( + "DELETE", + f"{_keymaster_api}/polls/{poll}/voters/{safe}", + ) + return response["ok"] + + +def list_poll_voters(poll): + response = proxy_request("GET", f"{_keymaster_api}/polls/{poll}/voters") + return response["voters"] + + +# Nostr + +def add_nostr(id=None): + response = proxy_request( + "POST", + f"{_keymaster_api}/nostr", + json={"id": id}, + ) + return response + + +def remove_nostr(id=None): + response = proxy_request( + "DELETE", + f"{_keymaster_api}/nostr", + json={"id": id}, + ) + return response["ok"] + + +def export_nsec(id=None): + response = proxy_request( + "POST", + f"{_keymaster_api}/nostr/nsec", + json={"id": id}, + ) + return response["nsec"] + + +def sign_nostr_event(event): + response = proxy_request( + "POST", + f"{_keymaster_api}/nostr/sign", + json={"event": event}, + ) + return response + + +# Lightning + +def add_lightning(id=None): + response = proxy_request( + "POST", + f"{_keymaster_api}/lightning", + json={"id": id}, + ) + return response + + +def remove_lightning(id=None): + response = proxy_request( + "DELETE", + f"{_keymaster_api}/lightning", + json={"id": id}, + ) + return response["ok"] + + +def get_lightning_balance(id=None): + response = proxy_request( + "POST", + f"{_keymaster_api}/lightning/balance", + json={"id": id}, + ) + return response + + +def create_lightning_invoice(amount, memo, id=None): + response = proxy_request( + "POST", + f"{_keymaster_api}/lightning/invoice", + json={"amount": amount, "memo": memo, "id": id}, + ) + return response + + +def pay_lightning_invoice(bolt11, id=None): + response = proxy_request( + "POST", + f"{_keymaster_api}/lightning/pay", + json={"bolt11": bolt11, "id": id}, + ) + return response + + +def check_lightning_payment(payment_hash, id=None): + response = proxy_request( + "POST", + f"{_keymaster_api}/lightning/payment", + json={"paymentHash": payment_hash, "id": id}, + ) + return response + + +def decode_lightning_invoice(bolt11): + response = proxy_request( + "POST", + f"{_keymaster_api}/lightning/decode", + json={"bolt11": bolt11}, + ) + return response diff --git a/services/keymaster/server/src/keymaster-api.ts b/services/keymaster/server/src/keymaster-api.ts index afa65622..df23104e 100644 --- a/services/keymaster/server/src/keymaster-api.ts +++ b/services/keymaster/server/src/keymaster-api.ts @@ -2133,6 +2133,36 @@ v1router.post('/lightning/payment', async (req, res) => { } }); +/** + * @swagger + * /lightning/decode: + * post: + * summary: Decode a Lightning BOLT11 invoice. + * requestBody: + * required: true + * content: + * application/json: + * schema: + * type: object + * properties: + * bolt11: + * type: string + * responses: + * 200: + * description: Decoded invoice details. + * 400: + * description: Error decoding invoice. + */ +v1router.post('/lightning/decode', async (req, res) => { + try { + const { bolt11 } = req.body; + const info = await keymaster.decodeLightningInvoice(bolt11); + res.json(info); + } catch (error: any) { + res.status(400).send({ error: error.toString() }); + } +}); + /** * @swagger * /challenge: diff --git a/tests/keymaster/client.test.ts b/tests/keymaster/client.test.ts index 0ff4ba36..a4732d91 100644 --- a/tests/keymaster/client.test.ts +++ b/tests/keymaster/client.test.ts @@ -45,6 +45,12 @@ const Endpoints = { dmail: '/api/v1/dmail', notices: '/api/v1/notices', export_wallet_encrypted: '/api/v1/export/wallet/encrypted', + lightning: '/api/v1/lightning', + lightning_balance: '/api/v1/lightning/balance', + lightning_invoice: '/api/v1/lightning/invoice', + lightning_pay: '/api/v1/lightning/pay', + lightning_payment: '/api/v1/lightning/payment', + lightning_decode: '/api/v1/lightning/decode', }; const mockConsole = { @@ -3597,3 +3603,219 @@ describe('exportEncryptedWallet', () => { } }); }); + +describe('addLightning', () => { + const mockConfig = { walletId: 'w1', adminKey: 'admin1', invoiceKey: 'invoice1' }; + + it('should add Lightning wallet', async () => { + nock(KeymasterURL) + .post(Endpoints.lightning) + .reply(200, mockConfig); + + const keymaster = await KeymasterClient.create({ url: KeymasterURL }); + const config = await keymaster.addLightning(); + + expect(config).toStrictEqual(mockConfig); + }); + + it('should throw exception on addLightning server error', async () => { + nock(KeymasterURL) + .post(Endpoints.lightning) + .reply(500, ServerError); + + const keymaster = await KeymasterClient.create({ url: KeymasterURL }); + + try { + await keymaster.addLightning(); + throw new ExpectedExceptionError(); + } + catch (error: any) { + expect(error.message).toBe(ServerError.message); + } + }); +}); + +describe('removeLightning', () => { + it('should remove Lightning wallet', async () => { + nock(KeymasterURL) + .delete(Endpoints.lightning) + .reply(200, { ok: true }); + + const keymaster = await KeymasterClient.create({ url: KeymasterURL }); + const ok = await keymaster.removeLightning(); + + expect(ok).toBe(true); + }); + + it('should throw exception on removeLightning server error', async () => { + nock(KeymasterURL) + .delete(Endpoints.lightning) + .reply(500, ServerError); + + const keymaster = await KeymasterClient.create({ url: KeymasterURL }); + + try { + await keymaster.removeLightning(); + throw new ExpectedExceptionError(); + } + catch (error: any) { + expect(error.message).toBe(ServerError.message); + } + }); +}); + +describe('getLightningBalance', () => { + it('should return balance', async () => { + nock(KeymasterURL) + .post(Endpoints.lightning_balance) + .reply(200, { balance: 1000 }); + + const keymaster = await KeymasterClient.create({ url: KeymasterURL }); + const result = await keymaster.getLightningBalance(); + + expect(result.balance).toBe(1000); + }); + + it('should throw exception on getLightningBalance server error', async () => { + nock(KeymasterURL) + .post(Endpoints.lightning_balance) + .reply(500, ServerError); + + const keymaster = await KeymasterClient.create({ url: KeymasterURL }); + + try { + await keymaster.getLightningBalance(); + throw new ExpectedExceptionError(); + } + catch (error: any) { + expect(error.message).toBe(ServerError.message); + } + }); +}); + +describe('createLightningInvoice', () => { + const mockInvoice = { paymentRequest: 'lnbc100...', paymentHash: 'hash123' }; + + it('should create an invoice', async () => { + nock(KeymasterURL) + .post(Endpoints.lightning_invoice) + .reply(200, mockInvoice); + + const keymaster = await KeymasterClient.create({ url: KeymasterURL }); + const invoice = await keymaster.createLightningInvoice(100, 'test payment'); + + expect(invoice).toStrictEqual(mockInvoice); + }); + + it('should throw exception on createLightningInvoice server error', async () => { + nock(KeymasterURL) + .post(Endpoints.lightning_invoice) + .reply(500, ServerError); + + const keymaster = await KeymasterClient.create({ url: KeymasterURL }); + + try { + await keymaster.createLightningInvoice(100, 'test'); + throw new ExpectedExceptionError(); + } + catch (error: any) { + expect(error.message).toBe(ServerError.message); + } + }); +}); + +describe('payLightningInvoice', () => { + it('should pay an invoice', async () => { + nock(KeymasterURL) + .post(Endpoints.lightning_pay) + .reply(200, { paymentHash: 'out-hash' }); + + const keymaster = await KeymasterClient.create({ url: KeymasterURL }); + const payment = await keymaster.payLightningInvoice('lnbc100...'); + + expect(payment.paymentHash).toBe('out-hash'); + }); + + it('should throw exception on payLightningInvoice server error', async () => { + nock(KeymasterURL) + .post(Endpoints.lightning_pay) + .reply(500, ServerError); + + const keymaster = await KeymasterClient.create({ url: KeymasterURL }); + + try { + await keymaster.payLightningInvoice('lnbc100...'); + throw new ExpectedExceptionError(); + } + catch (error: any) { + expect(error.message).toBe(ServerError.message); + } + }); +}); + +describe('checkLightningPayment', () => { + const mockStatus = { paid: true, preimage: 'preimage123', paymentHash: 'hash123' }; + + it('should check payment status', async () => { + nock(KeymasterURL) + .post(Endpoints.lightning_payment) + .reply(200, mockStatus); + + const keymaster = await KeymasterClient.create({ url: KeymasterURL }); + const status = await keymaster.checkLightningPayment('hash123'); + + expect(status).toStrictEqual(mockStatus); + }); + + it('should throw exception on checkLightningPayment server error', async () => { + nock(KeymasterURL) + .post(Endpoints.lightning_payment) + .reply(500, ServerError); + + const keymaster = await KeymasterClient.create({ url: KeymasterURL }); + + try { + await keymaster.checkLightningPayment('hash123'); + throw new ExpectedExceptionError(); + } + catch (error: any) { + expect(error.message).toBe(ServerError.message); + } + }); +}); + +describe('decodeLightningInvoice', () => { + const mockDecoded = { + amount: '250000 sats', + description: '1 cup coffee', + payment_hash: '0001020304050607080900010203040506070809000102030405060708090102', + network: 'bc', + }; + + it('should decode an invoice', async () => { + nock(KeymasterURL) + .post(Endpoints.lightning_decode) + .reply(200, mockDecoded); + + const keymaster = await KeymasterClient.create({ url: KeymasterURL }); + const info = await keymaster.decodeLightningInvoice('lnbc2500u1...'); + + expect(info).toStrictEqual(mockDecoded); + }); + + it('should throw exception on decodeLightningInvoice server error', async () => { + nock(KeymasterURL) + .post(Endpoints.lightning_decode) + .reply(500, ServerError); + + const keymaster = await KeymasterClient.create({ url: KeymasterURL }); + + try { + await keymaster.decodeLightningInvoice('lnbc2500u1...'); + throw new ExpectedExceptionError(); + } + catch (error: any) { + expect(error.message).toBe(ServerError.message); + } + }); +}); diff --git a/tests/keymaster/lightning.test.ts b/tests/keymaster/lightning.test.ts index c5a28d75..ceb4430d 100644 --- a/tests/keymaster/lightning.test.ts +++ b/tests/keymaster/lightning.test.ts @@ -3,7 +3,7 @@ import Keymaster from '@didcid/keymaster'; import CipherNode from '@didcid/cipher/node'; import DbJsonMemory from '@didcid/gatekeeper/db/json-memory'; import WalletJsonMemory from '@didcid/keymaster/wallet/json-memory'; -import { UnknownIDError, LightningNotConfiguredError, LightningUnavailableError } from '@didcid/common/errors'; +import { UnknownIDError, InvalidParameterError, LightningNotConfiguredError, LightningUnavailableError } from '@didcid/common/errors'; import HeliaClient from '@didcid/ipfs/helia'; let ipfs: HeliaClient; @@ -357,6 +357,61 @@ describe('checkLightningPayment', () => { }); }); +// BOLT11 test vectors from the spec (https://github.com/lightning/bolts/blob/master/11-payment-encoding.md) +const COFFEE_INVOICE = 'lnbc2500u1pvjluezsp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygspp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5xysxxatsyp3k7enxv4jsxqzpu9qrsgquk0rl77nj30yxdy8j9vdx85fkpmdla2087ne0xh8nhedh8w27kyke0lp53ut353s06fv3qfegext0eh0ymjpf39tuven09sam30g4vgpfna3rh'; +const DONATION_INVOICE = 'lnbc1pvjluezsp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygspp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdpl2pkx2ctnv5sxxmmwwd5kgetjypeh2ursdae8g6twvus8g6rfwvs8qun0dfjkxaq9qrsgq357wnc5r2ueh7ck6q93dj32dlqnls087fxdwk8qakdyafkq3yap9us6v52vjjsrvywa6rt52cm9r9zqt8r2t7mlcwspyetp5h2tztugp9lfyql'; + +describe('decodeLightningInvoice', () => { + it('should decode a coffee invoice with amount and expiry', async () => { + const info = await keymaster.decodeLightningInvoice(COFFEE_INVOICE); + + expect(info.amount).toBe('250000 sats'); + expect(info.description).toBe('1 cup coffee'); + expect(info.payment_hash).toBe('0001020304050607080900010203040506070809000102030405060708090102'); + expect(info.expiry).toBe('60 seconds'); + expect(info.network).toBe('bc'); + expect(info.created).toBeDefined(); + expect(info.expires).toBeDefined(); + }); + + it('should decode a donation invoice with no amount', async () => { + const info = await keymaster.decodeLightningInvoice(DONATION_INVOICE); + + expect(info.amount).toBeUndefined(); + expect(info.description).toBe('Please consider supporting this project'); + expect(info.payment_hash).toBe('0001020304050607080900010203040506070809000102030405060708090102'); + expect(info.network).toBe('bc'); + }); + + it('should compute expires from timestamp + expiry', async () => { + const info = await keymaster.decodeLightningInvoice(COFFEE_INVOICE); + + const expectedExpires = new Date((1496314658 + 60) * 1000).toISOString(); + expect(info.expires).toBe(expectedExpires); + }); + + it('should not set expires when no expiry in invoice', async () => { + const info = await keymaster.decodeLightningInvoice(DONATION_INVOICE); + + expect(info.expiry).toBeUndefined(); + expect(info.expires).toBeUndefined(); + }); + + it('should throw for empty bolt11', async () => { + try { + await keymaster.decodeLightningInvoice(''); + throw new Error('Expected exception'); + } + catch (error: any) { + expect(error.type).toBe(InvalidParameterError.type); + } + }); + + it('should throw for invalid bolt11 string', async () => { + await expect(keymaster.decodeLightningInvoice('not-a-valid-invoice')).rejects.toThrow(); + }); +}); + describe('Lightning without Drawbridge', () => { it('should throw when gatekeeper has no Lightning methods', async () => { const db = new DbJsonMemory('test');