From 655672b32940093634f7c41bb7ebf3496df38859 Mon Sep 17 00:00:00 2001 From: David McFadzean Date: Sun, 1 Mar 2026 22:29:20 -0500 Subject: [PATCH 1/5] feat: Add decodeLightningInvoice to Keymaster (#145) Add BOLT11 invoice decoding so users can inspect Lightning invoices before paying. Includes Keymaster method, API endpoint, CLI command, and full test coverage using BOLT11 spec test vectors. Co-Authored-By: Claude Opus 4.6 --- package-lock.json | 397 +----------------- packages/gatekeeper/src/drawbridge-client.ts | 2 +- packages/keymaster/package.json | 1 + packages/keymaster/src/cli.ts | 13 + packages/keymaster/src/keymaster-client.ts | 11 + packages/keymaster/src/keymaster.ts | 43 ++ packages/keymaster/src/types.ts | 11 + .../keymaster/server/src/keymaster-api.ts | 30 ++ tests/keymaster/client.test.ts | 222 ++++++++++ tests/keymaster/lightning.test.ts | 59 ++- 10 files changed, 412 insertions(+), 377 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7c85ab33..7b5f4dfe 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7480,381 +7480,6 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.59.0.tgz", - "integrity": "sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "peer": true - }, - "node_modules/@rollup/rollup-android-arm64": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.59.0.tgz", - "integrity": "sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "peer": true - }, - "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.59.0.tgz", - "integrity": "sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "peer": true - }, - "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.59.0.tgz", - "integrity": "sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "peer": true - }, - "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.59.0.tgz", - "integrity": "sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "peer": true - }, - "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.59.0.tgz", - "integrity": "sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "peer": true - }, - "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.59.0.tgz", - "integrity": "sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "peer": true - }, - "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.59.0.tgz", - "integrity": "sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "peer": true - }, - "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.59.0.tgz", - "integrity": "sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "peer": true - }, - "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.59.0.tgz", - "integrity": "sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "peer": true - }, - "node_modules/@rollup/rollup-linux-loong64-gnu": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.59.0.tgz", - "integrity": "sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "peer": true - }, - "node_modules/@rollup/rollup-linux-loong64-musl": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.59.0.tgz", - "integrity": "sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "peer": true - }, - "node_modules/@rollup/rollup-linux-ppc64-gnu": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.59.0.tgz", - "integrity": "sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "peer": true - }, - "node_modules/@rollup/rollup-linux-ppc64-musl": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.59.0.tgz", - "integrity": "sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "peer": true - }, - "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.59.0.tgz", - "integrity": "sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "peer": true - }, - "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.59.0.tgz", - "integrity": "sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "peer": true - }, - "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.59.0.tgz", - "integrity": "sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "peer": true - }, - "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.59.0.tgz", - "integrity": "sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "peer": true - }, - "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.59.0.tgz", - "integrity": "sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "peer": true - }, - "node_modules/@rollup/rollup-openbsd-x64": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.59.0.tgz", - "integrity": "sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "peer": true - }, - "node_modules/@rollup/rollup-openharmony-arm64": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.59.0.tgz", - "integrity": "sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ], - "peer": true - }, - "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.59.0.tgz", - "integrity": "sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "peer": true - }, - "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.59.0.tgz", - "integrity": "sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "peer": true - }, - "node_modules/@rollup/rollup-win32-x64-gnu": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.59.0.tgz", - "integrity": "sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "peer": true - }, - "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.59.0.tgz", - "integrity": "sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "peer": true - }, "node_modules/@rtsao/scc": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz", @@ -7869,6 +7494,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", @@ -18065,6 +17702,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", @@ -25921,6 +25567,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..8a822b3f 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 { }; } + decodeLightningInvoice(bolt11: string): DecodedLightningInvoice { + 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..7a63a8ec 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 | DecodedLightningInvoice; // DIDs resolveDID(did: string, options?: ResolveDIDOptions): Promise; diff --git a/services/keymaster/server/src/keymaster-api.ts b/services/keymaster/server/src/keymaster-api.ts index afa65622..7431418d 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 + * /api/v1/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', (req, res) => { + try { + const { bolt11 } = req.body; + const info = 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..68c3d1a9 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,63 @@ 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', () => { + const info = 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', () => { + const info = 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', () => { + const info = 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', () => { + const info = keymaster.decodeLightningInvoice(DONATION_INVOICE); + + expect(info.expiry).toBeUndefined(); + expect(info.expires).toBeUndefined(); + }); + + it('should throw for empty bolt11', () => { + try { + keymaster.decodeLightningInvoice(''); + throw new Error('Expected exception'); + } + catch (error: any) { + expect(error.type).toBe(InvalidParameterError.type); + } + }); + + it('should throw for invalid bolt11 string', () => { + expect(() => { + keymaster.decodeLightningInvoice('not-a-valid-invoice'); + }).toThrow(); + }); +}); + describe('Lightning without Drawbridge', () => { it('should throw when gatekeeper has no Lightning methods', async () => { const db = new DbJsonMemory('test'); From 1a7785427ed23f91f49579d73fd1e064679547f0 Mon Sep 17 00:00:00 2001 From: David McFadzean Date: Sun, 1 Mar 2026 22:41:43 -0500 Subject: [PATCH 2/5] feat: Add missing methods to Python SDK Add 26 methods to bring the Python SDK in sync with the JS client: - Lightning: add, remove, balance, invoice, pay, check, decode - Nostr: add, remove, export_nsec, sign_event - Assets: create, list, clone, merge_data, transfer - Polls: send_poll, send_ballot, view_ballot, add/remove/list voters - Wallet: change_passphrase, export_encrypted_wallet - DID: update_did Co-Authored-By: Claude Opus 4.6 --- .../src/keymaster_sdk/__init__.py | 30 +++ .../src/keymaster_sdk/keymaster_sdk.py | 221 ++++++++++++++++++ 2 files changed, 251 insertions(+) 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 From 096dbb45555b0a09b4c1b7e94d41f7e7ea428e51 Mon Sep 17 00:00:00 2001 From: David McFadzean Date: Sun, 1 Mar 2026 22:43:38 -0500 Subject: [PATCH 3/5] Build fix --- package-lock.json | 807 ++++++++++++++++++++++++++++++++++------------ 1 file changed, 598 insertions(+), 209 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7b5f4dfe..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": { @@ -7480,6 +7480,381 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.59.0.tgz", + "integrity": "sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "peer": true + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.59.0.tgz", + "integrity": "sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "peer": true + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.59.0.tgz", + "integrity": "sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "peer": true + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.59.0.tgz", + "integrity": "sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "peer": true + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.59.0.tgz", + "integrity": "sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "peer": true + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.59.0.tgz", + "integrity": "sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "peer": true + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.59.0.tgz", + "integrity": "sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.59.0.tgz", + "integrity": "sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.59.0.tgz", + "integrity": "sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.59.0.tgz", + "integrity": "sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.59.0.tgz", + "integrity": "sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.59.0.tgz", + "integrity": "sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.59.0.tgz", + "integrity": "sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.59.0.tgz", + "integrity": "sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.59.0.tgz", + "integrity": "sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.59.0.tgz", + "integrity": "sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.59.0.tgz", + "integrity": "sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.59.0.tgz", + "integrity": "sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.59.0.tgz", + "integrity": "sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.59.0.tgz", + "integrity": "sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "peer": true + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.59.0.tgz", + "integrity": "sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "peer": true + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.59.0.tgz", + "integrity": "sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "peer": true + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.59.0.tgz", + "integrity": "sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "peer": true + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.59.0.tgz", + "integrity": "sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "peer": true + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.59.0.tgz", + "integrity": "sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "peer": true + }, "node_modules/@rtsao/scc": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz", @@ -7663,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", @@ -7767,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": { @@ -9050,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", @@ -9734,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": { @@ -9921,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", @@ -10391,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": { @@ -10404,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": { @@ -10486,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": { @@ -10934,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": { @@ -11018,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": { @@ -11550,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": { @@ -12499,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", @@ -13660,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": { @@ -13715,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": { @@ -14396,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 }, @@ -14640,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": { @@ -14906,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", @@ -17159,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", @@ -17205,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", @@ -17228,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", @@ -17381,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": { @@ -17480,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": { @@ -18128,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": { @@ -18155,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", @@ -18183,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": { @@ -18216,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": { @@ -18245,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": { @@ -18265,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": { @@ -18301,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": { @@ -18315,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": { @@ -18328,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": { @@ -18342,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": { @@ -18352,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" }, @@ -18373,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" @@ -18404,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": { @@ -18422,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": { @@ -18433,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": { @@ -19722,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": { @@ -19830,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": { @@ -21063,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", @@ -21313,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", @@ -21335,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", @@ -22242,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" @@ -23766,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": { From 68a2c1bc2cee554f747f945f2e55795bf0af7c40 Mon Sep 17 00:00:00 2001 From: David McFadzean Date: Sun, 1 Mar 2026 22:45:15 -0500 Subject: [PATCH 4/5] Updated swagger docs --- doc/gatekeeper-api.json | 14 ++- doc/keymaster-api.json | 251 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 262 insertions(+), 3 deletions(-) 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..d61ddf41 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." + } + } + } + }, + "/api/v1/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.", From 5c941d7e2373da06519389c9be236d03839ac768 Mon Sep 17 00:00:00 2001 From: David McFadzean Date: Mon, 2 Mar 2026 11:27:08 -0500 Subject: [PATCH 5/5] fix: Address PR review comments - Make decodeLightningInvoice consistently async (Promise interface) - Fix Swagger path annotation: /api/v1/lightning/decode -> /lightning/decode - Regenerate OpenAPI spec with corrected path - Update lightning decode unit tests to await async method Co-Authored-By: Claude Opus 4.6 --- doc/keymaster-api.json | 2 +- packages/keymaster/src/keymaster.ts | 2 +- packages/keymaster/src/types.ts | 2 +- .../keymaster/server/src/keymaster-api.ts | 6 ++--- tests/keymaster/lightning.test.ts | 26 +++++++++---------- 5 files changed, 18 insertions(+), 20 deletions(-) diff --git a/doc/keymaster-api.json b/doc/keymaster-api.json index d61ddf41..1c427101 100644 --- a/doc/keymaster-api.json +++ b/doc/keymaster-api.json @@ -2296,7 +2296,7 @@ } } }, - "/api/v1/lightning/decode": { + "/lightning/decode": { "post": { "summary": "Decode a Lightning BOLT11 invoice.", "requestBody": { diff --git a/packages/keymaster/src/keymaster.ts b/packages/keymaster/src/keymaster.ts index 8a822b3f..55828f57 100644 --- a/packages/keymaster/src/keymaster.ts +++ b/packages/keymaster/src/keymaster.ts @@ -1865,7 +1865,7 @@ export default class Keymaster implements KeymasterInterface { }; } - decodeLightningInvoice(bolt11: string): DecodedLightningInvoice { + async decodeLightningInvoice(bolt11: string): Promise { if (!bolt11) { throw new InvalidParameterError('bolt11'); } diff --git a/packages/keymaster/src/types.ts b/packages/keymaster/src/types.ts index 7a63a8ec..5db657c5 100644 --- a/packages/keymaster/src/types.ts +++ b/packages/keymaster/src/types.ts @@ -365,7 +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 | DecodedLightningInvoice; + decodeLightningInvoice(bolt11: string): Promise; // DIDs resolveDID(did: string, options?: ResolveDIDOptions): Promise; diff --git a/services/keymaster/server/src/keymaster-api.ts b/services/keymaster/server/src/keymaster-api.ts index 7431418d..df23104e 100644 --- a/services/keymaster/server/src/keymaster-api.ts +++ b/services/keymaster/server/src/keymaster-api.ts @@ -2135,7 +2135,7 @@ v1router.post('/lightning/payment', async (req, res) => { /** * @swagger - * /api/v1/lightning/decode: + * /lightning/decode: * post: * summary: Decode a Lightning BOLT11 invoice. * requestBody: @@ -2153,10 +2153,10 @@ v1router.post('/lightning/payment', async (req, res) => { * 400: * description: Error decoding invoice. */ -v1router.post('/lightning/decode', (req, res) => { +v1router.post('/lightning/decode', async (req, res) => { try { const { bolt11 } = req.body; - const info = keymaster.decodeLightningInvoice(bolt11); + const info = await keymaster.decodeLightningInvoice(bolt11); res.json(info); } catch (error: any) { res.status(400).send({ error: error.toString() }); diff --git a/tests/keymaster/lightning.test.ts b/tests/keymaster/lightning.test.ts index 68c3d1a9..ceb4430d 100644 --- a/tests/keymaster/lightning.test.ts +++ b/tests/keymaster/lightning.test.ts @@ -362,8 +362,8 @@ const COFFEE_INVOICE = 'lnbc2500u1pvjluezsp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3 const DONATION_INVOICE = 'lnbc1pvjluezsp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygspp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdpl2pkx2ctnv5sxxmmwwd5kgetjypeh2ursdae8g6twvus8g6rfwvs8qun0dfjkxaq9qrsgq357wnc5r2ueh7ck6q93dj32dlqnls087fxdwk8qakdyafkq3yap9us6v52vjjsrvywa6rt52cm9r9zqt8r2t7mlcwspyetp5h2tztugp9lfyql'; describe('decodeLightningInvoice', () => { - it('should decode a coffee invoice with amount and expiry', () => { - const info = keymaster.decodeLightningInvoice(COFFEE_INVOICE); + 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'); @@ -374,8 +374,8 @@ describe('decodeLightningInvoice', () => { expect(info.expires).toBeDefined(); }); - it('should decode a donation invoice with no amount', () => { - const info = keymaster.decodeLightningInvoice(DONATION_INVOICE); + 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'); @@ -383,23 +383,23 @@ describe('decodeLightningInvoice', () => { expect(info.network).toBe('bc'); }); - it('should compute expires from timestamp + expiry', () => { - const info = keymaster.decodeLightningInvoice(COFFEE_INVOICE); + 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', () => { - const info = keymaster.decodeLightningInvoice(DONATION_INVOICE); + 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', () => { + it('should throw for empty bolt11', async () => { try { - keymaster.decodeLightningInvoice(''); + await keymaster.decodeLightningInvoice(''); throw new Error('Expected exception'); } catch (error: any) { @@ -407,10 +407,8 @@ describe('decodeLightningInvoice', () => { } }); - it('should throw for invalid bolt11 string', () => { - expect(() => { - keymaster.decodeLightningInvoice('not-a-valid-invoice'); - }).toThrow(); + it('should throw for invalid bolt11 string', async () => { + await expect(keymaster.decodeLightningInvoice('not-a-valid-invoice')).rejects.toThrow(); }); });