diff --git a/.gitignore b/.gitignore index fb16387f..0af635d4 100644 --- a/.gitignore +++ b/.gitignore @@ -10,4 +10,9 @@ db.sqlite metrics.sqlite .key/ logs -.jwt_secret \ No newline at end of file +.jwt_secret +data/ +.wallet_secret +.wallet_password +.admin_enroll +admin.npub \ No newline at end of file diff --git a/datasource.js b/datasource.js index 16ae8679..9ccbf9e7 100644 --- a/datasource.js +++ b/datasource.js @@ -1,25 +1,31 @@ -import { DataSource } from "typeorm" -import { User } from "./build/src/services/storage/entity/User.js" -import { UserReceivingInvoice } from "./build/src/services/storage/entity/UserReceivingInvoice.js" -import { AddressReceivingTransaction } from "./build/src/services/storage/entity/AddressReceivingTransaction.js" -import { Application } from "./build/src/services/storage/entity/Application.js" -import { ApplicationUser } from "./build/src/services/storage/entity/ApplicationUser.js" -import { BalanceEvent } from "./build/src/services/storage/entity/BalanceEvent.js" -import { ChannelBalanceEvent } from "./build/src/services/storage/entity/ChannelsBalanceEvent.js" -import { Product } from "./build/src/services/storage/entity/Product.js" -import { RoutingEvent } from "./build/src/services/storage/entity/RoutingEvent.js" -import { UserBasicAuth } from "./build/src/services/storage/entity/UserBasicAuth.js" -import { UserEphemeralKey } from "./build/src/services/storage/entity/UserEphemeralKey.js" -import { UserInvoicePayment } from "./build/src/services/storage/entity/UserInvoicePayment.js" -import { UserReceivingAddress } from "./build/src/services/storage/entity/UserReceivingAddress.js" -import { UserToUserPayment } from "./build/src/services/storage/entity/UserToUserPayment.js" -import { UserTransactionPayment } from "./build/src/services/storage/entity/UserTransactionPayment.js" - -export default new DataSource({ - type: "sqlite", - database: "source.sqlite", - // logging: true, - entities: [User, UserReceivingInvoice, UserReceivingAddress, AddressReceivingTransaction, UserInvoicePayment, UserTransactionPayment, - UserBasicAuth, UserEphemeralKey, Product, UserToUserPayment, Application, ApplicationUser, UserToUserPayment, RoutingEvent, BalanceEvent, ChannelBalanceEvent], - // synchronize: true, -}) \ No newline at end of file +import { DataSource } from "typeorm" +import { User } from "./build/src/services/storage/entity/User.js" +import { UserReceivingInvoice } from "./build/src/services/storage/entity/UserReceivingInvoice.js" +import { AddressReceivingTransaction } from "./build/src/services/storage/entity/AddressReceivingTransaction.js" +import { Application } from "./build/src/services/storage/entity/Application.js" +import { ApplicationUser } from "./build/src/services/storage/entity/ApplicationUser.js" +import { Product } from "./build/src/services/storage/entity/Product.js" +import { UserBasicAuth } from "./build/src/services/storage/entity/UserBasicAuth.js" +import { UserEphemeralKey } from "./build/src/services/storage/entity/UserEphemeralKey.js" +import { UserInvoicePayment } from "./build/src/services/storage/entity/UserInvoicePayment.js" +import { UserReceivingAddress } from "./build/src/services/storage/entity/UserReceivingAddress.js" +import { UserToUserPayment } from "./build/src/services/storage/entity/UserToUserPayment.js" +import { UserTransactionPayment } from "./build/src/services/storage/entity/UserTransactionPayment.js" +import { LspOrder } from "./build/src/services/storage/entity/LspOrder.js" +import { LndNodeInfo } from "./build/src/services/storage/entity/LndNodeInfo.js" +import { TrackedProvider } from "./build/src/services/storage/entity/TrackedProvider.js" + +import { Initial1703170309875 } from './build/src/services/storage/migrations/1703170309875-initial.js' +import { LspOrder1718387847693 } from './build/src/services/storage/migrations/1718387847693-lsp_order.js' +import { LndNodeInfo1720187506189 } from './build/src/services/storage/migrations/1720187506189-lnd_node_info.js' +import { LiquidityProvider1719335699480 } from './build/src/services/storage/migrations/1719335699480-liquidity_provider.js' +export default new DataSource({ + type: "sqlite", + database: "db.sqlite", + // logging: true, + migrations: [Initial1703170309875, LspOrder1718387847693, LiquidityProvider1719335699480, LndNodeInfo1720187506189], + entities: [User, UserReceivingInvoice, UserReceivingAddress, AddressReceivingTransaction, UserInvoicePayment, UserTransactionPayment, + UserBasicAuth, UserEphemeralKey, Product, UserToUserPayment, Application, ApplicationUser, UserToUserPayment, LspOrder, LndNodeInfo, TrackedProvider], + // synchronize: true, +}) +//npx typeorm migration:generate ./src/services/storage/migrations/lnd_node_info -d ./datasource.js \ No newline at end of file diff --git a/deploy.sh b/deploy.sh deleted file mode 100755 index 7d0ba72c..00000000 --- a/deploy.sh +++ /dev/null @@ -1,399 +0,0 @@ -#!/bin/bash -set -e - -PRIMARY_COLOR="\e[38;5;208m" # #f59322 -SECONDARY_COLOR="\e[38;5;165m" # #c740c7 -RESET_COLOR="\e[0m" - -LOG_FILE="/var/log/deploy.log" - -touch $LOG_FILE -chmod 644 $LOG_FILE - -log() { - local message="$(date '+%Y-%m-%d %H:%M:%S') $1" - if [ -t 1 ]; then - echo -e "$message" - fi - echo -e "$(echo $message | sed 's/\\e\[[0-9;]*m//g')" >> $LOG_FILE -} - -if [ "$EUID" -ne 0 ]; then - log "${PRIMARY_COLOR}Please run as root or use sudo.${RESET_COLOR}" - exit 1 -fi - -check_homebrew() { - if ! command -v brew &> /dev/null; then - log "${PRIMARY_COLOR}Homebrew not found. Installing Homebrew...${RESET_COLOR}" - /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" || { - log "${PRIMARY_COLOR}Failed to install Homebrew.${RESET_COLOR}" - exit 1 - } - fi -} - -install_rsync_mac() { - check_homebrew - log "${PRIMARY_COLOR}Installing${RESET_COLOR} rsync using Homebrew..." - brew install rsync || { - log "${PRIMARY_COLOR}Failed to install rsync.${RESET_COLOR}" - exit 1 - } -} - -create_launchd_plist() { - create_plist() { - local plist_path=$1 - local label=$2 - local program_args=$3 - local working_dir=$4 - - if [ -f "$plist_path" ]; then - log "${PRIMARY_COLOR}${label} already exists. Skipping creation.${RESET_COLOR}" - else - cat < "$plist_path" - - - - - Label - ${label} - ProgramArguments - - ${program_args} - - WorkingDirectory - ${working_dir} - RunAtLoad - - KeepAlive - - - -EOF - fi - } - USER_HOME=$(eval echo ~$(whoami)) - NVM_DIR="$([ -z "${XDG_CONFIG_HOME-}" ] && printf %s "${USER_HOME}/.nvm" || printf %s "${XDG_CONFIG_HOME}/nvm")" - LAUNCH_AGENTS_DIR="${USER_HOME}/Library/LaunchAgents" - - create_plist "${LAUNCH_AGENTS_DIR}/local.lnd.plist" "local.lnd" "${USER_HOME}/lnd/lnd" "" - create_plist "${LAUNCH_AGENTS_DIR}/local.lightning_pub.plist" "local.lightning_pub" "/bin/bash-csource ${NVM_DIR}/nvm.sh && npm start" "${USER_HOME}/lightning_pub" - - log "${PRIMARY_COLOR}Created launchd plists. Please load them using launchctl.${RESET_COLOR}" -} - -start_services_mac() { - create_launchd_plist - launchctl load "${LAUNCH_AGENTS_DIR}/local.lnd.plist" - launchctl load "${LAUNCH_AGENTS_DIR}/local.lightning_pub.plist" - log "${SECONDARY_COLOR}LND${RESET_COLOR} and ${SECONDARY_COLOR}Lightning.Pub${RESET_COLOR} services started using launchd." -} - -handle_macos() { - check_homebrew - install_rsync_mac - install_nodejs - install_lightning_pub - create_launchd_plist # Ensure this function is called - start_services_mac -} - -detect_os_arch() { - OS="$(uname -s)" - ARCH="$(uname -m)" - case "$OS" in - Linux*) OS=Linux;; - Darwin*) OS=Mac;; - CYGWIN*) OS=Cygwin;; - MINGW*) OS=MinGw;; - *) OS="UNKNOWN" - esac - case "$ARCH" in - x86_64) ARCH=amd64;; - arm64) ARCH=arm64;; - *) ARCH="UNKNOWN" - esac - - if [ "$OS" = "Linux" ] && command -v systemctl &> /dev/null; then - SYSTEMCTL_AVAILABLE=true - else - SYSTEMCTL_AVAILABLE=false - fi -} - -install_lnd() { - LND_VERSION=$(wget -qO- https://api.github.com/repos/lightningnetwork/lnd/releases/latest | grep 'tag_name' | cut -d\" -f4) - LND_URL="https://github.com/lightningnetwork/lnd/releases/download/${LND_VERSION}/lnd-${OS}-${ARCH}-${LND_VERSION}.tar.gz" - - # Check if LND is already installed - if [ -d "$HOME/lnd" ]; then - CURRENT_VERSION=$("$HOME/lnd/lnd" --version | grep -oP 'version \K[^\s]+') - if [ "$CURRENT_VERSION" == "${LND_VERSION#v}" ]; then - log "${SECONDARY_COLOR}LND${RESET_COLOR} is already up-to-date (version $CURRENT_VERSION)." - return - else - if [ "$SKIP_PROMPT" != true ]; then - read -p "LND version $CURRENT_VERSION is installed. Do you want to upgrade to version $LND_VERSION? (y/N): " response - case "$response" in - [yY][eE][sS]|[yY]) - log "${PRIMARY_COLOR}Upgrading${RESET_COLOR} ${SECONDARY_COLOR}LND${RESET_COLOR} from version $CURRENT_VERSION to $LND_VERSION..." - ;; - *) - log "$(date '+%Y-%m-%d %H:%M:%S') Upgrade cancelled." - return - ;; - esac - else - log "${PRIMARY_COLOR}Upgrading${RESET_COLOR} ${SECONDARY_COLOR}LND${RESET_COLOR} from version $CURRENT_VERSION to $LND_VERSION..." - fi - fi - fi - - log "${PRIMARY_COLOR}Downloading${RESET_COLOR} ${SECONDARY_COLOR}LND${RESET_COLOR}..." - - # Start the download - wget -q $LND_URL -O lnd.tar.gz || { - log "${PRIMARY_COLOR}Failed to download LND.${RESET_COLOR}" - exit 1 - } - - # Check if LND is already running and stop it if necessary (Linux) - if [ "$OS" = "Linux" ] && [ "$SYSTEMCTL_AVAILABLE" = true ]; then - if systemctl is-active --quiet lnd; then - log "${PRIMARY_COLOR}Stopping${RESET_COLOR} ${SECONDARY_COLOR}LND${RESET_COLOR} service..." - sudo systemctl stop lnd - fi - else - log "${PRIMARY_COLOR}systemctl not found. Please stop ${SECONDARY_COLOR}LND${RESET_COLOR} manually if it is running.${RESET_COLOR}" - fi - - tar -xzf lnd.tar.gz -C ~/ > /dev/null || { - log "${PRIMARY_COLOR}Failed to extract LND.${RESET_COLOR}" - exit 1 - } - rm lnd.tar.gz - mv lnd-* lnd - - # Create .lnd directory if it doesn't exist - mkdir -p ~/.lnd - - # Check if lnd.conf already exists and avoid overwriting it - if [ -f ~/.lnd/lnd.conf ]; then - log "${PRIMARY_COLOR}lnd.conf already exists. Skipping creation of new lnd.conf file.${RESET_COLOR}" - else - cat < ~/.lnd/lnd.conf -bitcoin.mainnet=true -bitcoin.node=neutrino -neutrino.addpeer=neutrino.shock.network -feeurl=https://nodes.lightning.computer/fees/v1/btc-fee-estimates.json -EOF - fi - - log "${SECONDARY_COLOR}LND${RESET_COLOR} installation and configuration completed." -} - -# Use nvm to install nodejs -install_nodejs() { - log "${PRIMARY_COLOR}Checking${RESET_COLOR} for Node.js..." - MINIMUM_VERSION="18.0.0" - - # Load nvm if it already exists - export NVM_DIR="${NVM_DIR}" - [ -s "${NVM_DIR}/nvm.sh" ] && \. "${NVM_DIR}/nvm.sh" - - if ! command -v nvm &> /dev/null; then - NVM_VERSION=$(wget -qO- https://api.github.com/repos/nvm-sh/nvm/releases/latest | grep -oP '"tag_name": "\K(.*)(?=")') - wget -qO- https://raw.githubusercontent.com/nvm-sh/nvm/${NVM_VERSION}/install.sh | bash > /dev/null 2>&1 - export NVM_DIR="${NVM_DIR}" - [ -s "${NVM_DIR}/nvm.sh" ] && \. "${NVM_DIR}/nvm.sh" - fi - - if command -v node &> /dev/null; then - NODE_VERSION=$(node -v | sed 's/v//') - if [ "$(printf '%s\n' "$MINIMUM_VERSION" "$NODE_VERSION" | sort -V | head -n1)" = "$MINIMUM_VERSION" ]; then - log "Node.js is already installed and meets the minimum version requirement." - return - else - log "${PRIMARY_COLOR}Updating${RESET_COLOR} Node.js to the LTS version..." - fi - else - log "Node.js is not installed. ${PRIMARY_COLOR}Installing the LTS version...${RESET_COLOR}" - fi - - nvm install --lts || { - log "${PRIMARY_COLOR}Failed to install Node.js.${RESET_COLOR}" - exit 1 - } - - log "Node.js LTS installation completed." -} - -install_lightning_pub() { - log "${PRIMARY_COLOR}Installing${RESET_COLOR} ${SECONDARY_COLOR}Lightning.Pub${RESET_COLOR}..." - REPO_URL="https://github.com/shocknet/Lightning.Pub/tarball/master" - wget $REPO_URL -O lightning_pub.tar.gz > /dev/null 2>&1 || { - log "${PRIMARY_COLOR}Failed to download Lightning.Pub.${RESET_COLOR}" - exit 1 - } - mkdir -p lightning_pub_temp - tar -xvzf lightning_pub.tar.gz -C lightning_pub_temp --strip-components=1 > /dev/null 2>&1 || { - log "${PRIMARY_COLOR}Failed to extract Lightning.Pub.${RESET_COLOR}" - exit 1 - } - rm lightning_pub.tar.gz - - if ! command -v rsync &> /dev/null; then - log "${PRIMARY_COLOR}rsync not found, installing...${RESET_COLOR}" - if [ "$OS" = "Mac" ]; then - brew install rsync - elif [ "$OS" = "Linux" ]; then - if [ -x "$(command -v apt-get)" ]; then - sudo apt-get update > /dev/null 2>&1 - sudo apt-get install -y rsync > /dev/null 2>&1 - elif [ -x "$(command -v yum)" ]; then - sudo yum install -y rsync > /dev/null 2>&1 - else - log "${PRIMARY_COLOR}Package manager not found. Please install rsync manually.${RESET_COLOR}" - exit 1 - fi - else - log "${PRIMARY_COLOR}Package manager not found. Please install rsync manually.${RESET_COLOR}" - exit 1 - fi - fi - - # Merge if upgrade - rsync -av --exclude='*.sqlite' --exclude='.env' --exclude='logs' --exclude='node_modules' lightning_pub_temp/ lightning_pub/ > /dev/null 2>&1 - rm -rf lightning_pub_temp - - # Load nvm and npm - export NVM_DIR="${NVM_DIR}" - [ -s "${NVM_DIR}/nvm.sh" ] && \. "${NVM_DIR}/nvm.sh" - - cd lightning_pub - - log "${PRIMARY_COLOR}Installing${RESET_COLOR} npm dependencies..." - - npm install > npm_install.log 2>&1 || { - log "${PRIMARY_COLOR}Failed to install npm dependencies.${RESET_COLOR}" - exit 1 - } - - log "${SECONDARY_COLOR}Lightning.Pub${RESET_COLOR} installation completed." -} - -create_start_script() { - cat < start.sh -#!/bin/bash -${USER_HOME}/lnd/lnd & -LND_PID=\$! -sleep 10 -npm start & -NODE_PID=\$! -wait \$LND_PID -wait \$NODE_PID -EOF - chmod +x start.sh - log "systemctl not available. Created start.sh. Please use this script to start the services manually." -} - -start_services() { - USER_HOME=$(eval echo ~$(whoami)) - if [ "$OS" = "Linux" ]; then - if [ "$SYSTEMCTL_AVAILABLE" = true ]; then - sudo bash -c "cat > /etc/systemd/system/lnd.service < /etc/systemd/system/lightning_pub.service < #METRICS #RECORD_PERFORMANCE=true diff --git a/proto/CODEGEN.md b/proto/CODEGEN.md index fe66c839..82e7b302 100644 --- a/proto/CODEGEN.md +++ b/proto/CODEGEN.md @@ -1,2 +1,5 @@ create lnd classes: `npx protoc -I ./others --ts_out=./lnd others/*` -create server classes: `npx protoc -I ./service --pub_out=. service/*` \ No newline at end of file +create server classes: `npx protoc -I ./service --pub_out=. service/*` +create wizard classes: `npx protoc -I ./wizard --pub_out=./wizard_service wizard/*` + +export PATH=$PATH:~/Lightning.Pub/proto \ No newline at end of file diff --git a/proto/autogenerated/client.md b/proto/autogenerated/client.md index 8b94cd9f..be3bc649 100644 --- a/proto/autogenerated/client.md +++ b/proto/autogenerated/client.md @@ -1,861 +1,914 @@ -# NOSTR API DEFINITION - - -A nostr request will take the same parameter and give the same response as an http request, but it will use nostr as transport, to do that it will send encrypted events to the server public key, in the event 6 thing are required: -- __rpcName__: string containing the name of the method -- __params__: a map with the all the url params for the method -- __query__: a map with the the url query for the method -- __body__: the body of the method request -- __requestId__: id of the request to be able to get a response - -The nostr server will send back a message response, and inside the body there will also be a __requestId__ to identify the request this response is answering - -## NOSTR Methods -### These are the nostr methods the client implements to communicate with the API via nostr - -- LinkNPubThroughToken - - auth type: __User__ - - input: [LinkNPubThroughTokenRequest](#LinkNPubThroughTokenRequest) - - This methods has an __empty__ __response__ body - -- UserHealth - - auth type: __User__ - - This methods has an __empty__ __request__ body - - This methods has an __empty__ __response__ body - -- GetUserInfo - - auth type: __User__ - - This methods has an __empty__ __request__ body - - output: [UserInfo](#UserInfo) - -- AddProduct - - auth type: __User__ - - input: [AddProductRequest](#AddProductRequest) - - output: [Product](#Product) - -- NewProductInvoice - - auth type: __User__ - - the request url __query__ can take the following string items: - - id - - This methods has an __empty__ __request__ body - - output: [NewInvoiceResponse](#NewInvoiceResponse) - -- GetUserOperations - - auth type: __User__ - - input: [GetUserOperationsRequest](#GetUserOperationsRequest) - - output: [GetUserOperationsResponse](#GetUserOperationsResponse) - -- NewAddress - - auth type: __User__ - - input: [NewAddressRequest](#NewAddressRequest) - - output: [NewAddressResponse](#NewAddressResponse) - -- PayAddress - - auth type: __User__ - - input: [PayAddressRequest](#PayAddressRequest) - - output: [PayAddressResponse](#PayAddressResponse) - -- NewInvoice - - auth type: __User__ - - input: [NewInvoiceRequest](#NewInvoiceRequest) - - output: [NewInvoiceResponse](#NewInvoiceResponse) - -- DecodeInvoice - - auth type: __User__ - - input: [DecodeInvoiceRequest](#DecodeInvoiceRequest) - - output: [DecodeInvoiceResponse](#DecodeInvoiceResponse) - -- PayInvoice - - auth type: __User__ - - input: [PayInvoiceRequest](#PayInvoiceRequest) - - output: [PayInvoiceResponse](#PayInvoiceResponse) - -- OpenChannel - - auth type: __User__ - - input: [OpenChannelRequest](#OpenChannelRequest) - - output: [OpenChannelResponse](#OpenChannelResponse) - -- GetLnurlWithdrawLink - - auth type: __User__ - - This methods has an __empty__ __request__ body - - output: [LnurlLinkResponse](#LnurlLinkResponse) - -- GetLnurlPayLink - - auth type: __User__ - - This methods has an __empty__ __request__ body - - output: [LnurlLinkResponse](#LnurlLinkResponse) - -- GetLNURLChannelLink - - auth type: __User__ - - This methods has an __empty__ __request__ body - - output: [LnurlLinkResponse](#LnurlLinkResponse) - -- GetLiveUserOperations - - auth type: __User__ - - This methods has an __empty__ __request__ body - - output: [LiveUserOperation](#LiveUserOperation) - -- GetMigrationUpdate - - auth type: __User__ - - This methods has an __empty__ __request__ body - - output: [MigrationUpdate](#MigrationUpdate) - -- GetHttpCreds - - auth type: __User__ - - This methods has an __empty__ __request__ body - - output: [HttpCreds](#HttpCreds) - -- BatchUser - - auth type: __User__ - - This methods has an __empty__ __request__ body - - This methods has an __empty__ __response__ body - -# HTTP API DEFINITION - -## Supported HTTP Auths -### These are the supported http auth types, to give different type of access to the API users - -- __Guest__: - - expected context content - -- __User__: - - expected context content - - __app_id__: _string_ - - __app_user_id__: _string_ - - __user_id__: _string_ - -- __Admin__: - - expected context content - - __admin_id__: _string_ - -- __Metrics__: - - expected context content - - __operator_id__: _string_ - -- __App__: - - expected context content - - __app_id__: _string_ - -## HTTP Methods -### These are the http methods the client implements to communicate with the API - -- LndGetInfo - - auth type: __Admin__ - - http method: __post__ - - http route: __/api/admin/lnd/getinfo__ - - input: [LndGetInfoRequest](#LndGetInfoRequest) - - output: [LndGetInfoResponse](#LndGetInfoResponse) - -- AddApp - - auth type: __Admin__ - - http method: __post__ - - http route: __/api/admin/app/add__ - - input: [AddAppRequest](#AddAppRequest) - - output: [AuthApp](#AuthApp) - -- AuthApp - - auth type: __Admin__ - - http method: __post__ - - http route: __/api/admin/app/auth__ - - input: [AuthAppRequest](#AuthAppRequest) - - output: [AuthApp](#AuthApp) - -- BanUser - - auth type: __Admin__ - - http method: __post__ - - http route: __/api/admin/user/ban__ - - input: [BanUserRequest](#BanUserRequest) - - output: [BanUserResponse](#BanUserResponse) - -- GetUsageMetrics - - auth type: __Metrics__ - - http method: __post__ - - http route: __/api/reports/usage__ - - This methods has an __empty__ __request__ body - - output: [UsageMetrics](#UsageMetrics) - -- GetAppsMetrics - - auth type: __Metrics__ - - http method: __post__ - - http route: __/api/reports/apps__ - - input: [AppsMetricsRequest](#AppsMetricsRequest) - - output: [AppsMetrics](#AppsMetrics) - -- GetLndMetrics - - auth type: __Metrics__ - - http method: __post__ - - http route: __/api/reports/lnd__ - - input: [LndMetricsRequest](#LndMetricsRequest) - - output: [LndMetrics](#LndMetrics) - -- Health - - auth type: __Guest__ - - http method: __get__ - - http route: __/api/health__ - - This methods has an __empty__ __request__ body - - This methods has an __empty__ __response__ body - -- EncryptionExchange - - auth type: __Guest__ - - http method: __post__ - - http route: __/api/encryption/exchange__ - - input: [EncryptionExchangeRequest](#EncryptionExchangeRequest) - - This methods has an __empty__ __response__ body - -- SetMockInvoiceAsPaid - - auth type: __Guest__ - - http method: __post__ - - http route: __/api/lnd/mock/invoice/paid__ - - input: [SetMockInvoiceAsPaidRequest](#SetMockInvoiceAsPaidRequest) - - This methods has an __empty__ __response__ body - -- GetLnurlWithdrawInfo - - auth type: __Guest__ - - http method: __get__ - - http route: __/api/guest/lnurl_withdraw/info__ - - the request url __query__ can take the following string items: - - k1 - - This methods has an __empty__ __request__ body - - output: [LnurlWithdrawInfoResponse](#LnurlWithdrawInfoResponse) - -- HandleLnurlWithdraw - - auth type: __Guest__ - - http method: __get__ - - http route: __/api/guest/lnurl_withdraw/handle__ - - the request url __query__ can take the following string items: - - k1 - - pr - - This methods has an __empty__ __request__ body - - This methods has an __empty__ __response__ body - -- GetLnurlPayInfo - - auth type: __Guest__ - - http method: __get__ - - http route: __/api/guest/lnurl_pay/info__ - - the request url __query__ can take the following string items: - - k1 - - This methods has an __empty__ __request__ body - - output: [LnurlPayInfoResponse](#LnurlPayInfoResponse) - -- HandleLnurlPay - - auth type: __Guest__ - - http method: __get__ - - http route: __/api/guest/lnurl_pay/handle__ - - the request url __query__ can take the following string items: - - k1 - - amount - - nostr - - lnurl - - This methods has an __empty__ __request__ body - - output: [HandleLnurlPayResponse](#HandleLnurlPayResponse) - -- HandleLnurlAddress - - auth type: __Guest__ - - http method: __get__ - - http route: __/.well-known/lnurlp/:address_name__ - - the request url __params__ are the following string items: - - address_name - - This methods has an __empty__ __request__ body - - output: [LnurlPayInfoResponse](#LnurlPayInfoResponse) - -- LinkNPubThroughToken - - auth type: __User__ - - http method: __post__ - - http route: __/api/guest/npub/link__ - - input: [LinkNPubThroughTokenRequest](#LinkNPubThroughTokenRequest) - - This methods has an __empty__ __response__ body - -- GetApp - - auth type: __App__ - - http method: __post__ - - http route: __/api/app/get__ - - This methods has an __empty__ __request__ body - - output: [Application](#Application) - -- AddAppUser - - auth type: __App__ - - http method: __post__ - - http route: __/api/app/user/add__ - - input: [AddAppUserRequest](#AddAppUserRequest) - - output: [AppUser](#AppUser) - -- AddAppInvoice - - auth type: __App__ - - http method: __post__ - - http route: __/api/app/add/invoice__ - - input: [AddAppInvoiceRequest](#AddAppInvoiceRequest) - - output: [NewInvoiceResponse](#NewInvoiceResponse) - -- AddAppUserInvoice - - auth type: __App__ - - http method: __post__ - - http route: __/api/app/user/add/invoice__ - - input: [AddAppUserInvoiceRequest](#AddAppUserInvoiceRequest) - - output: [NewInvoiceResponse](#NewInvoiceResponse) - -- GetAppUser - - auth type: __App__ - - http method: __post__ - - http route: __/api/app/user/get__ - - input: [GetAppUserRequest](#GetAppUserRequest) - - output: [AppUser](#AppUser) - -- PayAppUserInvoice - - auth type: __App__ - - http method: __post__ - - http route: __/api/app/invoice/pay__ - - input: [PayAppUserInvoiceRequest](#PayAppUserInvoiceRequest) - - output: [PayInvoiceResponse](#PayInvoiceResponse) - -- SendAppUserToAppUserPayment - - auth type: __App__ - - http method: __post__ - - http route: __/api/app/user/internal/pay__ - - input: [SendAppUserToAppUserPaymentRequest](#SendAppUserToAppUserPaymentRequest) - - This methods has an __empty__ __response__ body - -- SendAppUserToAppPayment - - auth type: __App__ - - http method: __post__ - - http route: __/api/app/internal/pay__ - - input: [SendAppUserToAppPaymentRequest](#SendAppUserToAppPaymentRequest) - - This methods has an __empty__ __response__ body - -- GetAppUserLNURLInfo - - auth type: __App__ - - http method: __post__ - - http route: __/api/app/user/lnurl/pay/info__ - - input: [GetAppUserLNURLInfoRequest](#GetAppUserLNURLInfoRequest) - - output: [LnurlPayInfoResponse](#LnurlPayInfoResponse) - -- SetMockAppUserBalance - - auth type: __App__ - - http method: __post__ - - http route: __/api/app/mock/user/blance/set__ - - input: [SetMockAppUserBalanceRequest](#SetMockAppUserBalanceRequest) - - This methods has an __empty__ __response__ body - -- SetMockAppBalance - - auth type: __App__ - - http method: __post__ - - http route: __/api/app/mock/blance/set__ - - input: [SetMockAppBalanceRequest](#SetMockAppBalanceRequest) - - This methods has an __empty__ __response__ body - -- RequestNPubLinkingToken - - auth type: __App__ - - http method: __post__ - - http route: __/api/app/user/npub/token__ - - input: [RequestNPubLinkingTokenRequest](#RequestNPubLinkingTokenRequest) - - output: [RequestNPubLinkingTokenResponse](#RequestNPubLinkingTokenResponse) - -- UserHealth - - auth type: __User__ - - http method: __post__ - - http route: __/api/user/health__ - - This methods has an __empty__ __request__ body - - This methods has an __empty__ __response__ body - -- GetUserInfo - - auth type: __User__ - - http method: __post__ - - http route: __/api/user/info__ - - This methods has an __empty__ __request__ body - - output: [UserInfo](#UserInfo) - -- AddProduct - - auth type: __User__ - - http method: __post__ - - http route: __/api/user/product/add__ - - input: [AddProductRequest](#AddProductRequest) - - output: [Product](#Product) - -- NewProductInvoice - - auth type: __User__ - - http method: __get__ - - http route: __/api/user/product/get/invoice__ - - the request url __query__ can take the following string items: - - id - - This methods has an __empty__ __request__ body - - output: [NewInvoiceResponse](#NewInvoiceResponse) - -- GetUserOperations - - auth type: __User__ - - http method: __post__ - - http route: __/api/user/operations__ - - input: [GetUserOperationsRequest](#GetUserOperationsRequest) - - output: [GetUserOperationsResponse](#GetUserOperationsResponse) - -- NewAddress - - auth type: __User__ - - http method: __post__ - - http route: __/api/user/chain/new__ - - input: [NewAddressRequest](#NewAddressRequest) - - output: [NewAddressResponse](#NewAddressResponse) - -- PayAddress - - auth type: __User__ - - http method: __post__ - - http route: __/api/user/chain/pay__ - - input: [PayAddressRequest](#PayAddressRequest) - - output: [PayAddressResponse](#PayAddressResponse) - -- NewInvoice - - auth type: __User__ - - http method: __post__ - - http route: __/api/user/invoice/new__ - - input: [NewInvoiceRequest](#NewInvoiceRequest) - - output: [NewInvoiceResponse](#NewInvoiceResponse) - -- DecodeInvoice - - auth type: __User__ - - http method: __post__ - - http route: __/api/user/invoice/decode__ - - input: [DecodeInvoiceRequest](#DecodeInvoiceRequest) - - output: [DecodeInvoiceResponse](#DecodeInvoiceResponse) - -- PayInvoice - - auth type: __User__ - - http method: __post__ - - http route: __/api/user/invoice/pay__ - - input: [PayInvoiceRequest](#PayInvoiceRequest) - - output: [PayInvoiceResponse](#PayInvoiceResponse) - -- OpenChannel - - auth type: __User__ - - http method: __post__ - - http route: __/api/user/open/channel__ - - input: [OpenChannelRequest](#OpenChannelRequest) - - output: [OpenChannelResponse](#OpenChannelResponse) - -- GetLnurlWithdrawLink - - auth type: __User__ - - http method: __get__ - - http route: __/api/user/lnurl_withdraw/link__ - - This methods has an __empty__ __request__ body - - output: [LnurlLinkResponse](#LnurlLinkResponse) - -- GetLnurlPayLink - - auth type: __User__ - - http method: __get__ - - http route: __/api/user/lnurl_pay/link__ - - This methods has an __empty__ __request__ body - - output: [LnurlLinkResponse](#LnurlLinkResponse) - -- GetLNURLChannelLink - - auth type: __User__ - - http method: __post__ - - http route: __/api/user/lnurl_channel/url__ - - This methods has an __empty__ __request__ body - - output: [LnurlLinkResponse](#LnurlLinkResponse) - -- GetLiveUserOperations - - auth type: __User__ - - http method: __post__ - - http route: __/api/user/operations/sub__ - - This methods has an __empty__ __request__ body - - output: [LiveUserOperation](#LiveUserOperation) - -- GetMigrationUpdate - - auth type: __User__ - - http method: __post__ - - http route: __/api/user/migrations/sub__ - - This methods has an __empty__ __request__ body - - output: [MigrationUpdate](#MigrationUpdate) - -- GetHttpCreds - - auth type: __User__ - - http method: __post__ - - http route: __/api/user/http_creds__ - - This methods has an __empty__ __request__ body - - output: [HttpCreds](#HttpCreds) - -- BatchUser - - auth type: __User__ - - http method: __post__ - - http route: __/api/user/batch__ - - This methods has an __empty__ __request__ body - - This methods has an __empty__ __response__ body - -# INPUTS AND OUTPUTS - -## Messages -### The content of requests and response from the methods - -### BanUserRequest - - __user_id__: _string_ - -### SendAppUserToAppUserPaymentRequest - - __from_user_identifier__: _string_ - - __to_user_identifier__: _string_ - - __amount__: _number_ - -### SendAppUserToAppPaymentRequest - - __from_user_identifier__: _string_ - - __amount__: _number_ - -### GetUserOperationsRequest - - __latestIncomingInvoice__: _number_ - - __latestOutgoingInvoice__: _number_ - - __latestIncomingTx__: _number_ - - __latestOutgoingTx__: _number_ - - __latestIncomingUserToUserPayment__: _number_ - - __latestOutgoingUserToUserPayment__: _number_ - - __max_size__: _number_ - -### GetUserOperationsResponse - - __latestOutgoingInvoiceOperations__: _[UserOperations](#UserOperations)_ - - __latestIncomingInvoiceOperations__: _[UserOperations](#UserOperations)_ - - __latestOutgoingTxOperations__: _[UserOperations](#UserOperations)_ - - __latestIncomingTxOperations__: _[UserOperations](#UserOperations)_ - - __latestOutgoingUserToUserPayemnts__: _[UserOperations](#UserOperations)_ - - __latestIncomingUserToUserPayemnts__: _[UserOperations](#UserOperations)_ - -### ClosureMigration - - __closes_at_unix__: _number_ - -### AuthAppRequest - - __name__: _string_ - - __allow_user_creation__: _boolean_ *this field is optional - -### Application - - __name__: _string_ - - __id__: _string_ - - __balance__: _number_ - - __npub__: _string_ - -### AddAppInvoiceRequest - - __payer_identifier__: _string_ - - __http_callback_url__: _string_ - - __invoice_req__: _[NewInvoiceRequest](#NewInvoiceRequest)_ - -### GetAppUserLNURLInfoRequest - - __user_identifier__: _string_ - - __base_url_override__: _string_ - -### LnurlLinkResponse - - __lnurl__: _string_ - - __k1__: _string_ - -### LnurlWithdrawInfoResponse - - __tag__: _string_ - - __callback__: _string_ - - __k1__: _string_ - - __defaultDescription__: _string_ - - __minWithdrawable__: _number_ - - __maxWithdrawable__: _number_ - - __balanceCheck__: _string_ - - __payLink__: _string_ - -### UserOperation - - __paidAtUnix__: _number_ - - __type__: _[UserOperationType](#UserOperationType)_ - - __inbound__: _boolean_ - - __amount__: _number_ - - __identifier__: _string_ - - __operationId__: _string_ - - __service_fee__: _number_ - - __network_fee__: _number_ - - __confirmed__: _boolean_ - - __tx_hash__: _string_ - - __internal__: _boolean_ - -### RelaysMigration - - __relays__: ARRAY of: _string_ - -### RequestNPubLinkingTokenRequest - - __user_identifier__: _string_ - -### EncryptionExchangeRequest - - __publicKey__: _string_ - - __deviceId__: _string_ - -### AppsMetricsRequest - - __from_unix__: _number_ *this field is optional - - __to_unix__: _number_ *this field is optional - - __include_operations__: _boolean_ *this field is optional - -### ClosedChannel - - __channel_id__: _string_ - - __capacity__: _number_ - - __closed_height__: _number_ - -### OpenChannelResponse - - __channelId__: _string_ - -### Product - - __id__: _string_ - - __name__: _string_ - - __price_sats__: _number_ - -### PayAppUserInvoiceRequest - - __user_identifier__: _string_ - - __invoice__: _string_ - - __amount__: _number_ - -### NewInvoiceRequest - - __amountSats__: _number_ - - __memo__: _string_ - -### LiveUserOperation - - __operation__: _[UserOperation](#UserOperation)_ - -### HttpCreds - - __url__: _string_ - - __token__: _string_ - -### UsageMetric - - __processed_at_ms__: _number_ - - __parsed_in_nano__: _number_ - - __auth_in_nano__: _number_ - - __validate_in_nano__: _number_ - - __handle_in_nano__: _number_ - - __rpc_name__: _string_ - - __batch__: _boolean_ - - __nostr__: _boolean_ - - __batch_size__: _number_ - -### RoutingEvent - - __incoming_channel_id__: _number_ - - __incoming_htlc_id__: _number_ - - __outgoing_channel_id__: _number_ - - __outgoing_htlc_id__: _number_ - - __timestamp_ns__: _number_ - - __event_type__: _string_ - - __incoming_amt_msat__: _number_ - - __outgoing_amt_msat__: _number_ - - __failure_string__: _string_ - - __settled__: _boolean_ - - __offchain__: _boolean_ - - __forward_fail_event__: _boolean_ - -### ChannelBalanceEvent - - __block_height__: _number_ - - __channel_id__: _string_ - - __local_balance_sats__: _number_ - - __remote_balance_sats__: _number_ - -### HandleLnurlPayResponse - - __pr__: _string_ - - __routes__: ARRAY of: _[Empty](#Empty)_ - -### UserOperations - - __fromIndex__: _number_ - - __toIndex__: _number_ - - __operations__: ARRAY of: _[UserOperation](#UserOperation)_ - -### ChainBalanceEvent - - __block_height__: _number_ - - __confirmed_balance__: _number_ - - __unconfirmed_balance__: _number_ - - __total_balance__: _number_ - -### LndNodeMetrics - - __channels_balance_events__: ARRAY of: _[ChannelBalanceEvent](#ChannelBalanceEvent)_ - - __chain_balance_events__: ARRAY of: _[ChainBalanceEvent](#ChainBalanceEvent)_ - - __offline_channels__: _number_ - - __online_channels__: _number_ - - __pending_channels__: _number_ - - __closing_channels__: _number_ - - __open_channels__: ARRAY of: _[OpenChannel](#OpenChannel)_ - - __closed_channels__: ARRAY of: _[ClosedChannel](#ClosedChannel)_ - - __channel_routing__: ARRAY of: _[ChannelRouting](#ChannelRouting)_ - -### SetMockInvoiceAsPaidRequest - - __invoice__: _string_ - - __amount__: _number_ - -### AddAppUserInvoiceRequest - - __receiver_identifier__: _string_ - - __payer_identifier__: _string_ - - __http_callback_url__: _string_ - - __invoice_req__: _[NewInvoiceRequest](#NewInvoiceRequest)_ - -### OpenChannelRequest - - __destination__: _string_ - - __fundingAmount__: _number_ - - __pushAmount__: _number_ - - __closeAddress__: _string_ - -### UsageMetrics - - __metrics__: ARRAY of: _[UsageMetric](#UsageMetric)_ - -### OpenChannel - - __channel_id__: _string_ - - __capacity__: _number_ - - __active__: _boolean_ - - __lifetime__: _number_ - - __local_balance__: _number_ - - __remote_balance__: _number_ - -### NewAddressRequest - - __addressType__: _[AddressType](#AddressType)_ - -### LnurlPayInfoResponse - - __tag__: _string_ - - __callback__: _string_ - - __maxSendable__: _number_ - - __minSendable__: _number_ - - __metadata__: _string_ - - __allowsNostr__: _boolean_ - - __nostrPubkey__: _string_ - -### GetProductBuyLinkResponse - - __link__: _string_ - -### UsersInfo - - __total__: _number_ - - __no_balance__: _number_ - - __negative_balance__: _number_ - - __always_been_inactive__: _number_ - - __balance_avg__: _number_ - - __balance_median__: _number_ - -### AddAppRequest - - __name__: _string_ - - __allow_user_creation__: _boolean_ - -### DecodeInvoiceResponse - - __amount__: _number_ - -### LndMetrics - - __nodes__: ARRAY of: _[LndNodeMetrics](#LndNodeMetrics)_ - -### AddProductRequest - - __name__: _string_ - - __price_sats__: _number_ - -### Empty - -### ChannelRouting - - __channel_id__: _string_ - - __send_errors__: _number_ - - __receive_errors__: _number_ - - __forward_errors_as_input__: _number_ - - __forward_errors_as_output__: _number_ - - __missed_forward_fee_as_input__: _number_ - - __missed_forward_fee_as_output__: _number_ - - __forward_fee_as_input__: _number_ - - __forward_fee_as_output__: _number_ - - __events_number__: _number_ - -### PayInvoiceResponse - - __preimage__: _string_ - - __amount_paid__: _number_ - - __operation_id__: _string_ - - __service_fee__: _number_ - - __network_fee__: _number_ - -### UserInfo - - __userId__: _string_ - - __balance__: _number_ - - __max_withdrawable__: _number_ - - __user_identifier__: _string_ - -### MigrationUpdate - - __closure__: _[ClosureMigration](#ClosureMigration)_ *this field is optional - - __relays__: _[RelaysMigration](#RelaysMigration)_ *this field is optional - -### LinkNPubThroughTokenRequest - - __token__: _string_ - - __nostr_pub__: _string_ - -### PayAddressRequest - - __address__: _string_ - - __amoutSats__: _number_ - - __satsPerVByte__: _number_ - -### PayAddressResponse - - __txId__: _string_ - - __operation_id__: _string_ - - __service_fee__: _number_ - - __network_fee__: _number_ - -### AppMetrics - - __app__: _[Application](#Application)_ - - __users__: _[UsersInfo](#UsersInfo)_ - - __received__: _number_ - - __spent__: _number_ - - __available__: _number_ - - __fees__: _number_ - - __invoices__: _number_ - - __total_fees__: _number_ - - __operations__: ARRAY of: _[UserOperation](#UserOperation)_ - -### BanUserResponse - - __balance_sats__: _number_ - - __banned_app_users__: ARRAY of: _[BannedAppUser](#BannedAppUser)_ - -### AuthApp - - __app__: _[Application](#Application)_ - - __auth_token__: _string_ - -### LndMetricsRequest - - __from_unix__: _number_ *this field is optional - - __to_unix__: _number_ *this field is optional - -### BannedAppUser - - __app_name__: _string_ - - __app_id__: _string_ - - __user_identifier__: _string_ - - __nostr_pub__: _string_ - -### GetAppUserRequest - - __user_identifier__: _string_ - -### SetMockAppBalanceRequest - - __amount__: _number_ - -### DecodeInvoiceRequest - - __invoice__: _string_ - -### RequestNPubLinkingTokenResponse - - __token__: _string_ - -### LndGetInfoRequest - - __nodeId__: _number_ - -### AppUser - - __identifier__: _string_ - - __info__: _[UserInfo](#UserInfo)_ - - __max_withdrawable__: _number_ - -### SetMockAppUserBalanceRequest - - __user_identifier__: _string_ - - __amount__: _number_ - -### PayInvoiceRequest - - __invoice__: _string_ - - __amount__: _number_ - -### AddAppUserRequest - - __identifier__: _string_ - - __fail_if_exists__: _boolean_ - - __balance__: _number_ - -### NewInvoiceResponse - - __invoice__: _string_ - -### AppsMetrics - - __apps__: ARRAY of: _[AppMetrics](#AppMetrics)_ - -### LndGetInfoResponse - - __alias__: _string_ - -### NewAddressResponse - - __address__: _string_ -## Enums -### The enumerators used in the messages - -### AddressType - - __WITNESS_PUBKEY_HASH__ - - __NESTED_PUBKEY_HASH__ - - __TAPROOT_PUBKEY__ - -### UserOperationType - - __INCOMING_TX__ - - __OUTGOING_TX__ - - __INCOMING_INVOICE__ - - __OUTGOING_INVOICE__ - - __OUTGOING_USER_TO_USER__ - - __INCOMING_USER_TO_USER__ +# NOSTR API DEFINITION + + +A nostr request will take the same parameter and give the same response as an http request, but it will use nostr as transport, to do that it will send encrypted events to the server public key, in the event 6 thing are required: +- __rpcName__: string containing the name of the method +- __params__: a map with the all the url params for the method +- __query__: a map with the the url query for the method +- __body__: the body of the method request +- __requestId__: id of the request to be able to get a response + +The nostr server will send back a message response, and inside the body there will also be a __requestId__ to identify the request this response is answering + +## NOSTR Methods +### These are the nostr methods the client implements to communicate with the API via nostr + +- LndGetInfo + - auth type: __Admin__ + - input: [LndGetInfoRequest](#LndGetInfoRequest) + - output: [LndGetInfoResponse](#LndGetInfoResponse) + +- AddApp + - auth type: __Admin__ + - input: [AddAppRequest](#AddAppRequest) + - output: [AuthApp](#AuthApp) + +- AuthApp + - auth type: __Admin__ + - input: [AuthAppRequest](#AuthAppRequest) + - output: [AuthApp](#AuthApp) + +- BanUser + - auth type: __Admin__ + - input: [BanUserRequest](#BanUserRequest) + - output: [BanUserResponse](#BanUserResponse) + +- GetUsageMetrics + - auth type: __Metrics__ + - This methods has an __empty__ __request__ body + - output: [UsageMetrics](#UsageMetrics) + +- GetAppsMetrics + - auth type: __Metrics__ + - input: [AppsMetricsRequest](#AppsMetricsRequest) + - output: [AppsMetrics](#AppsMetrics) + +- GetLndMetrics + - auth type: __Metrics__ + - input: [LndMetricsRequest](#LndMetricsRequest) + - output: [LndMetrics](#LndMetrics) + +- LinkNPubThroughToken + - auth type: __User__ + - input: [LinkNPubThroughTokenRequest](#LinkNPubThroughTokenRequest) + - This methods has an __empty__ __response__ body + +- EnrollAdminToken + - auth type: __User__ + - input: [EnrollAdminTokenRequest](#EnrollAdminTokenRequest) + - This methods has an __empty__ __response__ body + +- UserHealth + - auth type: __User__ + - This methods has an __empty__ __request__ body + - This methods has an __empty__ __response__ body + +- GetUserInfo + - auth type: __User__ + - This methods has an __empty__ __request__ body + - output: [UserInfo](#UserInfo) + +- AddProduct + - auth type: __User__ + - input: [AddProductRequest](#AddProductRequest) + - output: [Product](#Product) + +- NewProductInvoice + - auth type: __User__ + - the request url __query__ can take the following string items: + - id + - This methods has an __empty__ __request__ body + - output: [NewInvoiceResponse](#NewInvoiceResponse) + +- GetUserOperations + - auth type: __User__ + - input: [GetUserOperationsRequest](#GetUserOperationsRequest) + - output: [GetUserOperationsResponse](#GetUserOperationsResponse) + +- NewAddress + - auth type: __User__ + - input: [NewAddressRequest](#NewAddressRequest) + - output: [NewAddressResponse](#NewAddressResponse) + +- PayAddress + - auth type: __User__ + - input: [PayAddressRequest](#PayAddressRequest) + - output: [PayAddressResponse](#PayAddressResponse) + +- NewInvoice + - auth type: __User__ + - input: [NewInvoiceRequest](#NewInvoiceRequest) + - output: [NewInvoiceResponse](#NewInvoiceResponse) + +- DecodeInvoice + - auth type: __User__ + - input: [DecodeInvoiceRequest](#DecodeInvoiceRequest) + - output: [DecodeInvoiceResponse](#DecodeInvoiceResponse) + +- PayInvoice + - auth type: __User__ + - input: [PayInvoiceRequest](#PayInvoiceRequest) + - output: [PayInvoiceResponse](#PayInvoiceResponse) + +- OpenChannel + - auth type: __User__ + - input: [OpenChannelRequest](#OpenChannelRequest) + - output: [OpenChannelResponse](#OpenChannelResponse) + +- GetLnurlWithdrawLink + - auth type: __User__ + - This methods has an __empty__ __request__ body + - output: [LnurlLinkResponse](#LnurlLinkResponse) + +- GetLnurlPayLink + - auth type: __User__ + - This methods has an __empty__ __request__ body + - output: [LnurlLinkResponse](#LnurlLinkResponse) + +- GetLNURLChannelLink + - auth type: __User__ + - This methods has an __empty__ __request__ body + - output: [LnurlLinkResponse](#LnurlLinkResponse) + +- GetLiveUserOperations + - auth type: __User__ + - This methods has an __empty__ __request__ body + - output: [LiveUserOperation](#LiveUserOperation) + +- GetMigrationUpdate + - auth type: __User__ + - This methods has an __empty__ __request__ body + - output: [MigrationUpdate](#MigrationUpdate) + +- GetHttpCreds + - auth type: __User__ + - This methods has an __empty__ __request__ body + - output: [HttpCreds](#HttpCreds) + +- BatchUser + - auth type: __User__ + - This methods has an __empty__ __request__ body + - This methods has an __empty__ __response__ body + +# HTTP API DEFINITION + +## Supported HTTP Auths +### These are the supported http auth types, to give different type of access to the API users + +- __Guest__: + - expected context content + +- __User__: + - expected context content + - __user_id__: _string_ + - __app_id__: _string_ + - __app_user_id__: _string_ + +- __Admin__: + - expected context content + - __admin_id__: _string_ + +- __Metrics__: + - expected context content + - __operator_id__: _string_ + +- __App__: + - expected context content + - __app_id__: _string_ + +## HTTP Methods +### These are the http methods the client implements to communicate with the API + +- LndGetInfo + - auth type: __Admin__ + - http method: __post__ + - http route: __/api/admin/lnd/getinfo__ + - input: [LndGetInfoRequest](#LndGetInfoRequest) + - output: [LndGetInfoResponse](#LndGetInfoResponse) + +- AddApp + - auth type: __Admin__ + - http method: __post__ + - http route: __/api/admin/app/add__ + - input: [AddAppRequest](#AddAppRequest) + - output: [AuthApp](#AuthApp) + +- AuthApp + - auth type: __Admin__ + - http method: __post__ + - http route: __/api/admin/app/auth__ + - input: [AuthAppRequest](#AuthAppRequest) + - output: [AuthApp](#AuthApp) + +- BanUser + - auth type: __Admin__ + - http method: __post__ + - http route: __/api/admin/user/ban__ + - input: [BanUserRequest](#BanUserRequest) + - output: [BanUserResponse](#BanUserResponse) + +- GetUsageMetrics + - auth type: __Metrics__ + - http method: __post__ + - http route: __/api/reports/usage__ + - This methods has an __empty__ __request__ body + - output: [UsageMetrics](#UsageMetrics) + +- GetAppsMetrics + - auth type: __Metrics__ + - http method: __post__ + - http route: __/api/reports/apps__ + - input: [AppsMetricsRequest](#AppsMetricsRequest) + - output: [AppsMetrics](#AppsMetrics) + +- GetLndMetrics + - auth type: __Metrics__ + - http method: __post__ + - http route: __/api/reports/lnd__ + - input: [LndMetricsRequest](#LndMetricsRequest) + - output: [LndMetrics](#LndMetrics) + +- Health + - auth type: __Guest__ + - http method: __get__ + - http route: __/api/health__ + - This methods has an __empty__ __request__ body + - This methods has an __empty__ __response__ body + +- EncryptionExchange + - auth type: __Guest__ + - http method: __post__ + - http route: __/api/encryption/exchange__ + - input: [EncryptionExchangeRequest](#EncryptionExchangeRequest) + - This methods has an __empty__ __response__ body + +- SetMockInvoiceAsPaid + - auth type: __Guest__ + - http method: __post__ + - http route: __/api/lnd/mock/invoice/paid__ + - input: [SetMockInvoiceAsPaidRequest](#SetMockInvoiceAsPaidRequest) + - This methods has an __empty__ __response__ body + +- GetLnurlWithdrawInfo + - auth type: __Guest__ + - http method: __get__ + - http route: __/api/guest/lnurl_withdraw/info__ + - the request url __query__ can take the following string items: + - k1 + - This methods has an __empty__ __request__ body + - output: [LnurlWithdrawInfoResponse](#LnurlWithdrawInfoResponse) + +- HandleLnurlWithdraw + - auth type: __Guest__ + - http method: __get__ + - http route: __/api/guest/lnurl_withdraw/handle__ + - the request url __query__ can take the following string items: + - k1 + - pr + - This methods has an __empty__ __request__ body + - This methods has an __empty__ __response__ body + +- GetLnurlPayInfo + - auth type: __Guest__ + - http method: __get__ + - http route: __/api/guest/lnurl_pay/info__ + - the request url __query__ can take the following string items: + - k1 + - This methods has an __empty__ __request__ body + - output: [LnurlPayInfoResponse](#LnurlPayInfoResponse) + +- HandleLnurlPay + - auth type: __Guest__ + - http method: __get__ + - http route: __/api/guest/lnurl_pay/handle__ + - the request url __query__ can take the following string items: + - k1 + - amount + - nostr + - lnurl + - This methods has an __empty__ __request__ body + - output: [HandleLnurlPayResponse](#HandleLnurlPayResponse) + +- HandleLnurlAddress + - auth type: __Guest__ + - http method: __get__ + - http route: __/.well-known/lnurlp/:address_name__ + - the request url __params__ are the following string items: + - address_name + - This methods has an __empty__ __request__ body + - output: [LnurlPayInfoResponse](#LnurlPayInfoResponse) + +- LinkNPubThroughToken + - auth type: __User__ + - http method: __post__ + - http route: __/api/guest/npub/link__ + - input: [LinkNPubThroughTokenRequest](#LinkNPubThroughTokenRequest) + - This methods has an __empty__ __response__ body + +- EnrollAdminToken + - auth type: __User__ + - http method: __post__ + - http route: __/api/guest/npub/enroll/admin__ + - input: [EnrollAdminTokenRequest](#EnrollAdminTokenRequest) + - This methods has an __empty__ __response__ body + +- GetApp + - auth type: __App__ + - http method: __post__ + - http route: __/api/app/get__ + - This methods has an __empty__ __request__ body + - output: [Application](#Application) + +- AddAppUser + - auth type: __App__ + - http method: __post__ + - http route: __/api/app/user/add__ + - input: [AddAppUserRequest](#AddAppUserRequest) + - output: [AppUser](#AppUser) + +- AddAppInvoice + - auth type: __App__ + - http method: __post__ + - http route: __/api/app/add/invoice__ + - input: [AddAppInvoiceRequest](#AddAppInvoiceRequest) + - output: [NewInvoiceResponse](#NewInvoiceResponse) + +- AddAppUserInvoice + - auth type: __App__ + - http method: __post__ + - http route: __/api/app/user/add/invoice__ + - input: [AddAppUserInvoiceRequest](#AddAppUserInvoiceRequest) + - output: [NewInvoiceResponse](#NewInvoiceResponse) + +- GetAppUser + - auth type: __App__ + - http method: __post__ + - http route: __/api/app/user/get__ + - input: [GetAppUserRequest](#GetAppUserRequest) + - output: [AppUser](#AppUser) + +- PayAppUserInvoice + - auth type: __App__ + - http method: __post__ + - http route: __/api/app/invoice/pay__ + - input: [PayAppUserInvoiceRequest](#PayAppUserInvoiceRequest) + - output: [PayInvoiceResponse](#PayInvoiceResponse) + +- SendAppUserToAppUserPayment + - auth type: __App__ + - http method: __post__ + - http route: __/api/app/user/internal/pay__ + - input: [SendAppUserToAppUserPaymentRequest](#SendAppUserToAppUserPaymentRequest) + - This methods has an __empty__ __response__ body + +- SendAppUserToAppPayment + - auth type: __App__ + - http method: __post__ + - http route: __/api/app/internal/pay__ + - input: [SendAppUserToAppPaymentRequest](#SendAppUserToAppPaymentRequest) + - This methods has an __empty__ __response__ body + +- GetAppUserLNURLInfo + - auth type: __App__ + - http method: __post__ + - http route: __/api/app/user/lnurl/pay/info__ + - input: [GetAppUserLNURLInfoRequest](#GetAppUserLNURLInfoRequest) + - output: [LnurlPayInfoResponse](#LnurlPayInfoResponse) + +- SetMockAppUserBalance + - auth type: __App__ + - http method: __post__ + - http route: __/api/app/mock/user/blance/set__ + - input: [SetMockAppUserBalanceRequest](#SetMockAppUserBalanceRequest) + - This methods has an __empty__ __response__ body + +- SetMockAppBalance + - auth type: __App__ + - http method: __post__ + - http route: __/api/app/mock/blance/set__ + - input: [SetMockAppBalanceRequest](#SetMockAppBalanceRequest) + - This methods has an __empty__ __response__ body + +- RequestNPubLinkingToken + - auth type: __App__ + - http method: __post__ + - http route: __/api/app/user/npub/token__ + - input: [RequestNPubLinkingTokenRequest](#RequestNPubLinkingTokenRequest) + - output: [RequestNPubLinkingTokenResponse](#RequestNPubLinkingTokenResponse) + +- UserHealth + - auth type: __User__ + - http method: __post__ + - http route: __/api/user/health__ + - This methods has an __empty__ __request__ body + - This methods has an __empty__ __response__ body + +- GetUserInfo + - auth type: __User__ + - http method: __post__ + - http route: __/api/user/info__ + - This methods has an __empty__ __request__ body + - output: [UserInfo](#UserInfo) + +- AddProduct + - auth type: __User__ + - http method: __post__ + - http route: __/api/user/product/add__ + - input: [AddProductRequest](#AddProductRequest) + - output: [Product](#Product) + +- NewProductInvoice + - auth type: __User__ + - http method: __get__ + - http route: __/api/user/product/get/invoice__ + - the request url __query__ can take the following string items: + - id + - This methods has an __empty__ __request__ body + - output: [NewInvoiceResponse](#NewInvoiceResponse) + +- GetUserOperations + - auth type: __User__ + - http method: __post__ + - http route: __/api/user/operations__ + - input: [GetUserOperationsRequest](#GetUserOperationsRequest) + - output: [GetUserOperationsResponse](#GetUserOperationsResponse) + +- NewAddress + - auth type: __User__ + - http method: __post__ + - http route: __/api/user/chain/new__ + - input: [NewAddressRequest](#NewAddressRequest) + - output: [NewAddressResponse](#NewAddressResponse) + +- PayAddress + - auth type: __User__ + - http method: __post__ + - http route: __/api/user/chain/pay__ + - input: [PayAddressRequest](#PayAddressRequest) + - output: [PayAddressResponse](#PayAddressResponse) + +- NewInvoice + - auth type: __User__ + - http method: __post__ + - http route: __/api/user/invoice/new__ + - input: [NewInvoiceRequest](#NewInvoiceRequest) + - output: [NewInvoiceResponse](#NewInvoiceResponse) + +- DecodeInvoice + - auth type: __User__ + - http method: __post__ + - http route: __/api/user/invoice/decode__ + - input: [DecodeInvoiceRequest](#DecodeInvoiceRequest) + - output: [DecodeInvoiceResponse](#DecodeInvoiceResponse) + +- PayInvoice + - auth type: __User__ + - http method: __post__ + - http route: __/api/user/invoice/pay__ + - input: [PayInvoiceRequest](#PayInvoiceRequest) + - output: [PayInvoiceResponse](#PayInvoiceResponse) + +- OpenChannel + - auth type: __User__ + - http method: __post__ + - http route: __/api/user/open/channel__ + - input: [OpenChannelRequest](#OpenChannelRequest) + - output: [OpenChannelResponse](#OpenChannelResponse) + +- GetLnurlWithdrawLink + - auth type: __User__ + - http method: __get__ + - http route: __/api/user/lnurl_withdraw/link__ + - This methods has an __empty__ __request__ body + - output: [LnurlLinkResponse](#LnurlLinkResponse) + +- GetLnurlPayLink + - auth type: __User__ + - http method: __get__ + - http route: __/api/user/lnurl_pay/link__ + - This methods has an __empty__ __request__ body + - output: [LnurlLinkResponse](#LnurlLinkResponse) + +- GetLNURLChannelLink + - auth type: __User__ + - http method: __post__ + - http route: __/api/user/lnurl_channel/url__ + - This methods has an __empty__ __request__ body + - output: [LnurlLinkResponse](#LnurlLinkResponse) + +- GetLiveUserOperations + - auth type: __User__ + - http method: __post__ + - http route: __/api/user/operations/sub__ + - This methods has an __empty__ __request__ body + - output: [LiveUserOperation](#LiveUserOperation) + +- GetMigrationUpdate + - auth type: __User__ + - http method: __post__ + - http route: __/api/user/migrations/sub__ + - This methods has an __empty__ __request__ body + - output: [MigrationUpdate](#MigrationUpdate) + +- GetHttpCreds + - auth type: __User__ + - http method: __post__ + - http route: __/api/user/http_creds__ + - This methods has an __empty__ __request__ body + - output: [HttpCreds](#HttpCreds) + +- BatchUser + - auth type: __User__ + - http method: __post__ + - http route: __/api/user/batch__ + - This methods has an __empty__ __request__ body + - This methods has an __empty__ __response__ body + +# INPUTS AND OUTPUTS + +## Messages +### The content of requests and response from the methods + +### Empty + +### LndMetricsRequest + - __from_unix__: _number_ *this field is optional + - __to_unix__: _number_ *this field is optional + +### LndGetInfoResponse + - __alias__: _string_ + +### PayAppUserInvoiceRequest + - __user_identifier__: _string_ + - __invoice__: _string_ + - __amount__: _number_ + +### Product + - __id__: _string_ + - __name__: _string_ + - __price_sats__: _number_ + +### LndGetInfoRequest + - __nodeId__: _number_ + +### BanUserResponse + - __balance_sats__: _number_ + - __banned_app_users__: ARRAY of: _[BannedAppUser](#BannedAppUser)_ + +### AuthAppRequest + - __name__: _string_ + - __allow_user_creation__: _boolean_ *this field is optional + +### PayAddressRequest + - __address__: _string_ + - __amoutSats__: _number_ + - __satsPerVByte__: _number_ + +### AppsMetricsRequest + - __from_unix__: _number_ *this field is optional + - __to_unix__: _number_ *this field is optional + - __include_operations__: _boolean_ *this field is optional + +### AppsMetrics + - __apps__: ARRAY of: _[AppMetrics](#AppMetrics)_ + +### RoutingEvent + - __timestamp_ns__: _number_ + - __event_type__: _string_ + - __settled__: _boolean_ + - __offchain__: _boolean_ + - __incoming_channel_id__: _number_ + - __incoming_htlc_id__: _number_ + - __outgoing_channel_id__: _number_ + - __outgoing_htlc_id__: _number_ + - __forward_fail_event__: _boolean_ + - __incoming_amt_msat__: _number_ + - __outgoing_amt_msat__: _number_ + - __failure_string__: _string_ + +### BannedAppUser + - __app_name__: _string_ + - __app_id__: _string_ + - __user_identifier__: _string_ + - __nostr_pub__: _string_ + +### GetUserOperationsResponse + - __latestOutgoingTxOperations__: _[UserOperations](#UserOperations)_ + - __latestIncomingTxOperations__: _[UserOperations](#UserOperations)_ + - __latestOutgoingUserToUserPayemnts__: _[UserOperations](#UserOperations)_ + - __latestIncomingUserToUserPayemnts__: _[UserOperations](#UserOperations)_ + - __latestOutgoingInvoiceOperations__: _[UserOperations](#UserOperations)_ + - __latestIncomingInvoiceOperations__: _[UserOperations](#UserOperations)_ + +### RequestNPubLinkingTokenResponse + - __token__: _string_ + +### UsageMetric + - __processed_at_ms__: _number_ + - __auth_in_nano__: _number_ + - __rpc_name__: _string_ + - __nostr__: _boolean_ + - __batch_size__: _number_ + - __parsed_in_nano__: _number_ + - __validate_in_nano__: _number_ + - __handle_in_nano__: _number_ + - __batch__: _boolean_ + +### NewInvoiceRequest + - __amountSats__: _number_ + - __memo__: _string_ + +### OpenChannelRequest + - __destination__: _string_ + - __fundingAmount__: _number_ + - __pushAmount__: _number_ + - __closeAddress__: _string_ + +### ChainBalanceEvent + - __block_height__: _number_ + - __confirmed_balance__: _number_ + - __unconfirmed_balance__: _number_ + - __total_balance__: _number_ + +### GetAppUserRequest + - __user_identifier__: _string_ + +### NewAddressResponse + - __address__: _string_ + +### PayInvoiceResponse + - __preimage__: _string_ + - __amount_paid__: _number_ + - __operation_id__: _string_ + - __service_fee__: _number_ + - __network_fee__: _number_ + +### AddProductRequest + - __name__: _string_ + - __price_sats__: _number_ + +### MigrationUpdate + - __closure__: _[ClosureMigration](#ClosureMigration)_ *this field is optional + - __relays__: _[RelaysMigration](#RelaysMigration)_ *this field is optional + +### ClosureMigration + - __closes_at_unix__: _number_ + +### EncryptionExchangeRequest + - __publicKey__: _string_ + - __deviceId__: _string_ + +### UsersInfo + - __total__: _number_ + - __no_balance__: _number_ + - __negative_balance__: _number_ + - __always_been_inactive__: _number_ + - __balance_avg__: _number_ + - __balance_median__: _number_ + +### ChannelBalanceEvent + - __block_height__: _number_ + - __channel_id__: _string_ + - __local_balance_sats__: _number_ + - __remote_balance_sats__: _number_ + +### ChannelRouting + - __receive_errors__: _number_ + - __forward_errors_as_output__: _number_ + - __missed_forward_fee_as_output__: _number_ + - __events_number__: _number_ + - __channel_id__: _string_ + - __forward_errors_as_input__: _number_ + - __missed_forward_fee_as_input__: _number_ + - __forward_fee_as_input__: _number_ + - __forward_fee_as_output__: _number_ + - __send_errors__: _number_ + +### SendAppUserToAppPaymentRequest + - __from_user_identifier__: _string_ + - __amount__: _number_ + +### SetMockAppBalanceRequest + - __amount__: _number_ + +### HttpCreds + - __url__: _string_ + - __token__: _string_ + +### ClosedChannel + - __channel_id__: _string_ + - __capacity__: _number_ + - __closed_height__: _number_ + +### Application + - __id__: _string_ + - __balance__: _number_ + - __npub__: _string_ + - __name__: _string_ + +### AddAppUserRequest + - __balance__: _number_ + - __identifier__: _string_ + - __fail_if_exists__: _boolean_ + +### SetMockAppUserBalanceRequest + - __user_identifier__: _string_ + - __amount__: _number_ + +### PayAddressResponse + - __operation_id__: _string_ + - __service_fee__: _number_ + - __network_fee__: _number_ + - __txId__: _string_ + +### NewInvoiceResponse + - __invoice__: _string_ + +### RequestNPubLinkingTokenRequest + - __user_identifier__: _string_ + +### LinkNPubThroughTokenRequest + - __token__: _string_ + - __nostr_pub__: _string_ + +### OpenChannel + - __channel_id__: _string_ + - __capacity__: _number_ + - __active__: _boolean_ + - __lifetime__: _number_ + - __local_balance__: _number_ + - __remote_balance__: _number_ + +### SetMockInvoiceAsPaidRequest + - __invoice__: _string_ + - __amount__: _number_ + +### AddAppUserInvoiceRequest + - __receiver_identifier__: _string_ + - __payer_identifier__: _string_ + - __http_callback_url__: _string_ + - __invoice_req__: _[NewInvoiceRequest](#NewInvoiceRequest)_ + +### DecodeInvoiceResponse + - __amount__: _number_ + +### OpenChannelResponse + - __channelId__: _string_ + +### RelaysMigration + - __relays__: ARRAY of: _string_ + +### LndMetrics + - __nodes__: ARRAY of: _[LndNodeMetrics](#LndNodeMetrics)_ + +### AppUser + - __identifier__: _string_ + - __info__: _[UserInfo](#UserInfo)_ + - __max_withdrawable__: _number_ + +### AddAppInvoiceRequest + - __payer_identifier__: _string_ + - __http_callback_url__: _string_ + - __invoice_req__: _[NewInvoiceRequest](#NewInvoiceRequest)_ + +### UserOperations + - __fromIndex__: _number_ + - __toIndex__: _number_ + - __operations__: ARRAY of: _[UserOperation](#UserOperation)_ + +### BanUserRequest + - __user_id__: _string_ + +### NewAddressRequest + - __addressType__: _[AddressType](#AddressType)_ + +### DecodeInvoiceRequest + - __invoice__: _string_ + +### LnurlWithdrawInfoResponse + - __callback__: _string_ + - __k1__: _string_ + - __defaultDescription__: _string_ + - __minWithdrawable__: _number_ + - __maxWithdrawable__: _number_ + - __balanceCheck__: _string_ + - __payLink__: _string_ + - __tag__: _string_ + +### GetUserOperationsRequest + - __latestOutgoingInvoice__: _number_ + - __latestIncomingTx__: _number_ + - __latestOutgoingTx__: _number_ + - __latestIncomingUserToUserPayment__: _number_ + - __latestOutgoingUserToUserPayment__: _number_ + - __max_size__: _number_ + - __latestIncomingInvoice__: _number_ + +### AppMetrics + - __spent__: _number_ + - __available__: _number_ + - __fees__: _number_ + - __invoices__: _number_ + - __total_fees__: _number_ + - __app__: _[Application](#Application)_ + - __users__: _[UsersInfo](#UsersInfo)_ + - __received__: _number_ + - __operations__: ARRAY of: _[UserOperation](#UserOperation)_ + +### AddAppRequest + - __name__: _string_ + - __allow_user_creation__: _boolean_ + +### SendAppUserToAppUserPaymentRequest + - __amount__: _number_ + - __from_user_identifier__: _string_ + - __to_user_identifier__: _string_ + +### LnurlPayInfoResponse + - __callback__: _string_ + - __maxSendable__: _number_ + - __minSendable__: _number_ + - __metadata__: _string_ + - __allowsNostr__: _boolean_ + - __nostrPubkey__: _string_ + - __tag__: _string_ + +### HandleLnurlPayResponse + - __pr__: _string_ + - __routes__: ARRAY of: _[Empty](#Empty)_ + +### EnrollAdminTokenRequest + - __admin_token__: _string_ + +### UsageMetrics + - __metrics__: ARRAY of: _[UsageMetric](#UsageMetric)_ + +### LnurlLinkResponse + - __k1__: _string_ + - __lnurl__: _string_ + +### LiveUserOperation + - __operation__: _[UserOperation](#UserOperation)_ + +### PayInvoiceRequest + - __invoice__: _string_ + - __amount__: _number_ + +### GetProductBuyLinkResponse + - __link__: _string_ + +### LndNodeMetrics + - __chain_balance_events__: ARRAY of: _[ChainBalanceEvent](#ChainBalanceEvent)_ + - __online_channels__: _number_ + - __closing_channels__: _number_ + - __channels_balance_events__: ARRAY of: _[ChannelBalanceEvent](#ChannelBalanceEvent)_ + - __pending_channels__: _number_ + - __open_channels__: ARRAY of: _[OpenChannel](#OpenChannel)_ + - __closed_channels__: ARRAY of: _[ClosedChannel](#ClosedChannel)_ + - __channel_routing__: ARRAY of: _[ChannelRouting](#ChannelRouting)_ + - __offline_channels__: _number_ + +### AuthApp + - __app__: _[Application](#Application)_ + - __auth_token__: _string_ + +### GetAppUserLNURLInfoRequest + - __user_identifier__: _string_ + - __base_url_override__: _string_ + +### UserInfo + - __network_max_fee_fixed__: _number_ + - __userId__: _string_ + - __balance__: _number_ + - __max_withdrawable__: _number_ + - __user_identifier__: _string_ + - __service_fee_bps__: _number_ + - __network_max_fee_bps__: _number_ + +### UserOperation + - __paidAtUnix__: _number_ + - __service_fee__: _number_ + - __confirmed__: _boolean_ + - __tx_hash__: _string_ + - __internal__: _boolean_ + - __network_fee__: _number_ + - __type__: _[UserOperationType](#UserOperationType)_ + - __inbound__: _boolean_ + - __amount__: _number_ + - __identifier__: _string_ + - __operationId__: _string_ +## Enums +### The enumerators used in the messages + +### AddressType + - __WITNESS_PUBKEY_HASH__ + - __NESTED_PUBKEY_HASH__ + - __TAPROOT_PUBKEY__ + +### UserOperationType + - __INCOMING_TX__ + - __OUTGOING_TX__ + - __INCOMING_INVOICE__ + - __OUTGOING_INVOICE__ + - __OUTGOING_USER_TO_USER__ + - __INCOMING_USER_TO_USER__ diff --git a/proto/autogenerated/debug.txt b/proto/autogenerated/debug.txt index 751faf33..b6209372 100644 --- a/proto/autogenerated/debug.txt +++ b/proto/autogenerated/debug.txt @@ -1,3865 +1,4171 @@ -([]*main.Method) (len=46 cap=64) { - (*main.Method)(0xc00007a1e0)({ - in: (main.MethodMessage) { - name: (string) (len=17) "LndGetInfoRequest", - hasZeroFields: (bool) false - }, - name: (string) (len=10) "LndGetInfo", - out: (main.MethodMessage) { - name: (string) (len=18) "LndGetInfoResponse", - hasZeroFields: (bool) false - }, - opts: (*main.methodOptions)(0xc000071560)({ - authType: (*main.supportedAuth)(0xc0004ff020)({ - id: (string) (len=5) "admin", - name: (string) (len=5) "Admin", - context: (map[string]string) (len=1) { - (string) (len=8) "admin_id": (string) (len=6) "string" - } - }), - method: (string) (len=4) "post", - route: (main.decodedRoute) { - route: (string) (len=22) "/api/admin/lnd/getinfo", - params: ([]string) - }, - query: ([]string) , - nostr: (bool) false, - batch: (bool) false - }), - serverStream: (bool) false - }), - (*main.Method)(0xc00007a280)({ - in: (main.MethodMessage) { - name: (string) (len=13) "AddAppRequest", - hasZeroFields: (bool) false - }, - name: (string) (len=6) "AddApp", - out: (main.MethodMessage) { - name: (string) (len=7) "AuthApp", - hasZeroFields: (bool) false - }, - opts: (*main.methodOptions)(0xc0000716e0)({ - authType: (*main.supportedAuth)(0xc0004ff0b0)({ - id: (string) (len=5) "admin", - name: (string) (len=5) "Admin", - context: (map[string]string) (len=1) { - (string) (len=8) "admin_id": (string) (len=6) "string" - } - }), - method: (string) (len=4) "post", - route: (main.decodedRoute) { - route: (string) (len=18) "/api/admin/app/add", - params: ([]string) - }, - query: ([]string) , - nostr: (bool) false, - batch: (bool) false - }), - serverStream: (bool) false - }), - (*main.Method)(0xc00007a320)({ - in: (main.MethodMessage) { - name: (string) (len=14) "AuthAppRequest", - hasZeroFields: (bool) false - }, - name: (string) (len=7) "AuthApp", - out: (main.MethodMessage) { - name: (string) (len=7) "AuthApp", - hasZeroFields: (bool) false - }, - opts: (*main.methodOptions)(0xc000071860)({ - authType: (*main.supportedAuth)(0xc0004ff140)({ - id: (string) (len=5) "admin", - name: (string) (len=5) "Admin", - context: (map[string]string) (len=1) { - (string) (len=8) "admin_id": (string) (len=6) "string" - } - }), - method: (string) (len=4) "post", - route: (main.decodedRoute) { - route: (string) (len=19) "/api/admin/app/auth", - params: ([]string) - }, - query: ([]string) , - nostr: (bool) false, - batch: (bool) false - }), - serverStream: (bool) false - }), - (*main.Method)(0xc00007a3c0)({ - in: (main.MethodMessage) { - name: (string) (len=14) "BanUserRequest", - hasZeroFields: (bool) false - }, - name: (string) (len=7) "BanUser", - out: (main.MethodMessage) { - name: (string) (len=15) "BanUserResponse", - hasZeroFields: (bool) false - }, - opts: (*main.methodOptions)(0xc0000719e0)({ - authType: (*main.supportedAuth)(0xc0004ff1d0)({ - id: (string) (len=5) "admin", - name: (string) (len=5) "Admin", - context: (map[string]string) (len=1) { - (string) (len=8) "admin_id": (string) (len=6) "string" - } - }), - method: (string) (len=4) "post", - route: (main.decodedRoute) { - route: (string) (len=19) "/api/admin/user/ban", - params: ([]string) - }, - query: ([]string) , - nostr: (bool) false, - batch: (bool) false - }), - serverStream: (bool) false - }), - (*main.Method)(0xc00007a410)({ - in: (main.MethodMessage) { - name: (string) (len=5) "Empty", - hasZeroFields: (bool) true - }, - name: (string) (len=15) "GetUsageMetrics", - out: (main.MethodMessage) { - name: (string) (len=12) "UsageMetrics", - hasZeroFields: (bool) false - }, - opts: (*main.methodOptions)(0xc000071b60)({ - authType: (*main.supportedAuth)(0xc0004ff260)({ - id: (string) (len=7) "metrics", - name: (string) (len=7) "Metrics", - context: (map[string]string) (len=1) { - (string) (len=11) "operator_id": (string) (len=6) "string" - } - }), - method: (string) (len=4) "post", - route: (main.decodedRoute) { - route: (string) (len=18) "/api/reports/usage", - params: ([]string) - }, - query: ([]string) , - nostr: (bool) false, - batch: (bool) false - }), - serverStream: (bool) false - }), - (*main.Method)(0xc00007a460)({ - in: (main.MethodMessage) { - name: (string) (len=18) "AppsMetricsRequest", - hasZeroFields: (bool) false - }, - name: (string) (len=14) "GetAppsMetrics", - out: (main.MethodMessage) { - name: (string) (len=11) "AppsMetrics", - hasZeroFields: (bool) false - }, - opts: (*main.methodOptions)(0xc000071ce0)({ - authType: (*main.supportedAuth)(0xc0004ff2f0)({ - id: (string) (len=7) "metrics", - name: (string) (len=7) "Metrics", - context: (map[string]string) (len=1) { - (string) (len=11) "operator_id": (string) (len=6) "string" - } - }), - method: (string) (len=4) "post", - route: (main.decodedRoute) { - route: (string) (len=17) "/api/reports/apps", - params: ([]string) - }, - query: ([]string) , - nostr: (bool) false, - batch: (bool) false - }), - serverStream: (bool) false - }), - (*main.Method)(0xc00007a4b0)({ - in: (main.MethodMessage) { - name: (string) (len=17) "LndMetricsRequest", - hasZeroFields: (bool) false - }, - name: (string) (len=13) "GetLndMetrics", - out: (main.MethodMessage) { - name: (string) (len=10) "LndMetrics", - hasZeroFields: (bool) false - }, - opts: (*main.methodOptions)(0xc000071e60)({ - authType: (*main.supportedAuth)(0xc0004ff380)({ - id: (string) (len=7) "metrics", - name: (string) (len=7) "Metrics", - context: (map[string]string) (len=1) { - (string) (len=11) "operator_id": (string) (len=6) "string" - } - }), - method: (string) (len=4) "post", - route: (main.decodedRoute) { - route: (string) (len=16) "/api/reports/lnd", - params: ([]string) - }, - query: ([]string) , - nostr: (bool) false, - batch: (bool) false - }), - serverStream: (bool) false - }), - (*main.Method)(0xc00007a500)({ - in: (main.MethodMessage) { - name: (string) (len=5) "Empty", - hasZeroFields: (bool) true - }, - name: (string) (len=6) "Health", - out: (main.MethodMessage) { - name: (string) (len=5) "Empty", - hasZeroFields: (bool) true - }, - opts: (*main.methodOptions)(0xc000351800)({ - authType: (*main.supportedAuth)(0xc0004ff410)({ - id: (string) (len=5) "guest", - name: (string) (len=5) "Guest", - context: (map[string]string) { - } - }), - method: (string) (len=3) "get", - route: (main.decodedRoute) { - route: (string) (len=11) "/api/health", - params: ([]string) - }, - query: ([]string) , - nostr: (bool) false, - batch: (bool) false - }), - serverStream: (bool) false - }), - (*main.Method)(0xc00007a550)({ - in: (main.MethodMessage) { - name: (string) (len=25) "EncryptionExchangeRequest", - hasZeroFields: (bool) false - }, - name: (string) (len=18) "EncryptionExchange", - out: (main.MethodMessage) { - name: (string) (len=5) "Empty", - hasZeroFields: (bool) true - }, - opts: (*main.methodOptions)(0xc000351980)({ - authType: (*main.supportedAuth)(0xc0004ff4d0)({ - id: (string) (len=5) "guest", - name: (string) (len=5) "Guest", - context: (map[string]string) { - } - }), - method: (string) (len=4) "post", - route: (main.decodedRoute) { - route: (string) (len=24) "/api/encryption/exchange", - params: ([]string) - }, - query: ([]string) , - nostr: (bool) false, - batch: (bool) false - }), - serverStream: (bool) false - }), - (*main.Method)(0xc00007a5a0)({ - in: (main.MethodMessage) { - name: (string) (len=27) "SetMockInvoiceAsPaidRequest", - hasZeroFields: (bool) false - }, - name: (string) (len=20) "SetMockInvoiceAsPaid", - out: (main.MethodMessage) { - name: (string) (len=5) "Empty", - hasZeroFields: (bool) true - }, - opts: (*main.methodOptions)(0xc000351b60)({ - authType: (*main.supportedAuth)(0xc0004ff560)({ - id: (string) (len=5) "guest", - name: (string) (len=5) "Guest", - context: (map[string]string) { - } - }), - method: (string) (len=4) "post", - route: (main.decodedRoute) { - route: (string) (len=26) "/api/lnd/mock/invoice/paid", - params: ([]string) - }, - query: ([]string) , - nostr: (bool) false, - batch: (bool) false - }), - serverStream: (bool) false - }), - (*main.Method)(0xc00007a640)({ - in: (main.MethodMessage) { - name: (string) (len=5) "Empty", - hasZeroFields: (bool) true - }, - name: (string) (len=20) "GetLnurlWithdrawInfo", - out: (main.MethodMessage) { - name: (string) (len=25) "LnurlWithdrawInfoResponse", - hasZeroFields: (bool) false - }, - opts: (*main.methodOptions)(0xc000351ec0)({ - authType: (*main.supportedAuth)(0xc0004ff6b0)({ - id: (string) (len=5) "guest", - name: (string) (len=5) "Guest", - context: (map[string]string) { - } - }), - method: (string) (len=3) "get", - route: (main.decodedRoute) { - route: (string) (len=30) "/api/guest/lnurl_withdraw/info", - params: ([]string) - }, - query: ([]string) (len=1 cap=1) { - (string) (len=2) "k1" - }, - nostr: (bool) false, - batch: (bool) false - }), - serverStream: (bool) false - }), - (*main.Method)(0xc00007a6e0)({ - in: (main.MethodMessage) { - name: (string) (len=5) "Empty", - hasZeroFields: (bool) true - }, - name: (string) (len=19) "HandleLnurlWithdraw", - out: (main.MethodMessage) { - name: (string) (len=5) "Empty", - hasZeroFields: (bool) true - }, - opts: (*main.methodOptions)(0xc0000a4720)({ - authType: (*main.supportedAuth)(0xc0004ff800)({ - id: (string) (len=5) "guest", - name: (string) (len=5) "Guest", - context: (map[string]string) { - } - }), - method: (string) (len=3) "get", - route: (main.decodedRoute) { - route: (string) (len=32) "/api/guest/lnurl_withdraw/handle", - params: ([]string) - }, - query: ([]string) (len=2 cap=2) { - (string) (len=2) "k1", - (string) (len=2) "pr" - }, - nostr: (bool) false, - batch: (bool) false - }), - serverStream: (bool) false - }), - (*main.Method)(0xc00007a780)({ - in: (main.MethodMessage) { - name: (string) (len=5) "Empty", - hasZeroFields: (bool) true - }, - name: (string) (len=15) "GetLnurlPayInfo", - out: (main.MethodMessage) { - name: (string) (len=20) "LnurlPayInfoResponse", - hasZeroFields: (bool) false - }, - opts: (*main.methodOptions)(0xc0000a4a80)({ - authType: (*main.supportedAuth)(0xc0004ff920)({ - id: (string) (len=5) "guest", - name: (string) (len=5) "Guest", - context: (map[string]string) { - } - }), - method: (string) (len=3) "get", - route: (main.decodedRoute) { - route: (string) (len=25) "/api/guest/lnurl_pay/info", - params: ([]string) - }, - query: ([]string) (len=1 cap=1) { - (string) (len=2) "k1" - }, - nostr: (bool) false, - batch: (bool) false - }), - serverStream: (bool) false - }), - (*main.Method)(0xc00007a820)({ - in: (main.MethodMessage) { - name: (string) (len=5) "Empty", - hasZeroFields: (bool) true - }, - name: (string) (len=14) "HandleLnurlPay", - out: (main.MethodMessage) { - name: (string) (len=22) "HandleLnurlPayResponse", - hasZeroFields: (bool) false - }, - opts: (*main.methodOptions)(0xc0000a4e40)({ - authType: (*main.supportedAuth)(0xc0004ffa70)({ - id: (string) (len=5) "guest", - name: (string) (len=5) "Guest", - context: (map[string]string) { - } - }), - method: (string) (len=3) "get", - route: (main.decodedRoute) { - route: (string) (len=27) "/api/guest/lnurl_pay/handle", - params: ([]string) - }, - query: ([]string) (len=4 cap=4) { - (string) (len=2) "k1", - (string) (len=6) "amount", - (string) (len=5) "nostr", - (string) (len=5) "lnurl" - }, - nostr: (bool) false, - batch: (bool) false - }), - serverStream: (bool) false - }), - (*main.Method)(0xc00007a870)({ - in: (main.MethodMessage) { - name: (string) (len=5) "Empty", - hasZeroFields: (bool) true - }, - name: (string) (len=18) "HandleLnurlAddress", - out: (main.MethodMessage) { - name: (string) (len=20) "LnurlPayInfoResponse", - hasZeroFields: (bool) false - }, - opts: (*main.methodOptions)(0xc0000a5080)({ - authType: (*main.supportedAuth)(0xc0004ffb00)({ - id: (string) (len=5) "guest", - name: (string) (len=5) "Guest", - context: (map[string]string) { - } - }), - method: (string) (len=3) "get", - route: (main.decodedRoute) { - route: (string) (len=33) "/.well-known/lnurlp/:address_name", - params: ([]string) (len=1 cap=1) { - (string) (len=12) "address_name" - } - }, - query: ([]string) , - nostr: (bool) false, - batch: (bool) false - }), - serverStream: (bool) false - }), - (*main.Method)(0xc00007a910)({ - in: (main.MethodMessage) { - name: (string) (len=27) "LinkNPubThroughTokenRequest", - hasZeroFields: (bool) false - }, - name: (string) (len=20) "LinkNPubThroughToken", - out: (main.MethodMessage) { - name: (string) (len=5) "Empty", - hasZeroFields: (bool) true - }, - opts: (*main.methodOptions)(0xc0000a5260)({ - authType: (*main.supportedAuth)(0xc0004ffbc0)({ - id: (string) (len=4) "user", - name: (string) (len=4) "User", - context: (map[string]string) (len=3) { - (string) (len=7) "user_id": (string) (len=6) "string", - (string) (len=6) "app_id": (string) (len=6) "string", - (string) (len=11) "app_user_id": (string) (len=6) "string" - } - }), - method: (string) (len=4) "post", - route: (main.decodedRoute) { - route: (string) (len=20) "/api/guest/npub/link", - params: ([]string) - }, - query: ([]string) , - nostr: (bool) true, - batch: (bool) false - }), - serverStream: (bool) false - }), - (*main.Method)(0xc00007a960)({ - in: (main.MethodMessage) { - name: (string) (len=5) "Empty", - hasZeroFields: (bool) true - }, - name: (string) (len=6) "GetApp", - out: (main.MethodMessage) { - name: (string) (len=11) "Application", - hasZeroFields: (bool) false - }, - opts: (*main.methodOptions)(0xc0000a5440)({ - authType: (*main.supportedAuth)(0xc0004ffc50)({ - id: (string) (len=3) "app", - name: (string) (len=3) "App", - context: (map[string]string) (len=1) { - (string) (len=6) "app_id": (string) (len=6) "string" - } - }), - method: (string) (len=4) "post", - route: (main.decodedRoute) { - route: (string) (len=12) "/api/app/get", - params: ([]string) - }, - query: ([]string) , - nostr: (bool) false, - batch: (bool) false - }), - serverStream: (bool) false - }), - (*main.Method)(0xc00007aa00)({ - in: (main.MethodMessage) { - name: (string) (len=17) "AddAppUserRequest", - hasZeroFields: (bool) false - }, - name: (string) (len=10) "AddAppUser", - out: (main.MethodMessage) { - name: (string) (len=7) "AppUser", - hasZeroFields: (bool) false - }, - opts: (*main.methodOptions)(0xc00008a0c0)({ - authType: (*main.supportedAuth)(0xc0004ffce0)({ - id: (string) (len=3) "app", - name: (string) (len=3) "App", - context: (map[string]string) (len=1) { - (string) (len=6) "app_id": (string) (len=6) "string" - } - }), - method: (string) (len=4) "post", - route: (main.decodedRoute) { - route: (string) (len=17) "/api/app/user/add", - params: ([]string) - }, - query: ([]string) , - nostr: (bool) false, - batch: (bool) false - }), - serverStream: (bool) false - }), - (*main.Method)(0xc00007aaa0)({ - in: (main.MethodMessage) { - name: (string) (len=20) "AddAppInvoiceRequest", - hasZeroFields: (bool) false - }, - name: (string) (len=13) "AddAppInvoice", - out: (main.MethodMessage) { - name: (string) (len=18) "NewInvoiceResponse", - hasZeroFields: (bool) false - }, - opts: (*main.methodOptions)(0xc00008a240)({ - authType: (*main.supportedAuth)(0xc0004ffd70)({ - id: (string) (len=3) "app", - name: (string) (len=3) "App", - context: (map[string]string) (len=1) { - (string) (len=6) "app_id": (string) (len=6) "string" - } - }), - method: (string) (len=4) "post", - route: (main.decodedRoute) { - route: (string) (len=20) "/api/app/add/invoice", - params: ([]string) - }, - query: ([]string) , - nostr: (bool) false, - batch: (bool) false - }), - serverStream: (bool) false - }), - (*main.Method)(0xc00007aaf0)({ - in: (main.MethodMessage) { - name: (string) (len=24) "AddAppUserInvoiceRequest", - hasZeroFields: (bool) false - }, - name: (string) (len=17) "AddAppUserInvoice", - out: (main.MethodMessage) { - name: (string) (len=18) "NewInvoiceResponse", - hasZeroFields: (bool) false - }, - opts: (*main.methodOptions)(0xc00008a420)({ - authType: (*main.supportedAuth)(0xc0004ffe00)({ - id: (string) (len=3) "app", - name: (string) (len=3) "App", - context: (map[string]string) (len=1) { - (string) (len=6) "app_id": (string) (len=6) "string" - } - }), - method: (string) (len=4) "post", - route: (main.decodedRoute) { - route: (string) (len=25) "/api/app/user/add/invoice", - params: ([]string) - }, - query: ([]string) , - nostr: (bool) false, - batch: (bool) false - }), - serverStream: (bool) false - }), - (*main.Method)(0xc00007ab90)({ - in: (main.MethodMessage) { - name: (string) (len=17) "GetAppUserRequest", - hasZeroFields: (bool) false - }, - name: (string) (len=10) "GetAppUser", - out: (main.MethodMessage) { - name: (string) (len=7) "AppUser", - hasZeroFields: (bool) false - }, - opts: (*main.methodOptions)(0xc00008a5a0)({ - authType: (*main.supportedAuth)(0xc0004ffe90)({ - id: (string) (len=3) "app", - name: (string) (len=3) "App", - context: (map[string]string) (len=1) { - (string) (len=6) "app_id": (string) (len=6) "string" - } - }), - method: (string) (len=4) "post", - route: (main.decodedRoute) { - route: (string) (len=17) "/api/app/user/get", - params: ([]string) - }, - query: ([]string) , - nostr: (bool) false, - batch: (bool) false - }), - serverStream: (bool) false - }), - (*main.Method)(0xc00007ac30)({ - in: (main.MethodMessage) { - name: (string) (len=24) "PayAppUserInvoiceRequest", - hasZeroFields: (bool) false - }, - name: (string) (len=17) "PayAppUserInvoice", - out: (main.MethodMessage) { - name: (string) (len=18) "PayInvoiceResponse", - hasZeroFields: (bool) false - }, - opts: (*main.methodOptions)(0xc00008a720)({ - authType: (*main.supportedAuth)(0xc0004fff20)({ - id: (string) (len=3) "app", - name: (string) (len=3) "App", - context: (map[string]string) (len=1) { - (string) (len=6) "app_id": (string) (len=6) "string" - } - }), - method: (string) (len=4) "post", - route: (main.decodedRoute) { - route: (string) (len=20) "/api/app/invoice/pay", - params: ([]string) - }, - query: ([]string) , - nostr: (bool) false, - batch: (bool) false - }), - serverStream: (bool) false - }), - (*main.Method)(0xc00007ac80)({ - in: (main.MethodMessage) { - name: (string) (len=34) "SendAppUserToAppUserPaymentRequest", - hasZeroFields: (bool) false - }, - name: (string) (len=27) "SendAppUserToAppUserPayment", - out: (main.MethodMessage) { - name: (string) (len=5) "Empty", - hasZeroFields: (bool) true - }, - opts: (*main.methodOptions)(0xc00008a900)({ - authType: (*main.supportedAuth)(0xc0004fffb0)({ - id: (string) (len=3) "app", - name: (string) (len=3) "App", - context: (map[string]string) (len=1) { - (string) (len=6) "app_id": (string) (len=6) "string" - } - }), - method: (string) (len=4) "post", - route: (main.decodedRoute) { - route: (string) (len=26) "/api/app/user/internal/pay", - params: ([]string) - }, - query: ([]string) , - nostr: (bool) false, - batch: (bool) false - }), - serverStream: (bool) false - }), - (*main.Method)(0xc00007ad20)({ - in: (main.MethodMessage) { - name: (string) (len=30) "SendAppUserToAppPaymentRequest", - hasZeroFields: (bool) false - }, - name: (string) (len=23) "SendAppUserToAppPayment", - out: (main.MethodMessage) { - name: (string) (len=5) "Empty", - hasZeroFields: (bool) true - }, - opts: (*main.methodOptions)(0xc00008aa80)({ - authType: (*main.supportedAuth)(0xc000090060)({ - id: (string) (len=3) "app", - name: (string) (len=3) "App", - context: (map[string]string) (len=1) { - (string) (len=6) "app_id": (string) (len=6) "string" - } - }), - method: (string) (len=4) "post", - route: (main.decodedRoute) { - route: (string) (len=21) "/api/app/internal/pay", - params: ([]string) - }, - query: ([]string) , - nostr: (bool) false, - batch: (bool) false - }), - serverStream: (bool) false - }), - (*main.Method)(0xc00007ad70)({ - in: (main.MethodMessage) { - name: (string) (len=26) "GetAppUserLNURLInfoRequest", - hasZeroFields: (bool) false - }, - name: (string) (len=19) "GetAppUserLNURLInfo", - out: (main.MethodMessage) { - name: (string) (len=20) "LnurlPayInfoResponse", - hasZeroFields: (bool) false - }, - opts: (*main.methodOptions)(0xc00008ac00)({ - authType: (*main.supportedAuth)(0xc0000900f0)({ - id: (string) (len=3) "app", - name: (string) (len=3) "App", - context: (map[string]string) (len=1) { - (string) (len=6) "app_id": (string) (len=6) "string" - } - }), - method: (string) (len=4) "post", - route: (main.decodedRoute) { - route: (string) (len=28) "/api/app/user/lnurl/pay/info", - params: ([]string) - }, - query: ([]string) , - nostr: (bool) false, - batch: (bool) false - }), - serverStream: (bool) false - }), - (*main.Method)(0xc00007adc0)({ - in: (main.MethodMessage) { - name: (string) (len=28) "SetMockAppUserBalanceRequest", - hasZeroFields: (bool) false - }, - name: (string) (len=21) "SetMockAppUserBalance", - out: (main.MethodMessage) { - name: (string) (len=5) "Empty", - hasZeroFields: (bool) true - }, - opts: (*main.methodOptions)(0xc00008ad80)({ - authType: (*main.supportedAuth)(0xc000090180)({ - id: (string) (len=3) "app", - name: (string) (len=3) "App", - context: (map[string]string) (len=1) { - (string) (len=6) "app_id": (string) (len=6) "string" - } - }), - method: (string) (len=4) "post", - route: (main.decodedRoute) { - route: (string) (len=29) "/api/app/mock/user/blance/set", - params: ([]string) - }, - query: ([]string) , - nostr: (bool) false, - batch: (bool) false - }), - serverStream: (bool) false - }), - (*main.Method)(0xc00007ae10)({ - in: (main.MethodMessage) { - name: (string) (len=24) "SetMockAppBalanceRequest", - hasZeroFields: (bool) false - }, - name: (string) (len=17) "SetMockAppBalance", - out: (main.MethodMessage) { - name: (string) (len=5) "Empty", - hasZeroFields: (bool) true - }, - opts: (*main.methodOptions)(0xc00008af60)({ - authType: (*main.supportedAuth)(0xc000090210)({ - id: (string) (len=3) "app", - name: (string) (len=3) "App", - context: (map[string]string) (len=1) { - (string) (len=6) "app_id": (string) (len=6) "string" - } - }), - method: (string) (len=4) "post", - route: (main.decodedRoute) { - route: (string) (len=24) "/api/app/mock/blance/set", - params: ([]string) - }, - query: ([]string) , - nostr: (bool) false, - batch: (bool) false - }), - serverStream: (bool) false - }), - (*main.Method)(0xc00007ae60)({ - in: (main.MethodMessage) { - name: (string) (len=30) "RequestNPubLinkingTokenRequest", - hasZeroFields: (bool) false - }, - name: (string) (len=23) "RequestNPubLinkingToken", - out: (main.MethodMessage) { - name: (string) (len=31) "RequestNPubLinkingTokenResponse", - hasZeroFields: (bool) false - }, - opts: (*main.methodOptions)(0xc00008b140)({ - authType: (*main.supportedAuth)(0xc0000902a0)({ - id: (string) (len=3) "app", - name: (string) (len=3) "App", - context: (map[string]string) (len=1) { - (string) (len=6) "app_id": (string) (len=6) "string" - } - }), - method: (string) (len=4) "post", - route: (main.decodedRoute) { - route: (string) (len=24) "/api/app/user/npub/token", - params: ([]string) - }, - query: ([]string) , - nostr: (bool) false, - batch: (bool) false - }), - serverStream: (bool) false - }), - (*main.Method)(0xc00007aeb0)({ - in: (main.MethodMessage) { - name: (string) (len=5) "Empty", - hasZeroFields: (bool) true - }, - name: (string) (len=10) "UserHealth", - out: (main.MethodMessage) { - name: (string) (len=5) "Empty", - hasZeroFields: (bool) true - }, - opts: (*main.methodOptions)(0xc00008b320)({ - authType: (*main.supportedAuth)(0xc000090330)({ - id: (string) (len=4) "user", - name: (string) (len=4) "User", - context: (map[string]string) (len=3) { - (string) (len=7) "user_id": (string) (len=6) "string", - (string) (len=6) "app_id": (string) (len=6) "string", - (string) (len=11) "app_user_id": (string) (len=6) "string" - } - }), - method: (string) (len=4) "post", - route: (main.decodedRoute) { - route: (string) (len=16) "/api/user/health", - params: ([]string) - }, - query: ([]string) , - nostr: (bool) true, - batch: (bool) false - }), - serverStream: (bool) false - }), - (*main.Method)(0xc00007af00)({ - in: (main.MethodMessage) { - name: (string) (len=5) "Empty", - hasZeroFields: (bool) true - }, - name: (string) (len=11) "GetUserInfo", - out: (main.MethodMessage) { - name: (string) (len=8) "UserInfo", - hasZeroFields: (bool) false - }, - opts: (*main.methodOptions)(0xc00008b500)({ - authType: (*main.supportedAuth)(0xc0000903c0)({ - id: (string) (len=4) "user", - name: (string) (len=4) "User", - context: (map[string]string) (len=3) { - (string) (len=7) "user_id": (string) (len=6) "string", - (string) (len=6) "app_id": (string) (len=6) "string", - (string) (len=11) "app_user_id": (string) (len=6) "string" - } - }), - method: (string) (len=4) "post", - route: (main.decodedRoute) { - route: (string) (len=14) "/api/user/info", - params: ([]string) - }, - query: ([]string) , - nostr: (bool) true, - batch: (bool) false - }), - serverStream: (bool) false - }), - (*main.Method)(0xc00007afa0)({ - in: (main.MethodMessage) { - name: (string) (len=17) "AddProductRequest", - hasZeroFields: (bool) false - }, - name: (string) (len=10) "AddProduct", - out: (main.MethodMessage) { - name: (string) (len=7) "Product", - hasZeroFields: (bool) false - }, - opts: (*main.methodOptions)(0xc00008b6e0)({ - authType: (*main.supportedAuth)(0xc000090450)({ - id: (string) (len=4) "user", - name: (string) (len=4) "User", - context: (map[string]string) (len=3) { - (string) (len=6) "app_id": (string) (len=6) "string", - (string) (len=11) "app_user_id": (string) (len=6) "string", - (string) (len=7) "user_id": (string) (len=6) "string" - } - }), - method: (string) (len=4) "post", - route: (main.decodedRoute) { - route: (string) (len=21) "/api/user/product/add", - params: ([]string) - }, - query: ([]string) , - nostr: (bool) true, - batch: (bool) false - }), - serverStream: (bool) false - }), - (*main.Method)(0xc00007aff0)({ - in: (main.MethodMessage) { - name: (string) (len=5) "Empty", - hasZeroFields: (bool) true - }, - name: (string) (len=17) "NewProductInvoice", - out: (main.MethodMessage) { - name: (string) (len=18) "NewInvoiceResponse", - hasZeroFields: (bool) false - }, - opts: (*main.methodOptions)(0xc00008bb60)({ - authType: (*main.supportedAuth)(0xc000090570)({ - id: (string) (len=4) "user", - name: (string) (len=4) "User", - context: (map[string]string) (len=3) { - (string) (len=11) "app_user_id": (string) (len=6) "string", - (string) (len=7) "user_id": (string) (len=6) "string", - (string) (len=6) "app_id": (string) (len=6) "string" - } - }), - method: (string) (len=3) "get", - route: (main.decodedRoute) { - route: (string) (len=29) "/api/user/product/get/invoice", - params: ([]string) - }, - query: ([]string) (len=1 cap=1) { - (string) (len=2) "id" - }, - nostr: (bool) true, - batch: (bool) false - }), - serverStream: (bool) false - }), - (*main.Method)(0xc00007b040)({ - in: (main.MethodMessage) { - name: (string) (len=24) "GetUserOperationsRequest", - hasZeroFields: (bool) false - }, - name: (string) (len=17) "GetUserOperations", - out: (main.MethodMessage) { - name: (string) (len=25) "GetUserOperationsResponse", - hasZeroFields: (bool) false - }, - opts: (*main.methodOptions)(0xc00008bd40)({ - authType: (*main.supportedAuth)(0xc000090600)({ - id: (string) (len=4) "user", - name: (string) (len=4) "User", - context: (map[string]string) (len=3) { - (string) (len=7) "user_id": (string) (len=6) "string", - (string) (len=6) "app_id": (string) (len=6) "string", - (string) (len=11) "app_user_id": (string) (len=6) "string" - } - }), - method: (string) (len=4) "post", - route: (main.decodedRoute) { - route: (string) (len=20) "/api/user/operations", - params: ([]string) - }, - query: ([]string) , - nostr: (bool) true, - batch: (bool) false - }), - serverStream: (bool) false - }), - (*main.Method)(0xc00007b0e0)({ - in: (main.MethodMessage) { - name: (string) (len=17) "NewAddressRequest", - hasZeroFields: (bool) false - }, - name: (string) (len=10) "NewAddress", - out: (main.MethodMessage) { - name: (string) (len=18) "NewAddressResponse", - hasZeroFields: (bool) false - }, - opts: (*main.methodOptions)(0xc00008bf20)({ - authType: (*main.supportedAuth)(0xc000090690)({ - id: (string) (len=4) "user", - name: (string) (len=4) "User", - context: (map[string]string) (len=3) { - (string) (len=7) "user_id": (string) (len=6) "string", - (string) (len=6) "app_id": (string) (len=6) "string", - (string) (len=11) "app_user_id": (string) (len=6) "string" - } - }), - method: (string) (len=4) "post", - route: (main.decodedRoute) { - route: (string) (len=19) "/api/user/chain/new", - params: ([]string) - }, - query: ([]string) , - nostr: (bool) true, - batch: (bool) false - }), - serverStream: (bool) false - }), - (*main.Method)(0xc00007b180)({ - in: (main.MethodMessage) { - name: (string) (len=17) "PayAddressRequest", - hasZeroFields: (bool) false - }, - name: (string) (len=10) "PayAddress", - out: (main.MethodMessage) { - name: (string) (len=18) "PayAddressResponse", - hasZeroFields: (bool) false - }, - opts: (*main.methodOptions)(0xc00013a120)({ - authType: (*main.supportedAuth)(0xc000090720)({ - id: (string) (len=4) "user", - name: (string) (len=4) "User", - context: (map[string]string) (len=3) { - (string) (len=7) "user_id": (string) (len=6) "string", - (string) (len=6) "app_id": (string) (len=6) "string", - (string) (len=11) "app_user_id": (string) (len=6) "string" - } - }), - method: (string) (len=4) "post", - route: (main.decodedRoute) { - route: (string) (len=19) "/api/user/chain/pay", - params: ([]string) - }, - query: ([]string) , - nostr: (bool) true, - batch: (bool) false - }), - serverStream: (bool) false - }), - (*main.Method)(0xc00007b220)({ - in: (main.MethodMessage) { - name: (string) (len=17) "NewInvoiceRequest", - hasZeroFields: (bool) false - }, - name: (string) (len=10) "NewInvoice", - out: (main.MethodMessage) { - name: (string) (len=18) "NewInvoiceResponse", - hasZeroFields: (bool) false - }, - opts: (*main.methodOptions)(0xc00013a300)({ - authType: (*main.supportedAuth)(0xc0000907b0)({ - id: (string) (len=4) "user", - name: (string) (len=4) "User", - context: (map[string]string) (len=3) { - (string) (len=7) "user_id": (string) (len=6) "string", - (string) (len=6) "app_id": (string) (len=6) "string", - (string) (len=11) "app_user_id": (string) (len=6) "string" - } - }), - method: (string) (len=4) "post", - route: (main.decodedRoute) { - route: (string) (len=21) "/api/user/invoice/new", - params: ([]string) - }, - query: ([]string) , - nostr: (bool) true, - batch: (bool) false - }), - serverStream: (bool) false - }), - (*main.Method)(0xc00007b2c0)({ - in: (main.MethodMessage) { - name: (string) (len=20) "DecodeInvoiceRequest", - hasZeroFields: (bool) false - }, - name: (string) (len=13) "DecodeInvoice", - out: (main.MethodMessage) { - name: (string) (len=21) "DecodeInvoiceResponse", - hasZeroFields: (bool) false - }, - opts: (*main.methodOptions)(0xc00013a4e0)({ - authType: (*main.supportedAuth)(0xc000090840)({ - id: (string) (len=4) "user", - name: (string) (len=4) "User", - context: (map[string]string) (len=3) { - (string) (len=11) "app_user_id": (string) (len=6) "string", - (string) (len=7) "user_id": (string) (len=6) "string", - (string) (len=6) "app_id": (string) (len=6) "string" - } - }), - method: (string) (len=4) "post", - route: (main.decodedRoute) { - route: (string) (len=24) "/api/user/invoice/decode", - params: ([]string) - }, - query: ([]string) , - nostr: (bool) true, - batch: (bool) false - }), - serverStream: (bool) false - }), - (*main.Method)(0xc00007b360)({ - in: (main.MethodMessage) { - name: (string) (len=17) "PayInvoiceRequest", - hasZeroFields: (bool) false - }, - name: (string) (len=10) "PayInvoice", - out: (main.MethodMessage) { - name: (string) (len=18) "PayInvoiceResponse", - hasZeroFields: (bool) false - }, - opts: (*main.methodOptions)(0xc00013a6c0)({ - authType: (*main.supportedAuth)(0xc0000908d0)({ - id: (string) (len=4) "user", - name: (string) (len=4) "User", - context: (map[string]string) (len=3) { - (string) (len=7) "user_id": (string) (len=6) "string", - (string) (len=6) "app_id": (string) (len=6) "string", - (string) (len=11) "app_user_id": (string) (len=6) "string" - } - }), - method: (string) (len=4) "post", - route: (main.decodedRoute) { - route: (string) (len=21) "/api/user/invoice/pay", - params: ([]string) - }, - query: ([]string) , - nostr: (bool) true, - batch: (bool) false - }), - serverStream: (bool) false - }), - (*main.Method)(0xc00007b400)({ - in: (main.MethodMessage) { - name: (string) (len=18) "OpenChannelRequest", - hasZeroFields: (bool) false - }, - name: (string) (len=11) "OpenChannel", - out: (main.MethodMessage) { - name: (string) (len=19) "OpenChannelResponse", - hasZeroFields: (bool) false - }, - opts: (*main.methodOptions)(0xc00013a8a0)({ - authType: (*main.supportedAuth)(0xc000090960)({ - id: (string) (len=4) "user", - name: (string) (len=4) "User", - context: (map[string]string) (len=3) { - (string) (len=7) "user_id": (string) (len=6) "string", - (string) (len=6) "app_id": (string) (len=6) "string", - (string) (len=11) "app_user_id": (string) (len=6) "string" - } - }), - method: (string) (len=4) "post", - route: (main.decodedRoute) { - route: (string) (len=22) "/api/user/open/channel", - params: ([]string) - }, - query: ([]string) , - nostr: (bool) true, - batch: (bool) false - }), - serverStream: (bool) false - }), - (*main.Method)(0xc00007b4a0)({ - in: (main.MethodMessage) { - name: (string) (len=5) "Empty", - hasZeroFields: (bool) true - }, - name: (string) (len=20) "GetLnurlWithdrawLink", - out: (main.MethodMessage) { - name: (string) (len=17) "LnurlLinkResponse", - hasZeroFields: (bool) false - }, - opts: (*main.methodOptions)(0xc00013aa80)({ - authType: (*main.supportedAuth)(0xc0000909f0)({ - id: (string) (len=4) "user", - name: (string) (len=4) "User", - context: (map[string]string) (len=3) { - (string) (len=7) "user_id": (string) (len=6) "string", - (string) (len=6) "app_id": (string) (len=6) "string", - (string) (len=11) "app_user_id": (string) (len=6) "string" - } - }), - method: (string) (len=3) "get", - route: (main.decodedRoute) { - route: (string) (len=29) "/api/user/lnurl_withdraw/link", - params: ([]string) - }, - query: ([]string) , - nostr: (bool) true, - batch: (bool) false - }), - serverStream: (bool) false - }), - (*main.Method)(0xc00007b540)({ - in: (main.MethodMessage) { - name: (string) (len=5) "Empty", - hasZeroFields: (bool) true - }, - name: (string) (len=15) "GetLnurlPayLink", - out: (main.MethodMessage) { - name: (string) (len=17) "LnurlLinkResponse", - hasZeroFields: (bool) false - }, - opts: (*main.methodOptions)(0xc00013ac60)({ - authType: (*main.supportedAuth)(0xc000090a80)({ - id: (string) (len=4) "user", - name: (string) (len=4) "User", - context: (map[string]string) (len=3) { - (string) (len=7) "user_id": (string) (len=6) "string", - (string) (len=6) "app_id": (string) (len=6) "string", - (string) (len=11) "app_user_id": (string) (len=6) "string" - } - }), - method: (string) (len=3) "get", - route: (main.decodedRoute) { - route: (string) (len=24) "/api/user/lnurl_pay/link", - params: ([]string) - }, - query: ([]string) , - nostr: (bool) true, - batch: (bool) false - }), - serverStream: (bool) false - }), - (*main.Method)(0xc00007b5e0)({ - in: (main.MethodMessage) { - name: (string) (len=5) "Empty", - hasZeroFields: (bool) true - }, - name: (string) (len=19) "GetLNURLChannelLink", - out: (main.MethodMessage) { - name: (string) (len=17) "LnurlLinkResponse", - hasZeroFields: (bool) false - }, - opts: (*main.methodOptions)(0xc00013ae40)({ - authType: (*main.supportedAuth)(0xc000090b10)({ - id: (string) (len=4) "user", - name: (string) (len=4) "User", - context: (map[string]string) (len=3) { - (string) (len=7) "user_id": (string) (len=6) "string", - (string) (len=6) "app_id": (string) (len=6) "string", - (string) (len=11) "app_user_id": (string) (len=6) "string" - } - }), - method: (string) (len=4) "post", - route: (main.decodedRoute) { - route: (string) (len=27) "/api/user/lnurl_channel/url", - params: ([]string) - }, - query: ([]string) , - nostr: (bool) true, - batch: (bool) false - }), - serverStream: (bool) false - }), - (*main.Method)(0xc00007b680)({ - in: (main.MethodMessage) { - name: (string) (len=5) "Empty", - hasZeroFields: (bool) true - }, - name: (string) (len=21) "GetLiveUserOperations", - out: (main.MethodMessage) { - name: (string) (len=17) "LiveUserOperation", - hasZeroFields: (bool) false - }, - opts: (*main.methodOptions)(0xc00013b020)({ - authType: (*main.supportedAuth)(0xc000090ba0)({ - id: (string) (len=4) "user", - name: (string) (len=4) "User", - context: (map[string]string) (len=3) { - (string) (len=7) "user_id": (string) (len=6) "string", - (string) (len=6) "app_id": (string) (len=6) "string", - (string) (len=11) "app_user_id": (string) (len=6) "string" - } - }), - method: (string) (len=4) "post", - route: (main.decodedRoute) { - route: (string) (len=24) "/api/user/operations/sub", - params: ([]string) - }, - query: ([]string) , - nostr: (bool) true, - batch: (bool) false - }), - serverStream: (bool) true - }), - (*main.Method)(0xc00007b720)({ - in: (main.MethodMessage) { - name: (string) (len=5) "Empty", - hasZeroFields: (bool) true - }, - name: (string) (len=18) "GetMigrationUpdate", - out: (main.MethodMessage) { - name: (string) (len=15) "MigrationUpdate", - hasZeroFields: (bool) false - }, - opts: (*main.methodOptions)(0xc00013b200)({ - authType: (*main.supportedAuth)(0xc000090c30)({ - id: (string) (len=4) "user", - name: (string) (len=4) "User", - context: (map[string]string) (len=3) { - (string) (len=7) "user_id": (string) (len=6) "string", - (string) (len=6) "app_id": (string) (len=6) "string", - (string) (len=11) "app_user_id": (string) (len=6) "string" - } - }), - method: (string) (len=4) "post", - route: (main.decodedRoute) { - route: (string) (len=24) "/api/user/migrations/sub", - params: ([]string) - }, - query: ([]string) , - nostr: (bool) true, - batch: (bool) false - }), - serverStream: (bool) true - }), - (*main.Method)(0xc00007b770)({ - in: (main.MethodMessage) { - name: (string) (len=5) "Empty", - hasZeroFields: (bool) true - }, - name: (string) (len=12) "GetHttpCreds", - out: (main.MethodMessage) { - name: (string) (len=9) "HttpCreds", - hasZeroFields: (bool) false - }, - opts: (*main.methodOptions)(0xc00013b3e0)({ - authType: (*main.supportedAuth)(0xc000090cc0)({ - id: (string) (len=4) "user", - name: (string) (len=4) "User", - context: (map[string]string) (len=3) { - (string) (len=7) "user_id": (string) (len=6) "string", - (string) (len=6) "app_id": (string) (len=6) "string", - (string) (len=11) "app_user_id": (string) (len=6) "string" - } - }), - method: (string) (len=4) "post", - route: (main.decodedRoute) { - route: (string) (len=20) "/api/user/http_creds", - params: ([]string) - }, - query: ([]string) , - nostr: (bool) true, - batch: (bool) false - }), - serverStream: (bool) true - }), - (*main.Method)(0xc00007b7c0)({ - in: (main.MethodMessage) { - name: (string) (len=5) "Empty", - hasZeroFields: (bool) true - }, - name: (string) (len=9) "BatchUser", - out: (main.MethodMessage) { - name: (string) (len=5) "Empty", - hasZeroFields: (bool) true - }, - opts: (*main.methodOptions)(0xc00013b620)({ - authType: (*main.supportedAuth)(0xc000090d80)({ - id: (string) (len=4) "user", - name: (string) (len=4) "User", - context: (map[string]string) (len=3) { - (string) (len=7) "user_id": (string) (len=6) "string", - (string) (len=6) "app_id": (string) (len=6) "string", - (string) (len=11) "app_user_id": (string) (len=6) "string" - } - }), - method: (string) (len=4) "post", - route: (main.decodedRoute) { - route: (string) (len=15) "/api/user/batch", - params: ([]string) - }, - query: ([]string) , - nostr: (bool) true, - batch: (bool) true - }), - serverStream: (bool) false - }) -} - -([]*main.Enum) (len=2 cap=2) { - (*main.Enum)(0xc0004fe6f0)({ - name: (string) (len=11) "AddressType", - values: ([]main.EnumValue) (len=3 cap=4) { - (main.EnumValue) { - number: (int64) 0, - name: (string) (len=19) "WITNESS_PUBKEY_HASH" - }, - (main.EnumValue) { - number: (int64) 1, - name: (string) (len=18) "NESTED_PUBKEY_HASH" - }, - (main.EnumValue) { - number: (int64) 2, - name: (string) (len=14) "TAPROOT_PUBKEY" - } - } - }), - (*main.Enum)(0xc0004fe750)({ - name: (string) (len=17) "UserOperationType", - values: ([]main.EnumValue) (len=6 cap=8) { - (main.EnumValue) { - number: (int64) 0, - name: (string) (len=11) "INCOMING_TX" - }, - (main.EnumValue) { - number: (int64) 1, - name: (string) (len=11) "OUTGOING_TX" - }, - (main.EnumValue) { - number: (int64) 2, - name: (string) (len=16) "INCOMING_INVOICE" - }, - (main.EnumValue) { - number: (int64) 3, - name: (string) (len=16) "OUTGOING_INVOICE" - }, - (main.EnumValue) { - number: (int64) 4, - name: (string) (len=21) "OUTGOING_USER_TO_USER" - }, - (main.EnumValue) { - number: (int64) 5, - name: (string) (len=21) "INCOMING_USER_TO_USER" - } - } - }) -} - -(map[string]*main.Message) (len=70) { - (string) (len=12) "UsageMetrics": (*main.Message)(0xc000348580)({ - fullName: (string) (len=12) "UsageMetrics", - name: (string) (len=12) "UsageMetrics", - fields: ([]*main.Field) (len=1 cap=1) { - (*main.Field)(0xc000207f80)({ - name: (string) (len=7) "metrics", - kind: (string) (len=11) "UsageMetric", - isMap: (bool) false, - isArray: (bool) true, - isEnum: (bool) false, - isMessage: (bool) true, - isOptional: (bool) false - }) - } - }), - (string) (len=11) "OpenChannel": (*main.Message)(0xc000348d00)({ - fullName: (string) (len=11) "OpenChannel", - name: (string) (len=11) "OpenChannel", - fields: ([]*main.Field) (len=6 cap=8) { - (*main.Field)(0xc0004fc6c0)({ - name: (string) (len=10) "channel_id", - kind: (string) (len=6) "string", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fc6f0)({ - name: (string) (len=8) "capacity", - kind: (string) (len=5) "int64", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fc720)({ - name: (string) (len=6) "active", - kind: (string) (len=4) "bool", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fc750)({ - name: (string) (len=8) "lifetime", - kind: (string) (len=5) "int64", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fc780)({ - name: (string) (len=13) "local_balance", - kind: (string) (len=5) "int64", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fc7b0)({ - name: (string) (len=14) "remote_balance", - kind: (string) (len=5) "int64", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }) - } - }), - (string) (len=17) "NewAddressRequest": (*main.Message)(0xc000349400)({ - fullName: (string) (len=17) "NewAddressRequest", - name: (string) (len=17) "NewAddressRequest", - fields: ([]*main.Field) (len=1 cap=1) { - (*main.Field)(0xc0004fd530)({ - name: (string) (len=11) "addressType", - kind: (string) (len=11) "AddressType", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) true, - isMessage: (bool) false, - isOptional: (bool) false - }) - } - }), - (string) (len=20) "LnurlPayInfoResponse": (*main.Message)(0xc000349840)({ - fullName: (string) (len=20) "LnurlPayInfoResponse", - name: (string) (len=20) "LnurlPayInfoResponse", - fields: ([]*main.Field) (len=7 cap=8) { - (*main.Field)(0xc0004fdbf0)({ - name: (string) (len=3) "tag", - kind: (string) (len=6) "string", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fdc20)({ - name: (string) (len=8) "callback", - kind: (string) (len=6) "string", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fdc50)({ - name: (string) (len=11) "maxSendable", - kind: (string) (len=5) "int64", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fdc80)({ - name: (string) (len=11) "minSendable", - kind: (string) (len=5) "int64", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fdcb0)({ - name: (string) (len=8) "metadata", - kind: (string) (len=6) "string", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fdce0)({ - name: (string) (len=11) "allowsNostr", - kind: (string) (len=4) "bool", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fdd10)({ - name: (string) (len=11) "nostrPubkey", - kind: (string) (len=6) "string", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }) - } - }), - (string) (len=25) "GetProductBuyLinkResponse": (*main.Message)(0xc000349b40)({ - fullName: (string) (len=25) "GetProductBuyLinkResponse", - name: (string) (len=25) "GetProductBuyLinkResponse", - fields: ([]*main.Field) (len=1 cap=1) { - (*main.Field)(0xc0004fe480)({ - name: (string) (len=4) "link", - kind: (string) (len=6) "string", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }) - } - }), - (string) (len=9) "UsersInfo": (*main.Message)(0xc000348840)({ - fullName: (string) (len=9) "UsersInfo", - name: (string) (len=9) "UsersInfo", - fields: ([]*main.Field) (len=6 cap=8) { - (*main.Field)(0xc00024ac60)({ - name: (string) (len=5) "total", - kind: (string) (len=5) "int64", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc00024ac90)({ - name: (string) (len=10) "no_balance", - kind: (string) (len=5) "int64", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fc000)({ - name: (string) (len=16) "negative_balance", - kind: (string) (len=5) "int64", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fc030)({ - name: (string) (len=20) "always_been_inactive", - kind: (string) (len=5) "int64", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fc060)({ - name: (string) (len=11) "balance_avg", - kind: (string) (len=5) "int64", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fc090)({ - name: (string) (len=14) "balance_median", - kind: (string) (len=5) "int64", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }) - } - }), - (string) (len=13) "AddAppRequest": (*main.Message)(0xc000349040)({ - fullName: (string) (len=13) "AddAppRequest", - name: (string) (len=13) "AddAppRequest", - fields: ([]*main.Field) (len=2 cap=2) { - (*main.Field)(0xc0004fce40)({ - name: (string) (len=4) "name", - kind: (string) (len=6) "string", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fce70)({ - name: (string) (len=19) "allow_user_creation", - kind: (string) (len=4) "bool", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }) - } - }), - (string) (len=21) "DecodeInvoiceResponse": (*main.Message)(0xc0003495c0)({ - fullName: (string) (len=21) "DecodeInvoiceResponse", - name: (string) (len=21) "DecodeInvoiceResponse", - fields: ([]*main.Field) (len=1 cap=1) { - (*main.Field)(0xc0004fd7a0)({ - name: (string) (len=6) "amount", - kind: (string) (len=5) "int64", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }) - } - }), - (string) (len=10) "LndMetrics": (*main.Message)(0xc000348e80)({ - fullName: (string) (len=10) "LndMetrics", - name: (string) (len=10) "LndMetrics", - fields: ([]*main.Field) (len=1 cap=1) { - (*main.Field)(0xc0004fcc00)({ - name: (string) (len=5) "nodes", - kind: (string) (len=14) "LndNodeMetrics", - isMap: (bool) false, - isArray: (bool) true, - isEnum: (bool) false, - isMessage: (bool) true, - isOptional: (bool) false - }) - } - }), - (string) (len=17) "AddProductRequest": (*main.Message)(0xc000349ac0)({ - fullName: (string) (len=17) "AddProductRequest", - name: (string) (len=17) "AddProductRequest", - fields: ([]*main.Field) (len=2 cap=2) { - (*main.Field)(0xc0004fe390)({ - name: (string) (len=4) "name", - kind: (string) (len=6) "string", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fe3c0)({ - name: (string) (len=10) "price_sats", - kind: (string) (len=5) "int64", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }) - } - }), - (string) (len=5) "Empty": (*main.Message)(0xc000348080)({ - fullName: (string) (len=5) "Empty", - name: (string) (len=5) "Empty", - fields: ([]*main.Field) - }), - (string) (len=14) "ChannelRouting": (*main.Message)(0xc000348dc0)({ - fullName: (string) (len=14) "ChannelRouting", - name: (string) (len=14) "ChannelRouting", - fields: ([]*main.Field) (len=10 cap=16) { - (*main.Field)(0xc0004fc870)({ - name: (string) (len=10) "channel_id", - kind: (string) (len=6) "string", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fc8a0)({ - name: (string) (len=11) "send_errors", - kind: (string) (len=5) "int64", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fc8d0)({ - name: (string) (len=14) "receive_errors", - kind: (string) (len=5) "int64", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fc900)({ - name: (string) (len=23) "forward_errors_as_input", - kind: (string) (len=5) "int64", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fc930)({ - name: (string) (len=24) "forward_errors_as_output", - kind: (string) (len=5) "int64", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fc960)({ - name: (string) (len=27) "missed_forward_fee_as_input", - kind: (string) (len=5) "int64", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fc990)({ - name: (string) (len=28) "missed_forward_fee_as_output", - kind: (string) (len=5) "int64", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fc9c0)({ - name: (string) (len=20) "forward_fee_as_input", - kind: (string) (len=5) "int64", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fc9f0)({ - name: (string) (len=21) "forward_fee_as_output", - kind: (string) (len=5) "int64", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fca20)({ - name: (string) (len=13) "events_number", - kind: (string) (len=5) "int64", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }) - } - }), - (string) (len=18) "PayInvoiceResponse": (*main.Message)(0xc000349680)({ - fullName: (string) (len=18) "PayInvoiceResponse", - name: (string) (len=18) "PayInvoiceResponse", - fields: ([]*main.Field) (len=5 cap=8) { - (*main.Field)(0xc0004fd830)({ - name: (string) (len=8) "preimage", - kind: (string) (len=6) "string", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fd860)({ - name: (string) (len=11) "amount_paid", - kind: (string) (len=5) "int64", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fd890)({ - name: (string) (len=12) "operation_id", - kind: (string) (len=6) "string", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fd8c0)({ - name: (string) (len=11) "service_fee", - kind: (string) (len=5) "int64", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fd8f0)({ - name: (string) (len=11) "network_fee", - kind: (string) (len=5) "int64", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }) - } - }), - (string) (len=8) "UserInfo": (*main.Message)(0xc0003498c0)({ - fullName: (string) (len=8) "UserInfo", - name: (string) (len=8) "UserInfo", - fields: ([]*main.Field) (len=4 cap=4) { - (*main.Field)(0xc0004fdda0)({ - name: (string) (len=6) "userId", - kind: (string) (len=6) "string", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fddd0)({ - name: (string) (len=7) "balance", - kind: (string) (len=5) "int64", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fde00)({ - name: (string) (len=16) "max_withdrawable", - kind: (string) (len=5) "int64", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fde30)({ - name: (string) (len=15) "user_identifier", - kind: (string) (len=6) "string", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }) - } - }), - (string) (len=15) "MigrationUpdate": (*main.Message)(0xc000349bc0)({ - fullName: (string) (len=15) "MigrationUpdate", - name: (string) (len=15) "MigrationUpdate", - fields: ([]*main.Field) (len=2 cap=2) { - (*main.Field)(0xc0004fe4e0)({ - name: (string) (len=7) "closure", - kind: (string) (len=16) "ClosureMigration", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) true, - isOptional: (bool) true - }), - (*main.Field)(0xc0004fe510)({ - name: (string) (len=6) "relays", - kind: (string) (len=15) "RelaysMigration", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) true, - isOptional: (bool) true - }) - } - }), - (string) (len=27) "LinkNPubThroughTokenRequest": (*main.Message)(0xc000349d00)({ - fullName: (string) (len=27) "LinkNPubThroughTokenRequest", - name: (string) (len=27) "LinkNPubThroughTokenRequest", - fields: ([]*main.Field) (len=2 cap=2) { - (*main.Field)(0xc0004fe600)({ - name: (string) (len=5) "token", - kind: (string) (len=6) "string", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fe630)({ - name: (string) (len=9) "nostr_pub", - kind: (string) (len=6) "string", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }) - } - }), - (string) (len=17) "PayAddressRequest": (*main.Message)(0xc000349480)({ - fullName: (string) (len=17) "PayAddressRequest", - name: (string) (len=17) "PayAddressRequest", - fields: ([]*main.Field) (len=3 cap=4) { - (*main.Field)(0xc0004fd590)({ - name: (string) (len=7) "address", - kind: (string) (len=6) "string", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fd5c0)({ - name: (string) (len=9) "amoutSats", - kind: (string) (len=5) "int64", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fd5f0)({ - name: (string) (len=12) "satsPerVByte", - kind: (string) (len=5) "int64", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }) - } - }), - (string) (len=18) "PayAddressResponse": (*main.Message)(0xc0003494c0)({ - fullName: (string) (len=18) "PayAddressResponse", - name: (string) (len=18) "PayAddressResponse", - fields: ([]*main.Field) (len=4 cap=4) { - (*main.Field)(0xc0004fd620)({ - name: (string) (len=4) "txId", - kind: (string) (len=6) "string", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fd650)({ - name: (string) (len=12) "operation_id", - kind: (string) (len=6) "string", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fd680)({ - name: (string) (len=11) "service_fee", - kind: (string) (len=5) "int64", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fd6b0)({ - name: (string) (len=11) "network_fee", - kind: (string) (len=5) "int64", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }) - } - }), - (string) (len=10) "AppMetrics": (*main.Message)(0xc000348900)({ - fullName: (string) (len=10) "AppMetrics", - name: (string) (len=10) "AppMetrics", - fields: ([]*main.Field) (len=9 cap=16) { - (*main.Field)(0xc0004fc0c0)({ - name: (string) (len=3) "app", - kind: (string) (len=11) "Application", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) true, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fc0f0)({ - name: (string) (len=5) "users", - kind: (string) (len=9) "UsersInfo", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) true, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fc120)({ - name: (string) (len=8) "received", - kind: (string) (len=5) "int64", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fc150)({ - name: (string) (len=5) "spent", - kind: (string) (len=5) "int64", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fc180)({ - name: (string) (len=9) "available", - kind: (string) (len=5) "int64", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fc1b0)({ - name: (string) (len=4) "fees", - kind: (string) (len=5) "int64", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fc1e0)({ - name: (string) (len=8) "invoices", - kind: (string) (len=5) "int64", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fc210)({ - name: (string) (len=10) "total_fees", - kind: (string) (len=5) "int64", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fc240)({ - name: (string) (len=10) "operations", - kind: (string) (len=13) "UserOperation", - isMap: (bool) false, - isArray: (bool) true, - isEnum: (bool) false, - isMessage: (bool) true, - isOptional: (bool) false - }) - } - }), - (string) (len=15) "BanUserResponse": (*main.Message)(0xc000349000)({ - fullName: (string) (len=15) "BanUserResponse", - name: (string) (len=15) "BanUserResponse", - fields: ([]*main.Field) (len=2 cap=2) { - (*main.Field)(0xc0004fcde0)({ - name: (string) (len=12) "balance_sats", - kind: (string) (len=5) "int64", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fce10)({ - name: (string) (len=16) "banned_app_users", - kind: (string) (len=13) "BannedAppUser", - isMap: (bool) false, - isArray: (bool) true, - isEnum: (bool) false, - isMessage: (bool) true, - isOptional: (bool) false - }) - } - }), - (string) (len=7) "AuthApp": (*main.Message)(0xc000349100)({ - fullName: (string) (len=7) "AuthApp", - name: (string) (len=7) "AuthApp", - fields: ([]*main.Field) (len=2 cap=2) { - (*main.Field)(0xc0004fcfc0)({ - name: (string) (len=3) "app", - kind: (string) (len=11) "Application", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) true, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fcff0)({ - name: (string) (len=10) "auth_token", - kind: (string) (len=6) "string", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }) - } - }), - (string) (len=17) "LndMetricsRequest": (*main.Message)(0xc0003489c0)({ - fullName: (string) (len=17) "LndMetricsRequest", - name: (string) (len=17) "LndMetricsRequest", - fields: ([]*main.Field) (len=2 cap=2) { - (*main.Field)(0xc0004fc2a0)({ - name: (string) (len=9) "from_unix", - kind: (string) (len=5) "int64", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) true - }), - (*main.Field)(0xc0004fc2d0)({ - name: (string) (len=7) "to_unix", - kind: (string) (len=5) "int64", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) true - }) - } - }), - (string) (len=13) "BannedAppUser": (*main.Message)(0xc000348fc0)({ - fullName: (string) (len=13) "BannedAppUser", - name: (string) (len=13) "BannedAppUser", - fields: ([]*main.Field) (len=4 cap=4) { - (*main.Field)(0xc0004fcd20)({ - name: (string) (len=8) "app_name", - kind: (string) (len=6) "string", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fcd50)({ - name: (string) (len=6) "app_id", - kind: (string) (len=6) "string", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fcd80)({ - name: (string) (len=15) "user_identifier", - kind: (string) (len=6) "string", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fcdb0)({ - name: (string) (len=9) "nostr_pub", - kind: (string) (len=6) "string", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }) - } - }), - (string) (len=17) "GetAppUserRequest": (*main.Message)(0xc000349240)({ - fullName: (string) (len=17) "GetAppUserRequest", - name: (string) (len=17) "GetAppUserRequest", - fields: ([]*main.Field) (len=1 cap=1) { - (*main.Field)(0xc0004fd290)({ - name: (string) (len=15) "user_identifier", - kind: (string) (len=6) "string", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }) - } - }), - (string) (len=24) "SetMockAppBalanceRequest": (*main.Message)(0xc0003493c0)({ - fullName: (string) (len=24) "SetMockAppBalanceRequest", - name: (string) (len=24) "SetMockAppBalanceRequest", - fields: ([]*main.Field) (len=1 cap=1) { - (*main.Field)(0xc0004fd500)({ - name: (string) (len=6) "amount", - kind: (string) (len=5) "int64", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }) - } - }), - (string) (len=20) "DecodeInvoiceRequest": (*main.Message)(0xc000349580)({ - fullName: (string) (len=20) "DecodeInvoiceRequest", - name: (string) (len=20) "DecodeInvoiceRequest", - fields: ([]*main.Field) (len=1 cap=1) { - (*main.Field)(0xc0004fd770)({ - name: (string) (len=7) "invoice", - kind: (string) (len=6) "string", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }) - } - }), - (string) (len=31) "RequestNPubLinkingTokenResponse": (*main.Message)(0xc000349cc0)({ - fullName: (string) (len=31) "RequestNPubLinkingTokenResponse", - name: (string) (len=31) "RequestNPubLinkingTokenResponse", - fields: ([]*main.Field) (len=1 cap=1) { - (*main.Field)(0xc0004fe5d0)({ - name: (string) (len=5) "token", - kind: (string) (len=6) "string", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }) - } - }), - (string) (len=17) "LndGetInfoRequest": (*main.Message)(0xc000348ec0)({ - fullName: (string) (len=17) "LndGetInfoRequest", - name: (string) (len=17) "LndGetInfoRequest", - fields: ([]*main.Field) (len=1 cap=1) { - (*main.Field)(0xc0004fcc30)({ - name: (string) (len=6) "nodeId", - kind: (string) (len=5) "int64", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }) - } - }), - (string) (len=7) "AppUser": (*main.Message)(0xc000349180)({ - fullName: (string) (len=7) "AppUser", - name: (string) (len=7) "AppUser", - fields: ([]*main.Field) (len=3 cap=4) { - (*main.Field)(0xc0004fd0b0)({ - name: (string) (len=10) "identifier", - kind: (string) (len=6) "string", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fd0e0)({ - name: (string) (len=4) "info", - kind: (string) (len=8) "UserInfo", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) true, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fd110)({ - name: (string) (len=16) "max_withdrawable", - kind: (string) (len=5) "int64", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }) - } - }), - (string) (len=28) "SetMockAppUserBalanceRequest": (*main.Message)(0xc000349380)({ - fullName: (string) (len=28) "SetMockAppUserBalanceRequest", - name: (string) (len=28) "SetMockAppUserBalanceRequest", - fields: ([]*main.Field) (len=2 cap=2) { - (*main.Field)(0xc0004fd4a0)({ - name: (string) (len=15) "user_identifier", - kind: (string) (len=6) "string", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fd4d0)({ - name: (string) (len=6) "amount", - kind: (string) (len=5) "int64", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }) - } - }), - (string) (len=17) "PayInvoiceRequest": (*main.Message)(0xc000349600)({ - fullName: (string) (len=17) "PayInvoiceRequest", - name: (string) (len=17) "PayInvoiceRequest", - fields: ([]*main.Field) (len=2 cap=2) { - (*main.Field)(0xc0004fd7d0)({ - name: (string) (len=7) "invoice", - kind: (string) (len=6) "string", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fd800)({ - name: (string) (len=6) "amount", - kind: (string) (len=5) "int64", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }) - } - }), - (string) (len=17) "AddAppUserRequest": (*main.Message)(0xc000349140)({ - fullName: (string) (len=17) "AddAppUserRequest", - name: (string) (len=17) "AddAppUserRequest", - fields: ([]*main.Field) (len=3 cap=4) { - (*main.Field)(0xc0004fd020)({ - name: (string) (len=10) "identifier", - kind: (string) (len=6) "string", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fd050)({ - name: (string) (len=14) "fail_if_exists", - kind: (string) (len=4) "bool", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fd080)({ - name: (string) (len=7) "balance", - kind: (string) (len=5) "int64", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }) - } - }), - (string) (len=18) "NewInvoiceResponse": (*main.Message)(0xc000349540)({ - fullName: (string) (len=18) "NewInvoiceResponse", - name: (string) (len=18) "NewInvoiceResponse", - fields: ([]*main.Field) (len=1 cap=1) { - (*main.Field)(0xc0004fd740)({ - name: (string) (len=7) "invoice", - kind: (string) (len=6) "string", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }) - } - }), - (string) (len=11) "AppsMetrics": (*main.Message)(0xc000348940)({ - fullName: (string) (len=11) "AppsMetrics", - name: (string) (len=11) "AppsMetrics", - fields: ([]*main.Field) (len=1 cap=1) { - (*main.Field)(0xc0004fc270)({ - name: (string) (len=4) "apps", - kind: (string) (len=10) "AppMetrics", - isMap: (bool) false, - isArray: (bool) true, - isEnum: (bool) false, - isMessage: (bool) true, - isOptional: (bool) false - }) - } - }), - (string) (len=18) "LndGetInfoResponse": (*main.Message)(0xc000348f40)({ - fullName: (string) (len=18) "LndGetInfoResponse", - name: (string) (len=18) "LndGetInfoResponse", - fields: ([]*main.Field) (len=1 cap=1) { - (*main.Field)(0xc0004fccc0)({ - name: (string) (len=5) "alias", - kind: (string) (len=6) "string", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }) - } - }), - (string) (len=18) "NewAddressResponse": (*main.Message)(0xc000349440)({ - fullName: (string) (len=18) "NewAddressResponse", - name: (string) (len=18) "NewAddressResponse", - fields: ([]*main.Field) (len=1 cap=1) { - (*main.Field)(0xc0004fd560)({ - name: (string) (len=7) "address", - kind: (string) (len=6) "string", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }) - } - }), - (string) (len=14) "BanUserRequest": (*main.Message)(0xc000348f80)({ - fullName: (string) (len=14) "BanUserRequest", - name: (string) (len=14) "BanUserRequest", - fields: ([]*main.Field) (len=1 cap=1) { - (*main.Field)(0xc0004fccf0)({ - name: (string) (len=7) "user_id", - kind: (string) (len=6) "string", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }) - } - }), - (string) (len=34) "SendAppUserToAppUserPaymentRequest": (*main.Message)(0xc0003492c0)({ - fullName: (string) (len=34) "SendAppUserToAppUserPaymentRequest", - name: (string) (len=34) "SendAppUserToAppUserPaymentRequest", - fields: ([]*main.Field) (len=3 cap=4) { - (*main.Field)(0xc0004fd350)({ - name: (string) (len=20) "from_user_identifier", - kind: (string) (len=6) "string", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fd380)({ - name: (string) (len=18) "to_user_identifier", - kind: (string) (len=6) "string", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fd3b0)({ - name: (string) (len=6) "amount", - kind: (string) (len=5) "int64", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }) - } - }), - (string) (len=30) "SendAppUserToAppPaymentRequest": (*main.Message)(0xc000349300)({ - fullName: (string) (len=30) "SendAppUserToAppPaymentRequest", - name: (string) (len=30) "SendAppUserToAppPaymentRequest", - fields: ([]*main.Field) (len=2 cap=2) { - (*main.Field)(0xc0004fd3e0)({ - name: (string) (len=20) "from_user_identifier", - kind: (string) (len=6) "string", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fd410)({ - name: (string) (len=6) "amount", - kind: (string) (len=5) "int64", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }) - } - }), - (string) (len=24) "GetUserOperationsRequest": (*main.Message)(0xc000349940)({ - fullName: (string) (len=24) "GetUserOperationsRequest", - name: (string) (len=24) "GetUserOperationsRequest", - fields: ([]*main.Field) (len=7 cap=8) { - (*main.Field)(0xc0004fde60)({ - name: (string) (len=21) "latestIncomingInvoice", - kind: (string) (len=5) "int64", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fde90)({ - name: (string) (len=21) "latestOutgoingInvoice", - kind: (string) (len=5) "int64", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fdec0)({ - name: (string) (len=16) "latestIncomingTx", - kind: (string) (len=5) "int64", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fdef0)({ - name: (string) (len=16) "latestOutgoingTx", - kind: (string) (len=5) "int64", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fdf20)({ - name: (string) (len=31) "latestIncomingUserToUserPayment", - kind: (string) (len=5) "int64", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fdf50)({ - name: (string) (len=31) "latestOutgoingUserToUserPayment", - kind: (string) (len=5) "int64", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fdf80)({ - name: (string) (len=8) "max_size", - kind: (string) (len=5) "int64", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }) - } - }), - (string) (len=25) "GetUserOperationsResponse": (*main.Message)(0xc000349a80)({ - fullName: (string) (len=25) "GetUserOperationsResponse", - name: (string) (len=25) "GetUserOperationsResponse", - fields: ([]*main.Field) (len=6 cap=8) { - (*main.Field)(0xc0004fe270)({ - name: (string) (len=31) "latestOutgoingInvoiceOperations", - kind: (string) (len=14) "UserOperations", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) true, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fe2a0)({ - name: (string) (len=31) "latestIncomingInvoiceOperations", - kind: (string) (len=14) "UserOperations", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) true, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fe2d0)({ - name: (string) (len=26) "latestOutgoingTxOperations", - kind: (string) (len=14) "UserOperations", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) true, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fe300)({ - name: (string) (len=26) "latestIncomingTxOperations", - kind: (string) (len=14) "UserOperations", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) true, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fe330)({ - name: (string) (len=32) "latestOutgoingUserToUserPayemnts", - kind: (string) (len=14) "UserOperations", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) true, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fe360)({ - name: (string) (len=32) "latestIncomingUserToUserPayemnts", - kind: (string) (len=14) "UserOperations", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) true, - isOptional: (bool) false - }) - } - }), - (string) (len=16) "ClosureMigration": (*main.Message)(0xc000349c00)({ - fullName: (string) (len=16) "ClosureMigration", - name: (string) (len=16) "ClosureMigration", - fields: ([]*main.Field) (len=1 cap=1) { - (*main.Field)(0xc0004fe540)({ - name: (string) (len=14) "closes_at_unix", - kind: (string) (len=5) "int64", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }) - } - }), - (string) (len=14) "AuthAppRequest": (*main.Message)(0xc000349080)({ - fullName: (string) (len=14) "AuthAppRequest", - name: (string) (len=14) "AuthAppRequest", - fields: ([]*main.Field) (len=2 cap=2) { - (*main.Field)(0xc0004fcea0)({ - name: (string) (len=4) "name", - kind: (string) (len=6) "string", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fced0)({ - name: (string) (len=19) "allow_user_creation", - kind: (string) (len=4) "bool", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) true - }) - } - }), - (string) (len=11) "Application": (*main.Message)(0xc0003490c0)({ - fullName: (string) (len=11) "Application", - name: (string) (len=11) "Application", - fields: ([]*main.Field) (len=4 cap=4) { - (*main.Field)(0xc0004fcf00)({ - name: (string) (len=4) "name", - kind: (string) (len=6) "string", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fcf30)({ - name: (string) (len=2) "id", - kind: (string) (len=6) "string", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fcf60)({ - name: (string) (len=7) "balance", - kind: (string) (len=5) "int64", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fcf90)({ - name: (string) (len=4) "npub", - kind: (string) (len=6) "string", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }) - } - }), - (string) (len=20) "AddAppInvoiceRequest": (*main.Message)(0xc0003491c0)({ - fullName: (string) (len=20) "AddAppInvoiceRequest", - name: (string) (len=20) "AddAppInvoiceRequest", - fields: ([]*main.Field) (len=3 cap=4) { - (*main.Field)(0xc0004fd140)({ - name: (string) (len=16) "payer_identifier", - kind: (string) (len=6) "string", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fd170)({ - name: (string) (len=17) "http_callback_url", - kind: (string) (len=6) "string", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fd1a0)({ - name: (string) (len=11) "invoice_req", - kind: (string) (len=17) "NewInvoiceRequest", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) true, - isOptional: (bool) false - }) - } - }), - (string) (len=26) "GetAppUserLNURLInfoRequest": (*main.Message)(0xc000349340)({ - fullName: (string) (len=26) "GetAppUserLNURLInfoRequest", - name: (string) (len=26) "GetAppUserLNURLInfoRequest", - fields: ([]*main.Field) (len=2 cap=2) { - (*main.Field)(0xc0004fd440)({ - name: (string) (len=15) "user_identifier", - kind: (string) (len=6) "string", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fd470)({ - name: (string) (len=17) "base_url_override", - kind: (string) (len=6) "string", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }) - } - }), - (string) (len=17) "LnurlLinkResponse": (*main.Message)(0xc000349740)({ - fullName: (string) (len=17) "LnurlLinkResponse", - name: (string) (len=17) "LnurlLinkResponse", - fields: ([]*main.Field) (len=2 cap=2) { - (*main.Field)(0xc0004fda10)({ - name: (string) (len=5) "lnurl", - kind: (string) (len=6) "string", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fda40)({ - name: (string) (len=2) "k1", - kind: (string) (len=6) "string", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }) - } - }), - (string) (len=25) "LnurlWithdrawInfoResponse": (*main.Message)(0xc0003497c0)({ - fullName: (string) (len=25) "LnurlWithdrawInfoResponse", - name: (string) (len=25) "LnurlWithdrawInfoResponse", - fields: ([]*main.Field) (len=8 cap=8) { - (*main.Field)(0xc0004fda70)({ - name: (string) (len=3) "tag", - kind: (string) (len=6) "string", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fdaa0)({ - name: (string) (len=8) "callback", - kind: (string) (len=6) "string", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fdad0)({ - name: (string) (len=2) "k1", - kind: (string) (len=6) "string", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fdb00)({ - name: (string) (len=18) "defaultDescription", - kind: (string) (len=6) "string", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fdb30)({ - name: (string) (len=15) "minWithdrawable", - kind: (string) (len=5) "int64", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fdb60)({ - name: (string) (len=15) "maxWithdrawable", - kind: (string) (len=5) "int64", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fdb90)({ - name: (string) (len=12) "balanceCheck", - kind: (string) (len=6) "string", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fdbc0)({ - name: (string) (len=7) "payLink", - kind: (string) (len=6) "string", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }) - } - }), - (string) (len=13) "UserOperation": (*main.Message)(0xc0003499c0)({ - fullName: (string) (len=13) "UserOperation", - name: (string) (len=13) "UserOperation", - fields: ([]*main.Field) (len=11 cap=16) { - (*main.Field)(0xc0004fdfb0)({ - name: (string) (len=10) "paidAtUnix", - kind: (string) (len=5) "int64", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fe000)({ - name: (string) (len=4) "type", - kind: (string) (len=17) "UserOperationType", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) true, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fe030)({ - name: (string) (len=7) "inbound", - kind: (string) (len=4) "bool", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fe060)({ - name: (string) (len=6) "amount", - kind: (string) (len=5) "int64", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fe090)({ - name: (string) (len=10) "identifier", - kind: (string) (len=6) "string", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fe0c0)({ - name: (string) (len=11) "operationId", - kind: (string) (len=6) "string", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fe0f0)({ - name: (string) (len=11) "service_fee", - kind: (string) (len=5) "int64", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fe120)({ - name: (string) (len=11) "network_fee", - kind: (string) (len=5) "int64", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fe150)({ - name: (string) (len=9) "confirmed", - kind: (string) (len=4) "bool", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fe180)({ - name: (string) (len=7) "tx_hash", - kind: (string) (len=6) "string", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fe1b0)({ - name: (string) (len=8) "internal", - kind: (string) (len=4) "bool", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }) - } - }), - (string) (len=15) "RelaysMigration": (*main.Message)(0xc000349c40)({ - fullName: (string) (len=15) "RelaysMigration", - name: (string) (len=15) "RelaysMigration", - fields: ([]*main.Field) (len=1 cap=1) { - (*main.Field)(0xc0004fe570)({ - name: (string) (len=6) "relays", - kind: (string) (len=6) "string", - isMap: (bool) false, - isArray: (bool) true, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }) - } - }), - (string) (len=30) "RequestNPubLinkingTokenRequest": (*main.Message)(0xc000349c80)({ - fullName: (string) (len=30) "RequestNPubLinkingTokenRequest", - name: (string) (len=30) "RequestNPubLinkingTokenRequest", - fields: ([]*main.Field) (len=1 cap=1) { - (*main.Field)(0xc0004fe5a0)({ - name: (string) (len=15) "user_identifier", - kind: (string) (len=6) "string", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }) - } - }), - (string) (len=25) "EncryptionExchangeRequest": (*main.Message)(0xc000348180)({ - fullName: (string) (len=25) "EncryptionExchangeRequest", - name: (string) (len=25) "EncryptionExchangeRequest", - fields: ([]*main.Field) (len=2 cap=2) { - (*main.Field)(0xc000207d70)({ - name: (string) (len=9) "publicKey", - kind: (string) (len=6) "string", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc000207da0)({ - name: (string) (len=8) "deviceId", - kind: (string) (len=6) "string", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }) - } - }), - (string) (len=18) "AppsMetricsRequest": (*main.Message)(0xc000348600)({ - fullName: (string) (len=18) "AppsMetricsRequest", - name: (string) (len=18) "AppsMetricsRequest", - fields: ([]*main.Field) (len=3 cap=4) { - (*main.Field)(0xc000207fb0)({ - name: (string) (len=9) "from_unix", - kind: (string) (len=5) "int64", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) true - }), - (*main.Field)(0xc00034ec90)({ - name: (string) (len=7) "to_unix", - kind: (string) (len=5) "int64", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) true - }), - (*main.Field)(0xc00034ecc0)({ - name: (string) (len=18) "include_operations", - kind: (string) (len=4) "bool", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) true - }) - } - }), - (string) (len=13) "ClosedChannel": (*main.Message)(0xc000348d40)({ - fullName: (string) (len=13) "ClosedChannel", - name: (string) (len=13) "ClosedChannel", - fields: ([]*main.Field) (len=3 cap=4) { - (*main.Field)(0xc0004fc7e0)({ - name: (string) (len=10) "channel_id", - kind: (string) (len=6) "string", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fc810)({ - name: (string) (len=8) "capacity", - kind: (string) (len=5) "int64", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fc840)({ - name: (string) (len=13) "closed_height", - kind: (string) (len=5) "int64", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }) - } - }), - (string) (len=19) "OpenChannelResponse": (*main.Message)(0xc000349700)({ - fullName: (string) (len=19) "OpenChannelResponse", - name: (string) (len=19) "OpenChannelResponse", - fields: ([]*main.Field) (len=1 cap=1) { - (*main.Field)(0xc0004fd9e0)({ - name: (string) (len=9) "channelId", - kind: (string) (len=6) "string", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }) - } - }), - (string) (len=7) "Product": (*main.Message)(0xc000349b00)({ - fullName: (string) (len=7) "Product", - name: (string) (len=7) "Product", - fields: ([]*main.Field) (len=3 cap=4) { - (*main.Field)(0xc0004fe3f0)({ - name: (string) (len=2) "id", - kind: (string) (len=6) "string", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fe420)({ - name: (string) (len=4) "name", - kind: (string) (len=6) "string", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fe450)({ - name: (string) (len=10) "price_sats", - kind: (string) (len=5) "int64", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }) - } - }), - (string) (len=24) "PayAppUserInvoiceRequest": (*main.Message)(0xc000349280)({ - fullName: (string) (len=24) "PayAppUserInvoiceRequest", - name: (string) (len=24) "PayAppUserInvoiceRequest", - fields: ([]*main.Field) (len=3 cap=4) { - (*main.Field)(0xc0004fd2c0)({ - name: (string) (len=15) "user_identifier", - kind: (string) (len=6) "string", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fd2f0)({ - name: (string) (len=7) "invoice", - kind: (string) (len=6) "string", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fd320)({ - name: (string) (len=6) "amount", - kind: (string) (len=5) "int64", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }) - } - }), - (string) (len=17) "NewInvoiceRequest": (*main.Message)(0xc000349500)({ - fullName: (string) (len=17) "NewInvoiceRequest", - name: (string) (len=17) "NewInvoiceRequest", - fields: ([]*main.Field) (len=2 cap=2) { - (*main.Field)(0xc0004fd6e0)({ - name: (string) (len=10) "amountSats", - kind: (string) (len=5) "int64", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fd710)({ - name: (string) (len=4) "memo", - kind: (string) (len=6) "string", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }) - } - }), - (string) (len=17) "LiveUserOperation": (*main.Message)(0xc000349b80)({ - fullName: (string) (len=17) "LiveUserOperation", - name: (string) (len=17) "LiveUserOperation", - fields: ([]*main.Field) (len=1 cap=1) { - (*main.Field)(0xc0004fe4b0)({ - name: (string) (len=9) "operation", - kind: (string) (len=13) "UserOperation", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) true, - isOptional: (bool) false - }) - } - }), - (string) (len=9) "HttpCreds": (*main.Message)(0xc000349d40)({ - fullName: (string) (len=9) "HttpCreds", - name: (string) (len=9) "HttpCreds", - fields: ([]*main.Field) (len=2 cap=2) { - (*main.Field)(0xc0004fe660)({ - name: (string) (len=3) "url", - kind: (string) (len=6) "string", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fe690)({ - name: (string) (len=5) "token", - kind: (string) (len=6) "string", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }) - } - }), - (string) (len=11) "UsageMetric": (*main.Message)(0xc0003482c0)({ - fullName: (string) (len=11) "UsageMetric", - name: (string) (len=11) "UsageMetric", - fields: ([]*main.Field) (len=9 cap=16) { - (*main.Field)(0xc000207dd0)({ - name: (string) (len=15) "processed_at_ms", - kind: (string) (len=5) "int64", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc000207e00)({ - name: (string) (len=14) "parsed_in_nano", - kind: (string) (len=5) "int64", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc000207e30)({ - name: (string) (len=12) "auth_in_nano", - kind: (string) (len=5) "int64", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc000207e60)({ - name: (string) (len=16) "validate_in_nano", - kind: (string) (len=5) "int64", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc000207e90)({ - name: (string) (len=14) "handle_in_nano", - kind: (string) (len=5) "int64", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc000207ec0)({ - name: (string) (len=8) "rpc_name", - kind: (string) (len=6) "string", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc000207ef0)({ - name: (string) (len=5) "batch", - kind: (string) (len=4) "bool", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc000207f20)({ - name: (string) (len=5) "nostr", - kind: (string) (len=4) "bool", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc000207f50)({ - name: (string) (len=10) "batch_size", - kind: (string) (len=5) "int64", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }) - } - }), - (string) (len=12) "RoutingEvent": (*main.Message)(0xc000348b40)({ - fullName: (string) (len=12) "RoutingEvent", - name: (string) (len=12) "RoutingEvent", - fields: ([]*main.Field) (len=12 cap=16) { - (*main.Field)(0xc0004fc300)({ - name: (string) (len=19) "incoming_channel_id", - kind: (string) (len=5) "int64", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fc330)({ - name: (string) (len=16) "incoming_htlc_id", - kind: (string) (len=5) "int64", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fc360)({ - name: (string) (len=19) "outgoing_channel_id", - kind: (string) (len=5) "int64", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fc390)({ - name: (string) (len=16) "outgoing_htlc_id", - kind: (string) (len=5) "int64", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fc3c0)({ - name: (string) (len=12) "timestamp_ns", - kind: (string) (len=5) "int64", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fc3f0)({ - name: (string) (len=10) "event_type", - kind: (string) (len=6) "string", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fc420)({ - name: (string) (len=17) "incoming_amt_msat", - kind: (string) (len=5) "int64", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fc450)({ - name: (string) (len=17) "outgoing_amt_msat", - kind: (string) (len=5) "int64", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fc480)({ - name: (string) (len=14) "failure_string", - kind: (string) (len=6) "string", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fc4b0)({ - name: (string) (len=7) "settled", - kind: (string) (len=4) "bool", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fc4e0)({ - name: (string) (len=8) "offchain", - kind: (string) (len=4) "bool", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fc510)({ - name: (string) (len=18) "forward_fail_event", - kind: (string) (len=4) "bool", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }) - } - }), - (string) (len=19) "ChannelBalanceEvent": (*main.Message)(0xc000348c40)({ - fullName: (string) (len=19) "ChannelBalanceEvent", - name: (string) (len=19) "ChannelBalanceEvent", - fields: ([]*main.Field) (len=4 cap=4) { - (*main.Field)(0xc0004fc540)({ - name: (string) (len=12) "block_height", - kind: (string) (len=5) "int64", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fc570)({ - name: (string) (len=10) "channel_id", - kind: (string) (len=6) "string", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fc5a0)({ - name: (string) (len=18) "local_balance_sats", - kind: (string) (len=5) "int64", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fc5d0)({ - name: (string) (len=19) "remote_balance_sats", - kind: (string) (len=5) "int64", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }) - } - }), - (string) (len=22) "HandleLnurlPayResponse": (*main.Message)(0xc000349880)({ - fullName: (string) (len=22) "HandleLnurlPayResponse", - name: (string) (len=22) "HandleLnurlPayResponse", - fields: ([]*main.Field) (len=2 cap=2) { - (*main.Field)(0xc0004fdd40)({ - name: (string) (len=2) "pr", - kind: (string) (len=6) "string", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fdd70)({ - name: (string) (len=6) "routes", - kind: (string) (len=5) "Empty", - isMap: (bool) false, - isArray: (bool) true, - isEnum: (bool) false, - isMessage: (bool) true, - isOptional: (bool) false - }) - } - }), - (string) (len=14) "UserOperations": (*main.Message)(0xc000349a00)({ - fullName: (string) (len=14) "UserOperations", - name: (string) (len=14) "UserOperations", - fields: ([]*main.Field) (len=3 cap=4) { - (*main.Field)(0xc0004fe1e0)({ - name: (string) (len=9) "fromIndex", - kind: (string) (len=5) "int64", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fe210)({ - name: (string) (len=7) "toIndex", - kind: (string) (len=5) "int64", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fe240)({ - name: (string) (len=10) "operations", - kind: (string) (len=13) "UserOperation", - isMap: (bool) false, - isArray: (bool) true, - isEnum: (bool) false, - isMessage: (bool) true, - isOptional: (bool) false - }) - } - }), - (string) (len=17) "ChainBalanceEvent": (*main.Message)(0xc000348c80)({ - fullName: (string) (len=17) "ChainBalanceEvent", - name: (string) (len=17) "ChainBalanceEvent", - fields: ([]*main.Field) (len=4 cap=4) { - (*main.Field)(0xc0004fc600)({ - name: (string) (len=12) "block_height", - kind: (string) (len=5) "int64", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fc630)({ - name: (string) (len=17) "confirmed_balance", - kind: (string) (len=5) "int64", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fc660)({ - name: (string) (len=19) "unconfirmed_balance", - kind: (string) (len=5) "int64", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fc690)({ - name: (string) (len=13) "total_balance", - kind: (string) (len=5) "int64", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }) - } - }), - (string) (len=14) "LndNodeMetrics": (*main.Message)(0xc000348e40)({ - fullName: (string) (len=14) "LndNodeMetrics", - name: (string) (len=14) "LndNodeMetrics", - fields: ([]*main.Field) (len=9 cap=16) { - (*main.Field)(0xc0004fca50)({ - name: (string) (len=23) "channels_balance_events", - kind: (string) (len=19) "ChannelBalanceEvent", - isMap: (bool) false, - isArray: (bool) true, - isEnum: (bool) false, - isMessage: (bool) true, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fca80)({ - name: (string) (len=20) "chain_balance_events", - kind: (string) (len=17) "ChainBalanceEvent", - isMap: (bool) false, - isArray: (bool) true, - isEnum: (bool) false, - isMessage: (bool) true, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fcab0)({ - name: (string) (len=16) "offline_channels", - kind: (string) (len=5) "int64", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fcae0)({ - name: (string) (len=15) "online_channels", - kind: (string) (len=5) "int64", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fcb10)({ - name: (string) (len=16) "pending_channels", - kind: (string) (len=5) "int64", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fcb40)({ - name: (string) (len=16) "closing_channels", - kind: (string) (len=5) "int64", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fcb70)({ - name: (string) (len=13) "open_channels", - kind: (string) (len=11) "OpenChannel", - isMap: (bool) false, - isArray: (bool) true, - isEnum: (bool) false, - isMessage: (bool) true, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fcba0)({ - name: (string) (len=15) "closed_channels", - kind: (string) (len=13) "ClosedChannel", - isMap: (bool) false, - isArray: (bool) true, - isEnum: (bool) false, - isMessage: (bool) true, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fcbd0)({ - name: (string) (len=15) "channel_routing", - kind: (string) (len=14) "ChannelRouting", - isMap: (bool) false, - isArray: (bool) true, - isEnum: (bool) false, - isMessage: (bool) true, - isOptional: (bool) false - }) - } - }), - (string) (len=27) "SetMockInvoiceAsPaidRequest": (*main.Message)(0xc000348f00)({ - fullName: (string) (len=27) "SetMockInvoiceAsPaidRequest", - name: (string) (len=27) "SetMockInvoiceAsPaidRequest", - fields: ([]*main.Field) (len=2 cap=2) { - (*main.Field)(0xc0004fcc60)({ - name: (string) (len=7) "invoice", - kind: (string) (len=6) "string", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fcc90)({ - name: (string) (len=6) "amount", - kind: (string) (len=5) "int64", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }) - } - }), - (string) (len=24) "AddAppUserInvoiceRequest": (*main.Message)(0xc000349200)({ - fullName: (string) (len=24) "AddAppUserInvoiceRequest", - name: (string) (len=24) "AddAppUserInvoiceRequest", - fields: ([]*main.Field) (len=4 cap=4) { - (*main.Field)(0xc0004fd1d0)({ - name: (string) (len=19) "receiver_identifier", - kind: (string) (len=6) "string", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fd200)({ - name: (string) (len=16) "payer_identifier", - kind: (string) (len=6) "string", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fd230)({ - name: (string) (len=17) "http_callback_url", - kind: (string) (len=6) "string", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fd260)({ - name: (string) (len=11) "invoice_req", - kind: (string) (len=17) "NewInvoiceRequest", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) true, - isOptional: (bool) false - }) - } - }), - (string) (len=18) "OpenChannelRequest": (*main.Message)(0xc0003496c0)({ - fullName: (string) (len=18) "OpenChannelRequest", - name: (string) (len=18) "OpenChannelRequest", - fields: ([]*main.Field) (len=4 cap=4) { - (*main.Field)(0xc0004fd920)({ - name: (string) (len=11) "destination", - kind: (string) (len=6) "string", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fd950)({ - name: (string) (len=13) "fundingAmount", - kind: (string) (len=5) "int64", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fd980)({ - name: (string) (len=10) "pushAmount", - kind: (string) (len=5) "int64", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }), - (*main.Field)(0xc0004fd9b0)({ - name: (string) (len=12) "closeAddress", - kind: (string) (len=6) "string", - isMap: (bool) false, - isArray: (bool) false, - isEnum: (bool) false, - isMessage: (bool) false, - isOptional: (bool) false - }) - } - }) -} - -parsing file: structs 70 -parsing file: methods 2 --> [{guest Guest map[]} {user User map[app_id:string app_user_id:string user_id:string]} {admin Admin map[admin_id:string]} {metrics Metrics map[operator_id:string]} {app App map[app_id:string]}] - +([]*main.Method) (len=47 cap=64) { + (*main.Method)(0xc00007a230)({ + in: (main.MethodMessage) { + name: (string) (len=17) "LndGetInfoRequest", + hasZeroFields: (bool) false + }, + name: (string) (len=10) "LndGetInfo", + out: (main.MethodMessage) { + name: (string) (len=18) "LndGetInfoResponse", + hasZeroFields: (bool) false + }, + opts: (*main.methodOptions)(0xc000070f60)({ + authType: (*main.supportedAuth)(0xc0005be600)({ + id: (string) (len=5) "admin", + name: (string) (len=5) "Admin", + context: (map[string]string) (len=1) { + (string) (len=8) "admin_id": (string) (len=6) "string" + } + }), + method: (string) (len=4) "post", + route: (main.decodedRoute) { + route: (string) (len=22) "/api/admin/lnd/getinfo", + params: ([]string) + }, + query: ([]string) , + nostr: (bool) true, + batch: (bool) false + }), + serverStream: (bool) false + }), + (*main.Method)(0xc00007a2d0)({ + in: (main.MethodMessage) { + name: (string) (len=13) "AddAppRequest", + hasZeroFields: (bool) false + }, + name: (string) (len=6) "AddApp", + out: (main.MethodMessage) { + name: (string) (len=7) "AuthApp", + hasZeroFields: (bool) false + }, + opts: (*main.methodOptions)(0xc000071140)({ + authType: (*main.supportedAuth)(0xc0005be690)({ + id: (string) (len=5) "admin", + name: (string) (len=5) "Admin", + context: (map[string]string) (len=1) { + (string) (len=8) "admin_id": (string) (len=6) "string" + } + }), + method: (string) (len=4) "post", + route: (main.decodedRoute) { + route: (string) (len=18) "/api/admin/app/add", + params: ([]string) + }, + query: ([]string) , + nostr: (bool) true, + batch: (bool) false + }), + serverStream: (bool) false + }), + (*main.Method)(0xc00007a370)({ + in: (main.MethodMessage) { + name: (string) (len=14) "AuthAppRequest", + hasZeroFields: (bool) false + }, + name: (string) (len=7) "AuthApp", + out: (main.MethodMessage) { + name: (string) (len=7) "AuthApp", + hasZeroFields: (bool) false + }, + opts: (*main.methodOptions)(0xc000071320)({ + authType: (*main.supportedAuth)(0xc0005be720)({ + id: (string) (len=5) "admin", + name: (string) (len=5) "Admin", + context: (map[string]string) (len=1) { + (string) (len=8) "admin_id": (string) (len=6) "string" + } + }), + method: (string) (len=4) "post", + route: (main.decodedRoute) { + route: (string) (len=19) "/api/admin/app/auth", + params: ([]string) + }, + query: ([]string) , + nostr: (bool) true, + batch: (bool) false + }), + serverStream: (bool) false + }), + (*main.Method)(0xc00007a410)({ + in: (main.MethodMessage) { + name: (string) (len=14) "BanUserRequest", + hasZeroFields: (bool) false + }, + name: (string) (len=7) "BanUser", + out: (main.MethodMessage) { + name: (string) (len=15) "BanUserResponse", + hasZeroFields: (bool) false + }, + opts: (*main.methodOptions)(0xc000071500)({ + authType: (*main.supportedAuth)(0xc0005be7b0)({ + id: (string) (len=5) "admin", + name: (string) (len=5) "Admin", + context: (map[string]string) (len=1) { + (string) (len=8) "admin_id": (string) (len=6) "string" + } + }), + method: (string) (len=4) "post", + route: (main.decodedRoute) { + route: (string) (len=19) "/api/admin/user/ban", + params: ([]string) + }, + query: ([]string) , + nostr: (bool) true, + batch: (bool) false + }), + serverStream: (bool) false + }), + (*main.Method)(0xc00007a460)({ + in: (main.MethodMessage) { + name: (string) (len=5) "Empty", + hasZeroFields: (bool) true + }, + name: (string) (len=15) "GetUsageMetrics", + out: (main.MethodMessage) { + name: (string) (len=12) "UsageMetrics", + hasZeroFields: (bool) false + }, + opts: (*main.methodOptions)(0xc0000716e0)({ + authType: (*main.supportedAuth)(0xc0005be840)({ + id: (string) (len=7) "metrics", + name: (string) (len=7) "Metrics", + context: (map[string]string) (len=1) { + (string) (len=11) "operator_id": (string) (len=6) "string" + } + }), + method: (string) (len=4) "post", + route: (main.decodedRoute) { + route: (string) (len=18) "/api/reports/usage", + params: ([]string) + }, + query: ([]string) , + nostr: (bool) true, + batch: (bool) false + }), + serverStream: (bool) false + }), + (*main.Method)(0xc00007a4b0)({ + in: (main.MethodMessage) { + name: (string) (len=18) "AppsMetricsRequest", + hasZeroFields: (bool) false + }, + name: (string) (len=14) "GetAppsMetrics", + out: (main.MethodMessage) { + name: (string) (len=11) "AppsMetrics", + hasZeroFields: (bool) false + }, + opts: (*main.methodOptions)(0xc0000718c0)({ + authType: (*main.supportedAuth)(0xc0005be8d0)({ + id: (string) (len=7) "metrics", + name: (string) (len=7) "Metrics", + context: (map[string]string) (len=1) { + (string) (len=11) "operator_id": (string) (len=6) "string" + } + }), + method: (string) (len=4) "post", + route: (main.decodedRoute) { + route: (string) (len=17) "/api/reports/apps", + params: ([]string) + }, + query: ([]string) , + nostr: (bool) true, + batch: (bool) false + }), + serverStream: (bool) false + }), + (*main.Method)(0xc00007a500)({ + in: (main.MethodMessage) { + name: (string) (len=17) "LndMetricsRequest", + hasZeroFields: (bool) false + }, + name: (string) (len=13) "GetLndMetrics", + out: (main.MethodMessage) { + name: (string) (len=10) "LndMetrics", + hasZeroFields: (bool) false + }, + opts: (*main.methodOptions)(0xc000071aa0)({ + authType: (*main.supportedAuth)(0xc0005be960)({ + id: (string) (len=7) "metrics", + name: (string) (len=7) "Metrics", + context: (map[string]string) (len=1) { + (string) (len=11) "operator_id": (string) (len=6) "string" + } + }), + method: (string) (len=4) "post", + route: (main.decodedRoute) { + route: (string) (len=16) "/api/reports/lnd", + params: ([]string) + }, + query: ([]string) , + nostr: (bool) true, + batch: (bool) false + }), + serverStream: (bool) false + }), + (*main.Method)(0xc00007a550)({ + in: (main.MethodMessage) { + name: (string) (len=5) "Empty", + hasZeroFields: (bool) true + }, + name: (string) (len=6) "Health", + out: (main.MethodMessage) { + name: (string) (len=5) "Empty", + hasZeroFields: (bool) true + }, + opts: (*main.methodOptions)(0xc000071c20)({ + authType: (*main.supportedAuth)(0xc0005be9f0)({ + id: (string) (len=5) "guest", + name: (string) (len=5) "Guest", + context: (map[string]string) { + } + }), + method: (string) (len=3) "get", + route: (main.decodedRoute) { + route: (string) (len=11) "/api/health", + params: ([]string) + }, + query: ([]string) , + nostr: (bool) false, + batch: (bool) false + }), + serverStream: (bool) false + }), + (*main.Method)(0xc00007a5a0)({ + in: (main.MethodMessage) { + name: (string) (len=25) "EncryptionExchangeRequest", + hasZeroFields: (bool) false + }, + name: (string) (len=18) "EncryptionExchange", + out: (main.MethodMessage) { + name: (string) (len=5) "Empty", + hasZeroFields: (bool) true + }, + opts: (*main.methodOptions)(0xc000071da0)({ + authType: (*main.supportedAuth)(0xc0005beab0)({ + id: (string) (len=5) "guest", + name: (string) (len=5) "Guest", + context: (map[string]string) { + } + }), + method: (string) (len=4) "post", + route: (main.decodedRoute) { + route: (string) (len=24) "/api/encryption/exchange", + params: ([]string) + }, + query: ([]string) , + nostr: (bool) false, + batch: (bool) false + }), + serverStream: (bool) false + }), + (*main.Method)(0xc00007a5f0)({ + in: (main.MethodMessage) { + name: (string) (len=27) "SetMockInvoiceAsPaidRequest", + hasZeroFields: (bool) false + }, + name: (string) (len=20) "SetMockInvoiceAsPaid", + out: (main.MethodMessage) { + name: (string) (len=5) "Empty", + hasZeroFields: (bool) true + }, + opts: (*main.methodOptions)(0xc000071f80)({ + authType: (*main.supportedAuth)(0xc0005beb40)({ + id: (string) (len=5) "guest", + name: (string) (len=5) "Guest", + context: (map[string]string) { + } + }), + method: (string) (len=4) "post", + route: (main.decodedRoute) { + route: (string) (len=26) "/api/lnd/mock/invoice/paid", + params: ([]string) + }, + query: ([]string) , + nostr: (bool) false, + batch: (bool) false + }), + serverStream: (bool) false + }), + (*main.Method)(0xc00007a690)({ + in: (main.MethodMessage) { + name: (string) (len=5) "Empty", + hasZeroFields: (bool) true + }, + name: (string) (len=20) "GetLnurlWithdrawInfo", + out: (main.MethodMessage) { + name: (string) (len=25) "LnurlWithdrawInfoResponse", + hasZeroFields: (bool) false + }, + opts: (*main.methodOptions)(0xc0000ae7e0)({ + authType: (*main.supportedAuth)(0xc0005bec90)({ + id: (string) (len=5) "guest", + name: (string) (len=5) "Guest", + context: (map[string]string) { + } + }), + method: (string) (len=3) "get", + route: (main.decodedRoute) { + route: (string) (len=30) "/api/guest/lnurl_withdraw/info", + params: ([]string) + }, + query: ([]string) (len=1 cap=1) { + (string) (len=2) "k1" + }, + nostr: (bool) false, + batch: (bool) false + }), + serverStream: (bool) false + }), + (*main.Method)(0xc00007a730)({ + in: (main.MethodMessage) { + name: (string) (len=5) "Empty", + hasZeroFields: (bool) true + }, + name: (string) (len=19) "HandleLnurlWithdraw", + out: (main.MethodMessage) { + name: (string) (len=5) "Empty", + hasZeroFields: (bool) true + }, + opts: (*main.methodOptions)(0xc0000aeb40)({ + authType: (*main.supportedAuth)(0xc0005bede0)({ + id: (string) (len=5) "guest", + name: (string) (len=5) "Guest", + context: (map[string]string) { + } + }), + method: (string) (len=3) "get", + route: (main.decodedRoute) { + route: (string) (len=32) "/api/guest/lnurl_withdraw/handle", + params: ([]string) + }, + query: ([]string) (len=2 cap=2) { + (string) (len=2) "k1", + (string) (len=2) "pr" + }, + nostr: (bool) false, + batch: (bool) false + }), + serverStream: (bool) false + }), + (*main.Method)(0xc00007a7d0)({ + in: (main.MethodMessage) { + name: (string) (len=5) "Empty", + hasZeroFields: (bool) true + }, + name: (string) (len=15) "GetLnurlPayInfo", + out: (main.MethodMessage) { + name: (string) (len=20) "LnurlPayInfoResponse", + hasZeroFields: (bool) false + }, + opts: (*main.methodOptions)(0xc0000aeea0)({ + authType: (*main.supportedAuth)(0xc0005bef00)({ + id: (string) (len=5) "guest", + name: (string) (len=5) "Guest", + context: (map[string]string) { + } + }), + method: (string) (len=3) "get", + route: (main.decodedRoute) { + route: (string) (len=25) "/api/guest/lnurl_pay/info", + params: ([]string) + }, + query: ([]string) (len=1 cap=1) { + (string) (len=2) "k1" + }, + nostr: (bool) false, + batch: (bool) false + }), + serverStream: (bool) false + }), + (*main.Method)(0xc00007a870)({ + in: (main.MethodMessage) { + name: (string) (len=5) "Empty", + hasZeroFields: (bool) true + }, + name: (string) (len=14) "HandleLnurlPay", + out: (main.MethodMessage) { + name: (string) (len=22) "HandleLnurlPayResponse", + hasZeroFields: (bool) false + }, + opts: (*main.methodOptions)(0xc0000af320)({ + authType: (*main.supportedAuth)(0xc0005bf050)({ + id: (string) (len=5) "guest", + name: (string) (len=5) "Guest", + context: (map[string]string) { + } + }), + method: (string) (len=3) "get", + route: (main.decodedRoute) { + route: (string) (len=27) "/api/guest/lnurl_pay/handle", + params: ([]string) + }, + query: ([]string) (len=4 cap=4) { + (string) (len=2) "k1", + (string) (len=6) "amount", + (string) (len=5) "nostr", + (string) (len=5) "lnurl" + }, + nostr: (bool) false, + batch: (bool) false + }), + serverStream: (bool) false + }), + (*main.Method)(0xc00007a8c0)({ + in: (main.MethodMessage) { + name: (string) (len=5) "Empty", + hasZeroFields: (bool) true + }, + name: (string) (len=18) "HandleLnurlAddress", + out: (main.MethodMessage) { + name: (string) (len=20) "LnurlPayInfoResponse", + hasZeroFields: (bool) false + }, + opts: (*main.methodOptions)(0xc0005c4000)({ + authType: (*main.supportedAuth)(0xc0005bf0e0)({ + id: (string) (len=5) "guest", + name: (string) (len=5) "Guest", + context: (map[string]string) { + } + }), + method: (string) (len=3) "get", + route: (main.decodedRoute) { + route: (string) (len=33) "/.well-known/lnurlp/:address_name", + params: ([]string) (len=1 cap=1) { + (string) (len=12) "address_name" + } + }, + query: ([]string) , + nostr: (bool) false, + batch: (bool) false + }), + serverStream: (bool) false + }), + (*main.Method)(0xc00007a960)({ + in: (main.MethodMessage) { + name: (string) (len=27) "LinkNPubThroughTokenRequest", + hasZeroFields: (bool) false + }, + name: (string) (len=20) "LinkNPubThroughToken", + out: (main.MethodMessage) { + name: (string) (len=5) "Empty", + hasZeroFields: (bool) true + }, + opts: (*main.methodOptions)(0xc0005c41e0)({ + authType: (*main.supportedAuth)(0xc0005bf170)({ + id: (string) (len=4) "user", + name: (string) (len=4) "User", + context: (map[string]string) (len=3) { + (string) (len=7) "user_id": (string) (len=6) "string", + (string) (len=6) "app_id": (string) (len=6) "string", + (string) (len=11) "app_user_id": (string) (len=6) "string" + } + }), + method: (string) (len=4) "post", + route: (main.decodedRoute) { + route: (string) (len=20) "/api/guest/npub/link", + params: ([]string) + }, + query: ([]string) , + nostr: (bool) true, + batch: (bool) false + }), + serverStream: (bool) false + }), + (*main.Method)(0xc00007a9b0)({ + in: (main.MethodMessage) { + name: (string) (len=23) "EnrollAdminTokenRequest", + hasZeroFields: (bool) false + }, + name: (string) (len=16) "EnrollAdminToken", + out: (main.MethodMessage) { + name: (string) (len=5) "Empty", + hasZeroFields: (bool) true + }, + opts: (*main.methodOptions)(0xc0005c4420)({ + authType: (*main.supportedAuth)(0xc0005bf200)({ + id: (string) (len=4) "user", + name: (string) (len=4) "User", + context: (map[string]string) (len=3) { + (string) (len=7) "user_id": (string) (len=6) "string", + (string) (len=6) "app_id": (string) (len=6) "string", + (string) (len=11) "app_user_id": (string) (len=6) "string" + } + }), + method: (string) (len=4) "post", + route: (main.decodedRoute) { + route: (string) (len=28) "/api/guest/npub/enroll/admin", + params: ([]string) + }, + query: ([]string) , + nostr: (bool) true, + batch: (bool) false + }), + serverStream: (bool) false + }), + (*main.Method)(0xc00007aa00)({ + in: (main.MethodMessage) { + name: (string) (len=5) "Empty", + hasZeroFields: (bool) true + }, + name: (string) (len=6) "GetApp", + out: (main.MethodMessage) { + name: (string) (len=11) "Application", + hasZeroFields: (bool) false + }, + opts: (*main.methodOptions)(0xc0005c45a0)({ + authType: (*main.supportedAuth)(0xc0005bf290)({ + id: (string) (len=3) "app", + name: (string) (len=3) "App", + context: (map[string]string) (len=1) { + (string) (len=6) "app_id": (string) (len=6) "string" + } + }), + method: (string) (len=4) "post", + route: (main.decodedRoute) { + route: (string) (len=12) "/api/app/get", + params: ([]string) + }, + query: ([]string) , + nostr: (bool) false, + batch: (bool) false + }), + serverStream: (bool) false + }), + (*main.Method)(0xc00007aaa0)({ + in: (main.MethodMessage) { + name: (string) (len=17) "AddAppUserRequest", + hasZeroFields: (bool) false + }, + name: (string) (len=10) "AddAppUser", + out: (main.MethodMessage) { + name: (string) (len=7) "AppUser", + hasZeroFields: (bool) false + }, + opts: (*main.methodOptions)(0xc0005c4720)({ + authType: (*main.supportedAuth)(0xc0005bf320)({ + id: (string) (len=3) "app", + name: (string) (len=3) "App", + context: (map[string]string) (len=1) { + (string) (len=6) "app_id": (string) (len=6) "string" + } + }), + method: (string) (len=4) "post", + route: (main.decodedRoute) { + route: (string) (len=17) "/api/app/user/add", + params: ([]string) + }, + query: ([]string) , + nostr: (bool) false, + batch: (bool) false + }), + serverStream: (bool) false + }), + (*main.Method)(0xc00007ab40)({ + in: (main.MethodMessage) { + name: (string) (len=20) "AddAppInvoiceRequest", + hasZeroFields: (bool) false + }, + name: (string) (len=13) "AddAppInvoice", + out: (main.MethodMessage) { + name: (string) (len=18) "NewInvoiceResponse", + hasZeroFields: (bool) false + }, + opts: (*main.methodOptions)(0xc0005c48a0)({ + authType: (*main.supportedAuth)(0xc0005bf3b0)({ + id: (string) (len=3) "app", + name: (string) (len=3) "App", + context: (map[string]string) (len=1) { + (string) (len=6) "app_id": (string) (len=6) "string" + } + }), + method: (string) (len=4) "post", + route: (main.decodedRoute) { + route: (string) (len=20) "/api/app/add/invoice", + params: ([]string) + }, + query: ([]string) , + nostr: (bool) false, + batch: (bool) false + }), + serverStream: (bool) false + }), + (*main.Method)(0xc00007ab90)({ + in: (main.MethodMessage) { + name: (string) (len=24) "AddAppUserInvoiceRequest", + hasZeroFields: (bool) false + }, + name: (string) (len=17) "AddAppUserInvoice", + out: (main.MethodMessage) { + name: (string) (len=18) "NewInvoiceResponse", + hasZeroFields: (bool) false + }, + opts: (*main.methodOptions)(0xc0005c4a80)({ + authType: (*main.supportedAuth)(0xc0005bf440)({ + id: (string) (len=3) "app", + name: (string) (len=3) "App", + context: (map[string]string) (len=1) { + (string) (len=6) "app_id": (string) (len=6) "string" + } + }), + method: (string) (len=4) "post", + route: (main.decodedRoute) { + route: (string) (len=25) "/api/app/user/add/invoice", + params: ([]string) + }, + query: ([]string) , + nostr: (bool) false, + batch: (bool) false + }), + serverStream: (bool) false + }), + (*main.Method)(0xc00007ac30)({ + in: (main.MethodMessage) { + name: (string) (len=17) "GetAppUserRequest", + hasZeroFields: (bool) false + }, + name: (string) (len=10) "GetAppUser", + out: (main.MethodMessage) { + name: (string) (len=7) "AppUser", + hasZeroFields: (bool) false + }, + opts: (*main.methodOptions)(0xc0005c4c00)({ + authType: (*main.supportedAuth)(0xc0005bf4d0)({ + id: (string) (len=3) "app", + name: (string) (len=3) "App", + context: (map[string]string) (len=1) { + (string) (len=6) "app_id": (string) (len=6) "string" + } + }), + method: (string) (len=4) "post", + route: (main.decodedRoute) { + route: (string) (len=17) "/api/app/user/get", + params: ([]string) + }, + query: ([]string) , + nostr: (bool) false, + batch: (bool) false + }), + serverStream: (bool) false + }), + (*main.Method)(0xc00007acd0)({ + in: (main.MethodMessage) { + name: (string) (len=24) "PayAppUserInvoiceRequest", + hasZeroFields: (bool) false + }, + name: (string) (len=17) "PayAppUserInvoice", + out: (main.MethodMessage) { + name: (string) (len=18) "PayInvoiceResponse", + hasZeroFields: (bool) false + }, + opts: (*main.methodOptions)(0xc0005c4d80)({ + authType: (*main.supportedAuth)(0xc0005bf560)({ + id: (string) (len=3) "app", + name: (string) (len=3) "App", + context: (map[string]string) (len=1) { + (string) (len=6) "app_id": (string) (len=6) "string" + } + }), + method: (string) (len=4) "post", + route: (main.decodedRoute) { + route: (string) (len=20) "/api/app/invoice/pay", + params: ([]string) + }, + query: ([]string) , + nostr: (bool) false, + batch: (bool) false + }), + serverStream: (bool) false + }), + (*main.Method)(0xc00007ad20)({ + in: (main.MethodMessage) { + name: (string) (len=34) "SendAppUserToAppUserPaymentRequest", + hasZeroFields: (bool) false + }, + name: (string) (len=27) "SendAppUserToAppUserPayment", + out: (main.MethodMessage) { + name: (string) (len=5) "Empty", + hasZeroFields: (bool) true + }, + opts: (*main.methodOptions)(0xc0005c4f60)({ + authType: (*main.supportedAuth)(0xc0005bf5f0)({ + id: (string) (len=3) "app", + name: (string) (len=3) "App", + context: (map[string]string) (len=1) { + (string) (len=6) "app_id": (string) (len=6) "string" + } + }), + method: (string) (len=4) "post", + route: (main.decodedRoute) { + route: (string) (len=26) "/api/app/user/internal/pay", + params: ([]string) + }, + query: ([]string) , + nostr: (bool) false, + batch: (bool) false + }), + serverStream: (bool) false + }), + (*main.Method)(0xc00007adc0)({ + in: (main.MethodMessage) { + name: (string) (len=30) "SendAppUserToAppPaymentRequest", + hasZeroFields: (bool) false + }, + name: (string) (len=23) "SendAppUserToAppPayment", + out: (main.MethodMessage) { + name: (string) (len=5) "Empty", + hasZeroFields: (bool) true + }, + opts: (*main.methodOptions)(0xc0005c50e0)({ + authType: (*main.supportedAuth)(0xc0005bf680)({ + id: (string) (len=3) "app", + name: (string) (len=3) "App", + context: (map[string]string) (len=1) { + (string) (len=6) "app_id": (string) (len=6) "string" + } + }), + method: (string) (len=4) "post", + route: (main.decodedRoute) { + route: (string) (len=21) "/api/app/internal/pay", + params: ([]string) + }, + query: ([]string) , + nostr: (bool) false, + batch: (bool) false + }), + serverStream: (bool) false + }), + (*main.Method)(0xc00007ae10)({ + in: (main.MethodMessage) { + name: (string) (len=26) "GetAppUserLNURLInfoRequest", + hasZeroFields: (bool) false + }, + name: (string) (len=19) "GetAppUserLNURLInfo", + out: (main.MethodMessage) { + name: (string) (len=20) "LnurlPayInfoResponse", + hasZeroFields: (bool) false + }, + opts: (*main.methodOptions)(0xc0005c5260)({ + authType: (*main.supportedAuth)(0xc0005bf710)({ + id: (string) (len=3) "app", + name: (string) (len=3) "App", + context: (map[string]string) (len=1) { + (string) (len=6) "app_id": (string) (len=6) "string" + } + }), + method: (string) (len=4) "post", + route: (main.decodedRoute) { + route: (string) (len=28) "/api/app/user/lnurl/pay/info", + params: ([]string) + }, + query: ([]string) , + nostr: (bool) false, + batch: (bool) false + }), + serverStream: (bool) false + }), + (*main.Method)(0xc00007ae60)({ + in: (main.MethodMessage) { + name: (string) (len=28) "SetMockAppUserBalanceRequest", + hasZeroFields: (bool) false + }, + name: (string) (len=21) "SetMockAppUserBalance", + out: (main.MethodMessage) { + name: (string) (len=5) "Empty", + hasZeroFields: (bool) true + }, + opts: (*main.methodOptions)(0xc0005c53e0)({ + authType: (*main.supportedAuth)(0xc0005bf7a0)({ + id: (string) (len=3) "app", + name: (string) (len=3) "App", + context: (map[string]string) (len=1) { + (string) (len=6) "app_id": (string) (len=6) "string" + } + }), + method: (string) (len=4) "post", + route: (main.decodedRoute) { + route: (string) (len=29) "/api/app/mock/user/blance/set", + params: ([]string) + }, + query: ([]string) , + nostr: (bool) false, + batch: (bool) false + }), + serverStream: (bool) false + }), + (*main.Method)(0xc00007aeb0)({ + in: (main.MethodMessage) { + name: (string) (len=24) "SetMockAppBalanceRequest", + hasZeroFields: (bool) false + }, + name: (string) (len=17) "SetMockAppBalance", + out: (main.MethodMessage) { + name: (string) (len=5) "Empty", + hasZeroFields: (bool) true + }, + opts: (*main.methodOptions)(0xc0005c55c0)({ + authType: (*main.supportedAuth)(0xc0005bf830)({ + id: (string) (len=3) "app", + name: (string) (len=3) "App", + context: (map[string]string) (len=1) { + (string) (len=6) "app_id": (string) (len=6) "string" + } + }), + method: (string) (len=4) "post", + route: (main.decodedRoute) { + route: (string) (len=24) "/api/app/mock/blance/set", + params: ([]string) + }, + query: ([]string) , + nostr: (bool) false, + batch: (bool) false + }), + serverStream: (bool) false + }), + (*main.Method)(0xc00007af00)({ + in: (main.MethodMessage) { + name: (string) (len=30) "RequestNPubLinkingTokenRequest", + hasZeroFields: (bool) false + }, + name: (string) (len=23) "RequestNPubLinkingToken", + out: (main.MethodMessage) { + name: (string) (len=31) "RequestNPubLinkingTokenResponse", + hasZeroFields: (bool) false + }, + opts: (*main.methodOptions)(0xc0005c57a0)({ + authType: (*main.supportedAuth)(0xc0005bf8c0)({ + id: (string) (len=3) "app", + name: (string) (len=3) "App", + context: (map[string]string) (len=1) { + (string) (len=6) "app_id": (string) (len=6) "string" + } + }), + method: (string) (len=4) "post", + route: (main.decodedRoute) { + route: (string) (len=24) "/api/app/user/npub/token", + params: ([]string) + }, + query: ([]string) , + nostr: (bool) false, + batch: (bool) false + }), + serverStream: (bool) false + }), + (*main.Method)(0xc00007af50)({ + in: (main.MethodMessage) { + name: (string) (len=5) "Empty", + hasZeroFields: (bool) true + }, + name: (string) (len=10) "UserHealth", + out: (main.MethodMessage) { + name: (string) (len=5) "Empty", + hasZeroFields: (bool) true + }, + opts: (*main.methodOptions)(0xc0005c5980)({ + authType: (*main.supportedAuth)(0xc0005bf950)({ + id: (string) (len=4) "user", + name: (string) (len=4) "User", + context: (map[string]string) (len=3) { + (string) (len=7) "user_id": (string) (len=6) "string", + (string) (len=6) "app_id": (string) (len=6) "string", + (string) (len=11) "app_user_id": (string) (len=6) "string" + } + }), + method: (string) (len=4) "post", + route: (main.decodedRoute) { + route: (string) (len=16) "/api/user/health", + params: ([]string) + }, + query: ([]string) , + nostr: (bool) true, + batch: (bool) false + }), + serverStream: (bool) false + }), + (*main.Method)(0xc00007afa0)({ + in: (main.MethodMessage) { + name: (string) (len=5) "Empty", + hasZeroFields: (bool) true + }, + name: (string) (len=11) "GetUserInfo", + out: (main.MethodMessage) { + name: (string) (len=8) "UserInfo", + hasZeroFields: (bool) false + }, + opts: (*main.methodOptions)(0xc0005c5b60)({ + authType: (*main.supportedAuth)(0xc0005bf9e0)({ + id: (string) (len=4) "user", + name: (string) (len=4) "User", + context: (map[string]string) (len=3) { + (string) (len=6) "app_id": (string) (len=6) "string", + (string) (len=11) "app_user_id": (string) (len=6) "string", + (string) (len=7) "user_id": (string) (len=6) "string" + } + }), + method: (string) (len=4) "post", + route: (main.decodedRoute) { + route: (string) (len=14) "/api/user/info", + params: ([]string) + }, + query: ([]string) , + nostr: (bool) true, + batch: (bool) false + }), + serverStream: (bool) false + }), + (*main.Method)(0xc00007b040)({ + in: (main.MethodMessage) { + name: (string) (len=17) "AddProductRequest", + hasZeroFields: (bool) false + }, + name: (string) (len=10) "AddProduct", + out: (main.MethodMessage) { + name: (string) (len=7) "Product", + hasZeroFields: (bool) false + }, + opts: (*main.methodOptions)(0xc0005c5d40)({ + authType: (*main.supportedAuth)(0xc0005bfa70)({ + id: (string) (len=4) "user", + name: (string) (len=4) "User", + context: (map[string]string) (len=3) { + (string) (len=7) "user_id": (string) (len=6) "string", + (string) (len=6) "app_id": (string) (len=6) "string", + (string) (len=11) "app_user_id": (string) (len=6) "string" + } + }), + method: (string) (len=4) "post", + route: (main.decodedRoute) { + route: (string) (len=21) "/api/user/product/add", + params: ([]string) + }, + query: ([]string) , + nostr: (bool) true, + batch: (bool) false + }), + serverStream: (bool) false + }), + (*main.Method)(0xc00007b090)({ + in: (main.MethodMessage) { + name: (string) (len=5) "Empty", + hasZeroFields: (bool) true + }, + name: (string) (len=17) "NewProductInvoice", + out: (main.MethodMessage) { + name: (string) (len=18) "NewInvoiceResponse", + hasZeroFields: (bool) false + }, + opts: (*main.methodOptions)(0xc0005ca1e0)({ + authType: (*main.supportedAuth)(0xc0005bfb90)({ + id: (string) (len=4) "user", + name: (string) (len=4) "User", + context: (map[string]string) (len=3) { + (string) (len=7) "user_id": (string) (len=6) "string", + (string) (len=6) "app_id": (string) (len=6) "string", + (string) (len=11) "app_user_id": (string) (len=6) "string" + } + }), + method: (string) (len=3) "get", + route: (main.decodedRoute) { + route: (string) (len=29) "/api/user/product/get/invoice", + params: ([]string) + }, + query: ([]string) (len=1 cap=1) { + (string) (len=2) "id" + }, + nostr: (bool) true, + batch: (bool) false + }), + serverStream: (bool) false + }), + (*main.Method)(0xc00007b0e0)({ + in: (main.MethodMessage) { + name: (string) (len=24) "GetUserOperationsRequest", + hasZeroFields: (bool) false + }, + name: (string) (len=17) "GetUserOperations", + out: (main.MethodMessage) { + name: (string) (len=25) "GetUserOperationsResponse", + hasZeroFields: (bool) false + }, + opts: (*main.methodOptions)(0xc0005ca3c0)({ + authType: (*main.supportedAuth)(0xc0005bfc20)({ + id: (string) (len=4) "user", + name: (string) (len=4) "User", + context: (map[string]string) (len=3) { + (string) (len=7) "user_id": (string) (len=6) "string", + (string) (len=6) "app_id": (string) (len=6) "string", + (string) (len=11) "app_user_id": (string) (len=6) "string" + } + }), + method: (string) (len=4) "post", + route: (main.decodedRoute) { + route: (string) (len=20) "/api/user/operations", + params: ([]string) + }, + query: ([]string) , + nostr: (bool) true, + batch: (bool) false + }), + serverStream: (bool) false + }), + (*main.Method)(0xc00007b180)({ + in: (main.MethodMessage) { + name: (string) (len=17) "NewAddressRequest", + hasZeroFields: (bool) false + }, + name: (string) (len=10) "NewAddress", + out: (main.MethodMessage) { + name: (string) (len=18) "NewAddressResponse", + hasZeroFields: (bool) false + }, + opts: (*main.methodOptions)(0xc0005ca5a0)({ + authType: (*main.supportedAuth)(0xc0005bfcb0)({ + id: (string) (len=4) "user", + name: (string) (len=4) "User", + context: (map[string]string) (len=3) { + (string) (len=7) "user_id": (string) (len=6) "string", + (string) (len=6) "app_id": (string) (len=6) "string", + (string) (len=11) "app_user_id": (string) (len=6) "string" + } + }), + method: (string) (len=4) "post", + route: (main.decodedRoute) { + route: (string) (len=19) "/api/user/chain/new", + params: ([]string) + }, + query: ([]string) , + nostr: (bool) true, + batch: (bool) false + }), + serverStream: (bool) false + }), + (*main.Method)(0xc00007b220)({ + in: (main.MethodMessage) { + name: (string) (len=17) "PayAddressRequest", + hasZeroFields: (bool) false + }, + name: (string) (len=10) "PayAddress", + out: (main.MethodMessage) { + name: (string) (len=18) "PayAddressResponse", + hasZeroFields: (bool) false + }, + opts: (*main.methodOptions)(0xc0005ca780)({ + authType: (*main.supportedAuth)(0xc0005bfd40)({ + id: (string) (len=4) "user", + name: (string) (len=4) "User", + context: (map[string]string) (len=3) { + (string) (len=7) "user_id": (string) (len=6) "string", + (string) (len=6) "app_id": (string) (len=6) "string", + (string) (len=11) "app_user_id": (string) (len=6) "string" + } + }), + method: (string) (len=4) "post", + route: (main.decodedRoute) { + route: (string) (len=19) "/api/user/chain/pay", + params: ([]string) + }, + query: ([]string) , + nostr: (bool) true, + batch: (bool) false + }), + serverStream: (bool) false + }), + (*main.Method)(0xc00007b2c0)({ + in: (main.MethodMessage) { + name: (string) (len=17) "NewInvoiceRequest", + hasZeroFields: (bool) false + }, + name: (string) (len=10) "NewInvoice", + out: (main.MethodMessage) { + name: (string) (len=18) "NewInvoiceResponse", + hasZeroFields: (bool) false + }, + opts: (*main.methodOptions)(0xc0005ca960)({ + authType: (*main.supportedAuth)(0xc0005bfdd0)({ + id: (string) (len=4) "user", + name: (string) (len=4) "User", + context: (map[string]string) (len=3) { + (string) (len=7) "user_id": (string) (len=6) "string", + (string) (len=6) "app_id": (string) (len=6) "string", + (string) (len=11) "app_user_id": (string) (len=6) "string" + } + }), + method: (string) (len=4) "post", + route: (main.decodedRoute) { + route: (string) (len=21) "/api/user/invoice/new", + params: ([]string) + }, + query: ([]string) , + nostr: (bool) true, + batch: (bool) false + }), + serverStream: (bool) false + }), + (*main.Method)(0xc00007b360)({ + in: (main.MethodMessage) { + name: (string) (len=20) "DecodeInvoiceRequest", + hasZeroFields: (bool) false + }, + name: (string) (len=13) "DecodeInvoice", + out: (main.MethodMessage) { + name: (string) (len=21) "DecodeInvoiceResponse", + hasZeroFields: (bool) false + }, + opts: (*main.methodOptions)(0xc0005cab40)({ + authType: (*main.supportedAuth)(0xc0005bfe60)({ + id: (string) (len=4) "user", + name: (string) (len=4) "User", + context: (map[string]string) (len=3) { + (string) (len=7) "user_id": (string) (len=6) "string", + (string) (len=6) "app_id": (string) (len=6) "string", + (string) (len=11) "app_user_id": (string) (len=6) "string" + } + }), + method: (string) (len=4) "post", + route: (main.decodedRoute) { + route: (string) (len=24) "/api/user/invoice/decode", + params: ([]string) + }, + query: ([]string) , + nostr: (bool) true, + batch: (bool) false + }), + serverStream: (bool) false + }), + (*main.Method)(0xc00007b400)({ + in: (main.MethodMessage) { + name: (string) (len=17) "PayInvoiceRequest", + hasZeroFields: (bool) false + }, + name: (string) (len=10) "PayInvoice", + out: (main.MethodMessage) { + name: (string) (len=18) "PayInvoiceResponse", + hasZeroFields: (bool) false + }, + opts: (*main.methodOptions)(0xc0005cad20)({ + authType: (*main.supportedAuth)(0xc0005bfef0)({ + id: (string) (len=4) "user", + name: (string) (len=4) "User", + context: (map[string]string) (len=3) { + (string) (len=7) "user_id": (string) (len=6) "string", + (string) (len=6) "app_id": (string) (len=6) "string", + (string) (len=11) "app_user_id": (string) (len=6) "string" + } + }), + method: (string) (len=4) "post", + route: (main.decodedRoute) { + route: (string) (len=21) "/api/user/invoice/pay", + params: ([]string) + }, + query: ([]string) , + nostr: (bool) true, + batch: (bool) false + }), + serverStream: (bool) false + }), + (*main.Method)(0xc00007b4a0)({ + in: (main.MethodMessage) { + name: (string) (len=18) "OpenChannelRequest", + hasZeroFields: (bool) false + }, + name: (string) (len=11) "OpenChannel", + out: (main.MethodMessage) { + name: (string) (len=19) "OpenChannelResponse", + hasZeroFields: (bool) false + }, + opts: (*main.methodOptions)(0xc0005caf00)({ + authType: (*main.supportedAuth)(0xc0005bff80)({ + id: (string) (len=4) "user", + name: (string) (len=4) "User", + context: (map[string]string) (len=3) { + (string) (len=7) "user_id": (string) (len=6) "string", + (string) (len=6) "app_id": (string) (len=6) "string", + (string) (len=11) "app_user_id": (string) (len=6) "string" + } + }), + method: (string) (len=4) "post", + route: (main.decodedRoute) { + route: (string) (len=22) "/api/user/open/channel", + params: ([]string) + }, + query: ([]string) , + nostr: (bool) true, + batch: (bool) false + }), + serverStream: (bool) false + }), + (*main.Method)(0xc00007b540)({ + in: (main.MethodMessage) { + name: (string) (len=5) "Empty", + hasZeroFields: (bool) true + }, + name: (string) (len=20) "GetLnurlWithdrawLink", + out: (main.MethodMessage) { + name: (string) (len=17) "LnurlLinkResponse", + hasZeroFields: (bool) false + }, + opts: (*main.methodOptions)(0xc0005cb0e0)({ + authType: (*main.supportedAuth)(0xc0005ce030)({ + id: (string) (len=4) "user", + name: (string) (len=4) "User", + context: (map[string]string) (len=3) { + (string) (len=7) "user_id": (string) (len=6) "string", + (string) (len=6) "app_id": (string) (len=6) "string", + (string) (len=11) "app_user_id": (string) (len=6) "string" + } + }), + method: (string) (len=3) "get", + route: (main.decodedRoute) { + route: (string) (len=29) "/api/user/lnurl_withdraw/link", + params: ([]string) + }, + query: ([]string) , + nostr: (bool) true, + batch: (bool) false + }), + serverStream: (bool) false + }), + (*main.Method)(0xc00007b5e0)({ + in: (main.MethodMessage) { + name: (string) (len=5) "Empty", + hasZeroFields: (bool) true + }, + name: (string) (len=15) "GetLnurlPayLink", + out: (main.MethodMessage) { + name: (string) (len=17) "LnurlLinkResponse", + hasZeroFields: (bool) false + }, + opts: (*main.methodOptions)(0xc0005cb2c0)({ + authType: (*main.supportedAuth)(0xc0005ce0c0)({ + id: (string) (len=4) "user", + name: (string) (len=4) "User", + context: (map[string]string) (len=3) { + (string) (len=7) "user_id": (string) (len=6) "string", + (string) (len=6) "app_id": (string) (len=6) "string", + (string) (len=11) "app_user_id": (string) (len=6) "string" + } + }), + method: (string) (len=3) "get", + route: (main.decodedRoute) { + route: (string) (len=24) "/api/user/lnurl_pay/link", + params: ([]string) + }, + query: ([]string) , + nostr: (bool) true, + batch: (bool) false + }), + serverStream: (bool) false + }), + (*main.Method)(0xc00007b680)({ + in: (main.MethodMessage) { + name: (string) (len=5) "Empty", + hasZeroFields: (bool) true + }, + name: (string) (len=19) "GetLNURLChannelLink", + out: (main.MethodMessage) { + name: (string) (len=17) "LnurlLinkResponse", + hasZeroFields: (bool) false + }, + opts: (*main.methodOptions)(0xc0005cb4a0)({ + authType: (*main.supportedAuth)(0xc0005ce150)({ + id: (string) (len=4) "user", + name: (string) (len=4) "User", + context: (map[string]string) (len=3) { + (string) (len=7) "user_id": (string) (len=6) "string", + (string) (len=6) "app_id": (string) (len=6) "string", + (string) (len=11) "app_user_id": (string) (len=6) "string" + } + }), + method: (string) (len=4) "post", + route: (main.decodedRoute) { + route: (string) (len=27) "/api/user/lnurl_channel/url", + params: ([]string) + }, + query: ([]string) , + nostr: (bool) true, + batch: (bool) false + }), + serverStream: (bool) false + }), + (*main.Method)(0xc00007b720)({ + in: (main.MethodMessage) { + name: (string) (len=5) "Empty", + hasZeroFields: (bool) true + }, + name: (string) (len=21) "GetLiveUserOperations", + out: (main.MethodMessage) { + name: (string) (len=17) "LiveUserOperation", + hasZeroFields: (bool) false + }, + opts: (*main.methodOptions)(0xc0005cb680)({ + authType: (*main.supportedAuth)(0xc0005ce1e0)({ + id: (string) (len=4) "user", + name: (string) (len=4) "User", + context: (map[string]string) (len=3) { + (string) (len=7) "user_id": (string) (len=6) "string", + (string) (len=6) "app_id": (string) (len=6) "string", + (string) (len=11) "app_user_id": (string) (len=6) "string" + } + }), + method: (string) (len=4) "post", + route: (main.decodedRoute) { + route: (string) (len=24) "/api/user/operations/sub", + params: ([]string) + }, + query: ([]string) , + nostr: (bool) true, + batch: (bool) false + }), + serverStream: (bool) true + }), + (*main.Method)(0xc00007b7c0)({ + in: (main.MethodMessage) { + name: (string) (len=5) "Empty", + hasZeroFields: (bool) true + }, + name: (string) (len=18) "GetMigrationUpdate", + out: (main.MethodMessage) { + name: (string) (len=15) "MigrationUpdate", + hasZeroFields: (bool) false + }, + opts: (*main.methodOptions)(0xc0005cb860)({ + authType: (*main.supportedAuth)(0xc0005ce270)({ + id: (string) (len=4) "user", + name: (string) (len=4) "User", + context: (map[string]string) (len=3) { + (string) (len=6) "app_id": (string) (len=6) "string", + (string) (len=11) "app_user_id": (string) (len=6) "string", + (string) (len=7) "user_id": (string) (len=6) "string" + } + }), + method: (string) (len=4) "post", + route: (main.decodedRoute) { + route: (string) (len=24) "/api/user/migrations/sub", + params: ([]string) + }, + query: ([]string) , + nostr: (bool) true, + batch: (bool) false + }), + serverStream: (bool) true + }), + (*main.Method)(0xc00007b810)({ + in: (main.MethodMessage) { + name: (string) (len=5) "Empty", + hasZeroFields: (bool) true + }, + name: (string) (len=12) "GetHttpCreds", + out: (main.MethodMessage) { + name: (string) (len=9) "HttpCreds", + hasZeroFields: (bool) false + }, + opts: (*main.methodOptions)(0xc0005cba40)({ + authType: (*main.supportedAuth)(0xc0005ce300)({ + id: (string) (len=4) "user", + name: (string) (len=4) "User", + context: (map[string]string) (len=3) { + (string) (len=7) "user_id": (string) (len=6) "string", + (string) (len=6) "app_id": (string) (len=6) "string", + (string) (len=11) "app_user_id": (string) (len=6) "string" + } + }), + method: (string) (len=4) "post", + route: (main.decodedRoute) { + route: (string) (len=20) "/api/user/http_creds", + params: ([]string) + }, + query: ([]string) , + nostr: (bool) true, + batch: (bool) false + }), + serverStream: (bool) true + }), + (*main.Method)(0xc00007b860)({ + in: (main.MethodMessage) { + name: (string) (len=5) "Empty", + hasZeroFields: (bool) true + }, + name: (string) (len=9) "BatchUser", + out: (main.MethodMessage) { + name: (string) (len=5) "Empty", + hasZeroFields: (bool) true + }, + opts: (*main.methodOptions)(0xc0005cbc80)({ + authType: (*main.supportedAuth)(0xc0005ce3c0)({ + id: (string) (len=4) "user", + name: (string) (len=4) "User", + context: (map[string]string) (len=3) { + (string) (len=7) "user_id": (string) (len=6) "string", + (string) (len=6) "app_id": (string) (len=6) "string", + (string) (len=11) "app_user_id": (string) (len=6) "string" + } + }), + method: (string) (len=4) "post", + route: (main.decodedRoute) { + route: (string) (len=15) "/api/user/batch", + params: ([]string) + }, + query: ([]string) , + nostr: (bool) true, + batch: (bool) true + }), + serverStream: (bool) false + }) +} + +([]*main.Enum) (len=2 cap=2) { + (*main.Enum)(0xc0003ffd70)({ + name: (string) (len=11) "AddressType", + values: ([]main.EnumValue) (len=3 cap=4) { + (main.EnumValue) { + number: (int64) 0, + name: (string) (len=19) "WITNESS_PUBKEY_HASH" + }, + (main.EnumValue) { + number: (int64) 1, + name: (string) (len=18) "NESTED_PUBKEY_HASH" + }, + (main.EnumValue) { + number: (int64) 2, + name: (string) (len=14) "TAPROOT_PUBKEY" + } + } + }), + (*main.Enum)(0xc0003ffdd0)({ + name: (string) (len=17) "UserOperationType", + values: ([]main.EnumValue) (len=6 cap=8) { + (main.EnumValue) { + number: (int64) 0, + name: (string) (len=11) "INCOMING_TX" + }, + (main.EnumValue) { + number: (int64) 1, + name: (string) (len=11) "OUTGOING_TX" + }, + (main.EnumValue) { + number: (int64) 2, + name: (string) (len=16) "INCOMING_INVOICE" + }, + (main.EnumValue) { + number: (int64) 3, + name: (string) (len=16) "OUTGOING_INVOICE" + }, + (main.EnumValue) { + number: (int64) 4, + name: (string) (len=21) "OUTGOING_USER_TO_USER" + }, + (main.EnumValue) { + number: (int64) 5, + name: (string) (len=21) "INCOMING_USER_TO_USER" + } + } + }) +} + +(map[string]*main.Message) (len=71) { + (string) (len=11) "OpenChannel": (*main.Message)(0xc0003fe750)({ + fullName: (string) (len=11) "OpenChannel", + name: (string) (len=11) "OpenChannel", + fields: (map[string]*main.Field) (len=6) { + (string) (len=6) "active": (*main.Field)(0xc00031f740)({ + name: (string) (len=6) "active", + kind: (string) (len=4) "bool", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=8) "lifetime": (*main.Field)(0xc00031f780)({ + name: (string) (len=8) "lifetime", + kind: (string) (len=5) "int64", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=13) "local_balance": (*main.Field)(0xc00031f7c0)({ + name: (string) (len=13) "local_balance", + kind: (string) (len=5) "int64", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=14) "remote_balance": (*main.Field)(0xc00031f800)({ + name: (string) (len=14) "remote_balance", + kind: (string) (len=5) "int64", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=10) "channel_id": (*main.Field)(0xc00031f6c0)({ + name: (string) (len=10) "channel_id", + kind: (string) (len=6) "string", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=8) "capacity": (*main.Field)(0xc00031f700)({ + name: (string) (len=8) "capacity", + kind: (string) (len=5) "int64", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }) + } + }), + (string) (len=27) "SetMockInvoiceAsPaidRequest": (*main.Message)(0xc0003fe990)({ + fullName: (string) (len=27) "SetMockInvoiceAsPaidRequest", + name: (string) (len=27) "SetMockInvoiceAsPaidRequest", + fields: (map[string]*main.Field) (len=2) { + (string) (len=7) "invoice": (*main.Field)(0xc00031fe40)({ + name: (string) (len=7) "invoice", + kind: (string) (len=6) "string", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=6) "amount": (*main.Field)(0xc00031fe80)({ + name: (string) (len=6) "amount", + kind: (string) (len=5) "int64", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }) + } + }), + (string) (len=24) "AddAppUserInvoiceRequest": (*main.Message)(0xc0003fee10)({ + fullName: (string) (len=24) "AddAppUserInvoiceRequest", + name: (string) (len=24) "AddAppUserInvoiceRequest", + fields: (map[string]*main.Field) (len=4) { + (string) (len=19) "receiver_identifier": (*main.Field)(0xc0004625c0)({ + name: (string) (len=19) "receiver_identifier", + kind: (string) (len=6) "string", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=16) "payer_identifier": (*main.Field)(0xc000462600)({ + name: (string) (len=16) "payer_identifier", + kind: (string) (len=6) "string", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=17) "http_callback_url": (*main.Field)(0xc000462640)({ + name: (string) (len=17) "http_callback_url", + kind: (string) (len=6) "string", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=11) "invoice_req": (*main.Field)(0xc000462680)({ + name: (string) (len=11) "invoice_req", + kind: (string) (len=17) "NewInvoiceRequest", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) true, + isOptional: (bool) false, + oneOfName: (string) "" + }) + } + }), + (string) (len=21) "DecodeInvoiceResponse": (*main.Message)(0xc0003ff3b0)({ + fullName: (string) (len=21) "DecodeInvoiceResponse", + name: (string) (len=21) "DecodeInvoiceResponse", + fields: (map[string]*main.Field) (len=1) { + (string) (len=6) "amount": (*main.Field)(0xc000462d80)({ + name: (string) (len=6) "amount", + kind: (string) (len=5) "int64", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }) + } + }), + (string) (len=19) "OpenChannelResponse": (*main.Message)(0xc0003ff530)({ + fullName: (string) (len=19) "OpenChannelResponse", + name: (string) (len=19) "OpenChannelResponse", + fields: (map[string]*main.Field) (len=1) { + (string) (len=9) "channelId": (*main.Field)(0xc000463080)({ + name: (string) (len=9) "channelId", + kind: (string) (len=6) "string", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }) + } + }), + (string) (len=15) "RelaysMigration": (*main.Message)(0xc0003ffb30)({ + fullName: (string) (len=15) "RelaysMigration", + name: (string) (len=15) "RelaysMigration", + fields: (map[string]*main.Field) (len=1) { + (string) (len=6) "relays": (*main.Field)(0xc0000b0080)({ + name: (string) (len=6) "relays", + kind: (string) (len=6) "string", + isMap: (bool) false, + isArray: (bool) true, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }) + } + }), + (string) (len=30) "RequestNPubLinkingTokenRequest": (*main.Message)(0xc0003ffb90)({ + fullName: (string) (len=30) "RequestNPubLinkingTokenRequest", + name: (string) (len=30) "RequestNPubLinkingTokenRequest", + fields: (map[string]*main.Field) (len=1) { + (string) (len=15) "user_identifier": (*main.Field)(0xc0000b0180)({ + name: (string) (len=15) "user_identifier", + kind: (string) (len=6) "string", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }) + } + }), + (string) (len=27) "LinkNPubThroughTokenRequest": (*main.Message)(0xc0003ffc50)({ + fullName: (string) (len=27) "LinkNPubThroughTokenRequest", + name: (string) (len=27) "LinkNPubThroughTokenRequest", + fields: (map[string]*main.Field) (len=2) { + (string) (len=5) "token": (*main.Field)(0xc0000b0640)({ + name: (string) (len=5) "token", + kind: (string) (len=6) "string", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=9) "nostr_pub": (*main.Field)(0xc0000b0680)({ + name: (string) (len=9) "nostr_pub", + kind: (string) (len=6) "string", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }) + } + }), + (string) (len=10) "LndMetrics": (*main.Message)(0xc0003fe8d0)({ + fullName: (string) (len=10) "LndMetrics", + name: (string) (len=10) "LndMetrics", + fields: (map[string]*main.Field) (len=1) { + (string) (len=5) "nodes": (*main.Field)(0xc00031fdc0)({ + name: (string) (len=5) "nodes", + kind: (string) (len=14) "LndNodeMetrics", + isMap: (bool) false, + isArray: (bool) true, + isEnum: (bool) false, + isMessage: (bool) true, + isOptional: (bool) false, + oneOfName: (string) "" + }) + } + }), + (string) (len=7) "AppUser": (*main.Message)(0xc0003fed50)({ + fullName: (string) (len=7) "AppUser", + name: (string) (len=7) "AppUser", + fields: (map[string]*main.Field) (len=3) { + (string) (len=10) "identifier": (*main.Field)(0xc000462440)({ + name: (string) (len=10) "identifier", + kind: (string) (len=6) "string", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=4) "info": (*main.Field)(0xc000462480)({ + name: (string) (len=4) "info", + kind: (string) (len=8) "UserInfo", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) true, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=16) "max_withdrawable": (*main.Field)(0xc0004624c0)({ + name: (string) (len=16) "max_withdrawable", + kind: (string) (len=5) "int64", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }) + } + }), + (string) (len=20) "AddAppInvoiceRequest": (*main.Message)(0xc0003fedb0)({ + fullName: (string) (len=20) "AddAppInvoiceRequest", + name: (string) (len=20) "AddAppInvoiceRequest", + fields: (map[string]*main.Field) (len=3) { + (string) (len=16) "payer_identifier": (*main.Field)(0xc000462500)({ + name: (string) (len=16) "payer_identifier", + kind: (string) (len=6) "string", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=17) "http_callback_url": (*main.Field)(0xc000462540)({ + name: (string) (len=17) "http_callback_url", + kind: (string) (len=6) "string", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=11) "invoice_req": (*main.Field)(0xc000462580)({ + name: (string) (len=11) "invoice_req", + kind: (string) (len=17) "NewInvoiceRequest", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) true, + isOptional: (bool) false, + oneOfName: (string) "" + }) + } + }), + (string) (len=14) "UserOperations": (*main.Message)(0xc0003ff830)({ + fullName: (string) (len=14) "UserOperations", + name: (string) (len=14) "UserOperations", + fields: (map[string]*main.Field) (len=3) { + (string) (len=9) "fromIndex": (*main.Field)(0xc000463bc0)({ + name: (string) (len=9) "fromIndex", + kind: (string) (len=5) "int64", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=7) "toIndex": (*main.Field)(0xc000463c00)({ + name: (string) (len=7) "toIndex", + kind: (string) (len=5) "int64", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=10) "operations": (*main.Field)(0xc000463c40)({ + name: (string) (len=10) "operations", + kind: (string) (len=13) "UserOperation", + isMap: (bool) false, + isArray: (bool) true, + isEnum: (bool) false, + isMessage: (bool) true, + isOptional: (bool) false, + oneOfName: (string) "" + }) + } + }), + (string) (len=14) "BanUserRequest": (*main.Message)(0xc0003fea50)({ + fullName: (string) (len=14) "BanUserRequest", + name: (string) (len=14) "BanUserRequest", + fields: (map[string]*main.Field) (len=1) { + (string) (len=7) "user_id": (*main.Field)(0xc00031ff00)({ + name: (string) (len=7) "user_id", + kind: (string) (len=6) "string", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }) + } + }), + (string) (len=17) "NewAddressRequest": (*main.Message)(0xc0003ff110)({ + fullName: (string) (len=17) "NewAddressRequest", + name: (string) (len=17) "NewAddressRequest", + fields: (map[string]*main.Field) (len=1) { + (string) (len=11) "addressType": (*main.Field)(0xc000462a40)({ + name: (string) (len=11) "addressType", + kind: (string) (len=11) "AddressType", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) true, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }) + } + }), + (string) (len=20) "DecodeInvoiceRequest": (*main.Message)(0xc0003ff350)({ + fullName: (string) (len=20) "DecodeInvoiceRequest", + name: (string) (len=20) "DecodeInvoiceRequest", + fields: (map[string]*main.Field) (len=1) { + (string) (len=7) "invoice": (*main.Field)(0xc000462d40)({ + name: (string) (len=7) "invoice", + kind: (string) (len=6) "string", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }) + } + }), + (string) (len=25) "LnurlWithdrawInfoResponse": (*main.Message)(0xc0003ff5f0)({ + fullName: (string) (len=25) "LnurlWithdrawInfoResponse", + name: (string) (len=25) "LnurlWithdrawInfoResponse", + fields: (map[string]*main.Field) (len=8) { + (string) (len=8) "callback": (*main.Field)(0xc000463180)({ + name: (string) (len=8) "callback", + kind: (string) (len=6) "string", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=2) "k1": (*main.Field)(0xc0004631c0)({ + name: (string) (len=2) "k1", + kind: (string) (len=6) "string", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=18) "defaultDescription": (*main.Field)(0xc000463200)({ + name: (string) (len=18) "defaultDescription", + kind: (string) (len=6) "string", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=15) "minWithdrawable": (*main.Field)(0xc000463240)({ + name: (string) (len=15) "minWithdrawable", + kind: (string) (len=5) "int64", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=15) "maxWithdrawable": (*main.Field)(0xc000463280)({ + name: (string) (len=15) "maxWithdrawable", + kind: (string) (len=5) "int64", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=12) "balanceCheck": (*main.Field)(0xc0004632c0)({ + name: (string) (len=12) "balanceCheck", + kind: (string) (len=6) "string", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=7) "payLink": (*main.Field)(0xc000463300)({ + name: (string) (len=7) "payLink", + kind: (string) (len=6) "string", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=3) "tag": (*main.Field)(0xc000463140)({ + name: (string) (len=3) "tag", + kind: (string) (len=6) "string", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }) + } + }), + (string) (len=24) "GetUserOperationsRequest": (*main.Message)(0xc0003ff770)({ + fullName: (string) (len=24) "GetUserOperationsRequest", + name: (string) (len=24) "GetUserOperationsRequest", + fields: (map[string]*main.Field) (len=7) { + (string) (len=21) "latestIncomingInvoice": (*main.Field)(0xc000463740)({ + name: (string) (len=21) "latestIncomingInvoice", + kind: (string) (len=5) "int64", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=21) "latestOutgoingInvoice": (*main.Field)(0xc000463780)({ + name: (string) (len=21) "latestOutgoingInvoice", + kind: (string) (len=5) "int64", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=16) "latestIncomingTx": (*main.Field)(0xc0004637c0)({ + name: (string) (len=16) "latestIncomingTx", + kind: (string) (len=5) "int64", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=16) "latestOutgoingTx": (*main.Field)(0xc000463800)({ + name: (string) (len=16) "latestOutgoingTx", + kind: (string) (len=5) "int64", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=31) "latestIncomingUserToUserPayment": (*main.Field)(0xc000463840)({ + name: (string) (len=31) "latestIncomingUserToUserPayment", + kind: (string) (len=5) "int64", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=31) "latestOutgoingUserToUserPayment": (*main.Field)(0xc000463880)({ + name: (string) (len=31) "latestOutgoingUserToUserPayment", + kind: (string) (len=5) "int64", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=8) "max_size": (*main.Field)(0xc0004638c0)({ + name: (string) (len=8) "max_size", + kind: (string) (len=5) "int64", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }) + } + }), + (string) (len=10) "AppMetrics": (*main.Message)(0xc0003fe510)({ + fullName: (string) (len=10) "AppMetrics", + name: (string) (len=10) "AppMetrics", + fields: (map[string]*main.Field) (len=9) { + (string) (len=8) "received": (*main.Field)(0xc00031ef40)({ + name: (string) (len=8) "received", + kind: (string) (len=5) "int64", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=10) "operations": (*main.Field)(0xc00031f0c0)({ + name: (string) (len=10) "operations", + kind: (string) (len=13) "UserOperation", + isMap: (bool) false, + isArray: (bool) true, + isEnum: (bool) false, + isMessage: (bool) true, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=3) "app": (*main.Field)(0xc00031eec0)({ + name: (string) (len=3) "app", + kind: (string) (len=11) "Application", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) true, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=5) "users": (*main.Field)(0xc00031ef00)({ + name: (string) (len=5) "users", + kind: (string) (len=9) "UsersInfo", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) true, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=5) "spent": (*main.Field)(0xc00031ef80)({ + name: (string) (len=5) "spent", + kind: (string) (len=5) "int64", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=9) "available": (*main.Field)(0xc00031efc0)({ + name: (string) (len=9) "available", + kind: (string) (len=5) "int64", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=4) "fees": (*main.Field)(0xc00031f000)({ + name: (string) (len=4) "fees", + kind: (string) (len=5) "int64", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=8) "invoices": (*main.Field)(0xc00031f040)({ + name: (string) (len=8) "invoices", + kind: (string) (len=5) "int64", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=10) "total_fees": (*main.Field)(0xc00031f080)({ + name: (string) (len=10) "total_fees", + kind: (string) (len=5) "int64", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }) + } + }), + (string) (len=13) "AddAppRequest": (*main.Message)(0xc0003feb70)({ + fullName: (string) (len=13) "AddAppRequest", + name: (string) (len=13) "AddAppRequest", + fields: (map[string]*main.Field) (len=2) { + (string) (len=4) "name": (*main.Field)(0xc000462100)({ + name: (string) (len=4) "name", + kind: (string) (len=6) "string", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=19) "allow_user_creation": (*main.Field)(0xc000462140)({ + name: (string) (len=19) "allow_user_creation", + kind: (string) (len=4) "bool", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }) + } + }), + (string) (len=34) "SendAppUserToAppUserPaymentRequest": (*main.Message)(0xc0003fef30)({ + fullName: (string) (len=34) "SendAppUserToAppUserPaymentRequest", + name: (string) (len=34) "SendAppUserToAppUserPaymentRequest", + fields: (map[string]*main.Field) (len=3) { + (string) (len=20) "from_user_identifier": (*main.Field)(0xc0004627c0)({ + name: (string) (len=20) "from_user_identifier", + kind: (string) (len=6) "string", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=18) "to_user_identifier": (*main.Field)(0xc000462800)({ + name: (string) (len=18) "to_user_identifier", + kind: (string) (len=6) "string", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=6) "amount": (*main.Field)(0xc000462840)({ + name: (string) (len=6) "amount", + kind: (string) (len=5) "int64", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }) + } + }), + (string) (len=20) "LnurlPayInfoResponse": (*main.Message)(0xc0003ff650)({ + fullName: (string) (len=20) "LnurlPayInfoResponse", + name: (string) (len=20) "LnurlPayInfoResponse", + fields: (map[string]*main.Field) (len=7) { + (string) (len=11) "allowsNostr": (*main.Field)(0xc000463480)({ + name: (string) (len=11) "allowsNostr", + kind: (string) (len=4) "bool", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=11) "nostrPubkey": (*main.Field)(0xc0004634c0)({ + name: (string) (len=11) "nostrPubkey", + kind: (string) (len=6) "string", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=3) "tag": (*main.Field)(0xc000463340)({ + name: (string) (len=3) "tag", + kind: (string) (len=6) "string", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=8) "callback": (*main.Field)(0xc000463380)({ + name: (string) (len=8) "callback", + kind: (string) (len=6) "string", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=11) "maxSendable": (*main.Field)(0xc0004633c0)({ + name: (string) (len=11) "maxSendable", + kind: (string) (len=5) "int64", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=11) "minSendable": (*main.Field)(0xc000463400)({ + name: (string) (len=11) "minSendable", + kind: (string) (len=5) "int64", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=8) "metadata": (*main.Field)(0xc000463440)({ + name: (string) (len=8) "metadata", + kind: (string) (len=6) "string", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }) + } + }), + (string) (len=22) "HandleLnurlPayResponse": (*main.Message)(0xc0003ff6b0)({ + fullName: (string) (len=22) "HandleLnurlPayResponse", + name: (string) (len=22) "HandleLnurlPayResponse", + fields: (map[string]*main.Field) (len=2) { + (string) (len=2) "pr": (*main.Field)(0xc000463500)({ + name: (string) (len=2) "pr", + kind: (string) (len=6) "string", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=6) "routes": (*main.Field)(0xc000463540)({ + name: (string) (len=6) "routes", + kind: (string) (len=5) "Empty", + isMap: (bool) false, + isArray: (bool) true, + isEnum: (bool) false, + isMessage: (bool) true, + isOptional: (bool) false, + oneOfName: (string) "" + }) + } + }), + (string) (len=23) "EnrollAdminTokenRequest": (*main.Message)(0xc0003ffd10)({ + fullName: (string) (len=23) "EnrollAdminTokenRequest", + name: (string) (len=23) "EnrollAdminTokenRequest", + fields: (map[string]*main.Field) (len=1) { + (string) (len=11) "admin_token": (*main.Field)(0xc0000b07c0)({ + name: (string) (len=11) "admin_token", + kind: (string) (len=6) "string", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }) + } + }), + (string) (len=12) "UsageMetrics": (*main.Message)(0xc0003fe3f0)({ + fullName: (string) (len=12) "UsageMetrics", + name: (string) (len=12) "UsageMetrics", + fields: (map[string]*main.Field) (len=1) { + (string) (len=7) "metrics": (*main.Field)(0xc00031ec00)({ + name: (string) (len=7) "metrics", + kind: (string) (len=11) "UsageMetric", + isMap: (bool) false, + isArray: (bool) true, + isEnum: (bool) false, + isMessage: (bool) true, + isOptional: (bool) false, + oneOfName: (string) "" + }) + } + }), + (string) (len=17) "LnurlLinkResponse": (*main.Message)(0xc0003ff590)({ + fullName: (string) (len=17) "LnurlLinkResponse", + name: (string) (len=17) "LnurlLinkResponse", + fields: (map[string]*main.Field) (len=2) { + (string) (len=5) "lnurl": (*main.Field)(0xc0004630c0)({ + name: (string) (len=5) "lnurl", + kind: (string) (len=6) "string", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=2) "k1": (*main.Field)(0xc000463100)({ + name: (string) (len=2) "k1", + kind: (string) (len=6) "string", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }) + } + }), + (string) (len=17) "LiveUserOperation": (*main.Message)(0xc0003ffa10)({ + fullName: (string) (len=17) "LiveUserOperation", + name: (string) (len=17) "LiveUserOperation", + fields: (map[string]*main.Field) (len=1) { + (string) (len=9) "operation": (*main.Field)(0xc000463f80)({ + name: (string) (len=9) "operation", + kind: (string) (len=13) "UserOperation", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) true, + isOptional: (bool) false, + oneOfName: (string) "" + }) + } + }), + (string) (len=17) "PayInvoiceRequest": (*main.Message)(0xc0003ff410)({ + fullName: (string) (len=17) "PayInvoiceRequest", + name: (string) (len=17) "PayInvoiceRequest", + fields: (map[string]*main.Field) (len=2) { + (string) (len=7) "invoice": (*main.Field)(0xc000462dc0)({ + name: (string) (len=7) "invoice", + kind: (string) (len=6) "string", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=6) "amount": (*main.Field)(0xc000462e00)({ + name: (string) (len=6) "amount", + kind: (string) (len=5) "int64", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }) + } + }), + (string) (len=25) "GetProductBuyLinkResponse": (*main.Message)(0xc0003ff9b0)({ + fullName: (string) (len=25) "GetProductBuyLinkResponse", + name: (string) (len=25) "GetProductBuyLinkResponse", + fields: (map[string]*main.Field) (len=1) { + (string) (len=4) "link": (*main.Field)(0xc000463f40)({ + name: (string) (len=4) "link", + kind: (string) (len=6) "string", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }) + } + }), + (string) (len=14) "LndNodeMetrics": (*main.Message)(0xc0003fe870)({ + fullName: (string) (len=14) "LndNodeMetrics", + name: (string) (len=14) "LndNodeMetrics", + fields: (map[string]*main.Field) (len=9) { + (string) (len=23) "channels_balance_events": (*main.Field)(0xc00031fb80)({ + name: (string) (len=23) "channels_balance_events", + kind: (string) (len=19) "ChannelBalanceEvent", + isMap: (bool) false, + isArray: (bool) true, + isEnum: (bool) false, + isMessage: (bool) true, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=20) "chain_balance_events": (*main.Field)(0xc00031fbc0)({ + name: (string) (len=20) "chain_balance_events", + kind: (string) (len=17) "ChainBalanceEvent", + isMap: (bool) false, + isArray: (bool) true, + isEnum: (bool) false, + isMessage: (bool) true, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=15) "online_channels": (*main.Field)(0xc00031fc40)({ + name: (string) (len=15) "online_channels", + kind: (string) (len=5) "int64", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=16) "closing_channels": (*main.Field)(0xc00031fcc0)({ + name: (string) (len=16) "closing_channels", + kind: (string) (len=5) "int64", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=16) "offline_channels": (*main.Field)(0xc00031fc00)({ + name: (string) (len=16) "offline_channels", + kind: (string) (len=5) "int64", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=16) "pending_channels": (*main.Field)(0xc00031fc80)({ + name: (string) (len=16) "pending_channels", + kind: (string) (len=5) "int64", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=13) "open_channels": (*main.Field)(0xc00031fd00)({ + name: (string) (len=13) "open_channels", + kind: (string) (len=11) "OpenChannel", + isMap: (bool) false, + isArray: (bool) true, + isEnum: (bool) false, + isMessage: (bool) true, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=15) "closed_channels": (*main.Field)(0xc00031fd40)({ + name: (string) (len=15) "closed_channels", + kind: (string) (len=13) "ClosedChannel", + isMap: (bool) false, + isArray: (bool) true, + isEnum: (bool) false, + isMessage: (bool) true, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=15) "channel_routing": (*main.Field)(0xc00031fd80)({ + name: (string) (len=15) "channel_routing", + kind: (string) (len=14) "ChannelRouting", + isMap: (bool) false, + isArray: (bool) true, + isEnum: (bool) false, + isMessage: (bool) true, + isOptional: (bool) false, + oneOfName: (string) "" + }) + } + }), + (string) (len=7) "AuthApp": (*main.Message)(0xc0003fec90)({ + fullName: (string) (len=7) "AuthApp", + name: (string) (len=7) "AuthApp", + fields: (map[string]*main.Field) (len=2) { + (string) (len=3) "app": (*main.Field)(0xc000462300)({ + name: (string) (len=3) "app", + kind: (string) (len=11) "Application", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) true, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=10) "auth_token": (*main.Field)(0xc000462340)({ + name: (string) (len=10) "auth_token", + kind: (string) (len=6) "string", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }) + } + }), + (string) (len=26) "GetAppUserLNURLInfoRequest": (*main.Message)(0xc0003feff0)({ + fullName: (string) (len=26) "GetAppUserLNURLInfoRequest", + name: (string) (len=26) "GetAppUserLNURLInfoRequest", + fields: (map[string]*main.Field) (len=2) { + (string) (len=15) "user_identifier": (*main.Field)(0xc000462900)({ + name: (string) (len=15) "user_identifier", + kind: (string) (len=6) "string", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=17) "base_url_override": (*main.Field)(0xc000462940)({ + name: (string) (len=17) "base_url_override", + kind: (string) (len=6) "string", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }) + } + }), + (string) (len=8) "UserInfo": (*main.Message)(0xc0003ff710)({ + fullName: (string) (len=8) "UserInfo", + name: (string) (len=8) "UserInfo", + fields: (map[string]*main.Field) (len=7) { + (string) (len=6) "userId": (*main.Field)(0xc000463580)({ + name: (string) (len=6) "userId", + kind: (string) (len=6) "string", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=7) "balance": (*main.Field)(0xc0004635c0)({ + name: (string) (len=7) "balance", + kind: (string) (len=5) "int64", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=16) "max_withdrawable": (*main.Field)(0xc000463600)({ + name: (string) (len=16) "max_withdrawable", + kind: (string) (len=5) "int64", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=15) "user_identifier": (*main.Field)(0xc000463640)({ + name: (string) (len=15) "user_identifier", + kind: (string) (len=6) "string", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=15) "service_fee_bps": (*main.Field)(0xc000463680)({ + name: (string) (len=15) "service_fee_bps", + kind: (string) (len=5) "int64", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=19) "network_max_fee_bps": (*main.Field)(0xc0004636c0)({ + name: (string) (len=19) "network_max_fee_bps", + kind: (string) (len=5) "int64", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=21) "network_max_fee_fixed": (*main.Field)(0xc000463700)({ + name: (string) (len=21) "network_max_fee_fixed", + kind: (string) (len=5) "int64", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }) + } + }), + (string) (len=13) "UserOperation": (*main.Message)(0xc0003ff7d0)({ + fullName: (string) (len=13) "UserOperation", + name: (string) (len=13) "UserOperation", + fields: (map[string]*main.Field) (len=11) { + (string) (len=7) "inbound": (*main.Field)(0xc000463980)({ + name: (string) (len=7) "inbound", + kind: (string) (len=4) "bool", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=6) "amount": (*main.Field)(0xc0004639c0)({ + name: (string) (len=6) "amount", + kind: (string) (len=5) "int64", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=10) "identifier": (*main.Field)(0xc000463a00)({ + name: (string) (len=10) "identifier", + kind: (string) (len=6) "string", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=11) "operationId": (*main.Field)(0xc000463a40)({ + name: (string) (len=11) "operationId", + kind: (string) (len=6) "string", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=11) "network_fee": (*main.Field)(0xc000463ac0)({ + name: (string) (len=11) "network_fee", + kind: (string) (len=5) "int64", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=4) "type": (*main.Field)(0xc000463940)({ + name: (string) (len=4) "type", + kind: (string) (len=17) "UserOperationType", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) true, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=11) "service_fee": (*main.Field)(0xc000463a80)({ + name: (string) (len=11) "service_fee", + kind: (string) (len=5) "int64", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=9) "confirmed": (*main.Field)(0xc000463b00)({ + name: (string) (len=9) "confirmed", + kind: (string) (len=4) "bool", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=7) "tx_hash": (*main.Field)(0xc000463b40)({ + name: (string) (len=7) "tx_hash", + kind: (string) (len=6) "string", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=8) "internal": (*main.Field)(0xc000463b80)({ + name: (string) (len=8) "internal", + kind: (string) (len=4) "bool", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=10) "paidAtUnix": (*main.Field)(0xc000463900)({ + name: (string) (len=10) "paidAtUnix", + kind: (string) (len=5) "int64", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }) + } + }), + (string) (len=5) "Empty": (*main.Message)(0xc0003fe2d0)({ + fullName: (string) (len=5) "Empty", + name: (string) (len=5) "Empty", + fields: (map[string]*main.Field) { + } + }), + (string) (len=17) "LndMetricsRequest": (*main.Message)(0xc0003fe5d0)({ + fullName: (string) (len=17) "LndMetricsRequest", + name: (string) (len=17) "LndMetricsRequest", + fields: (map[string]*main.Field) (len=2) { + (string) (len=9) "from_unix": (*main.Field)(0xc00031f140)({ + name: (string) (len=9) "from_unix", + kind: (string) (len=5) "int64", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) true, + oneOfName: (string) "" + }), + (string) (len=7) "to_unix": (*main.Field)(0xc00031f180)({ + name: (string) (len=7) "to_unix", + kind: (string) (len=5) "int64", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) true, + oneOfName: (string) "" + }) + } + }), + (string) (len=18) "LndGetInfoResponse": (*main.Message)(0xc0003fe9f0)({ + fullName: (string) (len=18) "LndGetInfoResponse", + name: (string) (len=18) "LndGetInfoResponse", + fields: (map[string]*main.Field) (len=1) { + (string) (len=5) "alias": (*main.Field)(0xc00031fec0)({ + name: (string) (len=5) "alias", + kind: (string) (len=6) "string", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }) + } + }), + (string) (len=24) "PayAppUserInvoiceRequest": (*main.Message)(0xc0003feed0)({ + fullName: (string) (len=24) "PayAppUserInvoiceRequest", + name: (string) (len=24) "PayAppUserInvoiceRequest", + fields: (map[string]*main.Field) (len=3) { + (string) (len=15) "user_identifier": (*main.Field)(0xc000462700)({ + name: (string) (len=15) "user_identifier", + kind: (string) (len=6) "string", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=7) "invoice": (*main.Field)(0xc000462740)({ + name: (string) (len=7) "invoice", + kind: (string) (len=6) "string", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=6) "amount": (*main.Field)(0xc000462780)({ + name: (string) (len=6) "amount", + kind: (string) (len=5) "int64", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }) + } + }), + (string) (len=7) "Product": (*main.Message)(0xc0003ff950)({ + fullName: (string) (len=7) "Product", + name: (string) (len=7) "Product", + fields: (map[string]*main.Field) (len=3) { + (string) (len=4) "name": (*main.Field)(0xc000463ec0)({ + name: (string) (len=4) "name", + kind: (string) (len=6) "string", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=10) "price_sats": (*main.Field)(0xc000463f00)({ + name: (string) (len=10) "price_sats", + kind: (string) (len=5) "int64", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=2) "id": (*main.Field)(0xc000463e80)({ + name: (string) (len=2) "id", + kind: (string) (len=6) "string", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }) + } + }), + (string) (len=17) "LndGetInfoRequest": (*main.Message)(0xc0003fe930)({ + fullName: (string) (len=17) "LndGetInfoRequest", + name: (string) (len=17) "LndGetInfoRequest", + fields: (map[string]*main.Field) (len=1) { + (string) (len=6) "nodeId": (*main.Field)(0xc00031fe00)({ + name: (string) (len=6) "nodeId", + kind: (string) (len=5) "int64", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }) + } + }), + (string) (len=15) "BanUserResponse": (*main.Message)(0xc0003feb10)({ + fullName: (string) (len=15) "BanUserResponse", + name: (string) (len=15) "BanUserResponse", + fields: (map[string]*main.Field) (len=2) { + (string) (len=12) "balance_sats": (*main.Field)(0xc000462080)({ + name: (string) (len=12) "balance_sats", + kind: (string) (len=5) "int64", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=16) "banned_app_users": (*main.Field)(0xc0004620c0)({ + name: (string) (len=16) "banned_app_users", + kind: (string) (len=13) "BannedAppUser", + isMap: (bool) false, + isArray: (bool) true, + isEnum: (bool) false, + isMessage: (bool) true, + isOptional: (bool) false, + oneOfName: (string) "" + }) + } + }), + (string) (len=14) "AuthAppRequest": (*main.Message)(0xc0003febd0)({ + fullName: (string) (len=14) "AuthAppRequest", + name: (string) (len=14) "AuthAppRequest", + fields: (map[string]*main.Field) (len=2) { + (string) (len=4) "name": (*main.Field)(0xc000462180)({ + name: (string) (len=4) "name", + kind: (string) (len=6) "string", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=19) "allow_user_creation": (*main.Field)(0xc0004621c0)({ + name: (string) (len=19) "allow_user_creation", + kind: (string) (len=4) "bool", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) true, + oneOfName: (string) "" + }) + } + }), + (string) (len=17) "PayAddressRequest": (*main.Message)(0xc0003ff1d0)({ + fullName: (string) (len=17) "PayAddressRequest", + name: (string) (len=17) "PayAddressRequest", + fields: (map[string]*main.Field) (len=3) { + (string) (len=7) "address": (*main.Field)(0xc000462ac0)({ + name: (string) (len=7) "address", + kind: (string) (len=6) "string", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=9) "amoutSats": (*main.Field)(0xc000462b00)({ + name: (string) (len=9) "amoutSats", + kind: (string) (len=5) "int64", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=12) "satsPerVByte": (*main.Field)(0xc000462b40)({ + name: (string) (len=12) "satsPerVByte", + kind: (string) (len=5) "int64", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }) + } + }), + (string) (len=18) "AppsMetricsRequest": (*main.Message)(0xc0003fe450)({ + fullName: (string) (len=18) "AppsMetricsRequest", + name: (string) (len=18) "AppsMetricsRequest", + fields: (map[string]*main.Field) (len=3) { + (string) (len=18) "include_operations": (*main.Field)(0xc00031ed00)({ + name: (string) (len=18) "include_operations", + kind: (string) (len=4) "bool", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) true, + oneOfName: (string) "" + }), + (string) (len=9) "from_unix": (*main.Field)(0xc00031ec80)({ + name: (string) (len=9) "from_unix", + kind: (string) (len=5) "int64", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) true, + oneOfName: (string) "" + }), + (string) (len=7) "to_unix": (*main.Field)(0xc00031ecc0)({ + name: (string) (len=7) "to_unix", + kind: (string) (len=5) "int64", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) true, + oneOfName: (string) "" + }) + } + }), + (string) (len=11) "AppsMetrics": (*main.Message)(0xc0003fe570)({ + fullName: (string) (len=11) "AppsMetrics", + name: (string) (len=11) "AppsMetrics", + fields: (map[string]*main.Field) (len=1) { + (string) (len=4) "apps": (*main.Field)(0xc00031f100)({ + name: (string) (len=4) "apps", + kind: (string) (len=10) "AppMetrics", + isMap: (bool) false, + isArray: (bool) true, + isEnum: (bool) false, + isMessage: (bool) true, + isOptional: (bool) false, + oneOfName: (string) "" + }) + } + }), + (string) (len=12) "RoutingEvent": (*main.Message)(0xc0003fe630)({ + fullName: (string) (len=12) "RoutingEvent", + name: (string) (len=12) "RoutingEvent", + fields: (map[string]*main.Field) (len=12) { + (string) (len=17) "incoming_amt_msat": (*main.Field)(0xc00031f340)({ + name: (string) (len=17) "incoming_amt_msat", + kind: (string) (len=5) "int64", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=17) "outgoing_amt_msat": (*main.Field)(0xc00031f380)({ + name: (string) (len=17) "outgoing_amt_msat", + kind: (string) (len=5) "int64", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=14) "failure_string": (*main.Field)(0xc00031f3c0)({ + name: (string) (len=14) "failure_string", + kind: (string) (len=6) "string", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=19) "incoming_channel_id": (*main.Field)(0xc00031f1c0)({ + name: (string) (len=19) "incoming_channel_id", + kind: (string) (len=5) "int64", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=16) "incoming_htlc_id": (*main.Field)(0xc00031f200)({ + name: (string) (len=16) "incoming_htlc_id", + kind: (string) (len=5) "int64", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=19) "outgoing_channel_id": (*main.Field)(0xc00031f240)({ + name: (string) (len=19) "outgoing_channel_id", + kind: (string) (len=5) "int64", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=16) "outgoing_htlc_id": (*main.Field)(0xc00031f280)({ + name: (string) (len=16) "outgoing_htlc_id", + kind: (string) (len=5) "int64", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=12) "timestamp_ns": (*main.Field)(0xc00031f2c0)({ + name: (string) (len=12) "timestamp_ns", + kind: (string) (len=5) "int64", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=10) "event_type": (*main.Field)(0xc00031f300)({ + name: (string) (len=10) "event_type", + kind: (string) (len=6) "string", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=7) "settled": (*main.Field)(0xc00031f400)({ + name: (string) (len=7) "settled", + kind: (string) (len=4) "bool", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=8) "offchain": (*main.Field)(0xc00031f440)({ + name: (string) (len=8) "offchain", + kind: (string) (len=4) "bool", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=18) "forward_fail_event": (*main.Field)(0xc00031f480)({ + name: (string) (len=18) "forward_fail_event", + kind: (string) (len=4) "bool", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }) + } + }), + (string) (len=13) "BannedAppUser": (*main.Message)(0xc0003feab0)({ + fullName: (string) (len=13) "BannedAppUser", + name: (string) (len=13) "BannedAppUser", + fields: (map[string]*main.Field) (len=4) { + (string) (len=6) "app_id": (*main.Field)(0xc00031ff80)({ + name: (string) (len=6) "app_id", + kind: (string) (len=6) "string", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=15) "user_identifier": (*main.Field)(0xc00031ffc0)({ + name: (string) (len=15) "user_identifier", + kind: (string) (len=6) "string", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=9) "nostr_pub": (*main.Field)(0xc000462040)({ + name: (string) (len=9) "nostr_pub", + kind: (string) (len=6) "string", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=8) "app_name": (*main.Field)(0xc00031ff40)({ + name: (string) (len=8) "app_name", + kind: (string) (len=6) "string", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }) + } + }), + (string) (len=25) "GetUserOperationsResponse": (*main.Message)(0xc0003ff890)({ + fullName: (string) (len=25) "GetUserOperationsResponse", + name: (string) (len=25) "GetUserOperationsResponse", + fields: (map[string]*main.Field) (len=6) { + (string) (len=26) "latestIncomingTxOperations": (*main.Field)(0xc000463d40)({ + name: (string) (len=26) "latestIncomingTxOperations", + kind: (string) (len=14) "UserOperations", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) true, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=32) "latestOutgoingUserToUserPayemnts": (*main.Field)(0xc000463d80)({ + name: (string) (len=32) "latestOutgoingUserToUserPayemnts", + kind: (string) (len=14) "UserOperations", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) true, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=32) "latestIncomingUserToUserPayemnts": (*main.Field)(0xc000463dc0)({ + name: (string) (len=32) "latestIncomingUserToUserPayemnts", + kind: (string) (len=14) "UserOperations", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) true, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=31) "latestOutgoingInvoiceOperations": (*main.Field)(0xc000463c80)({ + name: (string) (len=31) "latestOutgoingInvoiceOperations", + kind: (string) (len=14) "UserOperations", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) true, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=31) "latestIncomingInvoiceOperations": (*main.Field)(0xc000463cc0)({ + name: (string) (len=31) "latestIncomingInvoiceOperations", + kind: (string) (len=14) "UserOperations", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) true, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=26) "latestOutgoingTxOperations": (*main.Field)(0xc000463d00)({ + name: (string) (len=26) "latestOutgoingTxOperations", + kind: (string) (len=14) "UserOperations", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) true, + isOptional: (bool) false, + oneOfName: (string) "" + }) + } + }), + (string) (len=31) "RequestNPubLinkingTokenResponse": (*main.Message)(0xc0003ffbf0)({ + fullName: (string) (len=31) "RequestNPubLinkingTokenResponse", + name: (string) (len=31) "RequestNPubLinkingTokenResponse", + fields: (map[string]*main.Field) (len=1) { + (string) (len=5) "token": (*main.Field)(0xc0000b03c0)({ + name: (string) (len=5) "token", + kind: (string) (len=6) "string", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }) + } + }), + (string) (len=11) "UsageMetric": (*main.Message)(0xc0003fe390)({ + fullName: (string) (len=11) "UsageMetric", + name: (string) (len=11) "UsageMetric", + fields: (map[string]*main.Field) (len=9) { + (string) (len=14) "parsed_in_nano": (*main.Field)(0xc00031e640)({ + name: (string) (len=14) "parsed_in_nano", + kind: (string) (len=5) "int64", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=16) "validate_in_nano": (*main.Field)(0xc00031e8c0)({ + name: (string) (len=16) "validate_in_nano", + kind: (string) (len=5) "int64", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=14) "handle_in_nano": (*main.Field)(0xc00031e900)({ + name: (string) (len=14) "handle_in_nano", + kind: (string) (len=5) "int64", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=5) "batch": (*main.Field)(0xc00031e9c0)({ + name: (string) (len=5) "batch", + kind: (string) (len=4) "bool", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=10) "batch_size": (*main.Field)(0xc00031ea80)({ + name: (string) (len=10) "batch_size", + kind: (string) (len=5) "int64", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=15) "processed_at_ms": (*main.Field)(0xc00031e5c0)({ + name: (string) (len=15) "processed_at_ms", + kind: (string) (len=5) "int64", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=12) "auth_in_nano": (*main.Field)(0xc00031e680)({ + name: (string) (len=12) "auth_in_nano", + kind: (string) (len=5) "int64", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=8) "rpc_name": (*main.Field)(0xc00031e980)({ + name: (string) (len=8) "rpc_name", + kind: (string) (len=6) "string", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=5) "nostr": (*main.Field)(0xc00031ea40)({ + name: (string) (len=5) "nostr", + kind: (string) (len=4) "bool", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }) + } + }), + (string) (len=17) "NewInvoiceRequest": (*main.Message)(0xc0003ff290)({ + fullName: (string) (len=17) "NewInvoiceRequest", + name: (string) (len=17) "NewInvoiceRequest", + fields: (map[string]*main.Field) (len=2) { + (string) (len=10) "amountSats": (*main.Field)(0xc000462c80)({ + name: (string) (len=10) "amountSats", + kind: (string) (len=5) "int64", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=4) "memo": (*main.Field)(0xc000462cc0)({ + name: (string) (len=4) "memo", + kind: (string) (len=6) "string", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }) + } + }), + (string) (len=18) "OpenChannelRequest": (*main.Message)(0xc0003ff4d0)({ + fullName: (string) (len=18) "OpenChannelRequest", + name: (string) (len=18) "OpenChannelRequest", + fields: (map[string]*main.Field) (len=4) { + (string) (len=10) "pushAmount": (*main.Field)(0xc000463000)({ + name: (string) (len=10) "pushAmount", + kind: (string) (len=5) "int64", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=12) "closeAddress": (*main.Field)(0xc000463040)({ + name: (string) (len=12) "closeAddress", + kind: (string) (len=6) "string", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=11) "destination": (*main.Field)(0xc000462f80)({ + name: (string) (len=11) "destination", + kind: (string) (len=6) "string", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=13) "fundingAmount": (*main.Field)(0xc000462fc0)({ + name: (string) (len=13) "fundingAmount", + kind: (string) (len=5) "int64", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }) + } + }), + (string) (len=17) "ChainBalanceEvent": (*main.Message)(0xc0003fe6f0)({ + fullName: (string) (len=17) "ChainBalanceEvent", + name: (string) (len=17) "ChainBalanceEvent", + fields: (map[string]*main.Field) (len=4) { + (string) (len=19) "unconfirmed_balance": (*main.Field)(0xc00031f640)({ + name: (string) (len=19) "unconfirmed_balance", + kind: (string) (len=5) "int64", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=13) "total_balance": (*main.Field)(0xc00031f680)({ + name: (string) (len=13) "total_balance", + kind: (string) (len=5) "int64", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=12) "block_height": (*main.Field)(0xc00031f5c0)({ + name: (string) (len=12) "block_height", + kind: (string) (len=5) "int64", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=17) "confirmed_balance": (*main.Field)(0xc00031f600)({ + name: (string) (len=17) "confirmed_balance", + kind: (string) (len=5) "int64", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }) + } + }), + (string) (len=17) "GetAppUserRequest": (*main.Message)(0xc0003fee70)({ + fullName: (string) (len=17) "GetAppUserRequest", + name: (string) (len=17) "GetAppUserRequest", + fields: (map[string]*main.Field) (len=1) { + (string) (len=15) "user_identifier": (*main.Field)(0xc0004626c0)({ + name: (string) (len=15) "user_identifier", + kind: (string) (len=6) "string", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }) + } + }), + (string) (len=18) "NewAddressResponse": (*main.Message)(0xc0003ff170)({ + fullName: (string) (len=18) "NewAddressResponse", + name: (string) (len=18) "NewAddressResponse", + fields: (map[string]*main.Field) (len=1) { + (string) (len=7) "address": (*main.Field)(0xc000462a80)({ + name: (string) (len=7) "address", + kind: (string) (len=6) "string", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }) + } + }), + (string) (len=18) "PayInvoiceResponse": (*main.Message)(0xc0003ff470)({ + fullName: (string) (len=18) "PayInvoiceResponse", + name: (string) (len=18) "PayInvoiceResponse", + fields: (map[string]*main.Field) (len=5) { + (string) (len=8) "preimage": (*main.Field)(0xc000462e40)({ + name: (string) (len=8) "preimage", + kind: (string) (len=6) "string", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=11) "amount_paid": (*main.Field)(0xc000462e80)({ + name: (string) (len=11) "amount_paid", + kind: (string) (len=5) "int64", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=12) "operation_id": (*main.Field)(0xc000462ec0)({ + name: (string) (len=12) "operation_id", + kind: (string) (len=6) "string", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=11) "service_fee": (*main.Field)(0xc000462f00)({ + name: (string) (len=11) "service_fee", + kind: (string) (len=5) "int64", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=11) "network_fee": (*main.Field)(0xc000462f40)({ + name: (string) (len=11) "network_fee", + kind: (string) (len=5) "int64", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }) + } + }), + (string) (len=17) "AddProductRequest": (*main.Message)(0xc0003ff8f0)({ + fullName: (string) (len=17) "AddProductRequest", + name: (string) (len=17) "AddProductRequest", + fields: (map[string]*main.Field) (len=2) { + (string) (len=4) "name": (*main.Field)(0xc000463e00)({ + name: (string) (len=4) "name", + kind: (string) (len=6) "string", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=10) "price_sats": (*main.Field)(0xc000463e40)({ + name: (string) (len=10) "price_sats", + kind: (string) (len=5) "int64", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }) + } + }), + (string) (len=25) "EncryptionExchangeRequest": (*main.Message)(0xc0003fe330)({ + fullName: (string) (len=25) "EncryptionExchangeRequest", + name: (string) (len=25) "EncryptionExchangeRequest", + fields: (map[string]*main.Field) (len=2) { + (string) (len=9) "publicKey": (*main.Field)(0xc00031e300)({ + name: (string) (len=9) "publicKey", + kind: (string) (len=6) "string", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=8) "deviceId": (*main.Field)(0xc00031e400)({ + name: (string) (len=8) "deviceId", + kind: (string) (len=6) "string", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }) + } + }), + (string) (len=9) "UsersInfo": (*main.Message)(0xc0003fe4b0)({ + fullName: (string) (len=9) "UsersInfo", + name: (string) (len=9) "UsersInfo", + fields: (map[string]*main.Field) (len=6) { + (string) (len=10) "no_balance": (*main.Field)(0xc00031ed80)({ + name: (string) (len=10) "no_balance", + kind: (string) (len=5) "int64", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=16) "negative_balance": (*main.Field)(0xc00031edc0)({ + name: (string) (len=16) "negative_balance", + kind: (string) (len=5) "int64", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=20) "always_been_inactive": (*main.Field)(0xc00031ee00)({ + name: (string) (len=20) "always_been_inactive", + kind: (string) (len=5) "int64", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=11) "balance_avg": (*main.Field)(0xc00031ee40)({ + name: (string) (len=11) "balance_avg", + kind: (string) (len=5) "int64", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=14) "balance_median": (*main.Field)(0xc00031ee80)({ + name: (string) (len=14) "balance_median", + kind: (string) (len=5) "int64", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=5) "total": (*main.Field)(0xc00031ed40)({ + name: (string) (len=5) "total", + kind: (string) (len=5) "int64", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }) + } + }), + (string) (len=19) "ChannelBalanceEvent": (*main.Message)(0xc0003fe690)({ + fullName: (string) (len=19) "ChannelBalanceEvent", + name: (string) (len=19) "ChannelBalanceEvent", + fields: (map[string]*main.Field) (len=4) { + (string) (len=12) "block_height": (*main.Field)(0xc00031f4c0)({ + name: (string) (len=12) "block_height", + kind: (string) (len=5) "int64", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=10) "channel_id": (*main.Field)(0xc00031f500)({ + name: (string) (len=10) "channel_id", + kind: (string) (len=6) "string", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=18) "local_balance_sats": (*main.Field)(0xc00031f540)({ + name: (string) (len=18) "local_balance_sats", + kind: (string) (len=5) "int64", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=19) "remote_balance_sats": (*main.Field)(0xc00031f580)({ + name: (string) (len=19) "remote_balance_sats", + kind: (string) (len=5) "int64", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }) + } + }), + (string) (len=14) "ChannelRouting": (*main.Message)(0xc0003fe810)({ + fullName: (string) (len=14) "ChannelRouting", + name: (string) (len=14) "ChannelRouting", + fields: (map[string]*main.Field) (len=10) { + (string) (len=21) "forward_fee_as_output": (*main.Field)(0xc00031fb00)({ + name: (string) (len=21) "forward_fee_as_output", + kind: (string) (len=5) "int64", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=11) "send_errors": (*main.Field)(0xc00031f940)({ + name: (string) (len=11) "send_errors", + kind: (string) (len=5) "int64", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=23) "forward_errors_as_input": (*main.Field)(0xc00031f9c0)({ + name: (string) (len=23) "forward_errors_as_input", + kind: (string) (len=5) "int64", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=27) "missed_forward_fee_as_input": (*main.Field)(0xc00031fa40)({ + name: (string) (len=27) "missed_forward_fee_as_input", + kind: (string) (len=5) "int64", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=20) "forward_fee_as_input": (*main.Field)(0xc00031fac0)({ + name: (string) (len=20) "forward_fee_as_input", + kind: (string) (len=5) "int64", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=13) "events_number": (*main.Field)(0xc00031fb40)({ + name: (string) (len=13) "events_number", + kind: (string) (len=5) "int64", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=10) "channel_id": (*main.Field)(0xc00031f900)({ + name: (string) (len=10) "channel_id", + kind: (string) (len=6) "string", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=14) "receive_errors": (*main.Field)(0xc00031f980)({ + name: (string) (len=14) "receive_errors", + kind: (string) (len=5) "int64", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=24) "forward_errors_as_output": (*main.Field)(0xc00031fa00)({ + name: (string) (len=24) "forward_errors_as_output", + kind: (string) (len=5) "int64", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=28) "missed_forward_fee_as_output": (*main.Field)(0xc00031fa80)({ + name: (string) (len=28) "missed_forward_fee_as_output", + kind: (string) (len=5) "int64", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }) + } + }), + (string) (len=30) "SendAppUserToAppPaymentRequest": (*main.Message)(0xc0003fef90)({ + fullName: (string) (len=30) "SendAppUserToAppPaymentRequest", + name: (string) (len=30) "SendAppUserToAppPaymentRequest", + fields: (map[string]*main.Field) (len=2) { + (string) (len=20) "from_user_identifier": (*main.Field)(0xc000462880)({ + name: (string) (len=20) "from_user_identifier", + kind: (string) (len=6) "string", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=6) "amount": (*main.Field)(0xc0004628c0)({ + name: (string) (len=6) "amount", + kind: (string) (len=5) "int64", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }) + } + }), + (string) (len=24) "SetMockAppBalanceRequest": (*main.Message)(0xc0003ff0b0)({ + fullName: (string) (len=24) "SetMockAppBalanceRequest", + name: (string) (len=24) "SetMockAppBalanceRequest", + fields: (map[string]*main.Field) (len=1) { + (string) (len=6) "amount": (*main.Field)(0xc000462a00)({ + name: (string) (len=6) "amount", + kind: (string) (len=5) "int64", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }) + } + }), + (string) (len=15) "MigrationUpdate": (*main.Message)(0xc0003ffa70)({ + fullName: (string) (len=15) "MigrationUpdate", + name: (string) (len=15) "MigrationUpdate", + fields: (map[string]*main.Field) (len=2) { + (string) (len=7) "closure": (*main.Field)(0xc000463fc0)({ + name: (string) (len=7) "closure", + kind: (string) (len=16) "ClosureMigration", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) true, + isOptional: (bool) true, + oneOfName: (string) "" + }), + (string) (len=6) "relays": (*main.Field)(0xc0000b0000)({ + name: (string) (len=6) "relays", + kind: (string) (len=15) "RelaysMigration", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) true, + isOptional: (bool) true, + oneOfName: (string) "" + }) + } + }), + (string) (len=16) "ClosureMigration": (*main.Message)(0xc0003ffad0)({ + fullName: (string) (len=16) "ClosureMigration", + name: (string) (len=16) "ClosureMigration", + fields: (map[string]*main.Field) (len=1) { + (string) (len=14) "closes_at_unix": (*main.Field)(0xc0000b0040)({ + name: (string) (len=14) "closes_at_unix", + kind: (string) (len=5) "int64", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }) + } + }), + (string) (len=13) "ClosedChannel": (*main.Message)(0xc0003fe7b0)({ + fullName: (string) (len=13) "ClosedChannel", + name: (string) (len=13) "ClosedChannel", + fields: (map[string]*main.Field) (len=3) { + (string) (len=10) "channel_id": (*main.Field)(0xc00031f840)({ + name: (string) (len=10) "channel_id", + kind: (string) (len=6) "string", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=8) "capacity": (*main.Field)(0xc00031f880)({ + name: (string) (len=8) "capacity", + kind: (string) (len=5) "int64", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=13) "closed_height": (*main.Field)(0xc00031f8c0)({ + name: (string) (len=13) "closed_height", + kind: (string) (len=5) "int64", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }) + } + }), + (string) (len=11) "Application": (*main.Message)(0xc0003fec30)({ + fullName: (string) (len=11) "Application", + name: (string) (len=11) "Application", + fields: (map[string]*main.Field) (len=4) { + (string) (len=4) "name": (*main.Field)(0xc000462200)({ + name: (string) (len=4) "name", + kind: (string) (len=6) "string", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=2) "id": (*main.Field)(0xc000462240)({ + name: (string) (len=2) "id", + kind: (string) (len=6) "string", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=7) "balance": (*main.Field)(0xc000462280)({ + name: (string) (len=7) "balance", + kind: (string) (len=5) "int64", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=4) "npub": (*main.Field)(0xc0004622c0)({ + name: (string) (len=4) "npub", + kind: (string) (len=6) "string", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }) + } + }), + (string) (len=17) "AddAppUserRequest": (*main.Message)(0xc0003fecf0)({ + fullName: (string) (len=17) "AddAppUserRequest", + name: (string) (len=17) "AddAppUserRequest", + fields: (map[string]*main.Field) (len=3) { + (string) (len=10) "identifier": (*main.Field)(0xc000462380)({ + name: (string) (len=10) "identifier", + kind: (string) (len=6) "string", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=14) "fail_if_exists": (*main.Field)(0xc0004623c0)({ + name: (string) (len=14) "fail_if_exists", + kind: (string) (len=4) "bool", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=7) "balance": (*main.Field)(0xc000462400)({ + name: (string) (len=7) "balance", + kind: (string) (len=5) "int64", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }) + } + }), + (string) (len=28) "SetMockAppUserBalanceRequest": (*main.Message)(0xc0003ff050)({ + fullName: (string) (len=28) "SetMockAppUserBalanceRequest", + name: (string) (len=28) "SetMockAppUserBalanceRequest", + fields: (map[string]*main.Field) (len=2) { + (string) (len=15) "user_identifier": (*main.Field)(0xc000462980)({ + name: (string) (len=15) "user_identifier", + kind: (string) (len=6) "string", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=6) "amount": (*main.Field)(0xc0004629c0)({ + name: (string) (len=6) "amount", + kind: (string) (len=5) "int64", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }) + } + }), + (string) (len=18) "PayAddressResponse": (*main.Message)(0xc0003ff230)({ + fullName: (string) (len=18) "PayAddressResponse", + name: (string) (len=18) "PayAddressResponse", + fields: (map[string]*main.Field) (len=4) { + (string) (len=4) "txId": (*main.Field)(0xc000462b80)({ + name: (string) (len=4) "txId", + kind: (string) (len=6) "string", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=12) "operation_id": (*main.Field)(0xc000462bc0)({ + name: (string) (len=12) "operation_id", + kind: (string) (len=6) "string", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=11) "service_fee": (*main.Field)(0xc000462c00)({ + name: (string) (len=11) "service_fee", + kind: (string) (len=5) "int64", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=11) "network_fee": (*main.Field)(0xc000462c40)({ + name: (string) (len=11) "network_fee", + kind: (string) (len=5) "int64", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }) + } + }), + (string) (len=18) "NewInvoiceResponse": (*main.Message)(0xc0003ff2f0)({ + fullName: (string) (len=18) "NewInvoiceResponse", + name: (string) (len=18) "NewInvoiceResponse", + fields: (map[string]*main.Field) (len=1) { + (string) (len=7) "invoice": (*main.Field)(0xc000462d00)({ + name: (string) (len=7) "invoice", + kind: (string) (len=6) "string", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }) + } + }), + (string) (len=9) "HttpCreds": (*main.Message)(0xc0003ffcb0)({ + fullName: (string) (len=9) "HttpCreds", + name: (string) (len=9) "HttpCreds", + fields: (map[string]*main.Field) (len=2) { + (string) (len=3) "url": (*main.Field)(0xc0000b06c0)({ + name: (string) (len=3) "url", + kind: (string) (len=6) "string", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=5) "token": (*main.Field)(0xc0000b0700)({ + name: (string) (len=5) "token", + kind: (string) (len=6) "string", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }) + } + }) +} + +(map[string][]*main.Field) { +} + +parsing file: structs 71 +parsing file: methods 2 +-> [{guest Guest map[]} {user User map[app_id:string app_user_id:string user_id:string]} {admin Admin map[admin_id:string]} {metrics Metrics map[operator_id:string]} {app App map[app_id:string]}] + +([]interface {}) + diff --git a/proto/autogenerated/ts/express_server.ts b/proto/autogenerated/ts/express_server.ts index 0b7efbce..f041058a 100644 --- a/proto/autogenerated/ts/express_server.ts +++ b/proto/autogenerated/ts/express_server.ts @@ -1,1126 +1,1160 @@ -// This file was autogenerated from a .proto file, DO NOT EDIT! - -import express, { Response, json, urlencoded } from 'express' -import cors from 'cors' -import * as Types from './types.js' -export type Logger = { log: (v: any) => void, error: (v: any) => void } -export type ServerOptions = { - allowCors?: true - staticFiles?: string - allowNotImplementedMethods?: true - logger?: Logger - throwErrors?: true - logMethod?: true - logBody?: true - metricsCallback: (metrics: Types.RequestMetric[]) => void - GuestAuthGuard: (authorizationHeader?: string) => Promise - UserAuthGuard: (authorizationHeader?: string) => Promise - AdminAuthGuard: (authorizationHeader?: string) => Promise - MetricsAuthGuard: (authorizationHeader?: string) => Promise - AppAuthGuard: (authorizationHeader?: string) => Promise -} -declare module 'express-serve-static-core' { interface Request { startTime?: bigint, bodySize?: number, startTimeMs: number } } -const logErrorAndReturnResponse = (error: Error, response: string, res: Response, logger: Logger, metric: Types.RequestMetric, metricsCallback: (metrics: Types.RequestMetric[]) => void) => { - logger.error(error.message || error); metricsCallback([{ ...metric, error: response }]); res.json({ status: 'ERROR', reason: response }) -} -export default (methods: Types.ServerMethods, opts: ServerOptions) => { - const logger = opts.logger || { log: console.log, error: console.error } - const app = express() - if (opts.allowCors) { - app.use(cors()) - } - app.use((req, _, next) => { req.startTime = process.hrtime.bigint(); req.startTimeMs = Date.now(); next() }) - app.use(json()) - app.use(urlencoded({ extended: true })) - if (opts.logMethod) app.use((req, _, next) => { console.log(req.method, req.path); if (opts.logBody) console.log(req.body); next() }) - if (!opts.allowNotImplementedMethods && !methods.LndGetInfo) throw new Error('method: LndGetInfo is not implemented') - app.post('/api/admin/lnd/getinfo', async (req, res) => { - const info: Types.RequestInfo = { rpcName: 'LndGetInfo', batch: false, nostr: false, batchSize: 0} - const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } - let authCtx: Types.AuthContext = {} - try { - if (!methods.LndGetInfo) throw new Error('method: LndGetInfo is not implemented') - const authContext = await opts.AdminAuthGuard(req.headers['authorization']) - authCtx = authContext - stats.guard = process.hrtime.bigint() - const request = req.body - const error = Types.LndGetInfoRequestValidate(request) - stats.validate = process.hrtime.bigint() - if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authContext }, opts.metricsCallback) - const query = req.query - const params = req.params - const response = await methods.LndGetInfo({rpcName:'LndGetInfo', ctx:authContext , req: request}) - stats.handle = process.hrtime.bigint() - res.json({status: 'OK', ...response}) - opts.metricsCallback([{ ...info, ...stats, ...authContext }]) - } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } - }) - if (!opts.allowNotImplementedMethods && !methods.AddApp) throw new Error('method: AddApp is not implemented') - app.post('/api/admin/app/add', async (req, res) => { - const info: Types.RequestInfo = { rpcName: 'AddApp', batch: false, nostr: false, batchSize: 0} - const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } - let authCtx: Types.AuthContext = {} - try { - if (!methods.AddApp) throw new Error('method: AddApp is not implemented') - const authContext = await opts.AdminAuthGuard(req.headers['authorization']) - authCtx = authContext - stats.guard = process.hrtime.bigint() - const request = req.body - const error = Types.AddAppRequestValidate(request) - stats.validate = process.hrtime.bigint() - if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authContext }, opts.metricsCallback) - const query = req.query - const params = req.params - const response = await methods.AddApp({rpcName:'AddApp', ctx:authContext , req: request}) - stats.handle = process.hrtime.bigint() - res.json({status: 'OK', ...response}) - opts.metricsCallback([{ ...info, ...stats, ...authContext }]) - } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } - }) - if (!opts.allowNotImplementedMethods && !methods.AuthApp) throw new Error('method: AuthApp is not implemented') - app.post('/api/admin/app/auth', async (req, res) => { - const info: Types.RequestInfo = { rpcName: 'AuthApp', batch: false, nostr: false, batchSize: 0} - const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } - let authCtx: Types.AuthContext = {} - try { - if (!methods.AuthApp) throw new Error('method: AuthApp is not implemented') - const authContext = await opts.AdminAuthGuard(req.headers['authorization']) - authCtx = authContext - stats.guard = process.hrtime.bigint() - const request = req.body - const error = Types.AuthAppRequestValidate(request) - stats.validate = process.hrtime.bigint() - if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authContext }, opts.metricsCallback) - const query = req.query - const params = req.params - const response = await methods.AuthApp({rpcName:'AuthApp', ctx:authContext , req: request}) - stats.handle = process.hrtime.bigint() - res.json({status: 'OK', ...response}) - opts.metricsCallback([{ ...info, ...stats, ...authContext }]) - } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } - }) - if (!opts.allowNotImplementedMethods && !methods.BanUser) throw new Error('method: BanUser is not implemented') - app.post('/api/admin/user/ban', async (req, res) => { - const info: Types.RequestInfo = { rpcName: 'BanUser', batch: false, nostr: false, batchSize: 0} - const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } - let authCtx: Types.AuthContext = {} - try { - if (!methods.BanUser) throw new Error('method: BanUser is not implemented') - const authContext = await opts.AdminAuthGuard(req.headers['authorization']) - authCtx = authContext - stats.guard = process.hrtime.bigint() - const request = req.body - const error = Types.BanUserRequestValidate(request) - stats.validate = process.hrtime.bigint() - if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authContext }, opts.metricsCallback) - const query = req.query - const params = req.params - const response = await methods.BanUser({rpcName:'BanUser', ctx:authContext , req: request}) - stats.handle = process.hrtime.bigint() - res.json({status: 'OK', ...response}) - opts.metricsCallback([{ ...info, ...stats, ...authContext }]) - } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } - }) - if (!opts.allowNotImplementedMethods && !methods.GetUsageMetrics) throw new Error('method: GetUsageMetrics is not implemented') - app.post('/api/reports/usage', async (req, res) => { - const info: Types.RequestInfo = { rpcName: 'GetUsageMetrics', batch: false, nostr: false, batchSize: 0} - const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } - let authCtx: Types.AuthContext = {} - try { - if (!methods.GetUsageMetrics) throw new Error('method: GetUsageMetrics is not implemented') - const authContext = await opts.MetricsAuthGuard(req.headers['authorization']) - authCtx = authContext - stats.guard = process.hrtime.bigint() - stats.validate = stats.guard - const query = req.query - const params = req.params - const response = await methods.GetUsageMetrics({rpcName:'GetUsageMetrics', ctx:authContext }) - stats.handle = process.hrtime.bigint() - res.json({status: 'OK', ...response}) - opts.metricsCallback([{ ...info, ...stats, ...authContext }]) - } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } - }) - if (!opts.allowNotImplementedMethods && !methods.GetAppsMetrics) throw new Error('method: GetAppsMetrics is not implemented') - app.post('/api/reports/apps', async (req, res) => { - const info: Types.RequestInfo = { rpcName: 'GetAppsMetrics', batch: false, nostr: false, batchSize: 0} - const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } - let authCtx: Types.AuthContext = {} - try { - if (!methods.GetAppsMetrics) throw new Error('method: GetAppsMetrics is not implemented') - const authContext = await opts.MetricsAuthGuard(req.headers['authorization']) - authCtx = authContext - stats.guard = process.hrtime.bigint() - const request = req.body - const error = Types.AppsMetricsRequestValidate(request) - stats.validate = process.hrtime.bigint() - if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authContext }, opts.metricsCallback) - const query = req.query - const params = req.params - const response = await methods.GetAppsMetrics({rpcName:'GetAppsMetrics', ctx:authContext , req: request}) - stats.handle = process.hrtime.bigint() - res.json({status: 'OK', ...response}) - opts.metricsCallback([{ ...info, ...stats, ...authContext }]) - } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } - }) - if (!opts.allowNotImplementedMethods && !methods.GetLndMetrics) throw new Error('method: GetLndMetrics is not implemented') - app.post('/api/reports/lnd', async (req, res) => { - const info: Types.RequestInfo = { rpcName: 'GetLndMetrics', batch: false, nostr: false, batchSize: 0} - const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } - let authCtx: Types.AuthContext = {} - try { - if (!methods.GetLndMetrics) throw new Error('method: GetLndMetrics is not implemented') - const authContext = await opts.MetricsAuthGuard(req.headers['authorization']) - authCtx = authContext - stats.guard = process.hrtime.bigint() - const request = req.body - const error = Types.LndMetricsRequestValidate(request) - stats.validate = process.hrtime.bigint() - if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authContext }, opts.metricsCallback) - const query = req.query - const params = req.params - const response = await methods.GetLndMetrics({rpcName:'GetLndMetrics', ctx:authContext , req: request}) - stats.handle = process.hrtime.bigint() - res.json({status: 'OK', ...response}) - opts.metricsCallback([{ ...info, ...stats, ...authContext }]) - } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } - }) - if (!opts.allowNotImplementedMethods && !methods.Health) throw new Error('method: Health is not implemented') - app.get('/api/health', async (req, res) => { - const info: Types.RequestInfo = { rpcName: 'Health', batch: false, nostr: false, batchSize: 0} - const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } - let authCtx: Types.AuthContext = {} - try { - if (!methods.Health) throw new Error('method: Health is not implemented') - const authContext = await opts.GuestAuthGuard(req.headers['authorization']) - authCtx = authContext - stats.guard = process.hrtime.bigint() - stats.validate = stats.guard - const query = req.query - const params = req.params - await methods.Health({rpcName:'Health', ctx:authContext }) - stats.handle = process.hrtime.bigint() - res.json({status: 'OK'}) - opts.metricsCallback([{ ...info, ...stats, ...authContext }]) - } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } - }) - if (!opts.allowNotImplementedMethods && !methods.EncryptionExchange) throw new Error('method: EncryptionExchange is not implemented') - app.post('/api/encryption/exchange', async (req, res) => { - const info: Types.RequestInfo = { rpcName: 'EncryptionExchange', batch: false, nostr: false, batchSize: 0} - const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } - let authCtx: Types.AuthContext = {} - try { - if (!methods.EncryptionExchange) throw new Error('method: EncryptionExchange is not implemented') - const authContext = await opts.GuestAuthGuard(req.headers['authorization']) - authCtx = authContext - stats.guard = process.hrtime.bigint() - const request = req.body - const error = Types.EncryptionExchangeRequestValidate(request) - stats.validate = process.hrtime.bigint() - if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authContext }, opts.metricsCallback) - const query = req.query - const params = req.params - await methods.EncryptionExchange({rpcName:'EncryptionExchange', ctx:authContext , req: request}) - stats.handle = process.hrtime.bigint() - res.json({status: 'OK'}) - opts.metricsCallback([{ ...info, ...stats, ...authContext }]) - } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } - }) - if (!opts.allowNotImplementedMethods && !methods.SetMockInvoiceAsPaid) throw new Error('method: SetMockInvoiceAsPaid is not implemented') - app.post('/api/lnd/mock/invoice/paid', async (req, res) => { - const info: Types.RequestInfo = { rpcName: 'SetMockInvoiceAsPaid', batch: false, nostr: false, batchSize: 0} - const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } - let authCtx: Types.AuthContext = {} - try { - if (!methods.SetMockInvoiceAsPaid) throw new Error('method: SetMockInvoiceAsPaid is not implemented') - const authContext = await opts.GuestAuthGuard(req.headers['authorization']) - authCtx = authContext - stats.guard = process.hrtime.bigint() - const request = req.body - const error = Types.SetMockInvoiceAsPaidRequestValidate(request) - stats.validate = process.hrtime.bigint() - if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authContext }, opts.metricsCallback) - const query = req.query - const params = req.params - await methods.SetMockInvoiceAsPaid({rpcName:'SetMockInvoiceAsPaid', ctx:authContext , req: request}) - stats.handle = process.hrtime.bigint() - res.json({status: 'OK'}) - opts.metricsCallback([{ ...info, ...stats, ...authContext }]) - } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } - }) - if (!opts.allowNotImplementedMethods && !methods.GetLnurlWithdrawInfo) throw new Error('method: GetLnurlWithdrawInfo is not implemented') - app.get('/api/guest/lnurl_withdraw/info', async (req, res) => { - const info: Types.RequestInfo = { rpcName: 'GetLnurlWithdrawInfo', batch: false, nostr: false, batchSize: 0} - const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } - let authCtx: Types.AuthContext = {} - try { - if (!methods.GetLnurlWithdrawInfo) throw new Error('method: GetLnurlWithdrawInfo is not implemented') - const authContext = await opts.GuestAuthGuard(req.headers['authorization']) - authCtx = authContext - stats.guard = process.hrtime.bigint() - stats.validate = stats.guard - const query = req.query - const params = req.params - const response = await methods.GetLnurlWithdrawInfo({rpcName:'GetLnurlWithdrawInfo', ctx:authContext ,query: req.query}) - stats.handle = process.hrtime.bigint() - res.json({status: 'OK', ...response}) - opts.metricsCallback([{ ...info, ...stats, ...authContext }]) - } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } - }) - if (!opts.allowNotImplementedMethods && !methods.HandleLnurlWithdraw) throw new Error('method: HandleLnurlWithdraw is not implemented') - app.get('/api/guest/lnurl_withdraw/handle', async (req, res) => { - const info: Types.RequestInfo = { rpcName: 'HandleLnurlWithdraw', batch: false, nostr: false, batchSize: 0} - const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } - let authCtx: Types.AuthContext = {} - try { - if (!methods.HandleLnurlWithdraw) throw new Error('method: HandleLnurlWithdraw is not implemented') - const authContext = await opts.GuestAuthGuard(req.headers['authorization']) - authCtx = authContext - stats.guard = process.hrtime.bigint() - stats.validate = stats.guard - const query = req.query - const params = req.params - await methods.HandleLnurlWithdraw({rpcName:'HandleLnurlWithdraw', ctx:authContext ,query: req.query}) - stats.handle = process.hrtime.bigint() - res.json({status: 'OK'}) - opts.metricsCallback([{ ...info, ...stats, ...authContext }]) - } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } - }) - if (!opts.allowNotImplementedMethods && !methods.GetLnurlPayInfo) throw new Error('method: GetLnurlPayInfo is not implemented') - app.get('/api/guest/lnurl_pay/info', async (req, res) => { - const info: Types.RequestInfo = { rpcName: 'GetLnurlPayInfo', batch: false, nostr: false, batchSize: 0} - const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } - let authCtx: Types.AuthContext = {} - try { - if (!methods.GetLnurlPayInfo) throw new Error('method: GetLnurlPayInfo is not implemented') - const authContext = await opts.GuestAuthGuard(req.headers['authorization']) - authCtx = authContext - stats.guard = process.hrtime.bigint() - stats.validate = stats.guard - const query = req.query - const params = req.params - const response = await methods.GetLnurlPayInfo({rpcName:'GetLnurlPayInfo', ctx:authContext ,query: req.query}) - stats.handle = process.hrtime.bigint() - res.json({status: 'OK', ...response}) - opts.metricsCallback([{ ...info, ...stats, ...authContext }]) - } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } - }) - if (!opts.allowNotImplementedMethods && !methods.HandleLnurlPay) throw new Error('method: HandleLnurlPay is not implemented') - app.get('/api/guest/lnurl_pay/handle', async (req, res) => { - const info: Types.RequestInfo = { rpcName: 'HandleLnurlPay', batch: false, nostr: false, batchSize: 0} - const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } - let authCtx: Types.AuthContext = {} - try { - if (!methods.HandleLnurlPay) throw new Error('method: HandleLnurlPay is not implemented') - const authContext = await opts.GuestAuthGuard(req.headers['authorization']) - authCtx = authContext - stats.guard = process.hrtime.bigint() - stats.validate = stats.guard - const query = req.query - const params = req.params - const response = await methods.HandleLnurlPay({rpcName:'HandleLnurlPay', ctx:authContext ,query: req.query}) - stats.handle = process.hrtime.bigint() - res.json({status: 'OK', ...response}) - opts.metricsCallback([{ ...info, ...stats, ...authContext }]) - } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } - }) - if (!opts.allowNotImplementedMethods && !methods.HandleLnurlAddress) throw new Error('method: HandleLnurlAddress is not implemented') - app.get('/.well-known/lnurlp/:address_name', async (req, res) => { - const info: Types.RequestInfo = { rpcName: 'HandleLnurlAddress', batch: false, nostr: false, batchSize: 0} - const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } - let authCtx: Types.AuthContext = {} - try { - if (!methods.HandleLnurlAddress) throw new Error('method: HandleLnurlAddress is not implemented') - const authContext = await opts.GuestAuthGuard(req.headers['authorization']) - authCtx = authContext - stats.guard = process.hrtime.bigint() - stats.validate = stats.guard - const query = req.query - const params = req.params - const response = await methods.HandleLnurlAddress({rpcName:'HandleLnurlAddress', ctx:authContext ,params: req.params}) - stats.handle = process.hrtime.bigint() - res.json({status: 'OK', ...response}) - opts.metricsCallback([{ ...info, ...stats, ...authContext }]) - } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } - }) - if (!opts.allowNotImplementedMethods && !methods.LinkNPubThroughToken) throw new Error('method: LinkNPubThroughToken is not implemented') - app.post('/api/guest/npub/link', async (req, res) => { - const info: Types.RequestInfo = { rpcName: 'LinkNPubThroughToken', batch: false, nostr: false, batchSize: 0} - const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } - let authCtx: Types.AuthContext = {} - try { - if (!methods.LinkNPubThroughToken) throw new Error('method: LinkNPubThroughToken is not implemented') - const authContext = await opts.UserAuthGuard(req.headers['authorization']) - authCtx = authContext - stats.guard = process.hrtime.bigint() - const request = req.body - const error = Types.LinkNPubThroughTokenRequestValidate(request) - stats.validate = process.hrtime.bigint() - if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authContext }, opts.metricsCallback) - const query = req.query - const params = req.params - await methods.LinkNPubThroughToken({rpcName:'LinkNPubThroughToken', ctx:authContext , req: request}) - stats.handle = process.hrtime.bigint() - res.json({status: 'OK'}) - opts.metricsCallback([{ ...info, ...stats, ...authContext }]) - } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } - }) - if (!opts.allowNotImplementedMethods && !methods.GetApp) throw new Error('method: GetApp is not implemented') - app.post('/api/app/get', async (req, res) => { - const info: Types.RequestInfo = { rpcName: 'GetApp', batch: false, nostr: false, batchSize: 0} - const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } - let authCtx: Types.AuthContext = {} - try { - if (!methods.GetApp) throw new Error('method: GetApp is not implemented') - const authContext = await opts.AppAuthGuard(req.headers['authorization']) - authCtx = authContext - stats.guard = process.hrtime.bigint() - stats.validate = stats.guard - const query = req.query - const params = req.params - const response = await methods.GetApp({rpcName:'GetApp', ctx:authContext }) - stats.handle = process.hrtime.bigint() - res.json({status: 'OK', ...response}) - opts.metricsCallback([{ ...info, ...stats, ...authContext }]) - } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } - }) - if (!opts.allowNotImplementedMethods && !methods.AddAppUser) throw new Error('method: AddAppUser is not implemented') - app.post('/api/app/user/add', async (req, res) => { - const info: Types.RequestInfo = { rpcName: 'AddAppUser', batch: false, nostr: false, batchSize: 0} - const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } - let authCtx: Types.AuthContext = {} - try { - if (!methods.AddAppUser) throw new Error('method: AddAppUser is not implemented') - const authContext = await opts.AppAuthGuard(req.headers['authorization']) - authCtx = authContext - stats.guard = process.hrtime.bigint() - const request = req.body - const error = Types.AddAppUserRequestValidate(request) - stats.validate = process.hrtime.bigint() - if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authContext }, opts.metricsCallback) - const query = req.query - const params = req.params - const response = await methods.AddAppUser({rpcName:'AddAppUser', ctx:authContext , req: request}) - stats.handle = process.hrtime.bigint() - res.json({status: 'OK', ...response}) - opts.metricsCallback([{ ...info, ...stats, ...authContext }]) - } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } - }) - if (!opts.allowNotImplementedMethods && !methods.AddAppInvoice) throw new Error('method: AddAppInvoice is not implemented') - app.post('/api/app/add/invoice', async (req, res) => { - const info: Types.RequestInfo = { rpcName: 'AddAppInvoice', batch: false, nostr: false, batchSize: 0} - const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } - let authCtx: Types.AuthContext = {} - try { - if (!methods.AddAppInvoice) throw new Error('method: AddAppInvoice is not implemented') - const authContext = await opts.AppAuthGuard(req.headers['authorization']) - authCtx = authContext - stats.guard = process.hrtime.bigint() - const request = req.body - const error = Types.AddAppInvoiceRequestValidate(request) - stats.validate = process.hrtime.bigint() - if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authContext }, opts.metricsCallback) - const query = req.query - const params = req.params - const response = await methods.AddAppInvoice({rpcName:'AddAppInvoice', ctx:authContext , req: request}) - stats.handle = process.hrtime.bigint() - res.json({status: 'OK', ...response}) - opts.metricsCallback([{ ...info, ...stats, ...authContext }]) - } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } - }) - if (!opts.allowNotImplementedMethods && !methods.AddAppUserInvoice) throw new Error('method: AddAppUserInvoice is not implemented') - app.post('/api/app/user/add/invoice', async (req, res) => { - const info: Types.RequestInfo = { rpcName: 'AddAppUserInvoice', batch: false, nostr: false, batchSize: 0} - const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } - let authCtx: Types.AuthContext = {} - try { - if (!methods.AddAppUserInvoice) throw new Error('method: AddAppUserInvoice is not implemented') - const authContext = await opts.AppAuthGuard(req.headers['authorization']) - authCtx = authContext - stats.guard = process.hrtime.bigint() - const request = req.body - const error = Types.AddAppUserInvoiceRequestValidate(request) - stats.validate = process.hrtime.bigint() - if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authContext }, opts.metricsCallback) - const query = req.query - const params = req.params - const response = await methods.AddAppUserInvoice({rpcName:'AddAppUserInvoice', ctx:authContext , req: request}) - stats.handle = process.hrtime.bigint() - res.json({status: 'OK', ...response}) - opts.metricsCallback([{ ...info, ...stats, ...authContext }]) - } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } - }) - if (!opts.allowNotImplementedMethods && !methods.GetAppUser) throw new Error('method: GetAppUser is not implemented') - app.post('/api/app/user/get', async (req, res) => { - const info: Types.RequestInfo = { rpcName: 'GetAppUser', batch: false, nostr: false, batchSize: 0} - const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } - let authCtx: Types.AuthContext = {} - try { - if (!methods.GetAppUser) throw new Error('method: GetAppUser is not implemented') - const authContext = await opts.AppAuthGuard(req.headers['authorization']) - authCtx = authContext - stats.guard = process.hrtime.bigint() - const request = req.body - const error = Types.GetAppUserRequestValidate(request) - stats.validate = process.hrtime.bigint() - if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authContext }, opts.metricsCallback) - const query = req.query - const params = req.params - const response = await methods.GetAppUser({rpcName:'GetAppUser', ctx:authContext , req: request}) - stats.handle = process.hrtime.bigint() - res.json({status: 'OK', ...response}) - opts.metricsCallback([{ ...info, ...stats, ...authContext }]) - } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } - }) - if (!opts.allowNotImplementedMethods && !methods.PayAppUserInvoice) throw new Error('method: PayAppUserInvoice is not implemented') - app.post('/api/app/invoice/pay', async (req, res) => { - const info: Types.RequestInfo = { rpcName: 'PayAppUserInvoice', batch: false, nostr: false, batchSize: 0} - const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } - let authCtx: Types.AuthContext = {} - try { - if (!methods.PayAppUserInvoice) throw new Error('method: PayAppUserInvoice is not implemented') - const authContext = await opts.AppAuthGuard(req.headers['authorization']) - authCtx = authContext - stats.guard = process.hrtime.bigint() - const request = req.body - const error = Types.PayAppUserInvoiceRequestValidate(request) - stats.validate = process.hrtime.bigint() - if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authContext }, opts.metricsCallback) - const query = req.query - const params = req.params - const response = await methods.PayAppUserInvoice({rpcName:'PayAppUserInvoice', ctx:authContext , req: request}) - stats.handle = process.hrtime.bigint() - res.json({status: 'OK', ...response}) - opts.metricsCallback([{ ...info, ...stats, ...authContext }]) - } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } - }) - if (!opts.allowNotImplementedMethods && !methods.SendAppUserToAppUserPayment) throw new Error('method: SendAppUserToAppUserPayment is not implemented') - app.post('/api/app/user/internal/pay', async (req, res) => { - const info: Types.RequestInfo = { rpcName: 'SendAppUserToAppUserPayment', batch: false, nostr: false, batchSize: 0} - const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } - let authCtx: Types.AuthContext = {} - try { - if (!methods.SendAppUserToAppUserPayment) throw new Error('method: SendAppUserToAppUserPayment is not implemented') - const authContext = await opts.AppAuthGuard(req.headers['authorization']) - authCtx = authContext - stats.guard = process.hrtime.bigint() - const request = req.body - const error = Types.SendAppUserToAppUserPaymentRequestValidate(request) - stats.validate = process.hrtime.bigint() - if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authContext }, opts.metricsCallback) - const query = req.query - const params = req.params - await methods.SendAppUserToAppUserPayment({rpcName:'SendAppUserToAppUserPayment', ctx:authContext , req: request}) - stats.handle = process.hrtime.bigint() - res.json({status: 'OK'}) - opts.metricsCallback([{ ...info, ...stats, ...authContext }]) - } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } - }) - if (!opts.allowNotImplementedMethods && !methods.SendAppUserToAppPayment) throw new Error('method: SendAppUserToAppPayment is not implemented') - app.post('/api/app/internal/pay', async (req, res) => { - const info: Types.RequestInfo = { rpcName: 'SendAppUserToAppPayment', batch: false, nostr: false, batchSize: 0} - const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } - let authCtx: Types.AuthContext = {} - try { - if (!methods.SendAppUserToAppPayment) throw new Error('method: SendAppUserToAppPayment is not implemented') - const authContext = await opts.AppAuthGuard(req.headers['authorization']) - authCtx = authContext - stats.guard = process.hrtime.bigint() - const request = req.body - const error = Types.SendAppUserToAppPaymentRequestValidate(request) - stats.validate = process.hrtime.bigint() - if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authContext }, opts.metricsCallback) - const query = req.query - const params = req.params - await methods.SendAppUserToAppPayment({rpcName:'SendAppUserToAppPayment', ctx:authContext , req: request}) - stats.handle = process.hrtime.bigint() - res.json({status: 'OK'}) - opts.metricsCallback([{ ...info, ...stats, ...authContext }]) - } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } - }) - if (!opts.allowNotImplementedMethods && !methods.GetAppUserLNURLInfo) throw new Error('method: GetAppUserLNURLInfo is not implemented') - app.post('/api/app/user/lnurl/pay/info', async (req, res) => { - const info: Types.RequestInfo = { rpcName: 'GetAppUserLNURLInfo', batch: false, nostr: false, batchSize: 0} - const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } - let authCtx: Types.AuthContext = {} - try { - if (!methods.GetAppUserLNURLInfo) throw new Error('method: GetAppUserLNURLInfo is not implemented') - const authContext = await opts.AppAuthGuard(req.headers['authorization']) - authCtx = authContext - stats.guard = process.hrtime.bigint() - const request = req.body - const error = Types.GetAppUserLNURLInfoRequestValidate(request) - stats.validate = process.hrtime.bigint() - if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authContext }, opts.metricsCallback) - const query = req.query - const params = req.params - const response = await methods.GetAppUserLNURLInfo({rpcName:'GetAppUserLNURLInfo', ctx:authContext , req: request}) - stats.handle = process.hrtime.bigint() - res.json({status: 'OK', ...response}) - opts.metricsCallback([{ ...info, ...stats, ...authContext }]) - } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } - }) - if (!opts.allowNotImplementedMethods && !methods.SetMockAppUserBalance) throw new Error('method: SetMockAppUserBalance is not implemented') - app.post('/api/app/mock/user/blance/set', async (req, res) => { - const info: Types.RequestInfo = { rpcName: 'SetMockAppUserBalance', batch: false, nostr: false, batchSize: 0} - const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } - let authCtx: Types.AuthContext = {} - try { - if (!methods.SetMockAppUserBalance) throw new Error('method: SetMockAppUserBalance is not implemented') - const authContext = await opts.AppAuthGuard(req.headers['authorization']) - authCtx = authContext - stats.guard = process.hrtime.bigint() - const request = req.body - const error = Types.SetMockAppUserBalanceRequestValidate(request) - stats.validate = process.hrtime.bigint() - if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authContext }, opts.metricsCallback) - const query = req.query - const params = req.params - await methods.SetMockAppUserBalance({rpcName:'SetMockAppUserBalance', ctx:authContext , req: request}) - stats.handle = process.hrtime.bigint() - res.json({status: 'OK'}) - opts.metricsCallback([{ ...info, ...stats, ...authContext }]) - } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } - }) - if (!opts.allowNotImplementedMethods && !methods.SetMockAppBalance) throw new Error('method: SetMockAppBalance is not implemented') - app.post('/api/app/mock/blance/set', async (req, res) => { - const info: Types.RequestInfo = { rpcName: 'SetMockAppBalance', batch: false, nostr: false, batchSize: 0} - const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } - let authCtx: Types.AuthContext = {} - try { - if (!methods.SetMockAppBalance) throw new Error('method: SetMockAppBalance is not implemented') - const authContext = await opts.AppAuthGuard(req.headers['authorization']) - authCtx = authContext - stats.guard = process.hrtime.bigint() - const request = req.body - const error = Types.SetMockAppBalanceRequestValidate(request) - stats.validate = process.hrtime.bigint() - if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authContext }, opts.metricsCallback) - const query = req.query - const params = req.params - await methods.SetMockAppBalance({rpcName:'SetMockAppBalance', ctx:authContext , req: request}) - stats.handle = process.hrtime.bigint() - res.json({status: 'OK'}) - opts.metricsCallback([{ ...info, ...stats, ...authContext }]) - } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } - }) - if (!opts.allowNotImplementedMethods && !methods.RequestNPubLinkingToken) throw new Error('method: RequestNPubLinkingToken is not implemented') - app.post('/api/app/user/npub/token', async (req, res) => { - const info: Types.RequestInfo = { rpcName: 'RequestNPubLinkingToken', batch: false, nostr: false, batchSize: 0} - const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } - let authCtx: Types.AuthContext = {} - try { - if (!methods.RequestNPubLinkingToken) throw new Error('method: RequestNPubLinkingToken is not implemented') - const authContext = await opts.AppAuthGuard(req.headers['authorization']) - authCtx = authContext - stats.guard = process.hrtime.bigint() - const request = req.body - const error = Types.RequestNPubLinkingTokenRequestValidate(request) - stats.validate = process.hrtime.bigint() - if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authContext }, opts.metricsCallback) - const query = req.query - const params = req.params - const response = await methods.RequestNPubLinkingToken({rpcName:'RequestNPubLinkingToken', ctx:authContext , req: request}) - stats.handle = process.hrtime.bigint() - res.json({status: 'OK', ...response}) - opts.metricsCallback([{ ...info, ...stats, ...authContext }]) - } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } - }) - if (!opts.allowNotImplementedMethods && !methods.UserHealth) throw new Error('method: UserHealth is not implemented') - app.post('/api/user/health', async (req, res) => { - const info: Types.RequestInfo = { rpcName: 'UserHealth', batch: false, nostr: false, batchSize: 0} - const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } - let authCtx: Types.AuthContext = {} - try { - if (!methods.UserHealth) throw new Error('method: UserHealth is not implemented') - const authContext = await opts.UserAuthGuard(req.headers['authorization']) - authCtx = authContext - stats.guard = process.hrtime.bigint() - stats.validate = stats.guard - const query = req.query - const params = req.params - await methods.UserHealth({rpcName:'UserHealth', ctx:authContext }) - stats.handle = process.hrtime.bigint() - res.json({status: 'OK'}) - opts.metricsCallback([{ ...info, ...stats, ...authContext }]) - } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } - }) - if (!opts.allowNotImplementedMethods && !methods.GetUserInfo) throw new Error('method: GetUserInfo is not implemented') - app.post('/api/user/info', async (req, res) => { - const info: Types.RequestInfo = { rpcName: 'GetUserInfo', batch: false, nostr: false, batchSize: 0} - const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } - let authCtx: Types.AuthContext = {} - try { - if (!methods.GetUserInfo) throw new Error('method: GetUserInfo is not implemented') - const authContext = await opts.UserAuthGuard(req.headers['authorization']) - authCtx = authContext - stats.guard = process.hrtime.bigint() - stats.validate = stats.guard - const query = req.query - const params = req.params - const response = await methods.GetUserInfo({rpcName:'GetUserInfo', ctx:authContext }) - stats.handle = process.hrtime.bigint() - res.json({status: 'OK', ...response}) - opts.metricsCallback([{ ...info, ...stats, ...authContext }]) - } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } - }) - if (!opts.allowNotImplementedMethods && !methods.AddProduct) throw new Error('method: AddProduct is not implemented') - app.post('/api/user/product/add', async (req, res) => { - const info: Types.RequestInfo = { rpcName: 'AddProduct', batch: false, nostr: false, batchSize: 0} - const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } - let authCtx: Types.AuthContext = {} - try { - if (!methods.AddProduct) throw new Error('method: AddProduct is not implemented') - const authContext = await opts.UserAuthGuard(req.headers['authorization']) - authCtx = authContext - stats.guard = process.hrtime.bigint() - const request = req.body - const error = Types.AddProductRequestValidate(request) - stats.validate = process.hrtime.bigint() - if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authContext }, opts.metricsCallback) - const query = req.query - const params = req.params - const response = await methods.AddProduct({rpcName:'AddProduct', ctx:authContext , req: request}) - stats.handle = process.hrtime.bigint() - res.json({status: 'OK', ...response}) - opts.metricsCallback([{ ...info, ...stats, ...authContext }]) - } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } - }) - if (!opts.allowNotImplementedMethods && !methods.NewProductInvoice) throw new Error('method: NewProductInvoice is not implemented') - app.get('/api/user/product/get/invoice', async (req, res) => { - const info: Types.RequestInfo = { rpcName: 'NewProductInvoice', batch: false, nostr: false, batchSize: 0} - const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } - let authCtx: Types.AuthContext = {} - try { - if (!methods.NewProductInvoice) throw new Error('method: NewProductInvoice is not implemented') - const authContext = await opts.UserAuthGuard(req.headers['authorization']) - authCtx = authContext - stats.guard = process.hrtime.bigint() - stats.validate = stats.guard - const query = req.query - const params = req.params - const response = await methods.NewProductInvoice({rpcName:'NewProductInvoice', ctx:authContext ,query: req.query}) - stats.handle = process.hrtime.bigint() - res.json({status: 'OK', ...response}) - opts.metricsCallback([{ ...info, ...stats, ...authContext }]) - } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } - }) - if (!opts.allowNotImplementedMethods && !methods.GetUserOperations) throw new Error('method: GetUserOperations is not implemented') - app.post('/api/user/operations', async (req, res) => { - const info: Types.RequestInfo = { rpcName: 'GetUserOperations', batch: false, nostr: false, batchSize: 0} - const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } - let authCtx: Types.AuthContext = {} - try { - if (!methods.GetUserOperations) throw new Error('method: GetUserOperations is not implemented') - const authContext = await opts.UserAuthGuard(req.headers['authorization']) - authCtx = authContext - stats.guard = process.hrtime.bigint() - const request = req.body - const error = Types.GetUserOperationsRequestValidate(request) - stats.validate = process.hrtime.bigint() - if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authContext }, opts.metricsCallback) - const query = req.query - const params = req.params - const response = await methods.GetUserOperations({rpcName:'GetUserOperations', ctx:authContext , req: request}) - stats.handle = process.hrtime.bigint() - res.json({status: 'OK', ...response}) - opts.metricsCallback([{ ...info, ...stats, ...authContext }]) - } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } - }) - if (!opts.allowNotImplementedMethods && !methods.NewAddress) throw new Error('method: NewAddress is not implemented') - app.post('/api/user/chain/new', async (req, res) => { - const info: Types.RequestInfo = { rpcName: 'NewAddress', batch: false, nostr: false, batchSize: 0} - const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } - let authCtx: Types.AuthContext = {} - try { - if (!methods.NewAddress) throw new Error('method: NewAddress is not implemented') - const authContext = await opts.UserAuthGuard(req.headers['authorization']) - authCtx = authContext - stats.guard = process.hrtime.bigint() - const request = req.body - const error = Types.NewAddressRequestValidate(request) - stats.validate = process.hrtime.bigint() - if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authContext }, opts.metricsCallback) - const query = req.query - const params = req.params - const response = await methods.NewAddress({rpcName:'NewAddress', ctx:authContext , req: request}) - stats.handle = process.hrtime.bigint() - res.json({status: 'OK', ...response}) - opts.metricsCallback([{ ...info, ...stats, ...authContext }]) - } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } - }) - if (!opts.allowNotImplementedMethods && !methods.PayAddress) throw new Error('method: PayAddress is not implemented') - app.post('/api/user/chain/pay', async (req, res) => { - const info: Types.RequestInfo = { rpcName: 'PayAddress', batch: false, nostr: false, batchSize: 0} - const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } - let authCtx: Types.AuthContext = {} - try { - if (!methods.PayAddress) throw new Error('method: PayAddress is not implemented') - const authContext = await opts.UserAuthGuard(req.headers['authorization']) - authCtx = authContext - stats.guard = process.hrtime.bigint() - const request = req.body - const error = Types.PayAddressRequestValidate(request) - stats.validate = process.hrtime.bigint() - if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authContext }, opts.metricsCallback) - const query = req.query - const params = req.params - const response = await methods.PayAddress({rpcName:'PayAddress', ctx:authContext , req: request}) - stats.handle = process.hrtime.bigint() - res.json({status: 'OK', ...response}) - opts.metricsCallback([{ ...info, ...stats, ...authContext }]) - } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } - }) - if (!opts.allowNotImplementedMethods && !methods.NewInvoice) throw new Error('method: NewInvoice is not implemented') - app.post('/api/user/invoice/new', async (req, res) => { - const info: Types.RequestInfo = { rpcName: 'NewInvoice', batch: false, nostr: false, batchSize: 0} - const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } - let authCtx: Types.AuthContext = {} - try { - if (!methods.NewInvoice) throw new Error('method: NewInvoice is not implemented') - const authContext = await opts.UserAuthGuard(req.headers['authorization']) - authCtx = authContext - stats.guard = process.hrtime.bigint() - const request = req.body - const error = Types.NewInvoiceRequestValidate(request) - stats.validate = process.hrtime.bigint() - if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authContext }, opts.metricsCallback) - const query = req.query - const params = req.params - const response = await methods.NewInvoice({rpcName:'NewInvoice', ctx:authContext , req: request}) - stats.handle = process.hrtime.bigint() - res.json({status: 'OK', ...response}) - opts.metricsCallback([{ ...info, ...stats, ...authContext }]) - } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } - }) - if (!opts.allowNotImplementedMethods && !methods.DecodeInvoice) throw new Error('method: DecodeInvoice is not implemented') - app.post('/api/user/invoice/decode', async (req, res) => { - const info: Types.RequestInfo = { rpcName: 'DecodeInvoice', batch: false, nostr: false, batchSize: 0} - const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } - let authCtx: Types.AuthContext = {} - try { - if (!methods.DecodeInvoice) throw new Error('method: DecodeInvoice is not implemented') - const authContext = await opts.UserAuthGuard(req.headers['authorization']) - authCtx = authContext - stats.guard = process.hrtime.bigint() - const request = req.body - const error = Types.DecodeInvoiceRequestValidate(request) - stats.validate = process.hrtime.bigint() - if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authContext }, opts.metricsCallback) - const query = req.query - const params = req.params - const response = await methods.DecodeInvoice({rpcName:'DecodeInvoice', ctx:authContext , req: request}) - stats.handle = process.hrtime.bigint() - res.json({status: 'OK', ...response}) - opts.metricsCallback([{ ...info, ...stats, ...authContext }]) - } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } - }) - if (!opts.allowNotImplementedMethods && !methods.PayInvoice) throw new Error('method: PayInvoice is not implemented') - app.post('/api/user/invoice/pay', async (req, res) => { - const info: Types.RequestInfo = { rpcName: 'PayInvoice', batch: false, nostr: false, batchSize: 0} - const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } - let authCtx: Types.AuthContext = {} - try { - if (!methods.PayInvoice) throw new Error('method: PayInvoice is not implemented') - const authContext = await opts.UserAuthGuard(req.headers['authorization']) - authCtx = authContext - stats.guard = process.hrtime.bigint() - const request = req.body - const error = Types.PayInvoiceRequestValidate(request) - stats.validate = process.hrtime.bigint() - if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authContext }, opts.metricsCallback) - const query = req.query - const params = req.params - const response = await methods.PayInvoice({rpcName:'PayInvoice', ctx:authContext , req: request}) - stats.handle = process.hrtime.bigint() - res.json({status: 'OK', ...response}) - opts.metricsCallback([{ ...info, ...stats, ...authContext }]) - } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } - }) - if (!opts.allowNotImplementedMethods && !methods.OpenChannel) throw new Error('method: OpenChannel is not implemented') - app.post('/api/user/open/channel', async (req, res) => { - const info: Types.RequestInfo = { rpcName: 'OpenChannel', batch: false, nostr: false, batchSize: 0} - const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } - let authCtx: Types.AuthContext = {} - try { - if (!methods.OpenChannel) throw new Error('method: OpenChannel is not implemented') - const authContext = await opts.UserAuthGuard(req.headers['authorization']) - authCtx = authContext - stats.guard = process.hrtime.bigint() - const request = req.body - const error = Types.OpenChannelRequestValidate(request) - stats.validate = process.hrtime.bigint() - if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authContext }, opts.metricsCallback) - const query = req.query - const params = req.params - const response = await methods.OpenChannel({rpcName:'OpenChannel', ctx:authContext , req: request}) - stats.handle = process.hrtime.bigint() - res.json({status: 'OK', ...response}) - opts.metricsCallback([{ ...info, ...stats, ...authContext }]) - } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } - }) - if (!opts.allowNotImplementedMethods && !methods.GetLnurlWithdrawLink) throw new Error('method: GetLnurlWithdrawLink is not implemented') - app.get('/api/user/lnurl_withdraw/link', async (req, res) => { - const info: Types.RequestInfo = { rpcName: 'GetLnurlWithdrawLink', batch: false, nostr: false, batchSize: 0} - const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } - let authCtx: Types.AuthContext = {} - try { - if (!methods.GetLnurlWithdrawLink) throw new Error('method: GetLnurlWithdrawLink is not implemented') - const authContext = await opts.UserAuthGuard(req.headers['authorization']) - authCtx = authContext - stats.guard = process.hrtime.bigint() - stats.validate = stats.guard - const query = req.query - const params = req.params - const response = await methods.GetLnurlWithdrawLink({rpcName:'GetLnurlWithdrawLink', ctx:authContext }) - stats.handle = process.hrtime.bigint() - res.json({status: 'OK', ...response}) - opts.metricsCallback([{ ...info, ...stats, ...authContext }]) - } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } - }) - if (!opts.allowNotImplementedMethods && !methods.GetLnurlPayLink) throw new Error('method: GetLnurlPayLink is not implemented') - app.get('/api/user/lnurl_pay/link', async (req, res) => { - const info: Types.RequestInfo = { rpcName: 'GetLnurlPayLink', batch: false, nostr: false, batchSize: 0} - const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } - let authCtx: Types.AuthContext = {} - try { - if (!methods.GetLnurlPayLink) throw new Error('method: GetLnurlPayLink is not implemented') - const authContext = await opts.UserAuthGuard(req.headers['authorization']) - authCtx = authContext - stats.guard = process.hrtime.bigint() - stats.validate = stats.guard - const query = req.query - const params = req.params - const response = await methods.GetLnurlPayLink({rpcName:'GetLnurlPayLink', ctx:authContext }) - stats.handle = process.hrtime.bigint() - res.json({status: 'OK', ...response}) - opts.metricsCallback([{ ...info, ...stats, ...authContext }]) - } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } - }) - if (!opts.allowNotImplementedMethods && !methods.GetLNURLChannelLink) throw new Error('method: GetLNURLChannelLink is not implemented') - app.post('/api/user/lnurl_channel/url', async (req, res) => { - const info: Types.RequestInfo = { rpcName: 'GetLNURLChannelLink', batch: false, nostr: false, batchSize: 0} - const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } - let authCtx: Types.AuthContext = {} - try { - if (!methods.GetLNURLChannelLink) throw new Error('method: GetLNURLChannelLink is not implemented') - const authContext = await opts.UserAuthGuard(req.headers['authorization']) - authCtx = authContext - stats.guard = process.hrtime.bigint() - stats.validate = stats.guard - const query = req.query - const params = req.params - const response = await methods.GetLNURLChannelLink({rpcName:'GetLNURLChannelLink', ctx:authContext }) - stats.handle = process.hrtime.bigint() - res.json({status: 'OK', ...response}) - opts.metricsCallback([{ ...info, ...stats, ...authContext }]) - } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } - }) - app.post('/api/user/batch', async (req, res) => { - const info: Types.RequestInfo = { rpcName: 'BatchUser', batch: true, nostr: false, batchSize: 1 } - const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } - let authCtx: Types.AuthContext = {} - try { - const requests = req.body.requests as Types.UserMethodInputs[] - if (!Array.isArray(requests))throw new Error('invalid body, is not an array') - info.batchSize = requests.length - if (requests.length > 10) throw new Error('too many requests in the batch') - const ctx = await opts.UserAuthGuard(req.headers['authorization']) - stats.guard = process.hrtime.bigint() - stats.validate = stats.guard - authCtx = ctx - const responses = [] - const callsMetrics: Types.RequestMetric[] = [] - for (let i = 0; i < requests.length; i++) { - const operation = requests[i] - const opInfo: Types.RequestInfo = { rpcName: operation.rpcName, batch: true, nostr: false, batchSize: 0 } - const opStats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: stats.parse, guard: stats.guard, validate: 0n, handle: 0n } - try { - switch(operation.rpcName) { - case 'LinkNPubThroughToken': - if (!methods.LinkNPubThroughToken) { - throw new Error('method LinkNPubThroughToken not found' ) - } else { - const error = Types.LinkNPubThroughTokenRequestValidate(operation.req) - opStats.validate = process.hrtime.bigint() - if (error !== null) throw error - await methods.LinkNPubThroughToken({...operation, ctx}); responses.push({ status: 'OK' }) - opStats.handle = process.hrtime.bigint() - callsMetrics.push({ ...opInfo, ...opStats, ...ctx }) - } - break - case 'UserHealth': - if (!methods.UserHealth) { - throw new Error('method UserHealth not found' ) - } else { - opStats.validate = opStats.guard - await methods.UserHealth({...operation, ctx}); responses.push({ status: 'OK' }) - opStats.handle = process.hrtime.bigint() - callsMetrics.push({ ...opInfo, ...opStats, ...ctx }) - } - break - case 'GetUserInfo': - if (!methods.GetUserInfo) { - throw new Error('method GetUserInfo not found' ) - } else { - opStats.validate = opStats.guard - const res = await methods.GetUserInfo({...operation, ctx}); responses.push({ status: 'OK', ...res }) - opStats.handle = process.hrtime.bigint() - callsMetrics.push({ ...opInfo, ...opStats, ...ctx }) - } - break - case 'AddProduct': - if (!methods.AddProduct) { - throw new Error('method AddProduct not found' ) - } else { - const error = Types.AddProductRequestValidate(operation.req) - opStats.validate = process.hrtime.bigint() - if (error !== null) throw error - const res = await methods.AddProduct({...operation, ctx}); responses.push({ status: 'OK', ...res }) - opStats.handle = process.hrtime.bigint() - callsMetrics.push({ ...opInfo, ...opStats, ...ctx }) - } - break - case 'NewProductInvoice': - if (!methods.NewProductInvoice) { - throw new Error('method NewProductInvoice not found' ) - } else { - opStats.validate = opStats.guard - const res = await methods.NewProductInvoice({...operation, ctx}); responses.push({ status: 'OK', ...res }) - opStats.handle = process.hrtime.bigint() - callsMetrics.push({ ...opInfo, ...opStats, ...ctx }) - } - break - case 'GetUserOperations': - if (!methods.GetUserOperations) { - throw new Error('method GetUserOperations not found' ) - } else { - const error = Types.GetUserOperationsRequestValidate(operation.req) - opStats.validate = process.hrtime.bigint() - if (error !== null) throw error - const res = await methods.GetUserOperations({...operation, ctx}); responses.push({ status: 'OK', ...res }) - opStats.handle = process.hrtime.bigint() - callsMetrics.push({ ...opInfo, ...opStats, ...ctx }) - } - break - case 'NewAddress': - if (!methods.NewAddress) { - throw new Error('method NewAddress not found' ) - } else { - const error = Types.NewAddressRequestValidate(operation.req) - opStats.validate = process.hrtime.bigint() - if (error !== null) throw error - const res = await methods.NewAddress({...operation, ctx}); responses.push({ status: 'OK', ...res }) - opStats.handle = process.hrtime.bigint() - callsMetrics.push({ ...opInfo, ...opStats, ...ctx }) - } - break - case 'PayAddress': - if (!methods.PayAddress) { - throw new Error('method PayAddress not found' ) - } else { - const error = Types.PayAddressRequestValidate(operation.req) - opStats.validate = process.hrtime.bigint() - if (error !== null) throw error - const res = await methods.PayAddress({...operation, ctx}); responses.push({ status: 'OK', ...res }) - opStats.handle = process.hrtime.bigint() - callsMetrics.push({ ...opInfo, ...opStats, ...ctx }) - } - break - case 'NewInvoice': - if (!methods.NewInvoice) { - throw new Error('method NewInvoice not found' ) - } else { - const error = Types.NewInvoiceRequestValidate(operation.req) - opStats.validate = process.hrtime.bigint() - if (error !== null) throw error - const res = await methods.NewInvoice({...operation, ctx}); responses.push({ status: 'OK', ...res }) - opStats.handle = process.hrtime.bigint() - callsMetrics.push({ ...opInfo, ...opStats, ...ctx }) - } - break - case 'DecodeInvoice': - if (!methods.DecodeInvoice) { - throw new Error('method DecodeInvoice not found' ) - } else { - const error = Types.DecodeInvoiceRequestValidate(operation.req) - opStats.validate = process.hrtime.bigint() - if (error !== null) throw error - const res = await methods.DecodeInvoice({...operation, ctx}); responses.push({ status: 'OK', ...res }) - opStats.handle = process.hrtime.bigint() - callsMetrics.push({ ...opInfo, ...opStats, ...ctx }) - } - break - case 'PayInvoice': - if (!methods.PayInvoice) { - throw new Error('method PayInvoice not found' ) - } else { - const error = Types.PayInvoiceRequestValidate(operation.req) - opStats.validate = process.hrtime.bigint() - if (error !== null) throw error - const res = await methods.PayInvoice({...operation, ctx}); responses.push({ status: 'OK', ...res }) - opStats.handle = process.hrtime.bigint() - callsMetrics.push({ ...opInfo, ...opStats, ...ctx }) - } - break - case 'OpenChannel': - if (!methods.OpenChannel) { - throw new Error('method OpenChannel not found' ) - } else { - const error = Types.OpenChannelRequestValidate(operation.req) - opStats.validate = process.hrtime.bigint() - if (error !== null) throw error - const res = await methods.OpenChannel({...operation, ctx}); responses.push({ status: 'OK', ...res }) - opStats.handle = process.hrtime.bigint() - callsMetrics.push({ ...opInfo, ...opStats, ...ctx }) - } - break - case 'GetLnurlWithdrawLink': - if (!methods.GetLnurlWithdrawLink) { - throw new Error('method GetLnurlWithdrawLink not found' ) - } else { - opStats.validate = opStats.guard - const res = await methods.GetLnurlWithdrawLink({...operation, ctx}); responses.push({ status: 'OK', ...res }) - opStats.handle = process.hrtime.bigint() - callsMetrics.push({ ...opInfo, ...opStats, ...ctx }) - } - break - case 'GetLnurlPayLink': - if (!methods.GetLnurlPayLink) { - throw new Error('method GetLnurlPayLink not found' ) - } else { - opStats.validate = opStats.guard - const res = await methods.GetLnurlPayLink({...operation, ctx}); responses.push({ status: 'OK', ...res }) - opStats.handle = process.hrtime.bigint() - callsMetrics.push({ ...opInfo, ...opStats, ...ctx }) - } - break - case 'GetLNURLChannelLink': - if (!methods.GetLNURLChannelLink) { - throw new Error('method GetLNURLChannelLink not found' ) - } else { - opStats.validate = opStats.guard - const res = await methods.GetLNURLChannelLink({...operation, ctx}); responses.push({ status: 'OK', ...res }) - opStats.handle = process.hrtime.bigint() - callsMetrics.push({ ...opInfo, ...opStats, ...ctx }) - } - break - default: - throw new Error('unkown rpcName') - } - } catch(ex) {const e = ex as any; logger.error(e.message || e); callsMetrics.push({ ...opInfo, ...opStats, ...ctx, error: e.message }); responses.push({ status: 'ERROR', reason: e.message || e })} - } - stats.handle = process.hrtime.bigint() - res.json({ status: 'OK', responses }) - opts.metricsCallback([{ ...info, ...stats, ...ctx }, ...callsMetrics]) - } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } - }) - if (opts.staticFiles) { - app.use(express.static(opts.staticFiles)) - app.get('*', function (_, res) { res.sendFile('index.html', { root: opts.staticFiles })}) - } - var server: { close: () => void } | undefined - return { - Close: () => { if (!server) { throw new Error('tried closing server before starting') } else server.close() }, - Listen: (port: number) => { server = app.listen(port, () => logger.log('Example app listening on port ' + port)) } - } -} +// This file was autogenerated from a .proto file, DO NOT EDIT! + +import express, { Response, json, urlencoded } from 'express' +import cors from 'cors' +import * as Types from './types.js' +export type Logger = { log: (v: any) => void, error: (v: any) => void } +export type ServerOptions = { + allowCors?: true + staticFiles?: string + allowNotImplementedMethods?: true + logger?: Logger + throwErrors?: true + logMethod?: true + logBody?: true + metricsCallback: (metrics: Types.RequestMetric[]) => void + GuestAuthGuard: (authorizationHeader?: string) => Promise + UserAuthGuard: (authorizationHeader?: string) => Promise + AdminAuthGuard: (authorizationHeader?: string) => Promise + MetricsAuthGuard: (authorizationHeader?: string) => Promise + AppAuthGuard: (authorizationHeader?: string) => Promise +} +declare module 'express-serve-static-core' { interface Request { startTime?: bigint, bodySize?: number, startTimeMs: number } } +const logErrorAndReturnResponse = (error: Error, response: string, res: Response, logger: Logger, metric: Types.RequestMetric, metricsCallback: (metrics: Types.RequestMetric[]) => void) => { + logger.error(error.message || error); metricsCallback([{ ...metric, error: response }]); res.json({ status: 'ERROR', reason: response }) +} +export default (methods: Types.ServerMethods, opts: ServerOptions) => { + const logger = opts.logger || { log: console.log, error: console.error } + const app = express() + if (opts.allowCors) { + app.use(cors()) + } + app.use((req, _, next) => { req.startTime = process.hrtime.bigint(); req.startTimeMs = Date.now(); next() }) + app.use(json()) + app.use(urlencoded({ extended: true })) + if (opts.logMethod) app.use((req, _, next) => { console.log(req.method, req.path); if (opts.logBody) console.log(req.body); next() }) + if (!opts.allowNotImplementedMethods && !methods.LndGetInfo) throw new Error('method: LndGetInfo is not implemented') + app.post('/api/admin/lnd/getinfo', async (req, res) => { + const info: Types.RequestInfo = { rpcName: 'LndGetInfo', batch: false, nostr: false, batchSize: 0} + const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } + let authCtx: Types.AuthContext = {} + try { + if (!methods.LndGetInfo) throw new Error('method: LndGetInfo is not implemented') + const authContext = await opts.AdminAuthGuard(req.headers['authorization']) + authCtx = authContext + stats.guard = process.hrtime.bigint() + const request = req.body + const error = Types.LndGetInfoRequestValidate(request) + stats.validate = process.hrtime.bigint() + if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authContext }, opts.metricsCallback) + const query = req.query + const params = req.params + const response = await methods.LndGetInfo({rpcName:'LndGetInfo', ctx:authContext , req: request}) + stats.handle = process.hrtime.bigint() + res.json({status: 'OK', ...response}) + opts.metricsCallback([{ ...info, ...stats, ...authContext }]) + } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } + }) + if (!opts.allowNotImplementedMethods && !methods.AddApp) throw new Error('method: AddApp is not implemented') + app.post('/api/admin/app/add', async (req, res) => { + const info: Types.RequestInfo = { rpcName: 'AddApp', batch: false, nostr: false, batchSize: 0} + const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } + let authCtx: Types.AuthContext = {} + try { + if (!methods.AddApp) throw new Error('method: AddApp is not implemented') + const authContext = await opts.AdminAuthGuard(req.headers['authorization']) + authCtx = authContext + stats.guard = process.hrtime.bigint() + const request = req.body + const error = Types.AddAppRequestValidate(request) + stats.validate = process.hrtime.bigint() + if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authContext }, opts.metricsCallback) + const query = req.query + const params = req.params + const response = await methods.AddApp({rpcName:'AddApp', ctx:authContext , req: request}) + stats.handle = process.hrtime.bigint() + res.json({status: 'OK', ...response}) + opts.metricsCallback([{ ...info, ...stats, ...authContext }]) + } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } + }) + if (!opts.allowNotImplementedMethods && !methods.AuthApp) throw new Error('method: AuthApp is not implemented') + app.post('/api/admin/app/auth', async (req, res) => { + const info: Types.RequestInfo = { rpcName: 'AuthApp', batch: false, nostr: false, batchSize: 0} + const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } + let authCtx: Types.AuthContext = {} + try { + if (!methods.AuthApp) throw new Error('method: AuthApp is not implemented') + const authContext = await opts.AdminAuthGuard(req.headers['authorization']) + authCtx = authContext + stats.guard = process.hrtime.bigint() + const request = req.body + const error = Types.AuthAppRequestValidate(request) + stats.validate = process.hrtime.bigint() + if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authContext }, opts.metricsCallback) + const query = req.query + const params = req.params + const response = await methods.AuthApp({rpcName:'AuthApp', ctx:authContext , req: request}) + stats.handle = process.hrtime.bigint() + res.json({status: 'OK', ...response}) + opts.metricsCallback([{ ...info, ...stats, ...authContext }]) + } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } + }) + if (!opts.allowNotImplementedMethods && !methods.BanUser) throw new Error('method: BanUser is not implemented') + app.post('/api/admin/user/ban', async (req, res) => { + const info: Types.RequestInfo = { rpcName: 'BanUser', batch: false, nostr: false, batchSize: 0} + const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } + let authCtx: Types.AuthContext = {} + try { + if (!methods.BanUser) throw new Error('method: BanUser is not implemented') + const authContext = await opts.AdminAuthGuard(req.headers['authorization']) + authCtx = authContext + stats.guard = process.hrtime.bigint() + const request = req.body + const error = Types.BanUserRequestValidate(request) + stats.validate = process.hrtime.bigint() + if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authContext }, opts.metricsCallback) + const query = req.query + const params = req.params + const response = await methods.BanUser({rpcName:'BanUser', ctx:authContext , req: request}) + stats.handle = process.hrtime.bigint() + res.json({status: 'OK', ...response}) + opts.metricsCallback([{ ...info, ...stats, ...authContext }]) + } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } + }) + if (!opts.allowNotImplementedMethods && !methods.GetUsageMetrics) throw new Error('method: GetUsageMetrics is not implemented') + app.post('/api/reports/usage', async (req, res) => { + const info: Types.RequestInfo = { rpcName: 'GetUsageMetrics', batch: false, nostr: false, batchSize: 0} + const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } + let authCtx: Types.AuthContext = {} + try { + if (!methods.GetUsageMetrics) throw new Error('method: GetUsageMetrics is not implemented') + const authContext = await opts.MetricsAuthGuard(req.headers['authorization']) + authCtx = authContext + stats.guard = process.hrtime.bigint() + stats.validate = stats.guard + const query = req.query + const params = req.params + const response = await methods.GetUsageMetrics({rpcName:'GetUsageMetrics', ctx:authContext }) + stats.handle = process.hrtime.bigint() + res.json({status: 'OK', ...response}) + opts.metricsCallback([{ ...info, ...stats, ...authContext }]) + } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } + }) + if (!opts.allowNotImplementedMethods && !methods.GetAppsMetrics) throw new Error('method: GetAppsMetrics is not implemented') + app.post('/api/reports/apps', async (req, res) => { + const info: Types.RequestInfo = { rpcName: 'GetAppsMetrics', batch: false, nostr: false, batchSize: 0} + const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } + let authCtx: Types.AuthContext = {} + try { + if (!methods.GetAppsMetrics) throw new Error('method: GetAppsMetrics is not implemented') + const authContext = await opts.MetricsAuthGuard(req.headers['authorization']) + authCtx = authContext + stats.guard = process.hrtime.bigint() + const request = req.body + const error = Types.AppsMetricsRequestValidate(request) + stats.validate = process.hrtime.bigint() + if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authContext }, opts.metricsCallback) + const query = req.query + const params = req.params + const response = await methods.GetAppsMetrics({rpcName:'GetAppsMetrics', ctx:authContext , req: request}) + stats.handle = process.hrtime.bigint() + res.json({status: 'OK', ...response}) + opts.metricsCallback([{ ...info, ...stats, ...authContext }]) + } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } + }) + if (!opts.allowNotImplementedMethods && !methods.GetLndMetrics) throw new Error('method: GetLndMetrics is not implemented') + app.post('/api/reports/lnd', async (req, res) => { + const info: Types.RequestInfo = { rpcName: 'GetLndMetrics', batch: false, nostr: false, batchSize: 0} + const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } + let authCtx: Types.AuthContext = {} + try { + if (!methods.GetLndMetrics) throw new Error('method: GetLndMetrics is not implemented') + const authContext = await opts.MetricsAuthGuard(req.headers['authorization']) + authCtx = authContext + stats.guard = process.hrtime.bigint() + const request = req.body + const error = Types.LndMetricsRequestValidate(request) + stats.validate = process.hrtime.bigint() + if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authContext }, opts.metricsCallback) + const query = req.query + const params = req.params + const response = await methods.GetLndMetrics({rpcName:'GetLndMetrics', ctx:authContext , req: request}) + stats.handle = process.hrtime.bigint() + res.json({status: 'OK', ...response}) + opts.metricsCallback([{ ...info, ...stats, ...authContext }]) + } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } + }) + if (!opts.allowNotImplementedMethods && !methods.Health) throw new Error('method: Health is not implemented') + app.get('/api/health', async (req, res) => { + const info: Types.RequestInfo = { rpcName: 'Health', batch: false, nostr: false, batchSize: 0} + const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } + let authCtx: Types.AuthContext = {} + try { + if (!methods.Health) throw new Error('method: Health is not implemented') + const authContext = await opts.GuestAuthGuard(req.headers['authorization']) + authCtx = authContext + stats.guard = process.hrtime.bigint() + stats.validate = stats.guard + const query = req.query + const params = req.params + await methods.Health({rpcName:'Health', ctx:authContext }) + stats.handle = process.hrtime.bigint() + res.json({status: 'OK'}) + opts.metricsCallback([{ ...info, ...stats, ...authContext }]) + } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } + }) + if (!opts.allowNotImplementedMethods && !methods.EncryptionExchange) throw new Error('method: EncryptionExchange is not implemented') + app.post('/api/encryption/exchange', async (req, res) => { + const info: Types.RequestInfo = { rpcName: 'EncryptionExchange', batch: false, nostr: false, batchSize: 0} + const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } + let authCtx: Types.AuthContext = {} + try { + if (!methods.EncryptionExchange) throw new Error('method: EncryptionExchange is not implemented') + const authContext = await opts.GuestAuthGuard(req.headers['authorization']) + authCtx = authContext + stats.guard = process.hrtime.bigint() + const request = req.body + const error = Types.EncryptionExchangeRequestValidate(request) + stats.validate = process.hrtime.bigint() + if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authContext }, opts.metricsCallback) + const query = req.query + const params = req.params + await methods.EncryptionExchange({rpcName:'EncryptionExchange', ctx:authContext , req: request}) + stats.handle = process.hrtime.bigint() + res.json({status: 'OK'}) + opts.metricsCallback([{ ...info, ...stats, ...authContext }]) + } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } + }) + if (!opts.allowNotImplementedMethods && !methods.SetMockInvoiceAsPaid) throw new Error('method: SetMockInvoiceAsPaid is not implemented') + app.post('/api/lnd/mock/invoice/paid', async (req, res) => { + const info: Types.RequestInfo = { rpcName: 'SetMockInvoiceAsPaid', batch: false, nostr: false, batchSize: 0} + const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } + let authCtx: Types.AuthContext = {} + try { + if (!methods.SetMockInvoiceAsPaid) throw new Error('method: SetMockInvoiceAsPaid is not implemented') + const authContext = await opts.GuestAuthGuard(req.headers['authorization']) + authCtx = authContext + stats.guard = process.hrtime.bigint() + const request = req.body + const error = Types.SetMockInvoiceAsPaidRequestValidate(request) + stats.validate = process.hrtime.bigint() + if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authContext }, opts.metricsCallback) + const query = req.query + const params = req.params + await methods.SetMockInvoiceAsPaid({rpcName:'SetMockInvoiceAsPaid', ctx:authContext , req: request}) + stats.handle = process.hrtime.bigint() + res.json({status: 'OK'}) + opts.metricsCallback([{ ...info, ...stats, ...authContext }]) + } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } + }) + if (!opts.allowNotImplementedMethods && !methods.GetLnurlWithdrawInfo) throw new Error('method: GetLnurlWithdrawInfo is not implemented') + app.get('/api/guest/lnurl_withdraw/info', async (req, res) => { + const info: Types.RequestInfo = { rpcName: 'GetLnurlWithdrawInfo', batch: false, nostr: false, batchSize: 0} + const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } + let authCtx: Types.AuthContext = {} + try { + if (!methods.GetLnurlWithdrawInfo) throw new Error('method: GetLnurlWithdrawInfo is not implemented') + const authContext = await opts.GuestAuthGuard(req.headers['authorization']) + authCtx = authContext + stats.guard = process.hrtime.bigint() + stats.validate = stats.guard + const query = req.query + const params = req.params + const response = await methods.GetLnurlWithdrawInfo({rpcName:'GetLnurlWithdrawInfo', ctx:authContext ,query: req.query}) + stats.handle = process.hrtime.bigint() + res.json({status: 'OK', ...response}) + opts.metricsCallback([{ ...info, ...stats, ...authContext }]) + } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } + }) + if (!opts.allowNotImplementedMethods && !methods.HandleLnurlWithdraw) throw new Error('method: HandleLnurlWithdraw is not implemented') + app.get('/api/guest/lnurl_withdraw/handle', async (req, res) => { + const info: Types.RequestInfo = { rpcName: 'HandleLnurlWithdraw', batch: false, nostr: false, batchSize: 0} + const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } + let authCtx: Types.AuthContext = {} + try { + if (!methods.HandleLnurlWithdraw) throw new Error('method: HandleLnurlWithdraw is not implemented') + const authContext = await opts.GuestAuthGuard(req.headers['authorization']) + authCtx = authContext + stats.guard = process.hrtime.bigint() + stats.validate = stats.guard + const query = req.query + const params = req.params + await methods.HandleLnurlWithdraw({rpcName:'HandleLnurlWithdraw', ctx:authContext ,query: req.query}) + stats.handle = process.hrtime.bigint() + res.json({status: 'OK'}) + opts.metricsCallback([{ ...info, ...stats, ...authContext }]) + } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } + }) + if (!opts.allowNotImplementedMethods && !methods.GetLnurlPayInfo) throw new Error('method: GetLnurlPayInfo is not implemented') + app.get('/api/guest/lnurl_pay/info', async (req, res) => { + const info: Types.RequestInfo = { rpcName: 'GetLnurlPayInfo', batch: false, nostr: false, batchSize: 0} + const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } + let authCtx: Types.AuthContext = {} + try { + if (!methods.GetLnurlPayInfo) throw new Error('method: GetLnurlPayInfo is not implemented') + const authContext = await opts.GuestAuthGuard(req.headers['authorization']) + authCtx = authContext + stats.guard = process.hrtime.bigint() + stats.validate = stats.guard + const query = req.query + const params = req.params + const response = await methods.GetLnurlPayInfo({rpcName:'GetLnurlPayInfo', ctx:authContext ,query: req.query}) + stats.handle = process.hrtime.bigint() + res.json({status: 'OK', ...response}) + opts.metricsCallback([{ ...info, ...stats, ...authContext }]) + } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } + }) + if (!opts.allowNotImplementedMethods && !methods.HandleLnurlPay) throw new Error('method: HandleLnurlPay is not implemented') + app.get('/api/guest/lnurl_pay/handle', async (req, res) => { + const info: Types.RequestInfo = { rpcName: 'HandleLnurlPay', batch: false, nostr: false, batchSize: 0} + const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } + let authCtx: Types.AuthContext = {} + try { + if (!methods.HandleLnurlPay) throw new Error('method: HandleLnurlPay is not implemented') + const authContext = await opts.GuestAuthGuard(req.headers['authorization']) + authCtx = authContext + stats.guard = process.hrtime.bigint() + stats.validate = stats.guard + const query = req.query + const params = req.params + const response = await methods.HandleLnurlPay({rpcName:'HandleLnurlPay', ctx:authContext ,query: req.query}) + stats.handle = process.hrtime.bigint() + res.json({status: 'OK', ...response}) + opts.metricsCallback([{ ...info, ...stats, ...authContext }]) + } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } + }) + if (!opts.allowNotImplementedMethods && !methods.HandleLnurlAddress) throw new Error('method: HandleLnurlAddress is not implemented') + app.get('/.well-known/lnurlp/:address_name', async (req, res) => { + const info: Types.RequestInfo = { rpcName: 'HandleLnurlAddress', batch: false, nostr: false, batchSize: 0} + const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } + let authCtx: Types.AuthContext = {} + try { + if (!methods.HandleLnurlAddress) throw new Error('method: HandleLnurlAddress is not implemented') + const authContext = await opts.GuestAuthGuard(req.headers['authorization']) + authCtx = authContext + stats.guard = process.hrtime.bigint() + stats.validate = stats.guard + const query = req.query + const params = req.params + const response = await methods.HandleLnurlAddress({rpcName:'HandleLnurlAddress', ctx:authContext ,params: req.params}) + stats.handle = process.hrtime.bigint() + res.json({status: 'OK', ...response}) + opts.metricsCallback([{ ...info, ...stats, ...authContext }]) + } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } + }) + if (!opts.allowNotImplementedMethods && !methods.LinkNPubThroughToken) throw new Error('method: LinkNPubThroughToken is not implemented') + app.post('/api/guest/npub/link', async (req, res) => { + const info: Types.RequestInfo = { rpcName: 'LinkNPubThroughToken', batch: false, nostr: false, batchSize: 0} + const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } + let authCtx: Types.AuthContext = {} + try { + if (!methods.LinkNPubThroughToken) throw new Error('method: LinkNPubThroughToken is not implemented') + const authContext = await opts.UserAuthGuard(req.headers['authorization']) + authCtx = authContext + stats.guard = process.hrtime.bigint() + const request = req.body + const error = Types.LinkNPubThroughTokenRequestValidate(request) + stats.validate = process.hrtime.bigint() + if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authContext }, opts.metricsCallback) + const query = req.query + const params = req.params + await methods.LinkNPubThroughToken({rpcName:'LinkNPubThroughToken', ctx:authContext , req: request}) + stats.handle = process.hrtime.bigint() + res.json({status: 'OK'}) + opts.metricsCallback([{ ...info, ...stats, ...authContext }]) + } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } + }) + if (!opts.allowNotImplementedMethods && !methods.EnrollAdminToken) throw new Error('method: EnrollAdminToken is not implemented') + app.post('/api/guest/npub/enroll/admin', async (req, res) => { + const info: Types.RequestInfo = { rpcName: 'EnrollAdminToken', batch: false, nostr: false, batchSize: 0} + const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } + let authCtx: Types.AuthContext = {} + try { + if (!methods.EnrollAdminToken) throw new Error('method: EnrollAdminToken is not implemented') + const authContext = await opts.UserAuthGuard(req.headers['authorization']) + authCtx = authContext + stats.guard = process.hrtime.bigint() + const request = req.body + const error = Types.EnrollAdminTokenRequestValidate(request) + stats.validate = process.hrtime.bigint() + if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authContext }, opts.metricsCallback) + const query = req.query + const params = req.params + await methods.EnrollAdminToken({rpcName:'EnrollAdminToken', ctx:authContext , req: request}) + stats.handle = process.hrtime.bigint() + res.json({status: 'OK'}) + opts.metricsCallback([{ ...info, ...stats, ...authContext }]) + } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } + }) + if (!opts.allowNotImplementedMethods && !methods.GetApp) throw new Error('method: GetApp is not implemented') + app.post('/api/app/get', async (req, res) => { + const info: Types.RequestInfo = { rpcName: 'GetApp', batch: false, nostr: false, batchSize: 0} + const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } + let authCtx: Types.AuthContext = {} + try { + if (!methods.GetApp) throw new Error('method: GetApp is not implemented') + const authContext = await opts.AppAuthGuard(req.headers['authorization']) + authCtx = authContext + stats.guard = process.hrtime.bigint() + stats.validate = stats.guard + const query = req.query + const params = req.params + const response = await methods.GetApp({rpcName:'GetApp', ctx:authContext }) + stats.handle = process.hrtime.bigint() + res.json({status: 'OK', ...response}) + opts.metricsCallback([{ ...info, ...stats, ...authContext }]) + } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } + }) + if (!opts.allowNotImplementedMethods && !methods.AddAppUser) throw new Error('method: AddAppUser is not implemented') + app.post('/api/app/user/add', async (req, res) => { + const info: Types.RequestInfo = { rpcName: 'AddAppUser', batch: false, nostr: false, batchSize: 0} + const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } + let authCtx: Types.AuthContext = {} + try { + if (!methods.AddAppUser) throw new Error('method: AddAppUser is not implemented') + const authContext = await opts.AppAuthGuard(req.headers['authorization']) + authCtx = authContext + stats.guard = process.hrtime.bigint() + const request = req.body + const error = Types.AddAppUserRequestValidate(request) + stats.validate = process.hrtime.bigint() + if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authContext }, opts.metricsCallback) + const query = req.query + const params = req.params + const response = await methods.AddAppUser({rpcName:'AddAppUser', ctx:authContext , req: request}) + stats.handle = process.hrtime.bigint() + res.json({status: 'OK', ...response}) + opts.metricsCallback([{ ...info, ...stats, ...authContext }]) + } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } + }) + if (!opts.allowNotImplementedMethods && !methods.AddAppInvoice) throw new Error('method: AddAppInvoice is not implemented') + app.post('/api/app/add/invoice', async (req, res) => { + const info: Types.RequestInfo = { rpcName: 'AddAppInvoice', batch: false, nostr: false, batchSize: 0} + const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } + let authCtx: Types.AuthContext = {} + try { + if (!methods.AddAppInvoice) throw new Error('method: AddAppInvoice is not implemented') + const authContext = await opts.AppAuthGuard(req.headers['authorization']) + authCtx = authContext + stats.guard = process.hrtime.bigint() + const request = req.body + const error = Types.AddAppInvoiceRequestValidate(request) + stats.validate = process.hrtime.bigint() + if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authContext }, opts.metricsCallback) + const query = req.query + const params = req.params + const response = await methods.AddAppInvoice({rpcName:'AddAppInvoice', ctx:authContext , req: request}) + stats.handle = process.hrtime.bigint() + res.json({status: 'OK', ...response}) + opts.metricsCallback([{ ...info, ...stats, ...authContext }]) + } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } + }) + if (!opts.allowNotImplementedMethods && !methods.AddAppUserInvoice) throw new Error('method: AddAppUserInvoice is not implemented') + app.post('/api/app/user/add/invoice', async (req, res) => { + const info: Types.RequestInfo = { rpcName: 'AddAppUserInvoice', batch: false, nostr: false, batchSize: 0} + const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } + let authCtx: Types.AuthContext = {} + try { + if (!methods.AddAppUserInvoice) throw new Error('method: AddAppUserInvoice is not implemented') + const authContext = await opts.AppAuthGuard(req.headers['authorization']) + authCtx = authContext + stats.guard = process.hrtime.bigint() + const request = req.body + const error = Types.AddAppUserInvoiceRequestValidate(request) + stats.validate = process.hrtime.bigint() + if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authContext }, opts.metricsCallback) + const query = req.query + const params = req.params + const response = await methods.AddAppUserInvoice({rpcName:'AddAppUserInvoice', ctx:authContext , req: request}) + stats.handle = process.hrtime.bigint() + res.json({status: 'OK', ...response}) + opts.metricsCallback([{ ...info, ...stats, ...authContext }]) + } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } + }) + if (!opts.allowNotImplementedMethods && !methods.GetAppUser) throw new Error('method: GetAppUser is not implemented') + app.post('/api/app/user/get', async (req, res) => { + const info: Types.RequestInfo = { rpcName: 'GetAppUser', batch: false, nostr: false, batchSize: 0} + const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } + let authCtx: Types.AuthContext = {} + try { + if (!methods.GetAppUser) throw new Error('method: GetAppUser is not implemented') + const authContext = await opts.AppAuthGuard(req.headers['authorization']) + authCtx = authContext + stats.guard = process.hrtime.bigint() + const request = req.body + const error = Types.GetAppUserRequestValidate(request) + stats.validate = process.hrtime.bigint() + if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authContext }, opts.metricsCallback) + const query = req.query + const params = req.params + const response = await methods.GetAppUser({rpcName:'GetAppUser', ctx:authContext , req: request}) + stats.handle = process.hrtime.bigint() + res.json({status: 'OK', ...response}) + opts.metricsCallback([{ ...info, ...stats, ...authContext }]) + } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } + }) + if (!opts.allowNotImplementedMethods && !methods.PayAppUserInvoice) throw new Error('method: PayAppUserInvoice is not implemented') + app.post('/api/app/invoice/pay', async (req, res) => { + const info: Types.RequestInfo = { rpcName: 'PayAppUserInvoice', batch: false, nostr: false, batchSize: 0} + const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } + let authCtx: Types.AuthContext = {} + try { + if (!methods.PayAppUserInvoice) throw new Error('method: PayAppUserInvoice is not implemented') + const authContext = await opts.AppAuthGuard(req.headers['authorization']) + authCtx = authContext + stats.guard = process.hrtime.bigint() + const request = req.body + const error = Types.PayAppUserInvoiceRequestValidate(request) + stats.validate = process.hrtime.bigint() + if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authContext }, opts.metricsCallback) + const query = req.query + const params = req.params + const response = await methods.PayAppUserInvoice({rpcName:'PayAppUserInvoice', ctx:authContext , req: request}) + stats.handle = process.hrtime.bigint() + res.json({status: 'OK', ...response}) + opts.metricsCallback([{ ...info, ...stats, ...authContext }]) + } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } + }) + if (!opts.allowNotImplementedMethods && !methods.SendAppUserToAppUserPayment) throw new Error('method: SendAppUserToAppUserPayment is not implemented') + app.post('/api/app/user/internal/pay', async (req, res) => { + const info: Types.RequestInfo = { rpcName: 'SendAppUserToAppUserPayment', batch: false, nostr: false, batchSize: 0} + const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } + let authCtx: Types.AuthContext = {} + try { + if (!methods.SendAppUserToAppUserPayment) throw new Error('method: SendAppUserToAppUserPayment is not implemented') + const authContext = await opts.AppAuthGuard(req.headers['authorization']) + authCtx = authContext + stats.guard = process.hrtime.bigint() + const request = req.body + const error = Types.SendAppUserToAppUserPaymentRequestValidate(request) + stats.validate = process.hrtime.bigint() + if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authContext }, opts.metricsCallback) + const query = req.query + const params = req.params + await methods.SendAppUserToAppUserPayment({rpcName:'SendAppUserToAppUserPayment', ctx:authContext , req: request}) + stats.handle = process.hrtime.bigint() + res.json({status: 'OK'}) + opts.metricsCallback([{ ...info, ...stats, ...authContext }]) + } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } + }) + if (!opts.allowNotImplementedMethods && !methods.SendAppUserToAppPayment) throw new Error('method: SendAppUserToAppPayment is not implemented') + app.post('/api/app/internal/pay', async (req, res) => { + const info: Types.RequestInfo = { rpcName: 'SendAppUserToAppPayment', batch: false, nostr: false, batchSize: 0} + const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } + let authCtx: Types.AuthContext = {} + try { + if (!methods.SendAppUserToAppPayment) throw new Error('method: SendAppUserToAppPayment is not implemented') + const authContext = await opts.AppAuthGuard(req.headers['authorization']) + authCtx = authContext + stats.guard = process.hrtime.bigint() + const request = req.body + const error = Types.SendAppUserToAppPaymentRequestValidate(request) + stats.validate = process.hrtime.bigint() + if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authContext }, opts.metricsCallback) + const query = req.query + const params = req.params + await methods.SendAppUserToAppPayment({rpcName:'SendAppUserToAppPayment', ctx:authContext , req: request}) + stats.handle = process.hrtime.bigint() + res.json({status: 'OK'}) + opts.metricsCallback([{ ...info, ...stats, ...authContext }]) + } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } + }) + if (!opts.allowNotImplementedMethods && !methods.GetAppUserLNURLInfo) throw new Error('method: GetAppUserLNURLInfo is not implemented') + app.post('/api/app/user/lnurl/pay/info', async (req, res) => { + const info: Types.RequestInfo = { rpcName: 'GetAppUserLNURLInfo', batch: false, nostr: false, batchSize: 0} + const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } + let authCtx: Types.AuthContext = {} + try { + if (!methods.GetAppUserLNURLInfo) throw new Error('method: GetAppUserLNURLInfo is not implemented') + const authContext = await opts.AppAuthGuard(req.headers['authorization']) + authCtx = authContext + stats.guard = process.hrtime.bigint() + const request = req.body + const error = Types.GetAppUserLNURLInfoRequestValidate(request) + stats.validate = process.hrtime.bigint() + if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authContext }, opts.metricsCallback) + const query = req.query + const params = req.params + const response = await methods.GetAppUserLNURLInfo({rpcName:'GetAppUserLNURLInfo', ctx:authContext , req: request}) + stats.handle = process.hrtime.bigint() + res.json({status: 'OK', ...response}) + opts.metricsCallback([{ ...info, ...stats, ...authContext }]) + } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } + }) + if (!opts.allowNotImplementedMethods && !methods.SetMockAppUserBalance) throw new Error('method: SetMockAppUserBalance is not implemented') + app.post('/api/app/mock/user/blance/set', async (req, res) => { + const info: Types.RequestInfo = { rpcName: 'SetMockAppUserBalance', batch: false, nostr: false, batchSize: 0} + const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } + let authCtx: Types.AuthContext = {} + try { + if (!methods.SetMockAppUserBalance) throw new Error('method: SetMockAppUserBalance is not implemented') + const authContext = await opts.AppAuthGuard(req.headers['authorization']) + authCtx = authContext + stats.guard = process.hrtime.bigint() + const request = req.body + const error = Types.SetMockAppUserBalanceRequestValidate(request) + stats.validate = process.hrtime.bigint() + if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authContext }, opts.metricsCallback) + const query = req.query + const params = req.params + await methods.SetMockAppUserBalance({rpcName:'SetMockAppUserBalance', ctx:authContext , req: request}) + stats.handle = process.hrtime.bigint() + res.json({status: 'OK'}) + opts.metricsCallback([{ ...info, ...stats, ...authContext }]) + } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } + }) + if (!opts.allowNotImplementedMethods && !methods.SetMockAppBalance) throw new Error('method: SetMockAppBalance is not implemented') + app.post('/api/app/mock/blance/set', async (req, res) => { + const info: Types.RequestInfo = { rpcName: 'SetMockAppBalance', batch: false, nostr: false, batchSize: 0} + const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } + let authCtx: Types.AuthContext = {} + try { + if (!methods.SetMockAppBalance) throw new Error('method: SetMockAppBalance is not implemented') + const authContext = await opts.AppAuthGuard(req.headers['authorization']) + authCtx = authContext + stats.guard = process.hrtime.bigint() + const request = req.body + const error = Types.SetMockAppBalanceRequestValidate(request) + stats.validate = process.hrtime.bigint() + if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authContext }, opts.metricsCallback) + const query = req.query + const params = req.params + await methods.SetMockAppBalance({rpcName:'SetMockAppBalance', ctx:authContext , req: request}) + stats.handle = process.hrtime.bigint() + res.json({status: 'OK'}) + opts.metricsCallback([{ ...info, ...stats, ...authContext }]) + } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } + }) + if (!opts.allowNotImplementedMethods && !methods.RequestNPubLinkingToken) throw new Error('method: RequestNPubLinkingToken is not implemented') + app.post('/api/app/user/npub/token', async (req, res) => { + const info: Types.RequestInfo = { rpcName: 'RequestNPubLinkingToken', batch: false, nostr: false, batchSize: 0} + const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } + let authCtx: Types.AuthContext = {} + try { + if (!methods.RequestNPubLinkingToken) throw new Error('method: RequestNPubLinkingToken is not implemented') + const authContext = await opts.AppAuthGuard(req.headers['authorization']) + authCtx = authContext + stats.guard = process.hrtime.bigint() + const request = req.body + const error = Types.RequestNPubLinkingTokenRequestValidate(request) + stats.validate = process.hrtime.bigint() + if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authContext }, opts.metricsCallback) + const query = req.query + const params = req.params + const response = await methods.RequestNPubLinkingToken({rpcName:'RequestNPubLinkingToken', ctx:authContext , req: request}) + stats.handle = process.hrtime.bigint() + res.json({status: 'OK', ...response}) + opts.metricsCallback([{ ...info, ...stats, ...authContext }]) + } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } + }) + if (!opts.allowNotImplementedMethods && !methods.UserHealth) throw new Error('method: UserHealth is not implemented') + app.post('/api/user/health', async (req, res) => { + const info: Types.RequestInfo = { rpcName: 'UserHealth', batch: false, nostr: false, batchSize: 0} + const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } + let authCtx: Types.AuthContext = {} + try { + if (!methods.UserHealth) throw new Error('method: UserHealth is not implemented') + const authContext = await opts.UserAuthGuard(req.headers['authorization']) + authCtx = authContext + stats.guard = process.hrtime.bigint() + stats.validate = stats.guard + const query = req.query + const params = req.params + await methods.UserHealth({rpcName:'UserHealth', ctx:authContext }) + stats.handle = process.hrtime.bigint() + res.json({status: 'OK'}) + opts.metricsCallback([{ ...info, ...stats, ...authContext }]) + } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } + }) + if (!opts.allowNotImplementedMethods && !methods.GetUserInfo) throw new Error('method: GetUserInfo is not implemented') + app.post('/api/user/info', async (req, res) => { + const info: Types.RequestInfo = { rpcName: 'GetUserInfo', batch: false, nostr: false, batchSize: 0} + const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } + let authCtx: Types.AuthContext = {} + try { + if (!methods.GetUserInfo) throw new Error('method: GetUserInfo is not implemented') + const authContext = await opts.UserAuthGuard(req.headers['authorization']) + authCtx = authContext + stats.guard = process.hrtime.bigint() + stats.validate = stats.guard + const query = req.query + const params = req.params + const response = await methods.GetUserInfo({rpcName:'GetUserInfo', ctx:authContext }) + stats.handle = process.hrtime.bigint() + res.json({status: 'OK', ...response}) + opts.metricsCallback([{ ...info, ...stats, ...authContext }]) + } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } + }) + if (!opts.allowNotImplementedMethods && !methods.AddProduct) throw new Error('method: AddProduct is not implemented') + app.post('/api/user/product/add', async (req, res) => { + const info: Types.RequestInfo = { rpcName: 'AddProduct', batch: false, nostr: false, batchSize: 0} + const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } + let authCtx: Types.AuthContext = {} + try { + if (!methods.AddProduct) throw new Error('method: AddProduct is not implemented') + const authContext = await opts.UserAuthGuard(req.headers['authorization']) + authCtx = authContext + stats.guard = process.hrtime.bigint() + const request = req.body + const error = Types.AddProductRequestValidate(request) + stats.validate = process.hrtime.bigint() + if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authContext }, opts.metricsCallback) + const query = req.query + const params = req.params + const response = await methods.AddProduct({rpcName:'AddProduct', ctx:authContext , req: request}) + stats.handle = process.hrtime.bigint() + res.json({status: 'OK', ...response}) + opts.metricsCallback([{ ...info, ...stats, ...authContext }]) + } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } + }) + if (!opts.allowNotImplementedMethods && !methods.NewProductInvoice) throw new Error('method: NewProductInvoice is not implemented') + app.get('/api/user/product/get/invoice', async (req, res) => { + const info: Types.RequestInfo = { rpcName: 'NewProductInvoice', batch: false, nostr: false, batchSize: 0} + const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } + let authCtx: Types.AuthContext = {} + try { + if (!methods.NewProductInvoice) throw new Error('method: NewProductInvoice is not implemented') + const authContext = await opts.UserAuthGuard(req.headers['authorization']) + authCtx = authContext + stats.guard = process.hrtime.bigint() + stats.validate = stats.guard + const query = req.query + const params = req.params + const response = await methods.NewProductInvoice({rpcName:'NewProductInvoice', ctx:authContext ,query: req.query}) + stats.handle = process.hrtime.bigint() + res.json({status: 'OK', ...response}) + opts.metricsCallback([{ ...info, ...stats, ...authContext }]) + } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } + }) + if (!opts.allowNotImplementedMethods && !methods.GetUserOperations) throw new Error('method: GetUserOperations is not implemented') + app.post('/api/user/operations', async (req, res) => { + const info: Types.RequestInfo = { rpcName: 'GetUserOperations', batch: false, nostr: false, batchSize: 0} + const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } + let authCtx: Types.AuthContext = {} + try { + if (!methods.GetUserOperations) throw new Error('method: GetUserOperations is not implemented') + const authContext = await opts.UserAuthGuard(req.headers['authorization']) + authCtx = authContext + stats.guard = process.hrtime.bigint() + const request = req.body + const error = Types.GetUserOperationsRequestValidate(request) + stats.validate = process.hrtime.bigint() + if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authContext }, opts.metricsCallback) + const query = req.query + const params = req.params + const response = await methods.GetUserOperations({rpcName:'GetUserOperations', ctx:authContext , req: request}) + stats.handle = process.hrtime.bigint() + res.json({status: 'OK', ...response}) + opts.metricsCallback([{ ...info, ...stats, ...authContext }]) + } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } + }) + if (!opts.allowNotImplementedMethods && !methods.NewAddress) throw new Error('method: NewAddress is not implemented') + app.post('/api/user/chain/new', async (req, res) => { + const info: Types.RequestInfo = { rpcName: 'NewAddress', batch: false, nostr: false, batchSize: 0} + const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } + let authCtx: Types.AuthContext = {} + try { + if (!methods.NewAddress) throw new Error('method: NewAddress is not implemented') + const authContext = await opts.UserAuthGuard(req.headers['authorization']) + authCtx = authContext + stats.guard = process.hrtime.bigint() + const request = req.body + const error = Types.NewAddressRequestValidate(request) + stats.validate = process.hrtime.bigint() + if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authContext }, opts.metricsCallback) + const query = req.query + const params = req.params + const response = await methods.NewAddress({rpcName:'NewAddress', ctx:authContext , req: request}) + stats.handle = process.hrtime.bigint() + res.json({status: 'OK', ...response}) + opts.metricsCallback([{ ...info, ...stats, ...authContext }]) + } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } + }) + if (!opts.allowNotImplementedMethods && !methods.PayAddress) throw new Error('method: PayAddress is not implemented') + app.post('/api/user/chain/pay', async (req, res) => { + const info: Types.RequestInfo = { rpcName: 'PayAddress', batch: false, nostr: false, batchSize: 0} + const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } + let authCtx: Types.AuthContext = {} + try { + if (!methods.PayAddress) throw new Error('method: PayAddress is not implemented') + const authContext = await opts.UserAuthGuard(req.headers['authorization']) + authCtx = authContext + stats.guard = process.hrtime.bigint() + const request = req.body + const error = Types.PayAddressRequestValidate(request) + stats.validate = process.hrtime.bigint() + if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authContext }, opts.metricsCallback) + const query = req.query + const params = req.params + const response = await methods.PayAddress({rpcName:'PayAddress', ctx:authContext , req: request}) + stats.handle = process.hrtime.bigint() + res.json({status: 'OK', ...response}) + opts.metricsCallback([{ ...info, ...stats, ...authContext }]) + } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } + }) + if (!opts.allowNotImplementedMethods && !methods.NewInvoice) throw new Error('method: NewInvoice is not implemented') + app.post('/api/user/invoice/new', async (req, res) => { + const info: Types.RequestInfo = { rpcName: 'NewInvoice', batch: false, nostr: false, batchSize: 0} + const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } + let authCtx: Types.AuthContext = {} + try { + if (!methods.NewInvoice) throw new Error('method: NewInvoice is not implemented') + const authContext = await opts.UserAuthGuard(req.headers['authorization']) + authCtx = authContext + stats.guard = process.hrtime.bigint() + const request = req.body + const error = Types.NewInvoiceRequestValidate(request) + stats.validate = process.hrtime.bigint() + if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authContext }, opts.metricsCallback) + const query = req.query + const params = req.params + const response = await methods.NewInvoice({rpcName:'NewInvoice', ctx:authContext , req: request}) + stats.handle = process.hrtime.bigint() + res.json({status: 'OK', ...response}) + opts.metricsCallback([{ ...info, ...stats, ...authContext }]) + } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } + }) + if (!opts.allowNotImplementedMethods && !methods.DecodeInvoice) throw new Error('method: DecodeInvoice is not implemented') + app.post('/api/user/invoice/decode', async (req, res) => { + const info: Types.RequestInfo = { rpcName: 'DecodeInvoice', batch: false, nostr: false, batchSize: 0} + const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } + let authCtx: Types.AuthContext = {} + try { + if (!methods.DecodeInvoice) throw new Error('method: DecodeInvoice is not implemented') + const authContext = await opts.UserAuthGuard(req.headers['authorization']) + authCtx = authContext + stats.guard = process.hrtime.bigint() + const request = req.body + const error = Types.DecodeInvoiceRequestValidate(request) + stats.validate = process.hrtime.bigint() + if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authContext }, opts.metricsCallback) + const query = req.query + const params = req.params + const response = await methods.DecodeInvoice({rpcName:'DecodeInvoice', ctx:authContext , req: request}) + stats.handle = process.hrtime.bigint() + res.json({status: 'OK', ...response}) + opts.metricsCallback([{ ...info, ...stats, ...authContext }]) + } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } + }) + if (!opts.allowNotImplementedMethods && !methods.PayInvoice) throw new Error('method: PayInvoice is not implemented') + app.post('/api/user/invoice/pay', async (req, res) => { + const info: Types.RequestInfo = { rpcName: 'PayInvoice', batch: false, nostr: false, batchSize: 0} + const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } + let authCtx: Types.AuthContext = {} + try { + if (!methods.PayInvoice) throw new Error('method: PayInvoice is not implemented') + const authContext = await opts.UserAuthGuard(req.headers['authorization']) + authCtx = authContext + stats.guard = process.hrtime.bigint() + const request = req.body + const error = Types.PayInvoiceRequestValidate(request) + stats.validate = process.hrtime.bigint() + if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authContext }, opts.metricsCallback) + const query = req.query + const params = req.params + const response = await methods.PayInvoice({rpcName:'PayInvoice', ctx:authContext , req: request}) + stats.handle = process.hrtime.bigint() + res.json({status: 'OK', ...response}) + opts.metricsCallback([{ ...info, ...stats, ...authContext }]) + } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } + }) + if (!opts.allowNotImplementedMethods && !methods.OpenChannel) throw new Error('method: OpenChannel is not implemented') + app.post('/api/user/open/channel', async (req, res) => { + const info: Types.RequestInfo = { rpcName: 'OpenChannel', batch: false, nostr: false, batchSize: 0} + const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } + let authCtx: Types.AuthContext = {} + try { + if (!methods.OpenChannel) throw new Error('method: OpenChannel is not implemented') + const authContext = await opts.UserAuthGuard(req.headers['authorization']) + authCtx = authContext + stats.guard = process.hrtime.bigint() + const request = req.body + const error = Types.OpenChannelRequestValidate(request) + stats.validate = process.hrtime.bigint() + if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authContext }, opts.metricsCallback) + const query = req.query + const params = req.params + const response = await methods.OpenChannel({rpcName:'OpenChannel', ctx:authContext , req: request}) + stats.handle = process.hrtime.bigint() + res.json({status: 'OK', ...response}) + opts.metricsCallback([{ ...info, ...stats, ...authContext }]) + } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } + }) + if (!opts.allowNotImplementedMethods && !methods.GetLnurlWithdrawLink) throw new Error('method: GetLnurlWithdrawLink is not implemented') + app.get('/api/user/lnurl_withdraw/link', async (req, res) => { + const info: Types.RequestInfo = { rpcName: 'GetLnurlWithdrawLink', batch: false, nostr: false, batchSize: 0} + const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } + let authCtx: Types.AuthContext = {} + try { + if (!methods.GetLnurlWithdrawLink) throw new Error('method: GetLnurlWithdrawLink is not implemented') + const authContext = await opts.UserAuthGuard(req.headers['authorization']) + authCtx = authContext + stats.guard = process.hrtime.bigint() + stats.validate = stats.guard + const query = req.query + const params = req.params + const response = await methods.GetLnurlWithdrawLink({rpcName:'GetLnurlWithdrawLink', ctx:authContext }) + stats.handle = process.hrtime.bigint() + res.json({status: 'OK', ...response}) + opts.metricsCallback([{ ...info, ...stats, ...authContext }]) + } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } + }) + if (!opts.allowNotImplementedMethods && !methods.GetLnurlPayLink) throw new Error('method: GetLnurlPayLink is not implemented') + app.get('/api/user/lnurl_pay/link', async (req, res) => { + const info: Types.RequestInfo = { rpcName: 'GetLnurlPayLink', batch: false, nostr: false, batchSize: 0} + const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } + let authCtx: Types.AuthContext = {} + try { + if (!methods.GetLnurlPayLink) throw new Error('method: GetLnurlPayLink is not implemented') + const authContext = await opts.UserAuthGuard(req.headers['authorization']) + authCtx = authContext + stats.guard = process.hrtime.bigint() + stats.validate = stats.guard + const query = req.query + const params = req.params + const response = await methods.GetLnurlPayLink({rpcName:'GetLnurlPayLink', ctx:authContext }) + stats.handle = process.hrtime.bigint() + res.json({status: 'OK', ...response}) + opts.metricsCallback([{ ...info, ...stats, ...authContext }]) + } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } + }) + if (!opts.allowNotImplementedMethods && !methods.GetLNURLChannelLink) throw new Error('method: GetLNURLChannelLink is not implemented') + app.post('/api/user/lnurl_channel/url', async (req, res) => { + const info: Types.RequestInfo = { rpcName: 'GetLNURLChannelLink', batch: false, nostr: false, batchSize: 0} + const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } + let authCtx: Types.AuthContext = {} + try { + if (!methods.GetLNURLChannelLink) throw new Error('method: GetLNURLChannelLink is not implemented') + const authContext = await opts.UserAuthGuard(req.headers['authorization']) + authCtx = authContext + stats.guard = process.hrtime.bigint() + stats.validate = stats.guard + const query = req.query + const params = req.params + const response = await methods.GetLNURLChannelLink({rpcName:'GetLNURLChannelLink', ctx:authContext }) + stats.handle = process.hrtime.bigint() + res.json({status: 'OK', ...response}) + opts.metricsCallback([{ ...info, ...stats, ...authContext }]) + } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } + }) + app.post('/api/user/batch', async (req, res) => { + const info: Types.RequestInfo = { rpcName: 'BatchUser', batch: true, nostr: false, batchSize: 1 } + const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } + let authCtx: Types.AuthContext = {} + try { + const requests = req.body.requests as Types.UserMethodInputs[] + if (!Array.isArray(requests))throw new Error('invalid body, is not an array') + info.batchSize = requests.length + if (requests.length > 10) throw new Error('too many requests in the batch') + const ctx = await opts.UserAuthGuard(req.headers['authorization']) + stats.guard = process.hrtime.bigint() + stats.validate = stats.guard + authCtx = ctx + const responses = [] + const callsMetrics: Types.RequestMetric[] = [] + for (let i = 0; i < requests.length; i++) { + const operation = requests[i] + const opInfo: Types.RequestInfo = { rpcName: operation.rpcName, batch: true, nostr: false, batchSize: 0 } + const opStats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: stats.parse, guard: stats.guard, validate: 0n, handle: 0n } + try { + switch(operation.rpcName) { + case 'LinkNPubThroughToken': + if (!methods.LinkNPubThroughToken) { + throw new Error('method LinkNPubThroughToken not found' ) + } else { + const error = Types.LinkNPubThroughTokenRequestValidate(operation.req) + opStats.validate = process.hrtime.bigint() + if (error !== null) throw error + await methods.LinkNPubThroughToken({...operation, ctx}); responses.push({ status: 'OK' }) + opStats.handle = process.hrtime.bigint() + callsMetrics.push({ ...opInfo, ...opStats, ...ctx }) + } + break + case 'EnrollAdminToken': + if (!methods.EnrollAdminToken) { + throw new Error('method EnrollAdminToken not found' ) + } else { + const error = Types.EnrollAdminTokenRequestValidate(operation.req) + opStats.validate = process.hrtime.bigint() + if (error !== null) throw error + await methods.EnrollAdminToken({...operation, ctx}); responses.push({ status: 'OK' }) + opStats.handle = process.hrtime.bigint() + callsMetrics.push({ ...opInfo, ...opStats, ...ctx }) + } + break + case 'UserHealth': + if (!methods.UserHealth) { + throw new Error('method UserHealth not found' ) + } else { + opStats.validate = opStats.guard + await methods.UserHealth({...operation, ctx}); responses.push({ status: 'OK' }) + opStats.handle = process.hrtime.bigint() + callsMetrics.push({ ...opInfo, ...opStats, ...ctx }) + } + break + case 'GetUserInfo': + if (!methods.GetUserInfo) { + throw new Error('method GetUserInfo not found' ) + } else { + opStats.validate = opStats.guard + const res = await methods.GetUserInfo({...operation, ctx}); responses.push({ status: 'OK', ...res }) + opStats.handle = process.hrtime.bigint() + callsMetrics.push({ ...opInfo, ...opStats, ...ctx }) + } + break + case 'AddProduct': + if (!methods.AddProduct) { + throw new Error('method AddProduct not found' ) + } else { + const error = Types.AddProductRequestValidate(operation.req) + opStats.validate = process.hrtime.bigint() + if (error !== null) throw error + const res = await methods.AddProduct({...operation, ctx}); responses.push({ status: 'OK', ...res }) + opStats.handle = process.hrtime.bigint() + callsMetrics.push({ ...opInfo, ...opStats, ...ctx }) + } + break + case 'NewProductInvoice': + if (!methods.NewProductInvoice) { + throw new Error('method NewProductInvoice not found' ) + } else { + opStats.validate = opStats.guard + const res = await methods.NewProductInvoice({...operation, ctx}); responses.push({ status: 'OK', ...res }) + opStats.handle = process.hrtime.bigint() + callsMetrics.push({ ...opInfo, ...opStats, ...ctx }) + } + break + case 'GetUserOperations': + if (!methods.GetUserOperations) { + throw new Error('method GetUserOperations not found' ) + } else { + const error = Types.GetUserOperationsRequestValidate(operation.req) + opStats.validate = process.hrtime.bigint() + if (error !== null) throw error + const res = await methods.GetUserOperations({...operation, ctx}); responses.push({ status: 'OK', ...res }) + opStats.handle = process.hrtime.bigint() + callsMetrics.push({ ...opInfo, ...opStats, ...ctx }) + } + break + case 'NewAddress': + if (!methods.NewAddress) { + throw new Error('method NewAddress not found' ) + } else { + const error = Types.NewAddressRequestValidate(operation.req) + opStats.validate = process.hrtime.bigint() + if (error !== null) throw error + const res = await methods.NewAddress({...operation, ctx}); responses.push({ status: 'OK', ...res }) + opStats.handle = process.hrtime.bigint() + callsMetrics.push({ ...opInfo, ...opStats, ...ctx }) + } + break + case 'PayAddress': + if (!methods.PayAddress) { + throw new Error('method PayAddress not found' ) + } else { + const error = Types.PayAddressRequestValidate(operation.req) + opStats.validate = process.hrtime.bigint() + if (error !== null) throw error + const res = await methods.PayAddress({...operation, ctx}); responses.push({ status: 'OK', ...res }) + opStats.handle = process.hrtime.bigint() + callsMetrics.push({ ...opInfo, ...opStats, ...ctx }) + } + break + case 'NewInvoice': + if (!methods.NewInvoice) { + throw new Error('method NewInvoice not found' ) + } else { + const error = Types.NewInvoiceRequestValidate(operation.req) + opStats.validate = process.hrtime.bigint() + if (error !== null) throw error + const res = await methods.NewInvoice({...operation, ctx}); responses.push({ status: 'OK', ...res }) + opStats.handle = process.hrtime.bigint() + callsMetrics.push({ ...opInfo, ...opStats, ...ctx }) + } + break + case 'DecodeInvoice': + if (!methods.DecodeInvoice) { + throw new Error('method DecodeInvoice not found' ) + } else { + const error = Types.DecodeInvoiceRequestValidate(operation.req) + opStats.validate = process.hrtime.bigint() + if (error !== null) throw error + const res = await methods.DecodeInvoice({...operation, ctx}); responses.push({ status: 'OK', ...res }) + opStats.handle = process.hrtime.bigint() + callsMetrics.push({ ...opInfo, ...opStats, ...ctx }) + } + break + case 'PayInvoice': + if (!methods.PayInvoice) { + throw new Error('method PayInvoice not found' ) + } else { + const error = Types.PayInvoiceRequestValidate(operation.req) + opStats.validate = process.hrtime.bigint() + if (error !== null) throw error + const res = await methods.PayInvoice({...operation, ctx}); responses.push({ status: 'OK', ...res }) + opStats.handle = process.hrtime.bigint() + callsMetrics.push({ ...opInfo, ...opStats, ...ctx }) + } + break + case 'OpenChannel': + if (!methods.OpenChannel) { + throw new Error('method OpenChannel not found' ) + } else { + const error = Types.OpenChannelRequestValidate(operation.req) + opStats.validate = process.hrtime.bigint() + if (error !== null) throw error + const res = await methods.OpenChannel({...operation, ctx}); responses.push({ status: 'OK', ...res }) + opStats.handle = process.hrtime.bigint() + callsMetrics.push({ ...opInfo, ...opStats, ...ctx }) + } + break + case 'GetLnurlWithdrawLink': + if (!methods.GetLnurlWithdrawLink) { + throw new Error('method GetLnurlWithdrawLink not found' ) + } else { + opStats.validate = opStats.guard + const res = await methods.GetLnurlWithdrawLink({...operation, ctx}); responses.push({ status: 'OK', ...res }) + opStats.handle = process.hrtime.bigint() + callsMetrics.push({ ...opInfo, ...opStats, ...ctx }) + } + break + case 'GetLnurlPayLink': + if (!methods.GetLnurlPayLink) { + throw new Error('method GetLnurlPayLink not found' ) + } else { + opStats.validate = opStats.guard + const res = await methods.GetLnurlPayLink({...operation, ctx}); responses.push({ status: 'OK', ...res }) + opStats.handle = process.hrtime.bigint() + callsMetrics.push({ ...opInfo, ...opStats, ...ctx }) + } + break + case 'GetLNURLChannelLink': + if (!methods.GetLNURLChannelLink) { + throw new Error('method GetLNURLChannelLink not found' ) + } else { + opStats.validate = opStats.guard + const res = await methods.GetLNURLChannelLink({...operation, ctx}); responses.push({ status: 'OK', ...res }) + opStats.handle = process.hrtime.bigint() + callsMetrics.push({ ...opInfo, ...opStats, ...ctx }) + } + break + default: + throw new Error('unkown rpcName') + } + } catch(ex) {const e = ex as any; logger.error(e.message || e); callsMetrics.push({ ...opInfo, ...opStats, ...ctx, error: e.message }); responses.push({ status: 'ERROR', reason: e.message || e })} + } + stats.handle = process.hrtime.bigint() + res.json({ status: 'OK', responses }) + opts.metricsCallback([{ ...info, ...stats, ...ctx }, ...callsMetrics]) + } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } + }) + if (opts.staticFiles) { + app.use(express.static(opts.staticFiles)) + app.get('*', function (_, res) { res.sendFile('index.html', { root: opts.staticFiles })}) + } + var server: { close: () => void } | undefined + return { + Close: () => { if (!server) { throw new Error('tried closing server before starting') } else server.close() }, + Listen: (port: number) => { server = app.listen(port, () => logger.log('LightningPub listening on port ' + port)) } + } +} diff --git a/proto/autogenerated/ts/http_client.ts b/proto/autogenerated/ts/http_client.ts index 87a553f1..1865e08a 100644 --- a/proto/autogenerated/ts/http_client.ts +++ b/proto/autogenerated/ts/http_client.ts @@ -1,602 +1,613 @@ -// This file was autogenerated from a .proto file, DO NOT EDIT! -import axios from 'axios' -import * as Types from './types.js' -export type ResultError = { status: 'ERROR', reason: string } - -export type ClientParams = { - baseUrl: string - retrieveGuestAuth: () => Promise - retrieveUserAuth: () => Promise - retrieveAdminAuth: () => Promise - retrieveMetricsAuth: () => Promise - retrieveAppAuth: () => Promise - encryptCallback: (plain: any) => Promise - decryptCallback: (encrypted: any) => Promise - deviceId: string - checkResult?: true -} -export default (params: ClientParams) => ({ - LndGetInfo: async (request: Types.LndGetInfoRequest): Promise => { - const auth = await params.retrieveAdminAuth() - if (auth === null) throw new Error('retrieveAdminAuth() returned null') - let finalRoute = '/api/admin/lnd/getinfo' - const { data } = await axios.post(params.baseUrl + finalRoute, request, { headers: { 'authorization': auth } }) - if (data.status === 'ERROR' && typeof data.reason === 'string') return data - if (data.status === 'OK') { - const result = data - if(!params.checkResult) return { status: 'OK', ...result } - const error = Types.LndGetInfoResponseValidate(result) - if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } - } - return { status: 'ERROR', reason: 'invalid response' } - }, - AddApp: async (request: Types.AddAppRequest): Promise => { - const auth = await params.retrieveAdminAuth() - if (auth === null) throw new Error('retrieveAdminAuth() returned null') - let finalRoute = '/api/admin/app/add' - const { data } = await axios.post(params.baseUrl + finalRoute, request, { headers: { 'authorization': auth } }) - if (data.status === 'ERROR' && typeof data.reason === 'string') return data - if (data.status === 'OK') { - const result = data - if(!params.checkResult) return { status: 'OK', ...result } - const error = Types.AuthAppValidate(result) - if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } - } - return { status: 'ERROR', reason: 'invalid response' } - }, - AuthApp: async (request: Types.AuthAppRequest): Promise => { - const auth = await params.retrieveAdminAuth() - if (auth === null) throw new Error('retrieveAdminAuth() returned null') - let finalRoute = '/api/admin/app/auth' - const { data } = await axios.post(params.baseUrl + finalRoute, request, { headers: { 'authorization': auth } }) - if (data.status === 'ERROR' && typeof data.reason === 'string') return data - if (data.status === 'OK') { - const result = data - if(!params.checkResult) return { status: 'OK', ...result } - const error = Types.AuthAppValidate(result) - if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } - } - return { status: 'ERROR', reason: 'invalid response' } - }, - BanUser: async (request: Types.BanUserRequest): Promise => { - const auth = await params.retrieveAdminAuth() - if (auth === null) throw new Error('retrieveAdminAuth() returned null') - let finalRoute = '/api/admin/user/ban' - const { data } = await axios.post(params.baseUrl + finalRoute, request, { headers: { 'authorization': auth } }) - if (data.status === 'ERROR' && typeof data.reason === 'string') return data - if (data.status === 'OK') { - const result = data - if(!params.checkResult) return { status: 'OK', ...result } - const error = Types.BanUserResponseValidate(result) - if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } - } - return { status: 'ERROR', reason: 'invalid response' } - }, - GetUsageMetrics: async (): Promise => { - const auth = await params.retrieveMetricsAuth() - if (auth === null) throw new Error('retrieveMetricsAuth() returned null') - let finalRoute = '/api/reports/usage' - const { data } = await axios.post(params.baseUrl + finalRoute, {}, { headers: { 'authorization': auth } }) - if (data.status === 'ERROR' && typeof data.reason === 'string') return data - if (data.status === 'OK') { - const result = data - if(!params.checkResult) return { status: 'OK', ...result } - const error = Types.UsageMetricsValidate(result) - if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } - } - return { status: 'ERROR', reason: 'invalid response' } - }, - GetAppsMetrics: async (request: Types.AppsMetricsRequest): Promise => { - const auth = await params.retrieveMetricsAuth() - if (auth === null) throw new Error('retrieveMetricsAuth() returned null') - let finalRoute = '/api/reports/apps' - const { data } = await axios.post(params.baseUrl + finalRoute, request, { headers: { 'authorization': auth } }) - if (data.status === 'ERROR' && typeof data.reason === 'string') return data - if (data.status === 'OK') { - const result = data - if(!params.checkResult) return { status: 'OK', ...result } - const error = Types.AppsMetricsValidate(result) - if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } - } - return { status: 'ERROR', reason: 'invalid response' } - }, - GetLndMetrics: async (request: Types.LndMetricsRequest): Promise => { - const auth = await params.retrieveMetricsAuth() - if (auth === null) throw new Error('retrieveMetricsAuth() returned null') - let finalRoute = '/api/reports/lnd' - const { data } = await axios.post(params.baseUrl + finalRoute, request, { headers: { 'authorization': auth } }) - if (data.status === 'ERROR' && typeof data.reason === 'string') return data - if (data.status === 'OK') { - const result = data - if(!params.checkResult) return { status: 'OK', ...result } - const error = Types.LndMetricsValidate(result) - if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } - } - return { status: 'ERROR', reason: 'invalid response' } - }, - Health: async (): Promise => { - const auth = await params.retrieveGuestAuth() - if (auth === null) throw new Error('retrieveGuestAuth() returned null') - let finalRoute = '/api/health' - const { data } = await axios.get(params.baseUrl + finalRoute, { headers: { 'authorization': auth } }) - if (data.status === 'ERROR' && typeof data.reason === 'string') return data - if (data.status === 'OK') { - return data - } - return { status: 'ERROR', reason: 'invalid response' } - }, - EncryptionExchange: async (request: Types.EncryptionExchangeRequest): Promise => { - const auth = await params.retrieveGuestAuth() - if (auth === null) throw new Error('retrieveGuestAuth() returned null') - let finalRoute = '/api/encryption/exchange' - const { data } = await axios.post(params.baseUrl + finalRoute, request, { headers: { 'authorization': auth } }) - if (data.status === 'ERROR' && typeof data.reason === 'string') return data - if (data.status === 'OK') { - return data - } - return { status: 'ERROR', reason: 'invalid response' } - }, - SetMockInvoiceAsPaid: async (request: Types.SetMockInvoiceAsPaidRequest): Promise => { - const auth = await params.retrieveGuestAuth() - if (auth === null) throw new Error('retrieveGuestAuth() returned null') - let finalRoute = '/api/lnd/mock/invoice/paid' - const { data } = await axios.post(params.baseUrl + finalRoute, request, { headers: { 'authorization': auth } }) - if (data.status === 'ERROR' && typeof data.reason === 'string') return data - if (data.status === 'OK') { - return data - } - return { status: 'ERROR', reason: 'invalid response' } - }, - GetLnurlWithdrawInfo: async (query: Types.GetLnurlWithdrawInfo_Query): Promise => { - const auth = await params.retrieveGuestAuth() - if (auth === null) throw new Error('retrieveGuestAuth() returned null') - let finalRoute = '/api/guest/lnurl_withdraw/info' - const q = (new URLSearchParams(query)).toString() - finalRoute = finalRoute + (q === '' ? '' : '?' + q) - const { data } = await axios.get(params.baseUrl + finalRoute, { headers: { 'authorization': auth } }) - if (data.status === 'ERROR' && typeof data.reason === 'string') return data - if (data.status === 'OK') { - const result = data - if(!params.checkResult) return { status: 'OK', ...result } - const error = Types.LnurlWithdrawInfoResponseValidate(result) - if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } - } - return { status: 'ERROR', reason: 'invalid response' } - }, - HandleLnurlWithdraw: async (query: Types.HandleLnurlWithdraw_Query): Promise => { - const auth = await params.retrieveGuestAuth() - if (auth === null) throw new Error('retrieveGuestAuth() returned null') - let finalRoute = '/api/guest/lnurl_withdraw/handle' - const q = (new URLSearchParams(query)).toString() - finalRoute = finalRoute + (q === '' ? '' : '?' + q) - const { data } = await axios.get(params.baseUrl + finalRoute, { headers: { 'authorization': auth } }) - if (data.status === 'ERROR' && typeof data.reason === 'string') return data - if (data.status === 'OK') { - return data - } - return { status: 'ERROR', reason: 'invalid response' } - }, - GetLnurlPayInfo: async (query: Types.GetLnurlPayInfo_Query): Promise => { - const auth = await params.retrieveGuestAuth() - if (auth === null) throw new Error('retrieveGuestAuth() returned null') - let finalRoute = '/api/guest/lnurl_pay/info' - const q = (new URLSearchParams(query)).toString() - finalRoute = finalRoute + (q === '' ? '' : '?' + q) - const { data } = await axios.get(params.baseUrl + finalRoute, { headers: { 'authorization': auth } }) - if (data.status === 'ERROR' && typeof data.reason === 'string') return data - if (data.status === 'OK') { - const result = data - if(!params.checkResult) return { status: 'OK', ...result } - const error = Types.LnurlPayInfoResponseValidate(result) - if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } - } - return { status: 'ERROR', reason: 'invalid response' } - }, - HandleLnurlPay: async (query: Types.HandleLnurlPay_Query): Promise => { - const auth = await params.retrieveGuestAuth() - if (auth === null) throw new Error('retrieveGuestAuth() returned null') - let finalRoute = '/api/guest/lnurl_pay/handle' - const q = (new URLSearchParams(query)).toString() - finalRoute = finalRoute + (q === '' ? '' : '?' + q) - const { data } = await axios.get(params.baseUrl + finalRoute, { headers: { 'authorization': auth } }) - if (data.status === 'ERROR' && typeof data.reason === 'string') return data - if (data.status === 'OK') { - const result = data - if(!params.checkResult) return { status: 'OK', ...result } - const error = Types.HandleLnurlPayResponseValidate(result) - if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } - } - return { status: 'ERROR', reason: 'invalid response' } - }, - HandleLnurlAddress: async (routeParams: Types.HandleLnurlAddress_RouteParams): Promise => { - const auth = await params.retrieveGuestAuth() - if (auth === null) throw new Error('retrieveGuestAuth() returned null') - let finalRoute = '/.well-known/lnurlp/:address_name' - finalRoute = finalRoute.replace(':address_name', routeParams['address_name']) - const { data } = await axios.get(params.baseUrl + finalRoute, { headers: { 'authorization': auth } }) - if (data.status === 'ERROR' && typeof data.reason === 'string') return data - if (data.status === 'OK') { - const result = data - if(!params.checkResult) return { status: 'OK', ...result } - const error = Types.LnurlPayInfoResponseValidate(result) - if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } - } - return { status: 'ERROR', reason: 'invalid response' } - }, - LinkNPubThroughToken: async (request: Types.LinkNPubThroughTokenRequest): Promise => { - const auth = await params.retrieveUserAuth() - if (auth === null) throw new Error('retrieveUserAuth() returned null') - let finalRoute = '/api/guest/npub/link' - const { data } = await axios.post(params.baseUrl + finalRoute, request, { headers: { 'authorization': auth } }) - if (data.status === 'ERROR' && typeof data.reason === 'string') return data - if (data.status === 'OK') { - return data - } - return { status: 'ERROR', reason: 'invalid response' } - }, - GetApp: async (): Promise => { - const auth = await params.retrieveAppAuth() - if (auth === null) throw new Error('retrieveAppAuth() returned null') - let finalRoute = '/api/app/get' - const { data } = await axios.post(params.baseUrl + finalRoute, {}, { headers: { 'authorization': auth } }) - if (data.status === 'ERROR' && typeof data.reason === 'string') return data - if (data.status === 'OK') { - const result = data - if(!params.checkResult) return { status: 'OK', ...result } - const error = Types.ApplicationValidate(result) - if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } - } - return { status: 'ERROR', reason: 'invalid response' } - }, - AddAppUser: async (request: Types.AddAppUserRequest): Promise => { - const auth = await params.retrieveAppAuth() - if (auth === null) throw new Error('retrieveAppAuth() returned null') - let finalRoute = '/api/app/user/add' - const { data } = await axios.post(params.baseUrl + finalRoute, request, { headers: { 'authorization': auth } }) - if (data.status === 'ERROR' && typeof data.reason === 'string') return data - if (data.status === 'OK') { - const result = data - if(!params.checkResult) return { status: 'OK', ...result } - const error = Types.AppUserValidate(result) - if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } - } - return { status: 'ERROR', reason: 'invalid response' } - }, - AddAppInvoice: async (request: Types.AddAppInvoiceRequest): Promise => { - const auth = await params.retrieveAppAuth() - if (auth === null) throw new Error('retrieveAppAuth() returned null') - let finalRoute = '/api/app/add/invoice' - const { data } = await axios.post(params.baseUrl + finalRoute, request, { headers: { 'authorization': auth } }) - if (data.status === 'ERROR' && typeof data.reason === 'string') return data - if (data.status === 'OK') { - const result = data - if(!params.checkResult) return { status: 'OK', ...result } - const error = Types.NewInvoiceResponseValidate(result) - if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } - } - return { status: 'ERROR', reason: 'invalid response' } - }, - AddAppUserInvoice: async (request: Types.AddAppUserInvoiceRequest): Promise => { - const auth = await params.retrieveAppAuth() - if (auth === null) throw new Error('retrieveAppAuth() returned null') - let finalRoute = '/api/app/user/add/invoice' - const { data } = await axios.post(params.baseUrl + finalRoute, request, { headers: { 'authorization': auth } }) - if (data.status === 'ERROR' && typeof data.reason === 'string') return data - if (data.status === 'OK') { - const result = data - if(!params.checkResult) return { status: 'OK', ...result } - const error = Types.NewInvoiceResponseValidate(result) - if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } - } - return { status: 'ERROR', reason: 'invalid response' } - }, - GetAppUser: async (request: Types.GetAppUserRequest): Promise => { - const auth = await params.retrieveAppAuth() - if (auth === null) throw new Error('retrieveAppAuth() returned null') - let finalRoute = '/api/app/user/get' - const { data } = await axios.post(params.baseUrl + finalRoute, request, { headers: { 'authorization': auth } }) - if (data.status === 'ERROR' && typeof data.reason === 'string') return data - if (data.status === 'OK') { - const result = data - if(!params.checkResult) return { status: 'OK', ...result } - const error = Types.AppUserValidate(result) - if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } - } - return { status: 'ERROR', reason: 'invalid response' } - }, - PayAppUserInvoice: async (request: Types.PayAppUserInvoiceRequest): Promise => { - const auth = await params.retrieveAppAuth() - if (auth === null) throw new Error('retrieveAppAuth() returned null') - let finalRoute = '/api/app/invoice/pay' - const { data } = await axios.post(params.baseUrl + finalRoute, request, { headers: { 'authorization': auth } }) - if (data.status === 'ERROR' && typeof data.reason === 'string') return data - if (data.status === 'OK') { - const result = data - if(!params.checkResult) return { status: 'OK', ...result } - const error = Types.PayInvoiceResponseValidate(result) - if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } - } - return { status: 'ERROR', reason: 'invalid response' } - }, - SendAppUserToAppUserPayment: async (request: Types.SendAppUserToAppUserPaymentRequest): Promise => { - const auth = await params.retrieveAppAuth() - if (auth === null) throw new Error('retrieveAppAuth() returned null') - let finalRoute = '/api/app/user/internal/pay' - const { data } = await axios.post(params.baseUrl + finalRoute, request, { headers: { 'authorization': auth } }) - if (data.status === 'ERROR' && typeof data.reason === 'string') return data - if (data.status === 'OK') { - return data - } - return { status: 'ERROR', reason: 'invalid response' } - }, - SendAppUserToAppPayment: async (request: Types.SendAppUserToAppPaymentRequest): Promise => { - const auth = await params.retrieveAppAuth() - if (auth === null) throw new Error('retrieveAppAuth() returned null') - let finalRoute = '/api/app/internal/pay' - const { data } = await axios.post(params.baseUrl + finalRoute, request, { headers: { 'authorization': auth } }) - if (data.status === 'ERROR' && typeof data.reason === 'string') return data - if (data.status === 'OK') { - return data - } - return { status: 'ERROR', reason: 'invalid response' } - }, - GetAppUserLNURLInfo: async (request: Types.GetAppUserLNURLInfoRequest): Promise => { - const auth = await params.retrieveAppAuth() - if (auth === null) throw new Error('retrieveAppAuth() returned null') - let finalRoute = '/api/app/user/lnurl/pay/info' - const { data } = await axios.post(params.baseUrl + finalRoute, request, { headers: { 'authorization': auth } }) - if (data.status === 'ERROR' && typeof data.reason === 'string') return data - if (data.status === 'OK') { - const result = data - if(!params.checkResult) return { status: 'OK', ...result } - const error = Types.LnurlPayInfoResponseValidate(result) - if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } - } - return { status: 'ERROR', reason: 'invalid response' } - }, - SetMockAppUserBalance: async (request: Types.SetMockAppUserBalanceRequest): Promise => { - const auth = await params.retrieveAppAuth() - if (auth === null) throw new Error('retrieveAppAuth() returned null') - let finalRoute = '/api/app/mock/user/blance/set' - const { data } = await axios.post(params.baseUrl + finalRoute, request, { headers: { 'authorization': auth } }) - if (data.status === 'ERROR' && typeof data.reason === 'string') return data - if (data.status === 'OK') { - return data - } - return { status: 'ERROR', reason: 'invalid response' } - }, - SetMockAppBalance: async (request: Types.SetMockAppBalanceRequest): Promise => { - const auth = await params.retrieveAppAuth() - if (auth === null) throw new Error('retrieveAppAuth() returned null') - let finalRoute = '/api/app/mock/blance/set' - const { data } = await axios.post(params.baseUrl + finalRoute, request, { headers: { 'authorization': auth } }) - if (data.status === 'ERROR' && typeof data.reason === 'string') return data - if (data.status === 'OK') { - return data - } - return { status: 'ERROR', reason: 'invalid response' } - }, - RequestNPubLinkingToken: async (request: Types.RequestNPubLinkingTokenRequest): Promise => { - const auth = await params.retrieveAppAuth() - if (auth === null) throw new Error('retrieveAppAuth() returned null') - let finalRoute = '/api/app/user/npub/token' - const { data } = await axios.post(params.baseUrl + finalRoute, request, { headers: { 'authorization': auth } }) - if (data.status === 'ERROR' && typeof data.reason === 'string') return data - if (data.status === 'OK') { - const result = data - if(!params.checkResult) return { status: 'OK', ...result } - const error = Types.RequestNPubLinkingTokenResponseValidate(result) - if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } - } - return { status: 'ERROR', reason: 'invalid response' } - }, - UserHealth: async (): Promise => { - const auth = await params.retrieveUserAuth() - if (auth === null) throw new Error('retrieveUserAuth() returned null') - let finalRoute = '/api/user/health' - const { data } = await axios.post(params.baseUrl + finalRoute, {}, { headers: { 'authorization': auth } }) - if (data.status === 'ERROR' && typeof data.reason === 'string') return data - if (data.status === 'OK') { - return data - } - return { status: 'ERROR', reason: 'invalid response' } - }, - GetUserInfo: async (): Promise => { - const auth = await params.retrieveUserAuth() - if (auth === null) throw new Error('retrieveUserAuth() returned null') - let finalRoute = '/api/user/info' - const { data } = await axios.post(params.baseUrl + finalRoute, {}, { headers: { 'authorization': auth } }) - if (data.status === 'ERROR' && typeof data.reason === 'string') return data - if (data.status === 'OK') { - const result = data - if(!params.checkResult) return { status: 'OK', ...result } - const error = Types.UserInfoValidate(result) - if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } - } - return { status: 'ERROR', reason: 'invalid response' } - }, - AddProduct: async (request: Types.AddProductRequest): Promise => { - const auth = await params.retrieveUserAuth() - if (auth === null) throw new Error('retrieveUserAuth() returned null') - let finalRoute = '/api/user/product/add' - const { data } = await axios.post(params.baseUrl + finalRoute, request, { headers: { 'authorization': auth } }) - if (data.status === 'ERROR' && typeof data.reason === 'string') return data - if (data.status === 'OK') { - const result = data - if(!params.checkResult) return { status: 'OK', ...result } - const error = Types.ProductValidate(result) - if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } - } - return { status: 'ERROR', reason: 'invalid response' } - }, - NewProductInvoice: async (query: Types.NewProductInvoice_Query): Promise => { - const auth = await params.retrieveUserAuth() - if (auth === null) throw new Error('retrieveUserAuth() returned null') - let finalRoute = '/api/user/product/get/invoice' - const q = (new URLSearchParams(query)).toString() - finalRoute = finalRoute + (q === '' ? '' : '?' + q) - const { data } = await axios.get(params.baseUrl + finalRoute, { headers: { 'authorization': auth } }) - if (data.status === 'ERROR' && typeof data.reason === 'string') return data - if (data.status === 'OK') { - const result = data - if(!params.checkResult) return { status: 'OK', ...result } - const error = Types.NewInvoiceResponseValidate(result) - if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } - } - return { status: 'ERROR', reason: 'invalid response' } - }, - GetUserOperations: async (request: Types.GetUserOperationsRequest): Promise => { - const auth = await params.retrieveUserAuth() - if (auth === null) throw new Error('retrieveUserAuth() returned null') - let finalRoute = '/api/user/operations' - const { data } = await axios.post(params.baseUrl + finalRoute, request, { headers: { 'authorization': auth } }) - if (data.status === 'ERROR' && typeof data.reason === 'string') return data - if (data.status === 'OK') { - const result = data - if(!params.checkResult) return { status: 'OK', ...result } - const error = Types.GetUserOperationsResponseValidate(result) - if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } - } - return { status: 'ERROR', reason: 'invalid response' } - }, - NewAddress: async (request: Types.NewAddressRequest): Promise => { - const auth = await params.retrieveUserAuth() - if (auth === null) throw new Error('retrieveUserAuth() returned null') - let finalRoute = '/api/user/chain/new' - const { data } = await axios.post(params.baseUrl + finalRoute, request, { headers: { 'authorization': auth } }) - if (data.status === 'ERROR' && typeof data.reason === 'string') return data - if (data.status === 'OK') { - const result = data - if(!params.checkResult) return { status: 'OK', ...result } - const error = Types.NewAddressResponseValidate(result) - if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } - } - return { status: 'ERROR', reason: 'invalid response' } - }, - PayAddress: async (request: Types.PayAddressRequest): Promise => { - const auth = await params.retrieveUserAuth() - if (auth === null) throw new Error('retrieveUserAuth() returned null') - let finalRoute = '/api/user/chain/pay' - const { data } = await axios.post(params.baseUrl + finalRoute, request, { headers: { 'authorization': auth } }) - if (data.status === 'ERROR' && typeof data.reason === 'string') return data - if (data.status === 'OK') { - const result = data - if(!params.checkResult) return { status: 'OK', ...result } - const error = Types.PayAddressResponseValidate(result) - if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } - } - return { status: 'ERROR', reason: 'invalid response' } - }, - NewInvoice: async (request: Types.NewInvoiceRequest): Promise => { - const auth = await params.retrieveUserAuth() - if (auth === null) throw new Error('retrieveUserAuth() returned null') - let finalRoute = '/api/user/invoice/new' - const { data } = await axios.post(params.baseUrl + finalRoute, request, { headers: { 'authorization': auth } }) - if (data.status === 'ERROR' && typeof data.reason === 'string') return data - if (data.status === 'OK') { - const result = data - if(!params.checkResult) return { status: 'OK', ...result } - const error = Types.NewInvoiceResponseValidate(result) - if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } - } - return { status: 'ERROR', reason: 'invalid response' } - }, - DecodeInvoice: async (request: Types.DecodeInvoiceRequest): Promise => { - const auth = await params.retrieveUserAuth() - if (auth === null) throw new Error('retrieveUserAuth() returned null') - let finalRoute = '/api/user/invoice/decode' - const { data } = await axios.post(params.baseUrl + finalRoute, request, { headers: { 'authorization': auth } }) - if (data.status === 'ERROR' && typeof data.reason === 'string') return data - if (data.status === 'OK') { - const result = data - if(!params.checkResult) return { status: 'OK', ...result } - const error = Types.DecodeInvoiceResponseValidate(result) - if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } - } - return { status: 'ERROR', reason: 'invalid response' } - }, - PayInvoice: async (request: Types.PayInvoiceRequest): Promise => { - const auth = await params.retrieveUserAuth() - if (auth === null) throw new Error('retrieveUserAuth() returned null') - let finalRoute = '/api/user/invoice/pay' - const { data } = await axios.post(params.baseUrl + finalRoute, request, { headers: { 'authorization': auth } }) - if (data.status === 'ERROR' && typeof data.reason === 'string') return data - if (data.status === 'OK') { - const result = data - if(!params.checkResult) return { status: 'OK', ...result } - const error = Types.PayInvoiceResponseValidate(result) - if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } - } - return { status: 'ERROR', reason: 'invalid response' } - }, - OpenChannel: async (request: Types.OpenChannelRequest): Promise => { - const auth = await params.retrieveUserAuth() - if (auth === null) throw new Error('retrieveUserAuth() returned null') - let finalRoute = '/api/user/open/channel' - const { data } = await axios.post(params.baseUrl + finalRoute, request, { headers: { 'authorization': auth } }) - if (data.status === 'ERROR' && typeof data.reason === 'string') return data - if (data.status === 'OK') { - const result = data - if(!params.checkResult) return { status: 'OK', ...result } - const error = Types.OpenChannelResponseValidate(result) - if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } - } - return { status: 'ERROR', reason: 'invalid response' } - }, - GetLnurlWithdrawLink: async (): Promise => { - const auth = await params.retrieveUserAuth() - if (auth === null) throw new Error('retrieveUserAuth() returned null') - let finalRoute = '/api/user/lnurl_withdraw/link' - const { data } = await axios.get(params.baseUrl + finalRoute, { headers: { 'authorization': auth } }) - if (data.status === 'ERROR' && typeof data.reason === 'string') return data - if (data.status === 'OK') { - const result = data - if(!params.checkResult) return { status: 'OK', ...result } - const error = Types.LnurlLinkResponseValidate(result) - if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } - } - return { status: 'ERROR', reason: 'invalid response' } - }, - GetLnurlPayLink: async (): Promise => { - const auth = await params.retrieveUserAuth() - if (auth === null) throw new Error('retrieveUserAuth() returned null') - let finalRoute = '/api/user/lnurl_pay/link' - const { data } = await axios.get(params.baseUrl + finalRoute, { headers: { 'authorization': auth } }) - if (data.status === 'ERROR' && typeof data.reason === 'string') return data - if (data.status === 'OK') { - const result = data - if(!params.checkResult) return { status: 'OK', ...result } - const error = Types.LnurlLinkResponseValidate(result) - if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } - } - return { status: 'ERROR', reason: 'invalid response' } - }, - GetLNURLChannelLink: async (): Promise => { - const auth = await params.retrieveUserAuth() - if (auth === null) throw new Error('retrieveUserAuth() returned null') - let finalRoute = '/api/user/lnurl_channel/url' - const { data } = await axios.post(params.baseUrl + finalRoute, {}, { headers: { 'authorization': auth } }) - if (data.status === 'ERROR' && typeof data.reason === 'string') return data - if (data.status === 'OK') { - const result = data - if(!params.checkResult) return { status: 'OK', ...result } - const error = Types.LnurlLinkResponseValidate(result) - if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } - } - return { status: 'ERROR', reason: 'invalid response' } - }, - GetLiveUserOperations: async (cb: (v:ResultError | ({ status: 'OK' }& Types.LiveUserOperation)) => void): Promise => { throw new Error('http streams are not supported')}, - GetMigrationUpdate: async (cb: (v:ResultError | ({ status: 'OK' }& Types.MigrationUpdate)) => void): Promise => { throw new Error('http streams are not supported')}, - GetHttpCreds: async (cb: (v:ResultError | ({ status: 'OK' }& Types.HttpCreds)) => void): Promise => { throw new Error('http streams are not supported')}, - BatchUser: async (requests:Types.UserMethodInputs[]): Promise => { - const auth = await params.retrieveUserAuth() - if (auth === null) throw new Error('retrieveUserAuth() returned null') - let finalRoute = '/api/user/batch' - const { data } = await axios.post(params.baseUrl + finalRoute, {requests}, { headers: { 'authorization': auth } }) - if (data.status === 'ERROR' && typeof data.reason === 'string') return data - if (data.status === 'OK') { - return { status: 'OK', ...data } - } - return { status: 'ERROR', reason: 'invalid response' } - } -}) +// This file was autogenerated from a .proto file, DO NOT EDIT! +import axios from 'axios' +import * as Types from './types.js' +export type ResultError = { status: 'ERROR', reason: string } + +export type ClientParams = { + baseUrl: string + retrieveGuestAuth: () => Promise + retrieveUserAuth: () => Promise + retrieveAdminAuth: () => Promise + retrieveMetricsAuth: () => Promise + retrieveAppAuth: () => Promise + encryptCallback: (plain: any) => Promise + decryptCallback: (encrypted: any) => Promise + deviceId: string + checkResult?: true +} +export default (params: ClientParams) => ({ + LndGetInfo: async (request: Types.LndGetInfoRequest): Promise => { + const auth = await params.retrieveAdminAuth() + if (auth === null) throw new Error('retrieveAdminAuth() returned null') + let finalRoute = '/api/admin/lnd/getinfo' + const { data } = await axios.post(params.baseUrl + finalRoute, request, { headers: { 'authorization': auth } }) + if (data.status === 'ERROR' && typeof data.reason === 'string') return data + if (data.status === 'OK') { + const result = data + if(!params.checkResult) return { status: 'OK', ...result } + const error = Types.LndGetInfoResponseValidate(result) + if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } + } + return { status: 'ERROR', reason: 'invalid response' } + }, + AddApp: async (request: Types.AddAppRequest): Promise => { + const auth = await params.retrieveAdminAuth() + if (auth === null) throw new Error('retrieveAdminAuth() returned null') + let finalRoute = '/api/admin/app/add' + const { data } = await axios.post(params.baseUrl + finalRoute, request, { headers: { 'authorization': auth } }) + if (data.status === 'ERROR' && typeof data.reason === 'string') return data + if (data.status === 'OK') { + const result = data + if(!params.checkResult) return { status: 'OK', ...result } + const error = Types.AuthAppValidate(result) + if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } + } + return { status: 'ERROR', reason: 'invalid response' } + }, + AuthApp: async (request: Types.AuthAppRequest): Promise => { + const auth = await params.retrieveAdminAuth() + if (auth === null) throw new Error('retrieveAdminAuth() returned null') + let finalRoute = '/api/admin/app/auth' + const { data } = await axios.post(params.baseUrl + finalRoute, request, { headers: { 'authorization': auth } }) + if (data.status === 'ERROR' && typeof data.reason === 'string') return data + if (data.status === 'OK') { + const result = data + if(!params.checkResult) return { status: 'OK', ...result } + const error = Types.AuthAppValidate(result) + if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } + } + return { status: 'ERROR', reason: 'invalid response' } + }, + BanUser: async (request: Types.BanUserRequest): Promise => { + const auth = await params.retrieveAdminAuth() + if (auth === null) throw new Error('retrieveAdminAuth() returned null') + let finalRoute = '/api/admin/user/ban' + const { data } = await axios.post(params.baseUrl + finalRoute, request, { headers: { 'authorization': auth } }) + if (data.status === 'ERROR' && typeof data.reason === 'string') return data + if (data.status === 'OK') { + const result = data + if(!params.checkResult) return { status: 'OK', ...result } + const error = Types.BanUserResponseValidate(result) + if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } + } + return { status: 'ERROR', reason: 'invalid response' } + }, + GetUsageMetrics: async (): Promise => { + const auth = await params.retrieveMetricsAuth() + if (auth === null) throw new Error('retrieveMetricsAuth() returned null') + let finalRoute = '/api/reports/usage' + const { data } = await axios.post(params.baseUrl + finalRoute, {}, { headers: { 'authorization': auth } }) + if (data.status === 'ERROR' && typeof data.reason === 'string') return data + if (data.status === 'OK') { + const result = data + if(!params.checkResult) return { status: 'OK', ...result } + const error = Types.UsageMetricsValidate(result) + if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } + } + return { status: 'ERROR', reason: 'invalid response' } + }, + GetAppsMetrics: async (request: Types.AppsMetricsRequest): Promise => { + const auth = await params.retrieveMetricsAuth() + if (auth === null) throw new Error('retrieveMetricsAuth() returned null') + let finalRoute = '/api/reports/apps' + const { data } = await axios.post(params.baseUrl + finalRoute, request, { headers: { 'authorization': auth } }) + if (data.status === 'ERROR' && typeof data.reason === 'string') return data + if (data.status === 'OK') { + const result = data + if(!params.checkResult) return { status: 'OK', ...result } + const error = Types.AppsMetricsValidate(result) + if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } + } + return { status: 'ERROR', reason: 'invalid response' } + }, + GetLndMetrics: async (request: Types.LndMetricsRequest): Promise => { + const auth = await params.retrieveMetricsAuth() + if (auth === null) throw new Error('retrieveMetricsAuth() returned null') + let finalRoute = '/api/reports/lnd' + const { data } = await axios.post(params.baseUrl + finalRoute, request, { headers: { 'authorization': auth } }) + if (data.status === 'ERROR' && typeof data.reason === 'string') return data + if (data.status === 'OK') { + const result = data + if(!params.checkResult) return { status: 'OK', ...result } + const error = Types.LndMetricsValidate(result) + if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } + } + return { status: 'ERROR', reason: 'invalid response' } + }, + Health: async (): Promise => { + const auth = await params.retrieveGuestAuth() + if (auth === null) throw new Error('retrieveGuestAuth() returned null') + let finalRoute = '/api/health' + const { data } = await axios.get(params.baseUrl + finalRoute, { headers: { 'authorization': auth } }) + if (data.status === 'ERROR' && typeof data.reason === 'string') return data + if (data.status === 'OK') { + return data + } + return { status: 'ERROR', reason: 'invalid response' } + }, + EncryptionExchange: async (request: Types.EncryptionExchangeRequest): Promise => { + const auth = await params.retrieveGuestAuth() + if (auth === null) throw new Error('retrieveGuestAuth() returned null') + let finalRoute = '/api/encryption/exchange' + const { data } = await axios.post(params.baseUrl + finalRoute, request, { headers: { 'authorization': auth } }) + if (data.status === 'ERROR' && typeof data.reason === 'string') return data + if (data.status === 'OK') { + return data + } + return { status: 'ERROR', reason: 'invalid response' } + }, + SetMockInvoiceAsPaid: async (request: Types.SetMockInvoiceAsPaidRequest): Promise => { + const auth = await params.retrieveGuestAuth() + if (auth === null) throw new Error('retrieveGuestAuth() returned null') + let finalRoute = '/api/lnd/mock/invoice/paid' + const { data } = await axios.post(params.baseUrl + finalRoute, request, { headers: { 'authorization': auth } }) + if (data.status === 'ERROR' && typeof data.reason === 'string') return data + if (data.status === 'OK') { + return data + } + return { status: 'ERROR', reason: 'invalid response' } + }, + GetLnurlWithdrawInfo: async (query: Types.GetLnurlWithdrawInfo_Query): Promise => { + const auth = await params.retrieveGuestAuth() + if (auth === null) throw new Error('retrieveGuestAuth() returned null') + let finalRoute = '/api/guest/lnurl_withdraw/info' + const q = (new URLSearchParams(query)).toString() + finalRoute = finalRoute + (q === '' ? '' : '?' + q) + const { data } = await axios.get(params.baseUrl + finalRoute, { headers: { 'authorization': auth } }) + if (data.status === 'ERROR' && typeof data.reason === 'string') return data + if (data.status === 'OK') { + const result = data + if(!params.checkResult) return { status: 'OK', ...result } + const error = Types.LnurlWithdrawInfoResponseValidate(result) + if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } + } + return { status: 'ERROR', reason: 'invalid response' } + }, + HandleLnurlWithdraw: async (query: Types.HandleLnurlWithdraw_Query): Promise => { + const auth = await params.retrieveGuestAuth() + if (auth === null) throw new Error('retrieveGuestAuth() returned null') + let finalRoute = '/api/guest/lnurl_withdraw/handle' + const q = (new URLSearchParams(query)).toString() + finalRoute = finalRoute + (q === '' ? '' : '?' + q) + const { data } = await axios.get(params.baseUrl + finalRoute, { headers: { 'authorization': auth } }) + if (data.status === 'ERROR' && typeof data.reason === 'string') return data + if (data.status === 'OK') { + return data + } + return { status: 'ERROR', reason: 'invalid response' } + }, + GetLnurlPayInfo: async (query: Types.GetLnurlPayInfo_Query): Promise => { + const auth = await params.retrieveGuestAuth() + if (auth === null) throw new Error('retrieveGuestAuth() returned null') + let finalRoute = '/api/guest/lnurl_pay/info' + const q = (new URLSearchParams(query)).toString() + finalRoute = finalRoute + (q === '' ? '' : '?' + q) + const { data } = await axios.get(params.baseUrl + finalRoute, { headers: { 'authorization': auth } }) + if (data.status === 'ERROR' && typeof data.reason === 'string') return data + if (data.status === 'OK') { + const result = data + if(!params.checkResult) return { status: 'OK', ...result } + const error = Types.LnurlPayInfoResponseValidate(result) + if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } + } + return { status: 'ERROR', reason: 'invalid response' } + }, + HandleLnurlPay: async (query: Types.HandleLnurlPay_Query): Promise => { + const auth = await params.retrieveGuestAuth() + if (auth === null) throw new Error('retrieveGuestAuth() returned null') + let finalRoute = '/api/guest/lnurl_pay/handle' + const q = (new URLSearchParams(query)).toString() + finalRoute = finalRoute + (q === '' ? '' : '?' + q) + const { data } = await axios.get(params.baseUrl + finalRoute, { headers: { 'authorization': auth } }) + if (data.status === 'ERROR' && typeof data.reason === 'string') return data + if (data.status === 'OK') { + const result = data + if(!params.checkResult) return { status: 'OK', ...result } + const error = Types.HandleLnurlPayResponseValidate(result) + if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } + } + return { status: 'ERROR', reason: 'invalid response' } + }, + HandleLnurlAddress: async (routeParams: Types.HandleLnurlAddress_RouteParams): Promise => { + const auth = await params.retrieveGuestAuth() + if (auth === null) throw new Error('retrieveGuestAuth() returned null') + let finalRoute = '/.well-known/lnurlp/:address_name' + finalRoute = finalRoute.replace(':address_name', routeParams['address_name']) + const { data } = await axios.get(params.baseUrl + finalRoute, { headers: { 'authorization': auth } }) + if (data.status === 'ERROR' && typeof data.reason === 'string') return data + if (data.status === 'OK') { + const result = data + if(!params.checkResult) return { status: 'OK', ...result } + const error = Types.LnurlPayInfoResponseValidate(result) + if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } + } + return { status: 'ERROR', reason: 'invalid response' } + }, + LinkNPubThroughToken: async (request: Types.LinkNPubThroughTokenRequest): Promise => { + const auth = await params.retrieveUserAuth() + if (auth === null) throw new Error('retrieveUserAuth() returned null') + let finalRoute = '/api/guest/npub/link' + const { data } = await axios.post(params.baseUrl + finalRoute, request, { headers: { 'authorization': auth } }) + if (data.status === 'ERROR' && typeof data.reason === 'string') return data + if (data.status === 'OK') { + return data + } + return { status: 'ERROR', reason: 'invalid response' } + }, + EnrollAdminToken: async (request: Types.EnrollAdminTokenRequest): Promise => { + const auth = await params.retrieveUserAuth() + if (auth === null) throw new Error('retrieveUserAuth() returned null') + let finalRoute = '/api/guest/npub/enroll/admin' + const { data } = await axios.post(params.baseUrl + finalRoute, request, { headers: { 'authorization': auth } }) + if (data.status === 'ERROR' && typeof data.reason === 'string') return data + if (data.status === 'OK') { + return data + } + return { status: 'ERROR', reason: 'invalid response' } + }, + GetApp: async (): Promise => { + const auth = await params.retrieveAppAuth() + if (auth === null) throw new Error('retrieveAppAuth() returned null') + let finalRoute = '/api/app/get' + const { data } = await axios.post(params.baseUrl + finalRoute, {}, { headers: { 'authorization': auth } }) + if (data.status === 'ERROR' && typeof data.reason === 'string') return data + if (data.status === 'OK') { + const result = data + if(!params.checkResult) return { status: 'OK', ...result } + const error = Types.ApplicationValidate(result) + if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } + } + return { status: 'ERROR', reason: 'invalid response' } + }, + AddAppUser: async (request: Types.AddAppUserRequest): Promise => { + const auth = await params.retrieveAppAuth() + if (auth === null) throw new Error('retrieveAppAuth() returned null') + let finalRoute = '/api/app/user/add' + const { data } = await axios.post(params.baseUrl + finalRoute, request, { headers: { 'authorization': auth } }) + if (data.status === 'ERROR' && typeof data.reason === 'string') return data + if (data.status === 'OK') { + const result = data + if(!params.checkResult) return { status: 'OK', ...result } + const error = Types.AppUserValidate(result) + if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } + } + return { status: 'ERROR', reason: 'invalid response' } + }, + AddAppInvoice: async (request: Types.AddAppInvoiceRequest): Promise => { + const auth = await params.retrieveAppAuth() + if (auth === null) throw new Error('retrieveAppAuth() returned null') + let finalRoute = '/api/app/add/invoice' + const { data } = await axios.post(params.baseUrl + finalRoute, request, { headers: { 'authorization': auth } }) + if (data.status === 'ERROR' && typeof data.reason === 'string') return data + if (data.status === 'OK') { + const result = data + if(!params.checkResult) return { status: 'OK', ...result } + const error = Types.NewInvoiceResponseValidate(result) + if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } + } + return { status: 'ERROR', reason: 'invalid response' } + }, + AddAppUserInvoice: async (request: Types.AddAppUserInvoiceRequest): Promise => { + const auth = await params.retrieveAppAuth() + if (auth === null) throw new Error('retrieveAppAuth() returned null') + let finalRoute = '/api/app/user/add/invoice' + const { data } = await axios.post(params.baseUrl + finalRoute, request, { headers: { 'authorization': auth } }) + if (data.status === 'ERROR' && typeof data.reason === 'string') return data + if (data.status === 'OK') { + const result = data + if(!params.checkResult) return { status: 'OK', ...result } + const error = Types.NewInvoiceResponseValidate(result) + if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } + } + return { status: 'ERROR', reason: 'invalid response' } + }, + GetAppUser: async (request: Types.GetAppUserRequest): Promise => { + const auth = await params.retrieveAppAuth() + if (auth === null) throw new Error('retrieveAppAuth() returned null') + let finalRoute = '/api/app/user/get' + const { data } = await axios.post(params.baseUrl + finalRoute, request, { headers: { 'authorization': auth } }) + if (data.status === 'ERROR' && typeof data.reason === 'string') return data + if (data.status === 'OK') { + const result = data + if(!params.checkResult) return { status: 'OK', ...result } + const error = Types.AppUserValidate(result) + if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } + } + return { status: 'ERROR', reason: 'invalid response' } + }, + PayAppUserInvoice: async (request: Types.PayAppUserInvoiceRequest): Promise => { + const auth = await params.retrieveAppAuth() + if (auth === null) throw new Error('retrieveAppAuth() returned null') + let finalRoute = '/api/app/invoice/pay' + const { data } = await axios.post(params.baseUrl + finalRoute, request, { headers: { 'authorization': auth } }) + if (data.status === 'ERROR' && typeof data.reason === 'string') return data + if (data.status === 'OK') { + const result = data + if(!params.checkResult) return { status: 'OK', ...result } + const error = Types.PayInvoiceResponseValidate(result) + if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } + } + return { status: 'ERROR', reason: 'invalid response' } + }, + SendAppUserToAppUserPayment: async (request: Types.SendAppUserToAppUserPaymentRequest): Promise => { + const auth = await params.retrieveAppAuth() + if (auth === null) throw new Error('retrieveAppAuth() returned null') + let finalRoute = '/api/app/user/internal/pay' + const { data } = await axios.post(params.baseUrl + finalRoute, request, { headers: { 'authorization': auth } }) + if (data.status === 'ERROR' && typeof data.reason === 'string') return data + if (data.status === 'OK') { + return data + } + return { status: 'ERROR', reason: 'invalid response' } + }, + SendAppUserToAppPayment: async (request: Types.SendAppUserToAppPaymentRequest): Promise => { + const auth = await params.retrieveAppAuth() + if (auth === null) throw new Error('retrieveAppAuth() returned null') + let finalRoute = '/api/app/internal/pay' + const { data } = await axios.post(params.baseUrl + finalRoute, request, { headers: { 'authorization': auth } }) + if (data.status === 'ERROR' && typeof data.reason === 'string') return data + if (data.status === 'OK') { + return data + } + return { status: 'ERROR', reason: 'invalid response' } + }, + GetAppUserLNURLInfo: async (request: Types.GetAppUserLNURLInfoRequest): Promise => { + const auth = await params.retrieveAppAuth() + if (auth === null) throw new Error('retrieveAppAuth() returned null') + let finalRoute = '/api/app/user/lnurl/pay/info' + const { data } = await axios.post(params.baseUrl + finalRoute, request, { headers: { 'authorization': auth } }) + if (data.status === 'ERROR' && typeof data.reason === 'string') return data + if (data.status === 'OK') { + const result = data + if(!params.checkResult) return { status: 'OK', ...result } + const error = Types.LnurlPayInfoResponseValidate(result) + if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } + } + return { status: 'ERROR', reason: 'invalid response' } + }, + SetMockAppUserBalance: async (request: Types.SetMockAppUserBalanceRequest): Promise => { + const auth = await params.retrieveAppAuth() + if (auth === null) throw new Error('retrieveAppAuth() returned null') + let finalRoute = '/api/app/mock/user/blance/set' + const { data } = await axios.post(params.baseUrl + finalRoute, request, { headers: { 'authorization': auth } }) + if (data.status === 'ERROR' && typeof data.reason === 'string') return data + if (data.status === 'OK') { + return data + } + return { status: 'ERROR', reason: 'invalid response' } + }, + SetMockAppBalance: async (request: Types.SetMockAppBalanceRequest): Promise => { + const auth = await params.retrieveAppAuth() + if (auth === null) throw new Error('retrieveAppAuth() returned null') + let finalRoute = '/api/app/mock/blance/set' + const { data } = await axios.post(params.baseUrl + finalRoute, request, { headers: { 'authorization': auth } }) + if (data.status === 'ERROR' && typeof data.reason === 'string') return data + if (data.status === 'OK') { + return data + } + return { status: 'ERROR', reason: 'invalid response' } + }, + RequestNPubLinkingToken: async (request: Types.RequestNPubLinkingTokenRequest): Promise => { + const auth = await params.retrieveAppAuth() + if (auth === null) throw new Error('retrieveAppAuth() returned null') + let finalRoute = '/api/app/user/npub/token' + const { data } = await axios.post(params.baseUrl + finalRoute, request, { headers: { 'authorization': auth } }) + if (data.status === 'ERROR' && typeof data.reason === 'string') return data + if (data.status === 'OK') { + const result = data + if(!params.checkResult) return { status: 'OK', ...result } + const error = Types.RequestNPubLinkingTokenResponseValidate(result) + if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } + } + return { status: 'ERROR', reason: 'invalid response' } + }, + UserHealth: async (): Promise => { + const auth = await params.retrieveUserAuth() + if (auth === null) throw new Error('retrieveUserAuth() returned null') + let finalRoute = '/api/user/health' + const { data } = await axios.post(params.baseUrl + finalRoute, {}, { headers: { 'authorization': auth } }) + if (data.status === 'ERROR' && typeof data.reason === 'string') return data + if (data.status === 'OK') { + return data + } + return { status: 'ERROR', reason: 'invalid response' } + }, + GetUserInfo: async (): Promise => { + const auth = await params.retrieveUserAuth() + if (auth === null) throw new Error('retrieveUserAuth() returned null') + let finalRoute = '/api/user/info' + const { data } = await axios.post(params.baseUrl + finalRoute, {}, { headers: { 'authorization': auth } }) + if (data.status === 'ERROR' && typeof data.reason === 'string') return data + if (data.status === 'OK') { + const result = data + if(!params.checkResult) return { status: 'OK', ...result } + const error = Types.UserInfoValidate(result) + if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } + } + return { status: 'ERROR', reason: 'invalid response' } + }, + AddProduct: async (request: Types.AddProductRequest): Promise => { + const auth = await params.retrieveUserAuth() + if (auth === null) throw new Error('retrieveUserAuth() returned null') + let finalRoute = '/api/user/product/add' + const { data } = await axios.post(params.baseUrl + finalRoute, request, { headers: { 'authorization': auth } }) + if (data.status === 'ERROR' && typeof data.reason === 'string') return data + if (data.status === 'OK') { + const result = data + if(!params.checkResult) return { status: 'OK', ...result } + const error = Types.ProductValidate(result) + if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } + } + return { status: 'ERROR', reason: 'invalid response' } + }, + NewProductInvoice: async (query: Types.NewProductInvoice_Query): Promise => { + const auth = await params.retrieveUserAuth() + if (auth === null) throw new Error('retrieveUserAuth() returned null') + let finalRoute = '/api/user/product/get/invoice' + const q = (new URLSearchParams(query)).toString() + finalRoute = finalRoute + (q === '' ? '' : '?' + q) + const { data } = await axios.get(params.baseUrl + finalRoute, { headers: { 'authorization': auth } }) + if (data.status === 'ERROR' && typeof data.reason === 'string') return data + if (data.status === 'OK') { + const result = data + if(!params.checkResult) return { status: 'OK', ...result } + const error = Types.NewInvoiceResponseValidate(result) + if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } + } + return { status: 'ERROR', reason: 'invalid response' } + }, + GetUserOperations: async (request: Types.GetUserOperationsRequest): Promise => { + const auth = await params.retrieveUserAuth() + if (auth === null) throw new Error('retrieveUserAuth() returned null') + let finalRoute = '/api/user/operations' + const { data } = await axios.post(params.baseUrl + finalRoute, request, { headers: { 'authorization': auth } }) + if (data.status === 'ERROR' && typeof data.reason === 'string') return data + if (data.status === 'OK') { + const result = data + if(!params.checkResult) return { status: 'OK', ...result } + const error = Types.GetUserOperationsResponseValidate(result) + if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } + } + return { status: 'ERROR', reason: 'invalid response' } + }, + NewAddress: async (request: Types.NewAddressRequest): Promise => { + const auth = await params.retrieveUserAuth() + if (auth === null) throw new Error('retrieveUserAuth() returned null') + let finalRoute = '/api/user/chain/new' + const { data } = await axios.post(params.baseUrl + finalRoute, request, { headers: { 'authorization': auth } }) + if (data.status === 'ERROR' && typeof data.reason === 'string') return data + if (data.status === 'OK') { + const result = data + if(!params.checkResult) return { status: 'OK', ...result } + const error = Types.NewAddressResponseValidate(result) + if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } + } + return { status: 'ERROR', reason: 'invalid response' } + }, + PayAddress: async (request: Types.PayAddressRequest): Promise => { + const auth = await params.retrieveUserAuth() + if (auth === null) throw new Error('retrieveUserAuth() returned null') + let finalRoute = '/api/user/chain/pay' + const { data } = await axios.post(params.baseUrl + finalRoute, request, { headers: { 'authorization': auth } }) + if (data.status === 'ERROR' && typeof data.reason === 'string') return data + if (data.status === 'OK') { + const result = data + if(!params.checkResult) return { status: 'OK', ...result } + const error = Types.PayAddressResponseValidate(result) + if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } + } + return { status: 'ERROR', reason: 'invalid response' } + }, + NewInvoice: async (request: Types.NewInvoiceRequest): Promise => { + const auth = await params.retrieveUserAuth() + if (auth === null) throw new Error('retrieveUserAuth() returned null') + let finalRoute = '/api/user/invoice/new' + const { data } = await axios.post(params.baseUrl + finalRoute, request, { headers: { 'authorization': auth } }) + if (data.status === 'ERROR' && typeof data.reason === 'string') return data + if (data.status === 'OK') { + const result = data + if(!params.checkResult) return { status: 'OK', ...result } + const error = Types.NewInvoiceResponseValidate(result) + if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } + } + return { status: 'ERROR', reason: 'invalid response' } + }, + DecodeInvoice: async (request: Types.DecodeInvoiceRequest): Promise => { + const auth = await params.retrieveUserAuth() + if (auth === null) throw new Error('retrieveUserAuth() returned null') + let finalRoute = '/api/user/invoice/decode' + const { data } = await axios.post(params.baseUrl + finalRoute, request, { headers: { 'authorization': auth } }) + if (data.status === 'ERROR' && typeof data.reason === 'string') return data + if (data.status === 'OK') { + const result = data + if(!params.checkResult) return { status: 'OK', ...result } + const error = Types.DecodeInvoiceResponseValidate(result) + if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } + } + return { status: 'ERROR', reason: 'invalid response' } + }, + PayInvoice: async (request: Types.PayInvoiceRequest): Promise => { + const auth = await params.retrieveUserAuth() + if (auth === null) throw new Error('retrieveUserAuth() returned null') + let finalRoute = '/api/user/invoice/pay' + const { data } = await axios.post(params.baseUrl + finalRoute, request, { headers: { 'authorization': auth } }) + if (data.status === 'ERROR' && typeof data.reason === 'string') return data + if (data.status === 'OK') { + const result = data + if(!params.checkResult) return { status: 'OK', ...result } + const error = Types.PayInvoiceResponseValidate(result) + if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } + } + return { status: 'ERROR', reason: 'invalid response' } + }, + OpenChannel: async (request: Types.OpenChannelRequest): Promise => { + const auth = await params.retrieveUserAuth() + if (auth === null) throw new Error('retrieveUserAuth() returned null') + let finalRoute = '/api/user/open/channel' + const { data } = await axios.post(params.baseUrl + finalRoute, request, { headers: { 'authorization': auth } }) + if (data.status === 'ERROR' && typeof data.reason === 'string') return data + if (data.status === 'OK') { + const result = data + if(!params.checkResult) return { status: 'OK', ...result } + const error = Types.OpenChannelResponseValidate(result) + if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } + } + return { status: 'ERROR', reason: 'invalid response' } + }, + GetLnurlWithdrawLink: async (): Promise => { + const auth = await params.retrieveUserAuth() + if (auth === null) throw new Error('retrieveUserAuth() returned null') + let finalRoute = '/api/user/lnurl_withdraw/link' + const { data } = await axios.get(params.baseUrl + finalRoute, { headers: { 'authorization': auth } }) + if (data.status === 'ERROR' && typeof data.reason === 'string') return data + if (data.status === 'OK') { + const result = data + if(!params.checkResult) return { status: 'OK', ...result } + const error = Types.LnurlLinkResponseValidate(result) + if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } + } + return { status: 'ERROR', reason: 'invalid response' } + }, + GetLnurlPayLink: async (): Promise => { + const auth = await params.retrieveUserAuth() + if (auth === null) throw new Error('retrieveUserAuth() returned null') + let finalRoute = '/api/user/lnurl_pay/link' + const { data } = await axios.get(params.baseUrl + finalRoute, { headers: { 'authorization': auth } }) + if (data.status === 'ERROR' && typeof data.reason === 'string') return data + if (data.status === 'OK') { + const result = data + if(!params.checkResult) return { status: 'OK', ...result } + const error = Types.LnurlLinkResponseValidate(result) + if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } + } + return { status: 'ERROR', reason: 'invalid response' } + }, + GetLNURLChannelLink: async (): Promise => { + const auth = await params.retrieveUserAuth() + if (auth === null) throw new Error('retrieveUserAuth() returned null') + let finalRoute = '/api/user/lnurl_channel/url' + const { data } = await axios.post(params.baseUrl + finalRoute, {}, { headers: { 'authorization': auth } }) + if (data.status === 'ERROR' && typeof data.reason === 'string') return data + if (data.status === 'OK') { + const result = data + if(!params.checkResult) return { status: 'OK', ...result } + const error = Types.LnurlLinkResponseValidate(result) + if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } + } + return { status: 'ERROR', reason: 'invalid response' } + }, + GetLiveUserOperations: async (cb: (v:ResultError | ({ status: 'OK' }& Types.LiveUserOperation)) => void): Promise => { throw new Error('http streams are not supported')}, + GetMigrationUpdate: async (cb: (v:ResultError | ({ status: 'OK' }& Types.MigrationUpdate)) => void): Promise => { throw new Error('http streams are not supported')}, + GetHttpCreds: async (cb: (v:ResultError | ({ status: 'OK' }& Types.HttpCreds)) => void): Promise => { throw new Error('http streams are not supported')}, + BatchUser: async (requests:Types.UserMethodInputs[]): Promise => { + const auth = await params.retrieveUserAuth() + if (auth === null) throw new Error('retrieveUserAuth() returned null') + let finalRoute = '/api/user/batch' + const { data } = await axios.post(params.baseUrl + finalRoute, {requests}, { headers: { 'authorization': auth } }) + if (data.status === 'ERROR' && typeof data.reason === 'string') return data + if (data.status === 'OK') { + return { status: 'OK', ...data } + } + return { status: 'ERROR', reason: 'invalid response' } + } +}) diff --git a/proto/autogenerated/ts/nostr_client.ts b/proto/autogenerated/ts/nostr_client.ts index 4a799394..ba7ec6b5 100644 --- a/proto/autogenerated/ts/nostr_client.ts +++ b/proto/autogenerated/ts/nostr_client.ts @@ -1,282 +1,400 @@ -// This file was autogenerated from a .proto file, DO NOT EDIT! -import { NostrRequest } from './nostr_transport.js' -import * as Types from './types.js' -export type ResultError = { status: 'ERROR', reason: string } - -export type NostrClientParams = { - pubDestination: string - retrieveNostrUserAuth: () => Promise - checkResult?: true -} -export default (params: NostrClientParams, send: (to:string, message: NostrRequest) => Promise, subscribe: (to:string, message: NostrRequest, cb:(res:any)=> void) => void) => ({ - LinkNPubThroughToken: async (request: Types.LinkNPubThroughTokenRequest): Promise => { - const auth = await params.retrieveNostrUserAuth() - if (auth === null) throw new Error('retrieveNostrUserAuth() returned null') - const nostrRequest: NostrRequest = {} - nostrRequest.body = request - const data = await send(params.pubDestination, {rpcName:'LinkNPubThroughToken',authIdentifier:auth, ...nostrRequest }) - if (data.status === 'ERROR' && typeof data.reason === 'string') return data - if (data.status === 'OK') { - return data - } - return { status: 'ERROR', reason: 'invalid response' } - }, - UserHealth: async (): Promise => { - const auth = await params.retrieveNostrUserAuth() - if (auth === null) throw new Error('retrieveNostrUserAuth() returned null') - const nostrRequest: NostrRequest = {} - const data = await send(params.pubDestination, {rpcName:'UserHealth',authIdentifier:auth, ...nostrRequest }) - if (data.status === 'ERROR' && typeof data.reason === 'string') return data - if (data.status === 'OK') { - return data - } - return { status: 'ERROR', reason: 'invalid response' } - }, - GetUserInfo: async (): Promise => { - const auth = await params.retrieveNostrUserAuth() - if (auth === null) throw new Error('retrieveNostrUserAuth() returned null') - const nostrRequest: NostrRequest = {} - const data = await send(params.pubDestination, {rpcName:'GetUserInfo',authIdentifier:auth, ...nostrRequest }) - if (data.status === 'ERROR' && typeof data.reason === 'string') return data - if (data.status === 'OK') { - const result = data - if(!params.checkResult) return { status: 'OK', ...result } - const error = Types.UserInfoValidate(result) - if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } - } - return { status: 'ERROR', reason: 'invalid response' } - }, - AddProduct: async (request: Types.AddProductRequest): Promise => { - const auth = await params.retrieveNostrUserAuth() - if (auth === null) throw new Error('retrieveNostrUserAuth() returned null') - const nostrRequest: NostrRequest = {} - nostrRequest.body = request - const data = await send(params.pubDestination, {rpcName:'AddProduct',authIdentifier:auth, ...nostrRequest }) - if (data.status === 'ERROR' && typeof data.reason === 'string') return data - if (data.status === 'OK') { - const result = data - if(!params.checkResult) return { status: 'OK', ...result } - const error = Types.ProductValidate(result) - if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } - } - return { status: 'ERROR', reason: 'invalid response' } - }, - NewProductInvoice: async (query: Types.NewProductInvoice_Query): Promise => { - const auth = await params.retrieveNostrUserAuth() - if (auth === null) throw new Error('retrieveNostrUserAuth() returned null') - const nostrRequest: NostrRequest = {} - nostrRequest.query = query - const data = await send(params.pubDestination, {rpcName:'NewProductInvoice',authIdentifier:auth, ...nostrRequest }) - if (data.status === 'ERROR' && typeof data.reason === 'string') return data - if (data.status === 'OK') { - const result = data - if(!params.checkResult) return { status: 'OK', ...result } - const error = Types.NewInvoiceResponseValidate(result) - if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } - } - return { status: 'ERROR', reason: 'invalid response' } - }, - GetUserOperations: async (request: Types.GetUserOperationsRequest): Promise => { - const auth = await params.retrieveNostrUserAuth() - if (auth === null) throw new Error('retrieveNostrUserAuth() returned null') - const nostrRequest: NostrRequest = {} - nostrRequest.body = request - const data = await send(params.pubDestination, {rpcName:'GetUserOperations',authIdentifier:auth, ...nostrRequest }) - if (data.status === 'ERROR' && typeof data.reason === 'string') return data - if (data.status === 'OK') { - const result = data - if(!params.checkResult) return { status: 'OK', ...result } - const error = Types.GetUserOperationsResponseValidate(result) - if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } - } - return { status: 'ERROR', reason: 'invalid response' } - }, - NewAddress: async (request: Types.NewAddressRequest): Promise => { - const auth = await params.retrieveNostrUserAuth() - if (auth === null) throw new Error('retrieveNostrUserAuth() returned null') - const nostrRequest: NostrRequest = {} - nostrRequest.body = request - const data = await send(params.pubDestination, {rpcName:'NewAddress',authIdentifier:auth, ...nostrRequest }) - if (data.status === 'ERROR' && typeof data.reason === 'string') return data - if (data.status === 'OK') { - const result = data - if(!params.checkResult) return { status: 'OK', ...result } - const error = Types.NewAddressResponseValidate(result) - if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } - } - return { status: 'ERROR', reason: 'invalid response' } - }, - PayAddress: async (request: Types.PayAddressRequest): Promise => { - const auth = await params.retrieveNostrUserAuth() - if (auth === null) throw new Error('retrieveNostrUserAuth() returned null') - const nostrRequest: NostrRequest = {} - nostrRequest.body = request - const data = await send(params.pubDestination, {rpcName:'PayAddress',authIdentifier:auth, ...nostrRequest }) - if (data.status === 'ERROR' && typeof data.reason === 'string') return data - if (data.status === 'OK') { - const result = data - if(!params.checkResult) return { status: 'OK', ...result } - const error = Types.PayAddressResponseValidate(result) - if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } - } - return { status: 'ERROR', reason: 'invalid response' } - }, - NewInvoice: async (request: Types.NewInvoiceRequest): Promise => { - const auth = await params.retrieveNostrUserAuth() - if (auth === null) throw new Error('retrieveNostrUserAuth() returned null') - const nostrRequest: NostrRequest = {} - nostrRequest.body = request - const data = await send(params.pubDestination, {rpcName:'NewInvoice',authIdentifier:auth, ...nostrRequest }) - if (data.status === 'ERROR' && typeof data.reason === 'string') return data - if (data.status === 'OK') { - const result = data - if(!params.checkResult) return { status: 'OK', ...result } - const error = Types.NewInvoiceResponseValidate(result) - if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } - } - return { status: 'ERROR', reason: 'invalid response' } - }, - DecodeInvoice: async (request: Types.DecodeInvoiceRequest): Promise => { - const auth = await params.retrieveNostrUserAuth() - if (auth === null) throw new Error('retrieveNostrUserAuth() returned null') - const nostrRequest: NostrRequest = {} - nostrRequest.body = request - const data = await send(params.pubDestination, {rpcName:'DecodeInvoice',authIdentifier:auth, ...nostrRequest }) - if (data.status === 'ERROR' && typeof data.reason === 'string') return data - if (data.status === 'OK') { - const result = data - if(!params.checkResult) return { status: 'OK', ...result } - const error = Types.DecodeInvoiceResponseValidate(result) - if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } - } - return { status: 'ERROR', reason: 'invalid response' } - }, - PayInvoice: async (request: Types.PayInvoiceRequest): Promise => { - const auth = await params.retrieveNostrUserAuth() - if (auth === null) throw new Error('retrieveNostrUserAuth() returned null') - const nostrRequest: NostrRequest = {} - nostrRequest.body = request - const data = await send(params.pubDestination, {rpcName:'PayInvoice',authIdentifier:auth, ...nostrRequest }) - if (data.status === 'ERROR' && typeof data.reason === 'string') return data - if (data.status === 'OK') { - const result = data - if(!params.checkResult) return { status: 'OK', ...result } - const error = Types.PayInvoiceResponseValidate(result) - if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } - } - return { status: 'ERROR', reason: 'invalid response' } - }, - OpenChannel: async (request: Types.OpenChannelRequest): Promise => { - const auth = await params.retrieveNostrUserAuth() - if (auth === null) throw new Error('retrieveNostrUserAuth() returned null') - const nostrRequest: NostrRequest = {} - nostrRequest.body = request - const data = await send(params.pubDestination, {rpcName:'OpenChannel',authIdentifier:auth, ...nostrRequest }) - if (data.status === 'ERROR' && typeof data.reason === 'string') return data - if (data.status === 'OK') { - const result = data - if(!params.checkResult) return { status: 'OK', ...result } - const error = Types.OpenChannelResponseValidate(result) - if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } - } - return { status: 'ERROR', reason: 'invalid response' } - }, - GetLnurlWithdrawLink: async (): Promise => { - const auth = await params.retrieveNostrUserAuth() - if (auth === null) throw new Error('retrieveNostrUserAuth() returned null') - const nostrRequest: NostrRequest = {} - const data = await send(params.pubDestination, {rpcName:'GetLnurlWithdrawLink',authIdentifier:auth, ...nostrRequest }) - if (data.status === 'ERROR' && typeof data.reason === 'string') return data - if (data.status === 'OK') { - const result = data - if(!params.checkResult) return { status: 'OK', ...result } - const error = Types.LnurlLinkResponseValidate(result) - if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } - } - return { status: 'ERROR', reason: 'invalid response' } - }, - GetLnurlPayLink: async (): Promise => { - const auth = await params.retrieveNostrUserAuth() - if (auth === null) throw new Error('retrieveNostrUserAuth() returned null') - const nostrRequest: NostrRequest = {} - const data = await send(params.pubDestination, {rpcName:'GetLnurlPayLink',authIdentifier:auth, ...nostrRequest }) - if (data.status === 'ERROR' && typeof data.reason === 'string') return data - if (data.status === 'OK') { - const result = data - if(!params.checkResult) return { status: 'OK', ...result } - const error = Types.LnurlLinkResponseValidate(result) - if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } - } - return { status: 'ERROR', reason: 'invalid response' } - }, - GetLNURLChannelLink: async (): Promise => { - const auth = await params.retrieveNostrUserAuth() - if (auth === null) throw new Error('retrieveNostrUserAuth() returned null') - const nostrRequest: NostrRequest = {} - const data = await send(params.pubDestination, {rpcName:'GetLNURLChannelLink',authIdentifier:auth, ...nostrRequest }) - if (data.status === 'ERROR' && typeof data.reason === 'string') return data - if (data.status === 'OK') { - const result = data - if(!params.checkResult) return { status: 'OK', ...result } - const error = Types.LnurlLinkResponseValidate(result) - if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } - } - return { status: 'ERROR', reason: 'invalid response' } - }, - GetLiveUserOperations: async (cb: (res:ResultError | ({ status: 'OK' }& Types.LiveUserOperation)) => void): Promise => { - const auth = await params.retrieveNostrUserAuth() - if (auth === null) throw new Error('retrieveNostrUserAuth() returned null') - const nostrRequest: NostrRequest = {} - subscribe(params.pubDestination, {rpcName:'GetLiveUserOperations',authIdentifier:auth, ...nostrRequest }, (data) => { - if (data.status === 'ERROR' && typeof data.reason === 'string') return cb(data) - if (data.status === 'OK') { - const result = data - if(!params.checkResult) return cb({ status: 'OK', ...result }) - const error = Types.LiveUserOperationValidate(result) - if (error === null) { return cb({ status: 'OK', ...result }) } else return cb({ status: 'ERROR', reason: error.message }) - } - return cb({ status: 'ERROR', reason: 'invalid response' }) - }) - }, - GetMigrationUpdate: async (cb: (res:ResultError | ({ status: 'OK' }& Types.MigrationUpdate)) => void): Promise => { - const auth = await params.retrieveNostrUserAuth() - if (auth === null) throw new Error('retrieveNostrUserAuth() returned null') - const nostrRequest: NostrRequest = {} - subscribe(params.pubDestination, {rpcName:'GetMigrationUpdate',authIdentifier:auth, ...nostrRequest }, (data) => { - if (data.status === 'ERROR' && typeof data.reason === 'string') return cb(data) - if (data.status === 'OK') { - const result = data - if(!params.checkResult) return cb({ status: 'OK', ...result }) - const error = Types.MigrationUpdateValidate(result) - if (error === null) { return cb({ status: 'OK', ...result }) } else return cb({ status: 'ERROR', reason: error.message }) - } - return cb({ status: 'ERROR', reason: 'invalid response' }) - }) - }, - GetHttpCreds: async (cb: (res:ResultError | ({ status: 'OK' }& Types.HttpCreds)) => void): Promise => { - const auth = await params.retrieveNostrUserAuth() - if (auth === null) throw new Error('retrieveNostrUserAuth() returned null') - const nostrRequest: NostrRequest = {} - subscribe(params.pubDestination, {rpcName:'GetHttpCreds',authIdentifier:auth, ...nostrRequest }, (data) => { - if (data.status === 'ERROR' && typeof data.reason === 'string') return cb(data) - if (data.status === 'OK') { - const result = data - if(!params.checkResult) return cb({ status: 'OK', ...result }) - const error = Types.HttpCredsValidate(result) - if (error === null) { return cb({ status: 'OK', ...result }) } else return cb({ status: 'ERROR', reason: error.message }) - } - return cb({ status: 'ERROR', reason: 'invalid response' }) - }) - }, - BatchUser: async (requests:Types.UserMethodInputs[]): Promise => { - const auth = await params.retrieveNostrUserAuth() - if (auth === null) throw new Error('retrieveNostrUserAuth() returned null') - const nostrRequest: NostrRequest = {body:{requests}} - const data = await send(params.pubDestination, {rpcName:'BatchUser',authIdentifier:auth, ...nostrRequest }) - if (data.status === 'ERROR' && typeof data.reason === 'string') return data - if (data.status === 'OK') { - return data - } - return { status: 'ERROR', reason: 'invalid response' } - } -}) +// This file was autogenerated from a .proto file, DO NOT EDIT! +import { NostrRequest } from './nostr_transport.js' +import * as Types from './types.js' +export type ResultError = { status: 'ERROR', reason: string } + +export type NostrClientParams = { + pubDestination: string + retrieveNostrAdminAuth: () => Promise + retrieveNostrMetricsAuth: () => Promise + retrieveNostrUserAuth: () => Promise + checkResult?: true +} +export default (params: NostrClientParams, send: (to:string, message: NostrRequest) => Promise, subscribe: (to:string, message: NostrRequest, cb:(res:any)=> void) => void) => ({ + LndGetInfo: async (request: Types.LndGetInfoRequest): Promise => { + const auth = await params.retrieveNostrAdminAuth() + if (auth === null) throw new Error('retrieveNostrAdminAuth() returned null') + const nostrRequest: NostrRequest = {} + nostrRequest.body = request + const data = await send(params.pubDestination, {rpcName:'LndGetInfo',authIdentifier:auth, ...nostrRequest }) + if (data.status === 'ERROR' && typeof data.reason === 'string') return data + if (data.status === 'OK') { + const result = data + if(!params.checkResult) return { status: 'OK', ...result } + const error = Types.LndGetInfoResponseValidate(result) + if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } + } + return { status: 'ERROR', reason: 'invalid response' } + }, + AddApp: async (request: Types.AddAppRequest): Promise => { + const auth = await params.retrieveNostrAdminAuth() + if (auth === null) throw new Error('retrieveNostrAdminAuth() returned null') + const nostrRequest: NostrRequest = {} + nostrRequest.body = request + const data = await send(params.pubDestination, {rpcName:'AddApp',authIdentifier:auth, ...nostrRequest }) + if (data.status === 'ERROR' && typeof data.reason === 'string') return data + if (data.status === 'OK') { + const result = data + if(!params.checkResult) return { status: 'OK', ...result } + const error = Types.AuthAppValidate(result) + if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } + } + return { status: 'ERROR', reason: 'invalid response' } + }, + AuthApp: async (request: Types.AuthAppRequest): Promise => { + const auth = await params.retrieveNostrAdminAuth() + if (auth === null) throw new Error('retrieveNostrAdminAuth() returned null') + const nostrRequest: NostrRequest = {} + nostrRequest.body = request + const data = await send(params.pubDestination, {rpcName:'AuthApp',authIdentifier:auth, ...nostrRequest }) + if (data.status === 'ERROR' && typeof data.reason === 'string') return data + if (data.status === 'OK') { + const result = data + if(!params.checkResult) return { status: 'OK', ...result } + const error = Types.AuthAppValidate(result) + if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } + } + return { status: 'ERROR', reason: 'invalid response' } + }, + BanUser: async (request: Types.BanUserRequest): Promise => { + const auth = await params.retrieveNostrAdminAuth() + if (auth === null) throw new Error('retrieveNostrAdminAuth() returned null') + const nostrRequest: NostrRequest = {} + nostrRequest.body = request + const data = await send(params.pubDestination, {rpcName:'BanUser',authIdentifier:auth, ...nostrRequest }) + if (data.status === 'ERROR' && typeof data.reason === 'string') return data + if (data.status === 'OK') { + const result = data + if(!params.checkResult) return { status: 'OK', ...result } + const error = Types.BanUserResponseValidate(result) + if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } + } + return { status: 'ERROR', reason: 'invalid response' } + }, + GetUsageMetrics: async (): Promise => { + const auth = await params.retrieveNostrMetricsAuth() + if (auth === null) throw new Error('retrieveNostrMetricsAuth() returned null') + const nostrRequest: NostrRequest = {} + const data = await send(params.pubDestination, {rpcName:'GetUsageMetrics',authIdentifier:auth, ...nostrRequest }) + if (data.status === 'ERROR' && typeof data.reason === 'string') return data + if (data.status === 'OK') { + const result = data + if(!params.checkResult) return { status: 'OK', ...result } + const error = Types.UsageMetricsValidate(result) + if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } + } + return { status: 'ERROR', reason: 'invalid response' } + }, + GetAppsMetrics: async (request: Types.AppsMetricsRequest): Promise => { + const auth = await params.retrieveNostrMetricsAuth() + if (auth === null) throw new Error('retrieveNostrMetricsAuth() returned null') + const nostrRequest: NostrRequest = {} + nostrRequest.body = request + const data = await send(params.pubDestination, {rpcName:'GetAppsMetrics',authIdentifier:auth, ...nostrRequest }) + if (data.status === 'ERROR' && typeof data.reason === 'string') return data + if (data.status === 'OK') { + const result = data + if(!params.checkResult) return { status: 'OK', ...result } + const error = Types.AppsMetricsValidate(result) + if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } + } + return { status: 'ERROR', reason: 'invalid response' } + }, + GetLndMetrics: async (request: Types.LndMetricsRequest): Promise => { + const auth = await params.retrieveNostrMetricsAuth() + if (auth === null) throw new Error('retrieveNostrMetricsAuth() returned null') + const nostrRequest: NostrRequest = {} + nostrRequest.body = request + const data = await send(params.pubDestination, {rpcName:'GetLndMetrics',authIdentifier:auth, ...nostrRequest }) + if (data.status === 'ERROR' && typeof data.reason === 'string') return data + if (data.status === 'OK') { + const result = data + if(!params.checkResult) return { status: 'OK', ...result } + const error = Types.LndMetricsValidate(result) + if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } + } + return { status: 'ERROR', reason: 'invalid response' } + }, + LinkNPubThroughToken: async (request: Types.LinkNPubThroughTokenRequest): Promise => { + const auth = await params.retrieveNostrUserAuth() + if (auth === null) throw new Error('retrieveNostrUserAuth() returned null') + const nostrRequest: NostrRequest = {} + nostrRequest.body = request + const data = await send(params.pubDestination, {rpcName:'LinkNPubThroughToken',authIdentifier:auth, ...nostrRequest }) + if (data.status === 'ERROR' && typeof data.reason === 'string') return data + if (data.status === 'OK') { + return data + } + return { status: 'ERROR', reason: 'invalid response' } + }, + EnrollAdminToken: async (request: Types.EnrollAdminTokenRequest): Promise => { + const auth = await params.retrieveNostrUserAuth() + if (auth === null) throw new Error('retrieveNostrUserAuth() returned null') + const nostrRequest: NostrRequest = {} + nostrRequest.body = request + const data = await send(params.pubDestination, {rpcName:'EnrollAdminToken',authIdentifier:auth, ...nostrRequest }) + if (data.status === 'ERROR' && typeof data.reason === 'string') return data + if (data.status === 'OK') { + return data + } + return { status: 'ERROR', reason: 'invalid response' } + }, + UserHealth: async (): Promise => { + const auth = await params.retrieveNostrUserAuth() + if (auth === null) throw new Error('retrieveNostrUserAuth() returned null') + const nostrRequest: NostrRequest = {} + const data = await send(params.pubDestination, {rpcName:'UserHealth',authIdentifier:auth, ...nostrRequest }) + if (data.status === 'ERROR' && typeof data.reason === 'string') return data + if (data.status === 'OK') { + return data + } + return { status: 'ERROR', reason: 'invalid response' } + }, + GetUserInfo: async (): Promise => { + const auth = await params.retrieveNostrUserAuth() + if (auth === null) throw new Error('retrieveNostrUserAuth() returned null') + const nostrRequest: NostrRequest = {} + const data = await send(params.pubDestination, {rpcName:'GetUserInfo',authIdentifier:auth, ...nostrRequest }) + if (data.status === 'ERROR' && typeof data.reason === 'string') return data + if (data.status === 'OK') { + const result = data + if(!params.checkResult) return { status: 'OK', ...result } + const error = Types.UserInfoValidate(result) + if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } + } + return { status: 'ERROR', reason: 'invalid response' } + }, + AddProduct: async (request: Types.AddProductRequest): Promise => { + const auth = await params.retrieveNostrUserAuth() + if (auth === null) throw new Error('retrieveNostrUserAuth() returned null') + const nostrRequest: NostrRequest = {} + nostrRequest.body = request + const data = await send(params.pubDestination, {rpcName:'AddProduct',authIdentifier:auth, ...nostrRequest }) + if (data.status === 'ERROR' && typeof data.reason === 'string') return data + if (data.status === 'OK') { + const result = data + if(!params.checkResult) return { status: 'OK', ...result } + const error = Types.ProductValidate(result) + if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } + } + return { status: 'ERROR', reason: 'invalid response' } + }, + NewProductInvoice: async (query: Types.NewProductInvoice_Query): Promise => { + const auth = await params.retrieveNostrUserAuth() + if (auth === null) throw new Error('retrieveNostrUserAuth() returned null') + const nostrRequest: NostrRequest = {} + nostrRequest.query = query + const data = await send(params.pubDestination, {rpcName:'NewProductInvoice',authIdentifier:auth, ...nostrRequest }) + if (data.status === 'ERROR' && typeof data.reason === 'string') return data + if (data.status === 'OK') { + const result = data + if(!params.checkResult) return { status: 'OK', ...result } + const error = Types.NewInvoiceResponseValidate(result) + if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } + } + return { status: 'ERROR', reason: 'invalid response' } + }, + GetUserOperations: async (request: Types.GetUserOperationsRequest): Promise => { + const auth = await params.retrieveNostrUserAuth() + if (auth === null) throw new Error('retrieveNostrUserAuth() returned null') + const nostrRequest: NostrRequest = {} + nostrRequest.body = request + const data = await send(params.pubDestination, {rpcName:'GetUserOperations',authIdentifier:auth, ...nostrRequest }) + if (data.status === 'ERROR' && typeof data.reason === 'string') return data + if (data.status === 'OK') { + const result = data + if(!params.checkResult) return { status: 'OK', ...result } + const error = Types.GetUserOperationsResponseValidate(result) + if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } + } + return { status: 'ERROR', reason: 'invalid response' } + }, + NewAddress: async (request: Types.NewAddressRequest): Promise => { + const auth = await params.retrieveNostrUserAuth() + if (auth === null) throw new Error('retrieveNostrUserAuth() returned null') + const nostrRequest: NostrRequest = {} + nostrRequest.body = request + const data = await send(params.pubDestination, {rpcName:'NewAddress',authIdentifier:auth, ...nostrRequest }) + if (data.status === 'ERROR' && typeof data.reason === 'string') return data + if (data.status === 'OK') { + const result = data + if(!params.checkResult) return { status: 'OK', ...result } + const error = Types.NewAddressResponseValidate(result) + if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } + } + return { status: 'ERROR', reason: 'invalid response' } + }, + PayAddress: async (request: Types.PayAddressRequest): Promise => { + const auth = await params.retrieveNostrUserAuth() + if (auth === null) throw new Error('retrieveNostrUserAuth() returned null') + const nostrRequest: NostrRequest = {} + nostrRequest.body = request + const data = await send(params.pubDestination, {rpcName:'PayAddress',authIdentifier:auth, ...nostrRequest }) + if (data.status === 'ERROR' && typeof data.reason === 'string') return data + if (data.status === 'OK') { + const result = data + if(!params.checkResult) return { status: 'OK', ...result } + const error = Types.PayAddressResponseValidate(result) + if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } + } + return { status: 'ERROR', reason: 'invalid response' } + }, + NewInvoice: async (request: Types.NewInvoiceRequest): Promise => { + const auth = await params.retrieveNostrUserAuth() + if (auth === null) throw new Error('retrieveNostrUserAuth() returned null') + const nostrRequest: NostrRequest = {} + nostrRequest.body = request + const data = await send(params.pubDestination, {rpcName:'NewInvoice',authIdentifier:auth, ...nostrRequest }) + if (data.status === 'ERROR' && typeof data.reason === 'string') return data + if (data.status === 'OK') { + const result = data + if(!params.checkResult) return { status: 'OK', ...result } + const error = Types.NewInvoiceResponseValidate(result) + if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } + } + return { status: 'ERROR', reason: 'invalid response' } + }, + DecodeInvoice: async (request: Types.DecodeInvoiceRequest): Promise => { + const auth = await params.retrieveNostrUserAuth() + if (auth === null) throw new Error('retrieveNostrUserAuth() returned null') + const nostrRequest: NostrRequest = {} + nostrRequest.body = request + const data = await send(params.pubDestination, {rpcName:'DecodeInvoice',authIdentifier:auth, ...nostrRequest }) + if (data.status === 'ERROR' && typeof data.reason === 'string') return data + if (data.status === 'OK') { + const result = data + if(!params.checkResult) return { status: 'OK', ...result } + const error = Types.DecodeInvoiceResponseValidate(result) + if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } + } + return { status: 'ERROR', reason: 'invalid response' } + }, + PayInvoice: async (request: Types.PayInvoiceRequest): Promise => { + const auth = await params.retrieveNostrUserAuth() + if (auth === null) throw new Error('retrieveNostrUserAuth() returned null') + const nostrRequest: NostrRequest = {} + nostrRequest.body = request + const data = await send(params.pubDestination, {rpcName:'PayInvoice',authIdentifier:auth, ...nostrRequest }) + if (data.status === 'ERROR' && typeof data.reason === 'string') return data + if (data.status === 'OK') { + const result = data + if(!params.checkResult) return { status: 'OK', ...result } + const error = Types.PayInvoiceResponseValidate(result) + if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } + } + return { status: 'ERROR', reason: 'invalid response' } + }, + OpenChannel: async (request: Types.OpenChannelRequest): Promise => { + const auth = await params.retrieveNostrUserAuth() + if (auth === null) throw new Error('retrieveNostrUserAuth() returned null') + const nostrRequest: NostrRequest = {} + nostrRequest.body = request + const data = await send(params.pubDestination, {rpcName:'OpenChannel',authIdentifier:auth, ...nostrRequest }) + if (data.status === 'ERROR' && typeof data.reason === 'string') return data + if (data.status === 'OK') { + const result = data + if(!params.checkResult) return { status: 'OK', ...result } + const error = Types.OpenChannelResponseValidate(result) + if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } + } + return { status: 'ERROR', reason: 'invalid response' } + }, + GetLnurlWithdrawLink: async (): Promise => { + const auth = await params.retrieveNostrUserAuth() + if (auth === null) throw new Error('retrieveNostrUserAuth() returned null') + const nostrRequest: NostrRequest = {} + const data = await send(params.pubDestination, {rpcName:'GetLnurlWithdrawLink',authIdentifier:auth, ...nostrRequest }) + if (data.status === 'ERROR' && typeof data.reason === 'string') return data + if (data.status === 'OK') { + const result = data + if(!params.checkResult) return { status: 'OK', ...result } + const error = Types.LnurlLinkResponseValidate(result) + if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } + } + return { status: 'ERROR', reason: 'invalid response' } + }, + GetLnurlPayLink: async (): Promise => { + const auth = await params.retrieveNostrUserAuth() + if (auth === null) throw new Error('retrieveNostrUserAuth() returned null') + const nostrRequest: NostrRequest = {} + const data = await send(params.pubDestination, {rpcName:'GetLnurlPayLink',authIdentifier:auth, ...nostrRequest }) + if (data.status === 'ERROR' && typeof data.reason === 'string') return data + if (data.status === 'OK') { + const result = data + if(!params.checkResult) return { status: 'OK', ...result } + const error = Types.LnurlLinkResponseValidate(result) + if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } + } + return { status: 'ERROR', reason: 'invalid response' } + }, + GetLNURLChannelLink: async (): Promise => { + const auth = await params.retrieveNostrUserAuth() + if (auth === null) throw new Error('retrieveNostrUserAuth() returned null') + const nostrRequest: NostrRequest = {} + const data = await send(params.pubDestination, {rpcName:'GetLNURLChannelLink',authIdentifier:auth, ...nostrRequest }) + if (data.status === 'ERROR' && typeof data.reason === 'string') return data + if (data.status === 'OK') { + const result = data + if(!params.checkResult) return { status: 'OK', ...result } + const error = Types.LnurlLinkResponseValidate(result) + if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } + } + return { status: 'ERROR', reason: 'invalid response' } + }, + GetLiveUserOperations: async (cb: (res:ResultError | ({ status: 'OK' }& Types.LiveUserOperation)) => void): Promise => { + const auth = await params.retrieveNostrUserAuth() + if (auth === null) throw new Error('retrieveNostrUserAuth() returned null') + const nostrRequest: NostrRequest = {} + subscribe(params.pubDestination, {rpcName:'GetLiveUserOperations',authIdentifier:auth, ...nostrRequest }, (data) => { + if (data.status === 'ERROR' && typeof data.reason === 'string') return cb(data) + if (data.status === 'OK') { + const result = data + if(!params.checkResult) return cb({ status: 'OK', ...result }) + const error = Types.LiveUserOperationValidate(result) + if (error === null) { return cb({ status: 'OK', ...result }) } else return cb({ status: 'ERROR', reason: error.message }) + } + return cb({ status: 'ERROR', reason: 'invalid response' }) + }) + }, + GetMigrationUpdate: async (cb: (res:ResultError | ({ status: 'OK' }& Types.MigrationUpdate)) => void): Promise => { + const auth = await params.retrieveNostrUserAuth() + if (auth === null) throw new Error('retrieveNostrUserAuth() returned null') + const nostrRequest: NostrRequest = {} + subscribe(params.pubDestination, {rpcName:'GetMigrationUpdate',authIdentifier:auth, ...nostrRequest }, (data) => { + if (data.status === 'ERROR' && typeof data.reason === 'string') return cb(data) + if (data.status === 'OK') { + const result = data + if(!params.checkResult) return cb({ status: 'OK', ...result }) + const error = Types.MigrationUpdateValidate(result) + if (error === null) { return cb({ status: 'OK', ...result }) } else return cb({ status: 'ERROR', reason: error.message }) + } + return cb({ status: 'ERROR', reason: 'invalid response' }) + }) + }, + GetHttpCreds: async (cb: (res:ResultError | ({ status: 'OK' }& Types.HttpCreds)) => void): Promise => { + const auth = await params.retrieveNostrUserAuth() + if (auth === null) throw new Error('retrieveNostrUserAuth() returned null') + const nostrRequest: NostrRequest = {} + subscribe(params.pubDestination, {rpcName:'GetHttpCreds',authIdentifier:auth, ...nostrRequest }, (data) => { + if (data.status === 'ERROR' && typeof data.reason === 'string') return cb(data) + if (data.status === 'OK') { + const result = data + if(!params.checkResult) return cb({ status: 'OK', ...result }) + const error = Types.HttpCredsValidate(result) + if (error === null) { return cb({ status: 'OK', ...result }) } else return cb({ status: 'ERROR', reason: error.message }) + } + return cb({ status: 'ERROR', reason: 'invalid response' }) + }) + }, + BatchUser: async (requests:Types.UserMethodInputs[]): Promise => { + const auth = await params.retrieveNostrUserAuth() + if (auth === null) throw new Error('retrieveNostrUserAuth() returned null') + const nostrRequest: NostrRequest = {body:{requests}} + const data = await send(params.pubDestination, {rpcName:'BatchUser',authIdentifier:auth, ...nostrRequest }) + if (data.status === 'ERROR' && typeof data.reason === 'string') return data + if (data.status === 'OK') { + return data + } + return { status: 'ERROR', reason: 'invalid response' } + } +}) diff --git a/proto/autogenerated/ts/nostr_transport.ts b/proto/autogenerated/ts/nostr_transport.ts index 6efa5a43..c73cd74d 100644 --- a/proto/autogenerated/ts/nostr_transport.ts +++ b/proto/autogenerated/ts/nostr_transport.ts @@ -1,499 +1,632 @@ -// This file was autogenerated from a .proto file, DO NOT EDIT! - -import * as Types from './types.js' -export type Logger = { log: (v: any) => void, error: (v: any) => void } -type NostrResponse = (message: object) => void -export type NostrRequest = { - rpcName?: string - params?: Record - query?: Record - body?: any - authIdentifier?: string - requestId?: string - appId?: string -} -export type NostrOptions = { - logger?: Logger - throwErrors?: true - metricsCallback: (metrics: Types.RequestMetric[]) => void - NostrUserAuthGuard: (appId?: string, identifier?: string) => Promise -} -const logErrorAndReturnResponse = (error: Error, response: string, res: NostrResponse, logger: Logger, metric: Types.RequestMetric, metricsCallback: (metrics: Types.RequestMetric[]) => void) => { - logger.error(error.message || error); metricsCallback([{ ...metric, error: response }]); res({ status: 'ERROR', reason: response }) -} -export default (methods: Types.ServerMethods, opts: NostrOptions) => { - const logger = opts.logger || { log: console.log, error: console.error } - return async (req: NostrRequest, res: NostrResponse, startString: string, startMs: number) => { - const startTime = BigInt(startString) - const info: Types.RequestInfo = { rpcName: req.rpcName || 'unkown', batch: false, nostr: true, batchSize: 0 } - const stats: Types.RequestStats = { startMs, start: startTime, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } - let authCtx: Types.AuthContext = {} - switch (req.rpcName) { - case 'LinkNPubThroughToken': - try { - if (!methods.LinkNPubThroughToken) throw new Error('method: LinkNPubThroughToken is not implemented') - const authContext = await opts.NostrUserAuthGuard(req.appId, req.authIdentifier) - stats.guard = process.hrtime.bigint() - authCtx = authContext - const request = req.body - const error = Types.LinkNPubThroughTokenRequestValidate(request) - stats.validate = process.hrtime.bigint() - if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback) - await methods.LinkNPubThroughToken({ rpcName: 'LinkNPubThroughToken', ctx: authContext, req: request }) - stats.handle = process.hrtime.bigint() - res({ status: 'OK' }) - opts.metricsCallback([{ ...info, ...stats, ...authContext }]) - } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } - break - case 'UserHealth': - try { - if (!methods.UserHealth) throw new Error('method: UserHealth is not implemented') - const authContext = await opts.NostrUserAuthGuard(req.appId, req.authIdentifier) - stats.guard = process.hrtime.bigint() - authCtx = authContext - stats.validate = stats.guard - await methods.UserHealth({ rpcName: 'UserHealth', ctx: authContext }) - stats.handle = process.hrtime.bigint() - res({ status: 'OK' }) - opts.metricsCallback([{ ...info, ...stats, ...authContext }]) - } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } - break - case 'GetUserInfo': - try { - if (!methods.GetUserInfo) throw new Error('method: GetUserInfo is not implemented') - const authContext = await opts.NostrUserAuthGuard(req.appId, req.authIdentifier) - stats.guard = process.hrtime.bigint() - authCtx = authContext - stats.validate = stats.guard - const response = await methods.GetUserInfo({ rpcName: 'GetUserInfo', ctx: authContext }) - stats.handle = process.hrtime.bigint() - res({ status: 'OK', ...response }) - opts.metricsCallback([{ ...info, ...stats, ...authContext }]) - } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } - break - case 'AddProduct': - try { - if (!methods.AddProduct) throw new Error('method: AddProduct is not implemented') - const authContext = await opts.NostrUserAuthGuard(req.appId, req.authIdentifier) - stats.guard = process.hrtime.bigint() - authCtx = authContext - const request = req.body - const error = Types.AddProductRequestValidate(request) - stats.validate = process.hrtime.bigint() - if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback) - const response = await methods.AddProduct({ rpcName: 'AddProduct', ctx: authContext, req: request }) - stats.handle = process.hrtime.bigint() - res({ status: 'OK', ...response }) - opts.metricsCallback([{ ...info, ...stats, ...authContext }]) - } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } - break - case 'NewProductInvoice': - try { - if (!methods.NewProductInvoice) throw new Error('method: NewProductInvoice is not implemented') - const authContext = await opts.NostrUserAuthGuard(req.appId, req.authIdentifier) - stats.guard = process.hrtime.bigint() - authCtx = authContext - stats.validate = stats.guard - const response = await methods.NewProductInvoice({ rpcName: 'NewProductInvoice', ctx: authContext, query: req.query || {} }) - stats.handle = process.hrtime.bigint() - res({ status: 'OK', ...response }) - opts.metricsCallback([{ ...info, ...stats, ...authContext }]) - } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } - break - case 'GetUserOperations': - try { - if (!methods.GetUserOperations) throw new Error('method: GetUserOperations is not implemented') - const authContext = await opts.NostrUserAuthGuard(req.appId, req.authIdentifier) - stats.guard = process.hrtime.bigint() - authCtx = authContext - const request = req.body - const error = Types.GetUserOperationsRequestValidate(request) - stats.validate = process.hrtime.bigint() - if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback) - const response = await methods.GetUserOperations({ rpcName: 'GetUserOperations', ctx: authContext, req: request }) - stats.handle = process.hrtime.bigint() - res({ status: 'OK', ...response }) - opts.metricsCallback([{ ...info, ...stats, ...authContext }]) - } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } - break - case 'NewAddress': - try { - if (!methods.NewAddress) throw new Error('method: NewAddress is not implemented') - const authContext = await opts.NostrUserAuthGuard(req.appId, req.authIdentifier) - stats.guard = process.hrtime.bigint() - authCtx = authContext - const request = req.body - const error = Types.NewAddressRequestValidate(request) - stats.validate = process.hrtime.bigint() - if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback) - const response = await methods.NewAddress({ rpcName: 'NewAddress', ctx: authContext, req: request }) - stats.handle = process.hrtime.bigint() - res({ status: 'OK', ...response }) - opts.metricsCallback([{ ...info, ...stats, ...authContext }]) - } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } - break - case 'PayAddress': - try { - if (!methods.PayAddress) throw new Error('method: PayAddress is not implemented') - const authContext = await opts.NostrUserAuthGuard(req.appId, req.authIdentifier) - stats.guard = process.hrtime.bigint() - authCtx = authContext - const request = req.body - const error = Types.PayAddressRequestValidate(request) - stats.validate = process.hrtime.bigint() - if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback) - const response = await methods.PayAddress({ rpcName: 'PayAddress', ctx: authContext, req: request }) - stats.handle = process.hrtime.bigint() - res({ status: 'OK', ...response }) - opts.metricsCallback([{ ...info, ...stats, ...authContext }]) - } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } - break - case 'NewInvoice': - try { - if (!methods.NewInvoice) throw new Error('method: NewInvoice is not implemented') - const authContext = await opts.NostrUserAuthGuard(req.appId, req.authIdentifier) - stats.guard = process.hrtime.bigint() - authCtx = authContext - const request = req.body - const error = Types.NewInvoiceRequestValidate(request) - stats.validate = process.hrtime.bigint() - if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback) - const response = await methods.NewInvoice({ rpcName: 'NewInvoice', ctx: authContext, req: request }) - stats.handle = process.hrtime.bigint() - res({ status: 'OK', ...response }) - opts.metricsCallback([{ ...info, ...stats, ...authContext }]) - } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } - break - case 'DecodeInvoice': - try { - if (!methods.DecodeInvoice) throw new Error('method: DecodeInvoice is not implemented') - const authContext = await opts.NostrUserAuthGuard(req.appId, req.authIdentifier) - stats.guard = process.hrtime.bigint() - authCtx = authContext - const request = req.body - const error = Types.DecodeInvoiceRequestValidate(request) - stats.validate = process.hrtime.bigint() - if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback) - const response = await methods.DecodeInvoice({ rpcName: 'DecodeInvoice', ctx: authContext, req: request }) - stats.handle = process.hrtime.bigint() - res({ status: 'OK', ...response }) - opts.metricsCallback([{ ...info, ...stats, ...authContext }]) - } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } - break - case 'PayInvoice': - try { - if (!methods.PayInvoice) throw new Error('method: PayInvoice is not implemented') - const authContext = await opts.NostrUserAuthGuard(req.appId, req.authIdentifier) - stats.guard = process.hrtime.bigint() - authCtx = authContext - const request = req.body - const error = Types.PayInvoiceRequestValidate(request) - stats.validate = process.hrtime.bigint() - if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback) - const response = await methods.PayInvoice({ rpcName: 'PayInvoice', ctx: authContext, req: request }) - stats.handle = process.hrtime.bigint() - res({ status: 'OK', ...response }) - opts.metricsCallback([{ ...info, ...stats, ...authContext }]) - } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } - break - case 'OpenChannel': - try { - if (!methods.OpenChannel) throw new Error('method: OpenChannel is not implemented') - const authContext = await opts.NostrUserAuthGuard(req.appId, req.authIdentifier) - stats.guard = process.hrtime.bigint() - authCtx = authContext - const request = req.body - const error = Types.OpenChannelRequestValidate(request) - stats.validate = process.hrtime.bigint() - if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback) - const response = await methods.OpenChannel({ rpcName: 'OpenChannel', ctx: authContext, req: request }) - stats.handle = process.hrtime.bigint() - res({ status: 'OK', ...response }) - opts.metricsCallback([{ ...info, ...stats, ...authContext }]) - } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } - break - case 'GetLnurlWithdrawLink': - try { - if (!methods.GetLnurlWithdrawLink) throw new Error('method: GetLnurlWithdrawLink is not implemented') - const authContext = await opts.NostrUserAuthGuard(req.appId, req.authIdentifier) - stats.guard = process.hrtime.bigint() - authCtx = authContext - stats.validate = stats.guard - const response = await methods.GetLnurlWithdrawLink({ rpcName: 'GetLnurlWithdrawLink', ctx: authContext }) - stats.handle = process.hrtime.bigint() - res({ status: 'OK', ...response }) - opts.metricsCallback([{ ...info, ...stats, ...authContext }]) - } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } - break - case 'GetLnurlPayLink': - try { - if (!methods.GetLnurlPayLink) throw new Error('method: GetLnurlPayLink is not implemented') - const authContext = await opts.NostrUserAuthGuard(req.appId, req.authIdentifier) - stats.guard = process.hrtime.bigint() - authCtx = authContext - stats.validate = stats.guard - const response = await methods.GetLnurlPayLink({ rpcName: 'GetLnurlPayLink', ctx: authContext }) - stats.handle = process.hrtime.bigint() - res({ status: 'OK', ...response }) - opts.metricsCallback([{ ...info, ...stats, ...authContext }]) - } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } - break - case 'GetLNURLChannelLink': - try { - if (!methods.GetLNURLChannelLink) throw new Error('method: GetLNURLChannelLink is not implemented') - const authContext = await opts.NostrUserAuthGuard(req.appId, req.authIdentifier) - stats.guard = process.hrtime.bigint() - authCtx = authContext - stats.validate = stats.guard - const response = await methods.GetLNURLChannelLink({ rpcName: 'GetLNURLChannelLink', ctx: authContext }) - stats.handle = process.hrtime.bigint() - res({ status: 'OK', ...response }) - opts.metricsCallback([{ ...info, ...stats, ...authContext }]) - } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } - break - case 'GetLiveUserOperations': - try { - if (!methods.GetLiveUserOperations) throw new Error('method: GetLiveUserOperations is not implemented') - const authContext = await opts.NostrUserAuthGuard(req.appId, req.authIdentifier) - stats.guard = process.hrtime.bigint() - authCtx = authContext - stats.validate = stats.guard - methods.GetLiveUserOperations({ - rpcName: 'GetLiveUserOperations', ctx: authContext, cb: (response, err) => { - stats.handle = process.hrtime.bigint() - if (err) { logErrorAndReturnResponse(err, err.message, res, logger, { ...info, ...stats, ...authContext }, opts.metricsCallback) } else { res({ status: 'OK', ...response }); opts.metricsCallback([{ ...info, ...stats, ...authContext }]) } - } - }) - } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } - break - case 'GetMigrationUpdate': - try { - if (!methods.GetMigrationUpdate) throw new Error('method: GetMigrationUpdate is not implemented') - const authContext = await opts.NostrUserAuthGuard(req.appId, req.authIdentifier) - stats.guard = process.hrtime.bigint() - authCtx = authContext - stats.validate = stats.guard - methods.GetMigrationUpdate({ - rpcName: 'GetMigrationUpdate', ctx: authContext, cb: (response, err) => { - stats.handle = process.hrtime.bigint() - if (err) { logErrorAndReturnResponse(err, err.message, res, logger, { ...info, ...stats, ...authContext }, opts.metricsCallback) } else { res({ status: 'OK', ...response }); opts.metricsCallback([{ ...info, ...stats, ...authContext }]) } - } - }) - } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } - break - case 'GetHttpCreds': - try { - if (!methods.GetHttpCreds) throw new Error('method: GetHttpCreds is not implemented') - const authContext = await opts.NostrUserAuthGuard(req.appId, req.authIdentifier) - stats.guard = process.hrtime.bigint() - authCtx = authContext - stats.validate = stats.guard - methods.GetHttpCreds({ - rpcName: 'GetHttpCreds', ctx: authContext, cb: (response, err) => { - stats.handle = process.hrtime.bigint() - if (err) { logErrorAndReturnResponse(err, err.message, res, logger, { ...info, ...stats, ...authContext }, opts.metricsCallback) } else { res({ status: 'OK', ...response }); opts.metricsCallback([{ ...info, ...stats, ...authContext }]) } - } - }) - } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } - break - case 'BatchUser': - try { - info.batch = true - const requests = req.body.requests as Types.UserMethodInputs[] - if (!Array.isArray(requests)) throw new Error('invalid body, is not an array') - info.batchSize = requests.length - if (requests.length > 10) throw new Error('too many requests in the batch') - const ctx = await opts.NostrUserAuthGuard(req.appId, req.authIdentifier) - stats.guard = process.hrtime.bigint() - authCtx = ctx - stats.validate = stats.guard - const responses = [] - const callsMetrics: Types.RequestMetric[] = [] - for (let i = 0; i < requests.length; i++) { - const operation = requests[i] - const opInfo: Types.RequestInfo = { rpcName: operation.rpcName, batch: true, nostr: true, batchSize: 0 } - const opStats: Types.RequestStats = { startMs, start: startTime, parse: stats.parse, guard: stats.guard, validate: 0n, handle: 0n } - try { - switch (operation.rpcName) { - case 'LinkNPubThroughToken': - if (!methods.LinkNPubThroughToken) { - throw new Error('method not defined: LinkNPubThroughToken') - } else { - const error = Types.LinkNPubThroughTokenRequestValidate(operation.req) - opStats.validate = process.hrtime.bigint() - if (error !== null) throw error - await methods.LinkNPubThroughToken({ ...operation, ctx }); responses.push({ status: 'OK' }) - opStats.handle = process.hrtime.bigint() - callsMetrics.push({ ...opInfo, ...opStats, ...ctx }) - } - break - case 'UserHealth': - if (!methods.UserHealth) { - throw new Error('method not defined: UserHealth') - } else { - opStats.validate = opStats.guard - await methods.UserHealth({ ...operation, ctx }); responses.push({ status: 'OK' }) - opStats.handle = process.hrtime.bigint() - callsMetrics.push({ ...opInfo, ...opStats, ...ctx }) - } - break - case 'GetUserInfo': - if (!methods.GetUserInfo) { - throw new Error('method not defined: GetUserInfo') - } else { - opStats.validate = opStats.guard - const res = await methods.GetUserInfo({ ...operation, ctx }); responses.push({ status: 'OK', ...res }) - opStats.handle = process.hrtime.bigint() - callsMetrics.push({ ...opInfo, ...opStats, ...ctx }) - } - break - case 'AddProduct': - if (!methods.AddProduct) { - throw new Error('method not defined: AddProduct') - } else { - const error = Types.AddProductRequestValidate(operation.req) - opStats.validate = process.hrtime.bigint() - if (error !== null) throw error - const res = await methods.AddProduct({ ...operation, ctx }); responses.push({ status: 'OK', ...res }) - opStats.handle = process.hrtime.bigint() - callsMetrics.push({ ...opInfo, ...opStats, ...ctx }) - } - break - case 'NewProductInvoice': - if (!methods.NewProductInvoice) { - throw new Error('method not defined: NewProductInvoice') - } else { - opStats.validate = opStats.guard - const res = await methods.NewProductInvoice({ ...operation, ctx }); responses.push({ status: 'OK', ...res }) - opStats.handle = process.hrtime.bigint() - callsMetrics.push({ ...opInfo, ...opStats, ...ctx }) - } - break - case 'GetUserOperations': - if (!methods.GetUserOperations) { - throw new Error('method not defined: GetUserOperations') - } else { - const error = Types.GetUserOperationsRequestValidate(operation.req) - opStats.validate = process.hrtime.bigint() - if (error !== null) throw error - const res = await methods.GetUserOperations({ ...operation, ctx }); responses.push({ status: 'OK', ...res }) - opStats.handle = process.hrtime.bigint() - callsMetrics.push({ ...opInfo, ...opStats, ...ctx }) - } - break - case 'NewAddress': - if (!methods.NewAddress) { - throw new Error('method not defined: NewAddress') - } else { - const error = Types.NewAddressRequestValidate(operation.req) - opStats.validate = process.hrtime.bigint() - if (error !== null) throw error - const res = await methods.NewAddress({ ...operation, ctx }); responses.push({ status: 'OK', ...res }) - opStats.handle = process.hrtime.bigint() - callsMetrics.push({ ...opInfo, ...opStats, ...ctx }) - } - break - case 'PayAddress': - if (!methods.PayAddress) { - throw new Error('method not defined: PayAddress') - } else { - const error = Types.PayAddressRequestValidate(operation.req) - opStats.validate = process.hrtime.bigint() - if (error !== null) throw error - const res = await methods.PayAddress({ ...operation, ctx }); responses.push({ status: 'OK', ...res }) - opStats.handle = process.hrtime.bigint() - callsMetrics.push({ ...opInfo, ...opStats, ...ctx }) - } - break - case 'NewInvoice': - if (!methods.NewInvoice) { - throw new Error('method not defined: NewInvoice') - } else { - const error = Types.NewInvoiceRequestValidate(operation.req) - opStats.validate = process.hrtime.bigint() - if (error !== null) throw error - const res = await methods.NewInvoice({ ...operation, ctx }); responses.push({ status: 'OK', ...res }) - opStats.handle = process.hrtime.bigint() - callsMetrics.push({ ...opInfo, ...opStats, ...ctx }) - } - break - case 'DecodeInvoice': - if (!methods.DecodeInvoice) { - throw new Error('method not defined: DecodeInvoice') - } else { - const error = Types.DecodeInvoiceRequestValidate(operation.req) - opStats.validate = process.hrtime.bigint() - if (error !== null) throw error - const res = await methods.DecodeInvoice({ ...operation, ctx }); responses.push({ status: 'OK', ...res }) - opStats.handle = process.hrtime.bigint() - callsMetrics.push({ ...opInfo, ...opStats, ...ctx }) - } - break - case 'PayInvoice': - if (!methods.PayInvoice) { - throw new Error('method not defined: PayInvoice') - } else { - const error = Types.PayInvoiceRequestValidate(operation.req) - opStats.validate = process.hrtime.bigint() - if (error !== null) throw error - const res = await methods.PayInvoice({ ...operation, ctx }); responses.push({ status: 'OK', ...res }) - opStats.handle = process.hrtime.bigint() - callsMetrics.push({ ...opInfo, ...opStats, ...ctx }) - } - break - case 'OpenChannel': - if (!methods.OpenChannel) { - throw new Error('method not defined: OpenChannel') - } else { - const error = Types.OpenChannelRequestValidate(operation.req) - opStats.validate = process.hrtime.bigint() - if (error !== null) throw error - const res = await methods.OpenChannel({ ...operation, ctx }); responses.push({ status: 'OK', ...res }) - opStats.handle = process.hrtime.bigint() - callsMetrics.push({ ...opInfo, ...opStats, ...ctx }) - } - break - case 'GetLnurlWithdrawLink': - if (!methods.GetLnurlWithdrawLink) { - throw new Error('method not defined: GetLnurlWithdrawLink') - } else { - opStats.validate = opStats.guard - const res = await methods.GetLnurlWithdrawLink({ ...operation, ctx }); responses.push({ status: 'OK', ...res }) - opStats.handle = process.hrtime.bigint() - callsMetrics.push({ ...opInfo, ...opStats, ...ctx }) - } - break - case 'GetLnurlPayLink': - if (!methods.GetLnurlPayLink) { - throw new Error('method not defined: GetLnurlPayLink') - } else { - opStats.validate = opStats.guard - const res = await methods.GetLnurlPayLink({ ...operation, ctx }); responses.push({ status: 'OK', ...res }) - opStats.handle = process.hrtime.bigint() - callsMetrics.push({ ...opInfo, ...opStats, ...ctx }) - } - break - case 'GetLNURLChannelLink': - if (!methods.GetLNURLChannelLink) { - throw new Error('method not defined: GetLNURLChannelLink') - } else { - opStats.validate = opStats.guard - const res = await methods.GetLNURLChannelLink({ ...operation, ctx }); responses.push({ status: 'OK', ...res }) - opStats.handle = process.hrtime.bigint() - callsMetrics.push({ ...opInfo, ...opStats, ...ctx }) - } - break - default: - throw new Error('unkown rpcName') - } - } catch (ex) { const e = ex as any; logger.error(e.message || e); callsMetrics.push({ ...opInfo, ...opStats, ...ctx, error: e.message }); responses.push({ status: 'ERROR', reason: e.message || e }) } - } - stats.handle = process.hrtime.bigint() - res({ status: 'OK', responses }) - opts.metricsCallback([{ ...info, ...stats, ...ctx }, ...callsMetrics]) - } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } - break - default: logger.error('unknown rpc call name from nostr event:' + req.rpcName) - } - } -} +// This file was autogenerated from a .proto file, DO NOT EDIT! + +import * as Types from './types.js' +export type Logger = { log: (v: any) => void, error: (v: any) => void } +type NostrResponse = (message: object) => void +export type NostrRequest = { + rpcName?: string + params?: Record + query?: Record + body?: any + authIdentifier?: string + requestId?: string + appId?: string +} +export type NostrOptions = { + logger?: Logger + throwErrors?: true + metricsCallback: (metrics: Types.RequestMetric[]) => void + NostrAdminAuthGuard: (appId?:string, identifier?: string) => Promise + NostrMetricsAuthGuard: (appId?:string, identifier?: string) => Promise + NostrUserAuthGuard: (appId?:string, identifier?: string) => Promise +} +const logErrorAndReturnResponse = (error: Error, response: string, res: NostrResponse, logger: Logger, metric: Types.RequestMetric, metricsCallback: (metrics: Types.RequestMetric[]) => void) => { + logger.error(error.message || error); metricsCallback([{ ...metric, error: response }]); res({ status: 'ERROR', reason: response }) +} +export default (methods: Types.ServerMethods, opts: NostrOptions) => { + const logger = opts.logger || { log: console.log, error: console.error } + return async (req: NostrRequest, res: NostrResponse, startString: string, startMs: number) => { + const startTime = BigInt(startString) + const info: Types.RequestInfo = { rpcName: req.rpcName || 'unkown', batch: false, nostr: true, batchSize: 0 } + const stats: Types.RequestStats = { startMs, start: startTime, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } + let authCtx: Types.AuthContext = {} + switch (req.rpcName) { + case 'LndGetInfo': + try { + if (!methods.LndGetInfo) throw new Error('method: LndGetInfo is not implemented') + const authContext = await opts.NostrAdminAuthGuard(req.appId, req.authIdentifier) + stats.guard = process.hrtime.bigint() + authCtx = authContext + const request = req.body + const error = Types.LndGetInfoRequestValidate(request) + stats.validate = process.hrtime.bigint() + if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback) + const response = await methods.LndGetInfo({rpcName:'LndGetInfo', ctx:authContext , req: request}) + stats.handle = process.hrtime.bigint() + res({status: 'OK', ...response}) + opts.metricsCallback([{ ...info, ...stats, ...authContext }]) + }catch(ex){ const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } + break + case 'AddApp': + try { + if (!methods.AddApp) throw new Error('method: AddApp is not implemented') + const authContext = await opts.NostrAdminAuthGuard(req.appId, req.authIdentifier) + stats.guard = process.hrtime.bigint() + authCtx = authContext + const request = req.body + const error = Types.AddAppRequestValidate(request) + stats.validate = process.hrtime.bigint() + if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback) + const response = await methods.AddApp({rpcName:'AddApp', ctx:authContext , req: request}) + stats.handle = process.hrtime.bigint() + res({status: 'OK', ...response}) + opts.metricsCallback([{ ...info, ...stats, ...authContext }]) + }catch(ex){ const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } + break + case 'AuthApp': + try { + if (!methods.AuthApp) throw new Error('method: AuthApp is not implemented') + const authContext = await opts.NostrAdminAuthGuard(req.appId, req.authIdentifier) + stats.guard = process.hrtime.bigint() + authCtx = authContext + const request = req.body + const error = Types.AuthAppRequestValidate(request) + stats.validate = process.hrtime.bigint() + if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback) + const response = await methods.AuthApp({rpcName:'AuthApp', ctx:authContext , req: request}) + stats.handle = process.hrtime.bigint() + res({status: 'OK', ...response}) + opts.metricsCallback([{ ...info, ...stats, ...authContext }]) + }catch(ex){ const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } + break + case 'BanUser': + try { + if (!methods.BanUser) throw new Error('method: BanUser is not implemented') + const authContext = await opts.NostrAdminAuthGuard(req.appId, req.authIdentifier) + stats.guard = process.hrtime.bigint() + authCtx = authContext + const request = req.body + const error = Types.BanUserRequestValidate(request) + stats.validate = process.hrtime.bigint() + if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback) + const response = await methods.BanUser({rpcName:'BanUser', ctx:authContext , req: request}) + stats.handle = process.hrtime.bigint() + res({status: 'OK', ...response}) + opts.metricsCallback([{ ...info, ...stats, ...authContext }]) + }catch(ex){ const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } + break + case 'GetUsageMetrics': + try { + if (!methods.GetUsageMetrics) throw new Error('method: GetUsageMetrics is not implemented') + const authContext = await opts.NostrMetricsAuthGuard(req.appId, req.authIdentifier) + stats.guard = process.hrtime.bigint() + authCtx = authContext + stats.validate = stats.guard + const response = await methods.GetUsageMetrics({rpcName:'GetUsageMetrics', ctx:authContext }) + stats.handle = process.hrtime.bigint() + res({status: 'OK', ...response}) + opts.metricsCallback([{ ...info, ...stats, ...authContext }]) + }catch(ex){ const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } + break + case 'GetAppsMetrics': + try { + if (!methods.GetAppsMetrics) throw new Error('method: GetAppsMetrics is not implemented') + const authContext = await opts.NostrMetricsAuthGuard(req.appId, req.authIdentifier) + stats.guard = process.hrtime.bigint() + authCtx = authContext + const request = req.body + const error = Types.AppsMetricsRequestValidate(request) + stats.validate = process.hrtime.bigint() + if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback) + const response = await methods.GetAppsMetrics({rpcName:'GetAppsMetrics', ctx:authContext , req: request}) + stats.handle = process.hrtime.bigint() + res({status: 'OK', ...response}) + opts.metricsCallback([{ ...info, ...stats, ...authContext }]) + }catch(ex){ const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } + break + case 'GetLndMetrics': + try { + if (!methods.GetLndMetrics) throw new Error('method: GetLndMetrics is not implemented') + const authContext = await opts.NostrMetricsAuthGuard(req.appId, req.authIdentifier) + stats.guard = process.hrtime.bigint() + authCtx = authContext + const request = req.body + const error = Types.LndMetricsRequestValidate(request) + stats.validate = process.hrtime.bigint() + if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback) + const response = await methods.GetLndMetrics({rpcName:'GetLndMetrics', ctx:authContext , req: request}) + stats.handle = process.hrtime.bigint() + res({status: 'OK', ...response}) + opts.metricsCallback([{ ...info, ...stats, ...authContext }]) + }catch(ex){ const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } + break + case 'LinkNPubThroughToken': + try { + if (!methods.LinkNPubThroughToken) throw new Error('method: LinkNPubThroughToken is not implemented') + const authContext = await opts.NostrUserAuthGuard(req.appId, req.authIdentifier) + stats.guard = process.hrtime.bigint() + authCtx = authContext + const request = req.body + const error = Types.LinkNPubThroughTokenRequestValidate(request) + stats.validate = process.hrtime.bigint() + if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback) + await methods.LinkNPubThroughToken({rpcName:'LinkNPubThroughToken', ctx:authContext , req: request}) + stats.handle = process.hrtime.bigint() + res({status: 'OK'}) + opts.metricsCallback([{ ...info, ...stats, ...authContext }]) + }catch(ex){ const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } + break + case 'EnrollAdminToken': + try { + if (!methods.EnrollAdminToken) throw new Error('method: EnrollAdminToken is not implemented') + const authContext = await opts.NostrUserAuthGuard(req.appId, req.authIdentifier) + stats.guard = process.hrtime.bigint() + authCtx = authContext + const request = req.body + const error = Types.EnrollAdminTokenRequestValidate(request) + stats.validate = process.hrtime.bigint() + if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback) + await methods.EnrollAdminToken({rpcName:'EnrollAdminToken', ctx:authContext , req: request}) + stats.handle = process.hrtime.bigint() + res({status: 'OK'}) + opts.metricsCallback([{ ...info, ...stats, ...authContext }]) + }catch(ex){ const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } + break + case 'UserHealth': + try { + if (!methods.UserHealth) throw new Error('method: UserHealth is not implemented') + const authContext = await opts.NostrUserAuthGuard(req.appId, req.authIdentifier) + stats.guard = process.hrtime.bigint() + authCtx = authContext + stats.validate = stats.guard + await methods.UserHealth({rpcName:'UserHealth', ctx:authContext }) + stats.handle = process.hrtime.bigint() + res({status: 'OK'}) + opts.metricsCallback([{ ...info, ...stats, ...authContext }]) + }catch(ex){ const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } + break + case 'GetUserInfo': + try { + if (!methods.GetUserInfo) throw new Error('method: GetUserInfo is not implemented') + const authContext = await opts.NostrUserAuthGuard(req.appId, req.authIdentifier) + stats.guard = process.hrtime.bigint() + authCtx = authContext + stats.validate = stats.guard + const response = await methods.GetUserInfo({rpcName:'GetUserInfo', ctx:authContext }) + stats.handle = process.hrtime.bigint() + res({status: 'OK', ...response}) + opts.metricsCallback([{ ...info, ...stats, ...authContext }]) + }catch(ex){ const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } + break + case 'AddProduct': + try { + if (!methods.AddProduct) throw new Error('method: AddProduct is not implemented') + const authContext = await opts.NostrUserAuthGuard(req.appId, req.authIdentifier) + stats.guard = process.hrtime.bigint() + authCtx = authContext + const request = req.body + const error = Types.AddProductRequestValidate(request) + stats.validate = process.hrtime.bigint() + if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback) + const response = await methods.AddProduct({rpcName:'AddProduct', ctx:authContext , req: request}) + stats.handle = process.hrtime.bigint() + res({status: 'OK', ...response}) + opts.metricsCallback([{ ...info, ...stats, ...authContext }]) + }catch(ex){ const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } + break + case 'NewProductInvoice': + try { + if (!methods.NewProductInvoice) throw new Error('method: NewProductInvoice is not implemented') + const authContext = await opts.NostrUserAuthGuard(req.appId, req.authIdentifier) + stats.guard = process.hrtime.bigint() + authCtx = authContext + stats.validate = stats.guard + const response = await methods.NewProductInvoice({rpcName:'NewProductInvoice', ctx:authContext ,query: req.query||{}}) + stats.handle = process.hrtime.bigint() + res({status: 'OK', ...response}) + opts.metricsCallback([{ ...info, ...stats, ...authContext }]) + }catch(ex){ const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } + break + case 'GetUserOperations': + try { + if (!methods.GetUserOperations) throw new Error('method: GetUserOperations is not implemented') + const authContext = await opts.NostrUserAuthGuard(req.appId, req.authIdentifier) + stats.guard = process.hrtime.bigint() + authCtx = authContext + const request = req.body + const error = Types.GetUserOperationsRequestValidate(request) + stats.validate = process.hrtime.bigint() + if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback) + const response = await methods.GetUserOperations({rpcName:'GetUserOperations', ctx:authContext , req: request}) + stats.handle = process.hrtime.bigint() + res({status: 'OK', ...response}) + opts.metricsCallback([{ ...info, ...stats, ...authContext }]) + }catch(ex){ const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } + break + case 'NewAddress': + try { + if (!methods.NewAddress) throw new Error('method: NewAddress is not implemented') + const authContext = await opts.NostrUserAuthGuard(req.appId, req.authIdentifier) + stats.guard = process.hrtime.bigint() + authCtx = authContext + const request = req.body + const error = Types.NewAddressRequestValidate(request) + stats.validate = process.hrtime.bigint() + if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback) + const response = await methods.NewAddress({rpcName:'NewAddress', ctx:authContext , req: request}) + stats.handle = process.hrtime.bigint() + res({status: 'OK', ...response}) + opts.metricsCallback([{ ...info, ...stats, ...authContext }]) + }catch(ex){ const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } + break + case 'PayAddress': + try { + if (!methods.PayAddress) throw new Error('method: PayAddress is not implemented') + const authContext = await opts.NostrUserAuthGuard(req.appId, req.authIdentifier) + stats.guard = process.hrtime.bigint() + authCtx = authContext + const request = req.body + const error = Types.PayAddressRequestValidate(request) + stats.validate = process.hrtime.bigint() + if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback) + const response = await methods.PayAddress({rpcName:'PayAddress', ctx:authContext , req: request}) + stats.handle = process.hrtime.bigint() + res({status: 'OK', ...response}) + opts.metricsCallback([{ ...info, ...stats, ...authContext }]) + }catch(ex){ const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } + break + case 'NewInvoice': + try { + if (!methods.NewInvoice) throw new Error('method: NewInvoice is not implemented') + const authContext = await opts.NostrUserAuthGuard(req.appId, req.authIdentifier) + stats.guard = process.hrtime.bigint() + authCtx = authContext + const request = req.body + const error = Types.NewInvoiceRequestValidate(request) + stats.validate = process.hrtime.bigint() + if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback) + const response = await methods.NewInvoice({rpcName:'NewInvoice', ctx:authContext , req: request}) + stats.handle = process.hrtime.bigint() + res({status: 'OK', ...response}) + opts.metricsCallback([{ ...info, ...stats, ...authContext }]) + }catch(ex){ const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } + break + case 'DecodeInvoice': + try { + if (!methods.DecodeInvoice) throw new Error('method: DecodeInvoice is not implemented') + const authContext = await opts.NostrUserAuthGuard(req.appId, req.authIdentifier) + stats.guard = process.hrtime.bigint() + authCtx = authContext + const request = req.body + const error = Types.DecodeInvoiceRequestValidate(request) + stats.validate = process.hrtime.bigint() + if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback) + const response = await methods.DecodeInvoice({rpcName:'DecodeInvoice', ctx:authContext , req: request}) + stats.handle = process.hrtime.bigint() + res({status: 'OK', ...response}) + opts.metricsCallback([{ ...info, ...stats, ...authContext }]) + }catch(ex){ const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } + break + case 'PayInvoice': + try { + if (!methods.PayInvoice) throw new Error('method: PayInvoice is not implemented') + const authContext = await opts.NostrUserAuthGuard(req.appId, req.authIdentifier) + stats.guard = process.hrtime.bigint() + authCtx = authContext + const request = req.body + const error = Types.PayInvoiceRequestValidate(request) + stats.validate = process.hrtime.bigint() + if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback) + const response = await methods.PayInvoice({rpcName:'PayInvoice', ctx:authContext , req: request}) + stats.handle = process.hrtime.bigint() + res({status: 'OK', ...response}) + opts.metricsCallback([{ ...info, ...stats, ...authContext }]) + }catch(ex){ const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } + break + case 'OpenChannel': + try { + if (!methods.OpenChannel) throw new Error('method: OpenChannel is not implemented') + const authContext = await opts.NostrUserAuthGuard(req.appId, req.authIdentifier) + stats.guard = process.hrtime.bigint() + authCtx = authContext + const request = req.body + const error = Types.OpenChannelRequestValidate(request) + stats.validate = process.hrtime.bigint() + if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback) + const response = await methods.OpenChannel({rpcName:'OpenChannel', ctx:authContext , req: request}) + stats.handle = process.hrtime.bigint() + res({status: 'OK', ...response}) + opts.metricsCallback([{ ...info, ...stats, ...authContext }]) + }catch(ex){ const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } + break + case 'GetLnurlWithdrawLink': + try { + if (!methods.GetLnurlWithdrawLink) throw new Error('method: GetLnurlWithdrawLink is not implemented') + const authContext = await opts.NostrUserAuthGuard(req.appId, req.authIdentifier) + stats.guard = process.hrtime.bigint() + authCtx = authContext + stats.validate = stats.guard + const response = await methods.GetLnurlWithdrawLink({rpcName:'GetLnurlWithdrawLink', ctx:authContext }) + stats.handle = process.hrtime.bigint() + res({status: 'OK', ...response}) + opts.metricsCallback([{ ...info, ...stats, ...authContext }]) + }catch(ex){ const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } + break + case 'GetLnurlPayLink': + try { + if (!methods.GetLnurlPayLink) throw new Error('method: GetLnurlPayLink is not implemented') + const authContext = await opts.NostrUserAuthGuard(req.appId, req.authIdentifier) + stats.guard = process.hrtime.bigint() + authCtx = authContext + stats.validate = stats.guard + const response = await methods.GetLnurlPayLink({rpcName:'GetLnurlPayLink', ctx:authContext }) + stats.handle = process.hrtime.bigint() + res({status: 'OK', ...response}) + opts.metricsCallback([{ ...info, ...stats, ...authContext }]) + }catch(ex){ const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } + break + case 'GetLNURLChannelLink': + try { + if (!methods.GetLNURLChannelLink) throw new Error('method: GetLNURLChannelLink is not implemented') + const authContext = await opts.NostrUserAuthGuard(req.appId, req.authIdentifier) + stats.guard = process.hrtime.bigint() + authCtx = authContext + stats.validate = stats.guard + const response = await methods.GetLNURLChannelLink({rpcName:'GetLNURLChannelLink', ctx:authContext }) + stats.handle = process.hrtime.bigint() + res({status: 'OK', ...response}) + opts.metricsCallback([{ ...info, ...stats, ...authContext }]) + }catch(ex){ const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } + break + case 'GetLiveUserOperations': + try { + if (!methods.GetLiveUserOperations) throw new Error('method: GetLiveUserOperations is not implemented') + const authContext = await opts.NostrUserAuthGuard(req.appId, req.authIdentifier) + stats.guard = process.hrtime.bigint() + authCtx = authContext + stats.validate = stats.guard + methods.GetLiveUserOperations({rpcName:'GetLiveUserOperations', ctx:authContext ,cb: (response, err) => { + stats.handle = process.hrtime.bigint() + if (err) { logErrorAndReturnResponse(err, err.message, res, logger, { ...info, ...stats, ...authContext }, opts.metricsCallback)} else { res({status: 'OK', ...response});opts.metricsCallback([{ ...info, ...stats, ...authContext }])} + }}) + }catch(ex){ const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } + break + case 'GetMigrationUpdate': + try { + if (!methods.GetMigrationUpdate) throw new Error('method: GetMigrationUpdate is not implemented') + const authContext = await opts.NostrUserAuthGuard(req.appId, req.authIdentifier) + stats.guard = process.hrtime.bigint() + authCtx = authContext + stats.validate = stats.guard + methods.GetMigrationUpdate({rpcName:'GetMigrationUpdate', ctx:authContext ,cb: (response, err) => { + stats.handle = process.hrtime.bigint() + if (err) { logErrorAndReturnResponse(err, err.message, res, logger, { ...info, ...stats, ...authContext }, opts.metricsCallback)} else { res({status: 'OK', ...response});opts.metricsCallback([{ ...info, ...stats, ...authContext }])} + }}) + }catch(ex){ const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } + break + case 'GetHttpCreds': + try { + if (!methods.GetHttpCreds) throw new Error('method: GetHttpCreds is not implemented') + const authContext = await opts.NostrUserAuthGuard(req.appId, req.authIdentifier) + stats.guard = process.hrtime.bigint() + authCtx = authContext + stats.validate = stats.guard + methods.GetHttpCreds({rpcName:'GetHttpCreds', ctx:authContext ,cb: (response, err) => { + stats.handle = process.hrtime.bigint() + if (err) { logErrorAndReturnResponse(err, err.message, res, logger, { ...info, ...stats, ...authContext }, opts.metricsCallback)} else { res({status: 'OK', ...response});opts.metricsCallback([{ ...info, ...stats, ...authContext }])} + }}) + }catch(ex){ const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } + break + case 'BatchUser': + try { + info.batch = true + const requests = req.body.requests as Types.UserMethodInputs[] + if (!Array.isArray(requests))throw new Error('invalid body, is not an array') + info.batchSize = requests.length + if (requests.length > 10) throw new Error('too many requests in the batch') + const ctx = await opts.NostrUserAuthGuard(req.appId, req.authIdentifier) + stats.guard = process.hrtime.bigint() + authCtx = ctx + stats.validate = stats.guard + const responses = [] + const callsMetrics: Types.RequestMetric[] = [] + for (let i = 0; i < requests.length; i++) { + const operation = requests[i] + const opInfo: Types.RequestInfo = { rpcName: operation.rpcName, batch: true, nostr: true, batchSize: 0 } + const opStats: Types.RequestStats = { startMs, start: startTime, parse: stats.parse, guard: stats.guard, validate: 0n, handle: 0n } + try { + switch(operation.rpcName) { + case 'LinkNPubThroughToken': + if (!methods.LinkNPubThroughToken) { + throw new Error('method not defined: LinkNPubThroughToken') + } else { + const error = Types.LinkNPubThroughTokenRequestValidate(operation.req) + opStats.validate = process.hrtime.bigint() + if (error !== null) throw error + await methods.LinkNPubThroughToken({...operation, ctx}); responses.push({ status: 'OK' }) + opStats.handle = process.hrtime.bigint() + callsMetrics.push({ ...opInfo, ...opStats, ...ctx }) + } + break + case 'EnrollAdminToken': + if (!methods.EnrollAdminToken) { + throw new Error('method not defined: EnrollAdminToken') + } else { + const error = Types.EnrollAdminTokenRequestValidate(operation.req) + opStats.validate = process.hrtime.bigint() + if (error !== null) throw error + await methods.EnrollAdminToken({...operation, ctx}); responses.push({ status: 'OK' }) + opStats.handle = process.hrtime.bigint() + callsMetrics.push({ ...opInfo, ...opStats, ...ctx }) + } + break + case 'UserHealth': + if (!methods.UserHealth) { + throw new Error('method not defined: UserHealth') + } else { + opStats.validate = opStats.guard + await methods.UserHealth({...operation, ctx}); responses.push({ status: 'OK' }) + opStats.handle = process.hrtime.bigint() + callsMetrics.push({ ...opInfo, ...opStats, ...ctx }) + } + break + case 'GetUserInfo': + if (!methods.GetUserInfo) { + throw new Error('method not defined: GetUserInfo') + } else { + opStats.validate = opStats.guard + const res = await methods.GetUserInfo({...operation, ctx}); responses.push({ status: 'OK', ...res }) + opStats.handle = process.hrtime.bigint() + callsMetrics.push({ ...opInfo, ...opStats, ...ctx }) + } + break + case 'AddProduct': + if (!methods.AddProduct) { + throw new Error('method not defined: AddProduct') + } else { + const error = Types.AddProductRequestValidate(operation.req) + opStats.validate = process.hrtime.bigint() + if (error !== null) throw error + const res = await methods.AddProduct({...operation, ctx}); responses.push({ status: 'OK', ...res }) + opStats.handle = process.hrtime.bigint() + callsMetrics.push({ ...opInfo, ...opStats, ...ctx }) + } + break + case 'NewProductInvoice': + if (!methods.NewProductInvoice) { + throw new Error('method not defined: NewProductInvoice') + } else { + opStats.validate = opStats.guard + const res = await methods.NewProductInvoice({...operation, ctx}); responses.push({ status: 'OK', ...res }) + opStats.handle = process.hrtime.bigint() + callsMetrics.push({ ...opInfo, ...opStats, ...ctx }) + } + break + case 'GetUserOperations': + if (!methods.GetUserOperations) { + throw new Error('method not defined: GetUserOperations') + } else { + const error = Types.GetUserOperationsRequestValidate(operation.req) + opStats.validate = process.hrtime.bigint() + if (error !== null) throw error + const res = await methods.GetUserOperations({...operation, ctx}); responses.push({ status: 'OK', ...res }) + opStats.handle = process.hrtime.bigint() + callsMetrics.push({ ...opInfo, ...opStats, ...ctx }) + } + break + case 'NewAddress': + if (!methods.NewAddress) { + throw new Error('method not defined: NewAddress') + } else { + const error = Types.NewAddressRequestValidate(operation.req) + opStats.validate = process.hrtime.bigint() + if (error !== null) throw error + const res = await methods.NewAddress({...operation, ctx}); responses.push({ status: 'OK', ...res }) + opStats.handle = process.hrtime.bigint() + callsMetrics.push({ ...opInfo, ...opStats, ...ctx }) + } + break + case 'PayAddress': + if (!methods.PayAddress) { + throw new Error('method not defined: PayAddress') + } else { + const error = Types.PayAddressRequestValidate(operation.req) + opStats.validate = process.hrtime.bigint() + if (error !== null) throw error + const res = await methods.PayAddress({...operation, ctx}); responses.push({ status: 'OK', ...res }) + opStats.handle = process.hrtime.bigint() + callsMetrics.push({ ...opInfo, ...opStats, ...ctx }) + } + break + case 'NewInvoice': + if (!methods.NewInvoice) { + throw new Error('method not defined: NewInvoice') + } else { + const error = Types.NewInvoiceRequestValidate(operation.req) + opStats.validate = process.hrtime.bigint() + if (error !== null) throw error + const res = await methods.NewInvoice({...operation, ctx}); responses.push({ status: 'OK', ...res }) + opStats.handle = process.hrtime.bigint() + callsMetrics.push({ ...opInfo, ...opStats, ...ctx }) + } + break + case 'DecodeInvoice': + if (!methods.DecodeInvoice) { + throw new Error('method not defined: DecodeInvoice') + } else { + const error = Types.DecodeInvoiceRequestValidate(operation.req) + opStats.validate = process.hrtime.bigint() + if (error !== null) throw error + const res = await methods.DecodeInvoice({...operation, ctx}); responses.push({ status: 'OK', ...res }) + opStats.handle = process.hrtime.bigint() + callsMetrics.push({ ...opInfo, ...opStats, ...ctx }) + } + break + case 'PayInvoice': + if (!methods.PayInvoice) { + throw new Error('method not defined: PayInvoice') + } else { + const error = Types.PayInvoiceRequestValidate(operation.req) + opStats.validate = process.hrtime.bigint() + if (error !== null) throw error + const res = await methods.PayInvoice({...operation, ctx}); responses.push({ status: 'OK', ...res }) + opStats.handle = process.hrtime.bigint() + callsMetrics.push({ ...opInfo, ...opStats, ...ctx }) + } + break + case 'OpenChannel': + if (!methods.OpenChannel) { + throw new Error('method not defined: OpenChannel') + } else { + const error = Types.OpenChannelRequestValidate(operation.req) + opStats.validate = process.hrtime.bigint() + if (error !== null) throw error + const res = await methods.OpenChannel({...operation, ctx}); responses.push({ status: 'OK', ...res }) + opStats.handle = process.hrtime.bigint() + callsMetrics.push({ ...opInfo, ...opStats, ...ctx }) + } + break + case 'GetLnurlWithdrawLink': + if (!methods.GetLnurlWithdrawLink) { + throw new Error('method not defined: GetLnurlWithdrawLink') + } else { + opStats.validate = opStats.guard + const res = await methods.GetLnurlWithdrawLink({...operation, ctx}); responses.push({ status: 'OK', ...res }) + opStats.handle = process.hrtime.bigint() + callsMetrics.push({ ...opInfo, ...opStats, ...ctx }) + } + break + case 'GetLnurlPayLink': + if (!methods.GetLnurlPayLink) { + throw new Error('method not defined: GetLnurlPayLink') + } else { + opStats.validate = opStats.guard + const res = await methods.GetLnurlPayLink({...operation, ctx}); responses.push({ status: 'OK', ...res }) + opStats.handle = process.hrtime.bigint() + callsMetrics.push({ ...opInfo, ...opStats, ...ctx }) + } + break + case 'GetLNURLChannelLink': + if (!methods.GetLNURLChannelLink) { + throw new Error('method not defined: GetLNURLChannelLink') + } else { + opStats.validate = opStats.guard + const res = await methods.GetLNURLChannelLink({...operation, ctx}); responses.push({ status: 'OK', ...res }) + opStats.handle = process.hrtime.bigint() + callsMetrics.push({ ...opInfo, ...opStats, ...ctx }) + } + break + default: + throw new Error('unkown rpcName') + } + } catch(ex) {const e = ex as any; logger.error(e.message || e); callsMetrics.push({ ...opInfo, ...opStats, ...ctx, error: e.message }); responses.push({ status: 'ERROR', reason: e.message || e })} + } + stats.handle = process.hrtime.bigint() + res({ status: 'OK', responses }) + opts.metricsCallback([{ ...info, ...stats, ...ctx }, ...callsMetrics]) + }catch(ex){ const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } + break + default: logger.error('unknown rpc call name from nostr event:'+req.rpcName) + } + } +} diff --git a/proto/autogenerated/ts/types.ts b/proto/autogenerated/ts/types.ts index e08314e8..691dfcf6 100644 --- a/proto/autogenerated/ts/types.ts +++ b/proto/autogenerated/ts/types.ts @@ -1,2379 +1,2416 @@ -// This file was autogenerated from a .proto file, DO NOT EDIT! - -export type ResultError = { status: 'ERROR', reason: string } -export type RequestInfo = { rpcName: string, batch: boolean, nostr: boolean, batchSize: number } -export type RequestStats = { startMs:number, start:bigint, parse: bigint, guard: bigint, validate: bigint, handle: bigint } -export type RequestMetric = AuthContext & RequestInfo & RequestStats & { error?: string } -export type GuestContext = { -} -export type GuestMethodInputs = Health_Input | EncryptionExchange_Input | SetMockInvoiceAsPaid_Input | GetLnurlWithdrawInfo_Input | HandleLnurlWithdraw_Input | GetLnurlPayInfo_Input | HandleLnurlPay_Input | HandleLnurlAddress_Input -export type GuestMethodOutputs = Health_Output | EncryptionExchange_Output | SetMockInvoiceAsPaid_Output | GetLnurlWithdrawInfo_Output | HandleLnurlWithdraw_Output | GetLnurlPayInfo_Output | HandleLnurlPay_Output | HandleLnurlAddress_Output -export type UserContext = { - user_id: string - app_id: string - app_user_id: string -} -export type UserMethodInputs = LinkNPubThroughToken_Input | UserHealth_Input | GetUserInfo_Input | AddProduct_Input | NewProductInvoice_Input | GetUserOperations_Input | NewAddress_Input | PayAddress_Input | NewInvoice_Input | DecodeInvoice_Input | PayInvoice_Input | OpenChannel_Input | GetLnurlWithdrawLink_Input | GetLnurlPayLink_Input | GetLNURLChannelLink_Input -export type UserMethodOutputs = LinkNPubThroughToken_Output | UserHealth_Output | GetUserInfo_Output | AddProduct_Output | NewProductInvoice_Output | GetUserOperations_Output | NewAddress_Output | PayAddress_Output | NewInvoice_Output | DecodeInvoice_Output | PayInvoice_Output | OpenChannel_Output | GetLnurlWithdrawLink_Output | GetLnurlPayLink_Output | GetLNURLChannelLink_Output -export type AdminContext = { - admin_id: string -} -export type AdminMethodInputs = LndGetInfo_Input | AddApp_Input | AuthApp_Input | BanUser_Input -export type AdminMethodOutputs = LndGetInfo_Output | AddApp_Output | AuthApp_Output | BanUser_Output -export type MetricsContext = { - operator_id: string -} -export type MetricsMethodInputs = GetUsageMetrics_Input | GetAppsMetrics_Input | GetLndMetrics_Input -export type MetricsMethodOutputs = GetUsageMetrics_Output | GetAppsMetrics_Output | GetLndMetrics_Output -export type AppContext = { - app_id: string -} -export type AppMethodInputs = GetApp_Input | AddAppUser_Input | AddAppInvoice_Input | AddAppUserInvoice_Input | GetAppUser_Input | PayAppUserInvoice_Input | SendAppUserToAppUserPayment_Input | SendAppUserToAppPayment_Input | GetAppUserLNURLInfo_Input | SetMockAppUserBalance_Input | SetMockAppBalance_Input | RequestNPubLinkingToken_Input -export type AppMethodOutputs = GetApp_Output | AddAppUser_Output | AddAppInvoice_Output | AddAppUserInvoice_Output | GetAppUser_Output | PayAppUserInvoice_Output | SendAppUserToAppUserPayment_Output | SendAppUserToAppPayment_Output | GetAppUserLNURLInfo_Output | SetMockAppUserBalance_Output | SetMockAppBalance_Output | RequestNPubLinkingToken_Output -export type AuthContext = GuestContext | UserContext | AdminContext | MetricsContext | AppContext - -export type LndGetInfo_Input = {rpcName:'LndGetInfo', req: LndGetInfoRequest} -export type LndGetInfo_Output = ResultError | ({ status: 'OK' } & LndGetInfoResponse) - -export type AddApp_Input = {rpcName:'AddApp', req: AddAppRequest} -export type AddApp_Output = ResultError | ({ status: 'OK' } & AuthApp) - -export type AuthApp_Input = {rpcName:'AuthApp', req: AuthAppRequest} -export type AuthApp_Output = ResultError | ({ status: 'OK' } & AuthApp) - -export type BanUser_Input = {rpcName:'BanUser', req: BanUserRequest} -export type BanUser_Output = ResultError | ({ status: 'OK' } & BanUserResponse) - -export type GetUsageMetrics_Input = {rpcName:'GetUsageMetrics'} -export type GetUsageMetrics_Output = ResultError | ({ status: 'OK' } & UsageMetrics) - -export type GetAppsMetrics_Input = {rpcName:'GetAppsMetrics', req: AppsMetricsRequest} -export type GetAppsMetrics_Output = ResultError | ({ status: 'OK' } & AppsMetrics) - -export type GetLndMetrics_Input = {rpcName:'GetLndMetrics', req: LndMetricsRequest} -export type GetLndMetrics_Output = ResultError | ({ status: 'OK' } & LndMetrics) - -export type Health_Input = {rpcName:'Health'} -export type Health_Output = ResultError | { status: 'OK' } - -export type EncryptionExchange_Input = {rpcName:'EncryptionExchange', req: EncryptionExchangeRequest} -export type EncryptionExchange_Output = ResultError | { status: 'OK' } - -export type SetMockInvoiceAsPaid_Input = {rpcName:'SetMockInvoiceAsPaid', req: SetMockInvoiceAsPaidRequest} -export type SetMockInvoiceAsPaid_Output = ResultError | { status: 'OK' } - -export type GetLnurlWithdrawInfo_Query = { - k1?: string -} -export type GetLnurlWithdrawInfo_Input = {rpcName:'GetLnurlWithdrawInfo', query: GetLnurlWithdrawInfo_Query} -export type GetLnurlWithdrawInfo_Output = ResultError | ({ status: 'OK' } & LnurlWithdrawInfoResponse) - -export type HandleLnurlWithdraw_Query = { - k1?: string - pr?: string -} -export type HandleLnurlWithdraw_Input = {rpcName:'HandleLnurlWithdraw', query: HandleLnurlWithdraw_Query} -export type HandleLnurlWithdraw_Output = ResultError | { status: 'OK' } - -export type GetLnurlPayInfo_Query = { - k1?: string -} -export type GetLnurlPayInfo_Input = {rpcName:'GetLnurlPayInfo', query: GetLnurlPayInfo_Query} -export type GetLnurlPayInfo_Output = ResultError | ({ status: 'OK' } & LnurlPayInfoResponse) - -export type HandleLnurlPay_Query = { - k1?: string - amount?: string - nostr?: string - lnurl?: string -} -export type HandleLnurlPay_Input = {rpcName:'HandleLnurlPay', query: HandleLnurlPay_Query} -export type HandleLnurlPay_Output = ResultError | ({ status: 'OK' } & HandleLnurlPayResponse) - -export type HandleLnurlAddress_RouteParams = { - address_name: string -} -export type HandleLnurlAddress_Input = {rpcName:'HandleLnurlAddress', params: HandleLnurlAddress_RouteParams} -export type HandleLnurlAddress_Output = ResultError | ({ status: 'OK' } & LnurlPayInfoResponse) - -export type LinkNPubThroughToken_Input = {rpcName:'LinkNPubThroughToken', req: LinkNPubThroughTokenRequest} -export type LinkNPubThroughToken_Output = ResultError | { status: 'OK' } - -export type GetApp_Input = {rpcName:'GetApp'} -export type GetApp_Output = ResultError | ({ status: 'OK' } & Application) - -export type AddAppUser_Input = {rpcName:'AddAppUser', req: AddAppUserRequest} -export type AddAppUser_Output = ResultError | ({ status: 'OK' } & AppUser) - -export type AddAppInvoice_Input = {rpcName:'AddAppInvoice', req: AddAppInvoiceRequest} -export type AddAppInvoice_Output = ResultError | ({ status: 'OK' } & NewInvoiceResponse) - -export type AddAppUserInvoice_Input = {rpcName:'AddAppUserInvoice', req: AddAppUserInvoiceRequest} -export type AddAppUserInvoice_Output = ResultError | ({ status: 'OK' } & NewInvoiceResponse) - -export type GetAppUser_Input = {rpcName:'GetAppUser', req: GetAppUserRequest} -export type GetAppUser_Output = ResultError | ({ status: 'OK' } & AppUser) - -export type PayAppUserInvoice_Input = {rpcName:'PayAppUserInvoice', req: PayAppUserInvoiceRequest} -export type PayAppUserInvoice_Output = ResultError | ({ status: 'OK' } & PayInvoiceResponse) - -export type SendAppUserToAppUserPayment_Input = {rpcName:'SendAppUserToAppUserPayment', req: SendAppUserToAppUserPaymentRequest} -export type SendAppUserToAppUserPayment_Output = ResultError | { status: 'OK' } - -export type SendAppUserToAppPayment_Input = {rpcName:'SendAppUserToAppPayment', req: SendAppUserToAppPaymentRequest} -export type SendAppUserToAppPayment_Output = ResultError | { status: 'OK' } - -export type GetAppUserLNURLInfo_Input = {rpcName:'GetAppUserLNURLInfo', req: GetAppUserLNURLInfoRequest} -export type GetAppUserLNURLInfo_Output = ResultError | ({ status: 'OK' } & LnurlPayInfoResponse) - -export type SetMockAppUserBalance_Input = {rpcName:'SetMockAppUserBalance', req: SetMockAppUserBalanceRequest} -export type SetMockAppUserBalance_Output = ResultError | { status: 'OK' } - -export type SetMockAppBalance_Input = {rpcName:'SetMockAppBalance', req: SetMockAppBalanceRequest} -export type SetMockAppBalance_Output = ResultError | { status: 'OK' } - -export type RequestNPubLinkingToken_Input = {rpcName:'RequestNPubLinkingToken', req: RequestNPubLinkingTokenRequest} -export type RequestNPubLinkingToken_Output = ResultError | ({ status: 'OK' } & RequestNPubLinkingTokenResponse) - -export type UserHealth_Input = {rpcName:'UserHealth'} -export type UserHealth_Output = ResultError | { status: 'OK' } - -export type GetUserInfo_Input = {rpcName:'GetUserInfo'} -export type GetUserInfo_Output = ResultError | ({ status: 'OK' } & UserInfo) - -export type AddProduct_Input = {rpcName:'AddProduct', req: AddProductRequest} -export type AddProduct_Output = ResultError | ({ status: 'OK' } & Product) - -export type NewProductInvoice_Query = { - id?: string -} -export type NewProductInvoice_Input = {rpcName:'NewProductInvoice', query: NewProductInvoice_Query} -export type NewProductInvoice_Output = ResultError | ({ status: 'OK' } & NewInvoiceResponse) - -export type GetUserOperations_Input = {rpcName:'GetUserOperations', req: GetUserOperationsRequest} -export type GetUserOperations_Output = ResultError | ({ status: 'OK' } & GetUserOperationsResponse) - -export type NewAddress_Input = {rpcName:'NewAddress', req: NewAddressRequest} -export type NewAddress_Output = ResultError | ({ status: 'OK' } & NewAddressResponse) - -export type PayAddress_Input = {rpcName:'PayAddress', req: PayAddressRequest} -export type PayAddress_Output = ResultError | ({ status: 'OK' } & PayAddressResponse) - -export type NewInvoice_Input = {rpcName:'NewInvoice', req: NewInvoiceRequest} -export type NewInvoice_Output = ResultError | ({ status: 'OK' } & NewInvoiceResponse) - -export type DecodeInvoice_Input = {rpcName:'DecodeInvoice', req: DecodeInvoiceRequest} -export type DecodeInvoice_Output = ResultError | ({ status: 'OK' } & DecodeInvoiceResponse) - -export type PayInvoice_Input = {rpcName:'PayInvoice', req: PayInvoiceRequest} -export type PayInvoice_Output = ResultError | ({ status: 'OK' } & PayInvoiceResponse) - -export type OpenChannel_Input = {rpcName:'OpenChannel', req: OpenChannelRequest} -export type OpenChannel_Output = ResultError | ({ status: 'OK' } & OpenChannelResponse) - -export type GetLnurlWithdrawLink_Input = {rpcName:'GetLnurlWithdrawLink'} -export type GetLnurlWithdrawLink_Output = ResultError | ({ status: 'OK' } & LnurlLinkResponse) - -export type GetLnurlPayLink_Input = {rpcName:'GetLnurlPayLink'} -export type GetLnurlPayLink_Output = ResultError | ({ status: 'OK' } & LnurlLinkResponse) - -export type GetLNURLChannelLink_Input = {rpcName:'GetLNURLChannelLink'} -export type GetLNURLChannelLink_Output = ResultError | ({ status: 'OK' } & LnurlLinkResponse) - -export type GetLiveUserOperations_Input = {rpcName:'GetLiveUserOperations', cb:(res: LiveUserOperation, err:Error|null)=> void} -export type GetLiveUserOperations_Output = ResultError | { status: 'OK' } - -export type GetMigrationUpdate_Input = {rpcName:'GetMigrationUpdate', cb:(res: MigrationUpdate, err:Error|null)=> void} -export type GetMigrationUpdate_Output = ResultError | { status: 'OK' } - -export type GetHttpCreds_Input = {rpcName:'GetHttpCreds', cb:(res: HttpCreds, err:Error|null)=> void} -export type GetHttpCreds_Output = ResultError | { status: 'OK' } - -export type BatchUser_Input = UserMethodInputs -export type BatchUser_Output = UserMethodOutputs - -export type ServerMethods = { - LndGetInfo?: (req: LndGetInfo_Input & {ctx: AdminContext }) => Promise - AddApp?: (req: AddApp_Input & {ctx: AdminContext }) => Promise - AuthApp?: (req: AuthApp_Input & {ctx: AdminContext }) => Promise - BanUser?: (req: BanUser_Input & {ctx: AdminContext }) => Promise - GetUsageMetrics?: (req: GetUsageMetrics_Input & {ctx: MetricsContext }) => Promise - GetAppsMetrics?: (req: GetAppsMetrics_Input & {ctx: MetricsContext }) => Promise - GetLndMetrics?: (req: GetLndMetrics_Input & {ctx: MetricsContext }) => Promise - Health?: (req: Health_Input & {ctx: GuestContext }) => Promise - EncryptionExchange?: (req: EncryptionExchange_Input & {ctx: GuestContext }) => Promise - SetMockInvoiceAsPaid?: (req: SetMockInvoiceAsPaid_Input & {ctx: GuestContext }) => Promise - GetLnurlWithdrawInfo?: (req: GetLnurlWithdrawInfo_Input & {ctx: GuestContext }) => Promise - HandleLnurlWithdraw?: (req: HandleLnurlWithdraw_Input & {ctx: GuestContext }) => Promise - GetLnurlPayInfo?: (req: GetLnurlPayInfo_Input & {ctx: GuestContext }) => Promise - HandleLnurlPay?: (req: HandleLnurlPay_Input & {ctx: GuestContext }) => Promise - HandleLnurlAddress?: (req: HandleLnurlAddress_Input & {ctx: GuestContext }) => Promise - LinkNPubThroughToken?: (req: LinkNPubThroughToken_Input & {ctx: UserContext }) => Promise - GetApp?: (req: GetApp_Input & {ctx: AppContext }) => Promise - AddAppUser?: (req: AddAppUser_Input & {ctx: AppContext }) => Promise - AddAppInvoice?: (req: AddAppInvoice_Input & {ctx: AppContext }) => Promise - AddAppUserInvoice?: (req: AddAppUserInvoice_Input & {ctx: AppContext }) => Promise - GetAppUser?: (req: GetAppUser_Input & {ctx: AppContext }) => Promise - PayAppUserInvoice?: (req: PayAppUserInvoice_Input & {ctx: AppContext }) => Promise - SendAppUserToAppUserPayment?: (req: SendAppUserToAppUserPayment_Input & {ctx: AppContext }) => Promise - SendAppUserToAppPayment?: (req: SendAppUserToAppPayment_Input & {ctx: AppContext }) => Promise - GetAppUserLNURLInfo?: (req: GetAppUserLNURLInfo_Input & {ctx: AppContext }) => Promise - SetMockAppUserBalance?: (req: SetMockAppUserBalance_Input & {ctx: AppContext }) => Promise - SetMockAppBalance?: (req: SetMockAppBalance_Input & {ctx: AppContext }) => Promise - RequestNPubLinkingToken?: (req: RequestNPubLinkingToken_Input & {ctx: AppContext }) => Promise - UserHealth?: (req: UserHealth_Input & {ctx: UserContext }) => Promise - GetUserInfo?: (req: GetUserInfo_Input & {ctx: UserContext }) => Promise - AddProduct?: (req: AddProduct_Input & {ctx: UserContext }) => Promise - NewProductInvoice?: (req: NewProductInvoice_Input & {ctx: UserContext }) => Promise - GetUserOperations?: (req: GetUserOperations_Input & {ctx: UserContext }) => Promise - NewAddress?: (req: NewAddress_Input & {ctx: UserContext }) => Promise - PayAddress?: (req: PayAddress_Input & {ctx: UserContext }) => Promise - NewInvoice?: (req: NewInvoice_Input & {ctx: UserContext }) => Promise - DecodeInvoice?: (req: DecodeInvoice_Input & {ctx: UserContext }) => Promise - PayInvoice?: (req: PayInvoice_Input & {ctx: UserContext }) => Promise - OpenChannel?: (req: OpenChannel_Input & {ctx: UserContext }) => Promise - GetLnurlWithdrawLink?: (req: GetLnurlWithdrawLink_Input & {ctx: UserContext }) => Promise - GetLnurlPayLink?: (req: GetLnurlPayLink_Input & {ctx: UserContext }) => Promise - GetLNURLChannelLink?: (req: GetLNURLChannelLink_Input & {ctx: UserContext }) => Promise - GetLiveUserOperations?: (req: GetLiveUserOperations_Input & {ctx: UserContext }) => Promise - GetMigrationUpdate?: (req: GetMigrationUpdate_Input & {ctx: UserContext }) => Promise - GetHttpCreds?: (req: GetHttpCreds_Input & {ctx: UserContext }) => Promise -} - -export enum AddressType { - WITNESS_PUBKEY_HASH = 'WITNESS_PUBKEY_HASH', - NESTED_PUBKEY_HASH = 'NESTED_PUBKEY_HASH', - TAPROOT_PUBKEY = 'TAPROOT_PUBKEY', -} -const enumCheckAddressType = (e?: AddressType): boolean => { - for (const v in AddressType) if (e === v) return true - return false -} -export enum UserOperationType { - INCOMING_TX = 'INCOMING_TX', - OUTGOING_TX = 'OUTGOING_TX', - INCOMING_INVOICE = 'INCOMING_INVOICE', - OUTGOING_INVOICE = 'OUTGOING_INVOICE', - OUTGOING_USER_TO_USER = 'OUTGOING_USER_TO_USER', - INCOMING_USER_TO_USER = 'INCOMING_USER_TO_USER', -} -const enumCheckUserOperationType = (e?: UserOperationType): boolean => { - for (const v in UserOperationType) if (e === v) return true - return false -} - -export type OptionsBaseMessage = { - allOptionalsAreSet?: true -} - -export type NewAddressRequest = { - addressType: AddressType -} -export const NewAddressRequestOptionalFields: [] = [] -export type NewAddressRequestOptions = OptionsBaseMessage & { - checkOptionalsAreSet?: [] - addressType_CustomCheck?: (v: AddressType) => boolean -} -export const NewAddressRequestValidate = (o?: NewAddressRequest, opts: NewAddressRequestOptions = {}, path: string = 'NewAddressRequest::root.'): Error | null => { - if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') - if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') - - if (!enumCheckAddressType(o.addressType)) return new Error(`${path}.addressType: is not a valid AddressType`) - if (opts.addressType_CustomCheck && !opts.addressType_CustomCheck(o.addressType)) return new Error(`${path}.addressType: custom check failed`) - - return null -} - -export type LnurlPayInfoResponse = { - tag: string - callback: string - maxSendable: number - minSendable: number - metadata: string - allowsNostr: boolean - nostrPubkey: string -} -export const LnurlPayInfoResponseOptionalFields: [] = [] -export type LnurlPayInfoResponseOptions = OptionsBaseMessage & { - checkOptionalsAreSet?: [] - tag_CustomCheck?: (v: string) => boolean - callback_CustomCheck?: (v: string) => boolean - maxSendable_CustomCheck?: (v: number) => boolean - minSendable_CustomCheck?: (v: number) => boolean - metadata_CustomCheck?: (v: string) => boolean - allowsNostr_CustomCheck?: (v: boolean) => boolean - nostrPubkey_CustomCheck?: (v: string) => boolean -} -export const LnurlPayInfoResponseValidate = (o?: LnurlPayInfoResponse, opts: LnurlPayInfoResponseOptions = {}, path: string = 'LnurlPayInfoResponse::root.'): Error | null => { - if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') - if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') - - if (typeof o.tag !== 'string') return new Error(`${path}.tag: is not a string`) - if (opts.tag_CustomCheck && !opts.tag_CustomCheck(o.tag)) return new Error(`${path}.tag: custom check failed`) - - if (typeof o.callback !== 'string') return new Error(`${path}.callback: is not a string`) - if (opts.callback_CustomCheck && !opts.callback_CustomCheck(o.callback)) return new Error(`${path}.callback: custom check failed`) - - if (typeof o.maxSendable !== 'number') return new Error(`${path}.maxSendable: is not a number`) - if (opts.maxSendable_CustomCheck && !opts.maxSendable_CustomCheck(o.maxSendable)) return new Error(`${path}.maxSendable: custom check failed`) - - if (typeof o.minSendable !== 'number') return new Error(`${path}.minSendable: is not a number`) - if (opts.minSendable_CustomCheck && !opts.minSendable_CustomCheck(o.minSendable)) return new Error(`${path}.minSendable: custom check failed`) - - if (typeof o.metadata !== 'string') return new Error(`${path}.metadata: is not a string`) - if (opts.metadata_CustomCheck && !opts.metadata_CustomCheck(o.metadata)) return new Error(`${path}.metadata: custom check failed`) - - if (typeof o.allowsNostr !== 'boolean') return new Error(`${path}.allowsNostr: is not a boolean`) - if (opts.allowsNostr_CustomCheck && !opts.allowsNostr_CustomCheck(o.allowsNostr)) return new Error(`${path}.allowsNostr: custom check failed`) - - if (typeof o.nostrPubkey !== 'string') return new Error(`${path}.nostrPubkey: is not a string`) - if (opts.nostrPubkey_CustomCheck && !opts.nostrPubkey_CustomCheck(o.nostrPubkey)) return new Error(`${path}.nostrPubkey: custom check failed`) - - return null -} - -export type GetProductBuyLinkResponse = { - link: string -} -export const GetProductBuyLinkResponseOptionalFields: [] = [] -export type GetProductBuyLinkResponseOptions = OptionsBaseMessage & { - checkOptionalsAreSet?: [] - link_CustomCheck?: (v: string) => boolean -} -export const GetProductBuyLinkResponseValidate = (o?: GetProductBuyLinkResponse, opts: GetProductBuyLinkResponseOptions = {}, path: string = 'GetProductBuyLinkResponse::root.'): Error | null => { - if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') - if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') - - if (typeof o.link !== 'string') return new Error(`${path}.link: is not a string`) - if (opts.link_CustomCheck && !opts.link_CustomCheck(o.link)) return new Error(`${path}.link: custom check failed`) - - return null -} - -export type UsageMetrics = { - metrics: UsageMetric[] -} -export const UsageMetricsOptionalFields: [] = [] -export type UsageMetricsOptions = OptionsBaseMessage & { - checkOptionalsAreSet?: [] - metrics_ItemOptions?: UsageMetricOptions - metrics_CustomCheck?: (v: UsageMetric[]) => boolean -} -export const UsageMetricsValidate = (o?: UsageMetrics, opts: UsageMetricsOptions = {}, path: string = 'UsageMetrics::root.'): Error | null => { - if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') - if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') - - if (!Array.isArray(o.metrics)) return new Error(`${path}.metrics: is not an array`) - for (let index = 0; index < o.metrics.length; index++) { - const metricsErr = UsageMetricValidate(o.metrics[index], opts.metrics_ItemOptions, `${path}.metrics[${index}]`) - if (metricsErr !== null) return metricsErr - } - if (opts.metrics_CustomCheck && !opts.metrics_CustomCheck(o.metrics)) return new Error(`${path}.metrics: custom check failed`) - - return null -} - -export type OpenChannel = { - channel_id: string - capacity: number - active: boolean - lifetime: number - local_balance: number - remote_balance: number -} -export const OpenChannelOptionalFields: [] = [] -export type OpenChannelOptions = OptionsBaseMessage & { - checkOptionalsAreSet?: [] - channel_id_CustomCheck?: (v: string) => boolean - capacity_CustomCheck?: (v: number) => boolean - active_CustomCheck?: (v: boolean) => boolean - lifetime_CustomCheck?: (v: number) => boolean - local_balance_CustomCheck?: (v: number) => boolean - remote_balance_CustomCheck?: (v: number) => boolean -} -export const OpenChannelValidate = (o?: OpenChannel, opts: OpenChannelOptions = {}, path: string = 'OpenChannel::root.'): Error | null => { - if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') - if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') - - if (typeof o.channel_id !== 'string') return new Error(`${path}.channel_id: is not a string`) - if (opts.channel_id_CustomCheck && !opts.channel_id_CustomCheck(o.channel_id)) return new Error(`${path}.channel_id: custom check failed`) - - if (typeof o.capacity !== 'number') return new Error(`${path}.capacity: is not a number`) - if (opts.capacity_CustomCheck && !opts.capacity_CustomCheck(o.capacity)) return new Error(`${path}.capacity: custom check failed`) - - if (typeof o.active !== 'boolean') return new Error(`${path}.active: is not a boolean`) - if (opts.active_CustomCheck && !opts.active_CustomCheck(o.active)) return new Error(`${path}.active: custom check failed`) - - if (typeof o.lifetime !== 'number') return new Error(`${path}.lifetime: is not a number`) - if (opts.lifetime_CustomCheck && !opts.lifetime_CustomCheck(o.lifetime)) return new Error(`${path}.lifetime: custom check failed`) - - if (typeof o.local_balance !== 'number') return new Error(`${path}.local_balance: is not a number`) - if (opts.local_balance_CustomCheck && !opts.local_balance_CustomCheck(o.local_balance)) return new Error(`${path}.local_balance: custom check failed`) - - if (typeof o.remote_balance !== 'number') return new Error(`${path}.remote_balance: is not a number`) - if (opts.remote_balance_CustomCheck && !opts.remote_balance_CustomCheck(o.remote_balance)) return new Error(`${path}.remote_balance: custom check failed`) - - return null -} - -export type DecodeInvoiceResponse = { - amount: number -} -export const DecodeInvoiceResponseOptionalFields: [] = [] -export type DecodeInvoiceResponseOptions = OptionsBaseMessage & { - checkOptionalsAreSet?: [] - amount_CustomCheck?: (v: number) => boolean -} -export const DecodeInvoiceResponseValidate = (o?: DecodeInvoiceResponse, opts: DecodeInvoiceResponseOptions = {}, path: string = 'DecodeInvoiceResponse::root.'): Error | null => { - if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') - if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') - - if (typeof o.amount !== 'number') return new Error(`${path}.amount: is not a number`) - if (opts.amount_CustomCheck && !opts.amount_CustomCheck(o.amount)) return new Error(`${path}.amount: custom check failed`) - - return null -} - -export type UsersInfo = { - total: number - no_balance: number - negative_balance: number - always_been_inactive: number - balance_avg: number - balance_median: number -} -export const UsersInfoOptionalFields: [] = [] -export type UsersInfoOptions = OptionsBaseMessage & { - checkOptionalsAreSet?: [] - total_CustomCheck?: (v: number) => boolean - no_balance_CustomCheck?: (v: number) => boolean - negative_balance_CustomCheck?: (v: number) => boolean - always_been_inactive_CustomCheck?: (v: number) => boolean - balance_avg_CustomCheck?: (v: number) => boolean - balance_median_CustomCheck?: (v: number) => boolean -} -export const UsersInfoValidate = (o?: UsersInfo, opts: UsersInfoOptions = {}, path: string = 'UsersInfo::root.'): Error | null => { - if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') - if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') - - if (typeof o.total !== 'number') return new Error(`${path}.total: is not a number`) - if (opts.total_CustomCheck && !opts.total_CustomCheck(o.total)) return new Error(`${path}.total: custom check failed`) - - if (typeof o.no_balance !== 'number') return new Error(`${path}.no_balance: is not a number`) - if (opts.no_balance_CustomCheck && !opts.no_balance_CustomCheck(o.no_balance)) return new Error(`${path}.no_balance: custom check failed`) - - if (typeof o.negative_balance !== 'number') return new Error(`${path}.negative_balance: is not a number`) - if (opts.negative_balance_CustomCheck && !opts.negative_balance_CustomCheck(o.negative_balance)) return new Error(`${path}.negative_balance: custom check failed`) - - if (typeof o.always_been_inactive !== 'number') return new Error(`${path}.always_been_inactive: is not a number`) - if (opts.always_been_inactive_CustomCheck && !opts.always_been_inactive_CustomCheck(o.always_been_inactive)) return new Error(`${path}.always_been_inactive: custom check failed`) - - if (typeof o.balance_avg !== 'number') return new Error(`${path}.balance_avg: is not a number`) - if (opts.balance_avg_CustomCheck && !opts.balance_avg_CustomCheck(o.balance_avg)) return new Error(`${path}.balance_avg: custom check failed`) - - if (typeof o.balance_median !== 'number') return new Error(`${path}.balance_median: is not a number`) - if (opts.balance_median_CustomCheck && !opts.balance_median_CustomCheck(o.balance_median)) return new Error(`${path}.balance_median: custom check failed`) - - return null -} - -export type AddAppRequest = { - name: string - allow_user_creation: boolean -} -export const AddAppRequestOptionalFields: [] = [] -export type AddAppRequestOptions = OptionsBaseMessage & { - checkOptionalsAreSet?: [] - name_CustomCheck?: (v: string) => boolean - allow_user_creation_CustomCheck?: (v: boolean) => boolean -} -export const AddAppRequestValidate = (o?: AddAppRequest, opts: AddAppRequestOptions = {}, path: string = 'AddAppRequest::root.'): Error | null => { - if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') - if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') - - if (typeof o.name !== 'string') return new Error(`${path}.name: is not a string`) - if (opts.name_CustomCheck && !opts.name_CustomCheck(o.name)) return new Error(`${path}.name: custom check failed`) - - if (typeof o.allow_user_creation !== 'boolean') return new Error(`${path}.allow_user_creation: is not a boolean`) - if (opts.allow_user_creation_CustomCheck && !opts.allow_user_creation_CustomCheck(o.allow_user_creation)) return new Error(`${path}.allow_user_creation: custom check failed`) - - return null -} - -export type LndMetrics = { - nodes: LndNodeMetrics[] -} -export const LndMetricsOptionalFields: [] = [] -export type LndMetricsOptions = OptionsBaseMessage & { - checkOptionalsAreSet?: [] - nodes_ItemOptions?: LndNodeMetricsOptions - nodes_CustomCheck?: (v: LndNodeMetrics[]) => boolean -} -export const LndMetricsValidate = (o?: LndMetrics, opts: LndMetricsOptions = {}, path: string = 'LndMetrics::root.'): Error | null => { - if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') - if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') - - if (!Array.isArray(o.nodes)) return new Error(`${path}.nodes: is not an array`) - for (let index = 0; index < o.nodes.length; index++) { - const nodesErr = LndNodeMetricsValidate(o.nodes[index], opts.nodes_ItemOptions, `${path}.nodes[${index}]`) - if (nodesErr !== null) return nodesErr - } - if (opts.nodes_CustomCheck && !opts.nodes_CustomCheck(o.nodes)) return new Error(`${path}.nodes: custom check failed`) - - return null -} - -export type AddProductRequest = { - name: string - price_sats: number -} -export const AddProductRequestOptionalFields: [] = [] -export type AddProductRequestOptions = OptionsBaseMessage & { - checkOptionalsAreSet?: [] - name_CustomCheck?: (v: string) => boolean - price_sats_CustomCheck?: (v: number) => boolean -} -export const AddProductRequestValidate = (o?: AddProductRequest, opts: AddProductRequestOptions = {}, path: string = 'AddProductRequest::root.'): Error | null => { - if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') - if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') - - if (typeof o.name !== 'string') return new Error(`${path}.name: is not a string`) - if (opts.name_CustomCheck && !opts.name_CustomCheck(o.name)) return new Error(`${path}.name: custom check failed`) - - if (typeof o.price_sats !== 'number') return new Error(`${path}.price_sats: is not a number`) - if (opts.price_sats_CustomCheck && !opts.price_sats_CustomCheck(o.price_sats)) return new Error(`${path}.price_sats: custom check failed`) - - return null -} - -export type PayInvoiceResponse = { - preimage: string - amount_paid: number - operation_id: string - service_fee: number - network_fee: number -} -export const PayInvoiceResponseOptionalFields: [] = [] -export type PayInvoiceResponseOptions = OptionsBaseMessage & { - checkOptionalsAreSet?: [] - preimage_CustomCheck?: (v: string) => boolean - amount_paid_CustomCheck?: (v: number) => boolean - operation_id_CustomCheck?: (v: string) => boolean - service_fee_CustomCheck?: (v: number) => boolean - network_fee_CustomCheck?: (v: number) => boolean -} -export const PayInvoiceResponseValidate = (o?: PayInvoiceResponse, opts: PayInvoiceResponseOptions = {}, path: string = 'PayInvoiceResponse::root.'): Error | null => { - if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') - if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') - - if (typeof o.preimage !== 'string') return new Error(`${path}.preimage: is not a string`) - if (opts.preimage_CustomCheck && !opts.preimage_CustomCheck(o.preimage)) return new Error(`${path}.preimage: custom check failed`) - - if (typeof o.amount_paid !== 'number') return new Error(`${path}.amount_paid: is not a number`) - if (opts.amount_paid_CustomCheck && !opts.amount_paid_CustomCheck(o.amount_paid)) return new Error(`${path}.amount_paid: custom check failed`) - - if (typeof o.operation_id !== 'string') return new Error(`${path}.operation_id: is not a string`) - if (opts.operation_id_CustomCheck && !opts.operation_id_CustomCheck(o.operation_id)) return new Error(`${path}.operation_id: custom check failed`) - - if (typeof o.service_fee !== 'number') return new Error(`${path}.service_fee: is not a number`) - if (opts.service_fee_CustomCheck && !opts.service_fee_CustomCheck(o.service_fee)) return new Error(`${path}.service_fee: custom check failed`) - - if (typeof o.network_fee !== 'number') return new Error(`${path}.network_fee: is not a number`) - if (opts.network_fee_CustomCheck && !opts.network_fee_CustomCheck(o.network_fee)) return new Error(`${path}.network_fee: custom check failed`) - - return null -} - -export type UserInfo = { - userId: string - balance: number - max_withdrawable: number - user_identifier: string -} -export const UserInfoOptionalFields: [] = [] -export type UserInfoOptions = OptionsBaseMessage & { - checkOptionalsAreSet?: [] - userId_CustomCheck?: (v: string) => boolean - balance_CustomCheck?: (v: number) => boolean - max_withdrawable_CustomCheck?: (v: number) => boolean - user_identifier_CustomCheck?: (v: string) => boolean -} -export const UserInfoValidate = (o?: UserInfo, opts: UserInfoOptions = {}, path: string = 'UserInfo::root.'): Error | null => { - if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') - if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') - - if (typeof o.userId !== 'string') return new Error(`${path}.userId: is not a string`) - if (opts.userId_CustomCheck && !opts.userId_CustomCheck(o.userId)) return new Error(`${path}.userId: custom check failed`) - - if (typeof o.balance !== 'number') return new Error(`${path}.balance: is not a number`) - if (opts.balance_CustomCheck && !opts.balance_CustomCheck(o.balance)) return new Error(`${path}.balance: custom check failed`) - - if (typeof o.max_withdrawable !== 'number') return new Error(`${path}.max_withdrawable: is not a number`) - if (opts.max_withdrawable_CustomCheck && !opts.max_withdrawable_CustomCheck(o.max_withdrawable)) return new Error(`${path}.max_withdrawable: custom check failed`) - - if (typeof o.user_identifier !== 'string') return new Error(`${path}.user_identifier: is not a string`) - if (opts.user_identifier_CustomCheck && !opts.user_identifier_CustomCheck(o.user_identifier)) return new Error(`${path}.user_identifier: custom check failed`) - - return null -} - -export type MigrationUpdate = { - closure?: ClosureMigration - relays?: RelaysMigration -} -export type MigrationUpdateOptionalField = 'closure' | 'relays' -export const MigrationUpdateOptionalFields: MigrationUpdateOptionalField[] = ['closure', 'relays'] -export type MigrationUpdateOptions = OptionsBaseMessage & { - checkOptionalsAreSet?: MigrationUpdateOptionalField[] - closure_Options?: ClosureMigrationOptions - relays_Options?: RelaysMigrationOptions -} -export const MigrationUpdateValidate = (o?: MigrationUpdate, opts: MigrationUpdateOptions = {}, path: string = 'MigrationUpdate::root.'): Error | null => { - if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') - if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') - - if (typeof o.closure === 'object' || opts.allOptionalsAreSet || opts.checkOptionalsAreSet?.includes('closure')) { - const closureErr = ClosureMigrationValidate(o.closure, opts.closure_Options, `${path}.closure`) - if (closureErr !== null) return closureErr - } - - - if (typeof o.relays === 'object' || opts.allOptionalsAreSet || opts.checkOptionalsAreSet?.includes('relays')) { - const relaysErr = RelaysMigrationValidate(o.relays, opts.relays_Options, `${path}.relays`) - if (relaysErr !== null) return relaysErr - } - - - return null -} - -export type LinkNPubThroughTokenRequest = { - token: string - nostr_pub: string -} -export const LinkNPubThroughTokenRequestOptionalFields: [] = [] -export type LinkNPubThroughTokenRequestOptions = OptionsBaseMessage & { - checkOptionalsAreSet?: [] - token_CustomCheck?: (v: string) => boolean - nostr_pub_CustomCheck?: (v: string) => boolean -} -export const LinkNPubThroughTokenRequestValidate = (o?: LinkNPubThroughTokenRequest, opts: LinkNPubThroughTokenRequestOptions = {}, path: string = 'LinkNPubThroughTokenRequest::root.'): Error | null => { - if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') - if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') - - if (typeof o.token !== 'string') return new Error(`${path}.token: is not a string`) - if (opts.token_CustomCheck && !opts.token_CustomCheck(o.token)) return new Error(`${path}.token: custom check failed`) - - if (typeof o.nostr_pub !== 'string') return new Error(`${path}.nostr_pub: is not a string`) - if (opts.nostr_pub_CustomCheck && !opts.nostr_pub_CustomCheck(o.nostr_pub)) return new Error(`${path}.nostr_pub: custom check failed`) - - return null -} - -export type Empty = { -} -export const EmptyOptionalFields: [] = [] -export type EmptyOptions = OptionsBaseMessage & { - checkOptionalsAreSet?: [] -} -export const EmptyValidate = (o?: Empty, opts: EmptyOptions = {}, path: string = 'Empty::root.'): Error | null => { - if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') - if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') - - return null -} - -export type ChannelRouting = { - channel_id: string - send_errors: number - receive_errors: number - forward_errors_as_input: number - forward_errors_as_output: number - missed_forward_fee_as_input: number - missed_forward_fee_as_output: number - forward_fee_as_input: number - forward_fee_as_output: number - events_number: number -} -export const ChannelRoutingOptionalFields: [] = [] -export type ChannelRoutingOptions = OptionsBaseMessage & { - checkOptionalsAreSet?: [] - channel_id_CustomCheck?: (v: string) => boolean - send_errors_CustomCheck?: (v: number) => boolean - receive_errors_CustomCheck?: (v: number) => boolean - forward_errors_as_input_CustomCheck?: (v: number) => boolean - forward_errors_as_output_CustomCheck?: (v: number) => boolean - missed_forward_fee_as_input_CustomCheck?: (v: number) => boolean - missed_forward_fee_as_output_CustomCheck?: (v: number) => boolean - forward_fee_as_input_CustomCheck?: (v: number) => boolean - forward_fee_as_output_CustomCheck?: (v: number) => boolean - events_number_CustomCheck?: (v: number) => boolean -} -export const ChannelRoutingValidate = (o?: ChannelRouting, opts: ChannelRoutingOptions = {}, path: string = 'ChannelRouting::root.'): Error | null => { - if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') - if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') - - if (typeof o.channel_id !== 'string') return new Error(`${path}.channel_id: is not a string`) - if (opts.channel_id_CustomCheck && !opts.channel_id_CustomCheck(o.channel_id)) return new Error(`${path}.channel_id: custom check failed`) - - if (typeof o.send_errors !== 'number') return new Error(`${path}.send_errors: is not a number`) - if (opts.send_errors_CustomCheck && !opts.send_errors_CustomCheck(o.send_errors)) return new Error(`${path}.send_errors: custom check failed`) - - if (typeof o.receive_errors !== 'number') return new Error(`${path}.receive_errors: is not a number`) - if (opts.receive_errors_CustomCheck && !opts.receive_errors_CustomCheck(o.receive_errors)) return new Error(`${path}.receive_errors: custom check failed`) - - if (typeof o.forward_errors_as_input !== 'number') return new Error(`${path}.forward_errors_as_input: is not a number`) - if (opts.forward_errors_as_input_CustomCheck && !opts.forward_errors_as_input_CustomCheck(o.forward_errors_as_input)) return new Error(`${path}.forward_errors_as_input: custom check failed`) - - if (typeof o.forward_errors_as_output !== 'number') return new Error(`${path}.forward_errors_as_output: is not a number`) - if (opts.forward_errors_as_output_CustomCheck && !opts.forward_errors_as_output_CustomCheck(o.forward_errors_as_output)) return new Error(`${path}.forward_errors_as_output: custom check failed`) - - if (typeof o.missed_forward_fee_as_input !== 'number') return new Error(`${path}.missed_forward_fee_as_input: is not a number`) - if (opts.missed_forward_fee_as_input_CustomCheck && !opts.missed_forward_fee_as_input_CustomCheck(o.missed_forward_fee_as_input)) return new Error(`${path}.missed_forward_fee_as_input: custom check failed`) - - if (typeof o.missed_forward_fee_as_output !== 'number') return new Error(`${path}.missed_forward_fee_as_output: is not a number`) - if (opts.missed_forward_fee_as_output_CustomCheck && !opts.missed_forward_fee_as_output_CustomCheck(o.missed_forward_fee_as_output)) return new Error(`${path}.missed_forward_fee_as_output: custom check failed`) - - if (typeof o.forward_fee_as_input !== 'number') return new Error(`${path}.forward_fee_as_input: is not a number`) - if (opts.forward_fee_as_input_CustomCheck && !opts.forward_fee_as_input_CustomCheck(o.forward_fee_as_input)) return new Error(`${path}.forward_fee_as_input: custom check failed`) - - if (typeof o.forward_fee_as_output !== 'number') return new Error(`${path}.forward_fee_as_output: is not a number`) - if (opts.forward_fee_as_output_CustomCheck && !opts.forward_fee_as_output_CustomCheck(o.forward_fee_as_output)) return new Error(`${path}.forward_fee_as_output: custom check failed`) - - if (typeof o.events_number !== 'number') return new Error(`${path}.events_number: is not a number`) - if (opts.events_number_CustomCheck && !opts.events_number_CustomCheck(o.events_number)) return new Error(`${path}.events_number: custom check failed`) - - return null -} - -export type PayAddressRequest = { - address: string - amoutSats: number - satsPerVByte: number -} -export const PayAddressRequestOptionalFields: [] = [] -export type PayAddressRequestOptions = OptionsBaseMessage & { - checkOptionalsAreSet?: [] - address_CustomCheck?: (v: string) => boolean - amoutSats_CustomCheck?: (v: number) => boolean - satsPerVByte_CustomCheck?: (v: number) => boolean -} -export const PayAddressRequestValidate = (o?: PayAddressRequest, opts: PayAddressRequestOptions = {}, path: string = 'PayAddressRequest::root.'): Error | null => { - if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') - if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') - - if (typeof o.address !== 'string') return new Error(`${path}.address: is not a string`) - if (opts.address_CustomCheck && !opts.address_CustomCheck(o.address)) return new Error(`${path}.address: custom check failed`) - - if (typeof o.amoutSats !== 'number') return new Error(`${path}.amoutSats: is not a number`) - if (opts.amoutSats_CustomCheck && !opts.amoutSats_CustomCheck(o.amoutSats)) return new Error(`${path}.amoutSats: custom check failed`) - - if (typeof o.satsPerVByte !== 'number') return new Error(`${path}.satsPerVByte: is not a number`) - if (opts.satsPerVByte_CustomCheck && !opts.satsPerVByte_CustomCheck(o.satsPerVByte)) return new Error(`${path}.satsPerVByte: custom check failed`) - - return null -} - -export type PayAddressResponse = { - txId: string - operation_id: string - service_fee: number - network_fee: number -} -export const PayAddressResponseOptionalFields: [] = [] -export type PayAddressResponseOptions = OptionsBaseMessage & { - checkOptionalsAreSet?: [] - txId_CustomCheck?: (v: string) => boolean - operation_id_CustomCheck?: (v: string) => boolean - service_fee_CustomCheck?: (v: number) => boolean - network_fee_CustomCheck?: (v: number) => boolean -} -export const PayAddressResponseValidate = (o?: PayAddressResponse, opts: PayAddressResponseOptions = {}, path: string = 'PayAddressResponse::root.'): Error | null => { - if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') - if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') - - if (typeof o.txId !== 'string') return new Error(`${path}.txId: is not a string`) - if (opts.txId_CustomCheck && !opts.txId_CustomCheck(o.txId)) return new Error(`${path}.txId: custom check failed`) - - if (typeof o.operation_id !== 'string') return new Error(`${path}.operation_id: is not a string`) - if (opts.operation_id_CustomCheck && !opts.operation_id_CustomCheck(o.operation_id)) return new Error(`${path}.operation_id: custom check failed`) - - if (typeof o.service_fee !== 'number') return new Error(`${path}.service_fee: is not a number`) - if (opts.service_fee_CustomCheck && !opts.service_fee_CustomCheck(o.service_fee)) return new Error(`${path}.service_fee: custom check failed`) - - if (typeof o.network_fee !== 'number') return new Error(`${path}.network_fee: is not a number`) - if (opts.network_fee_CustomCheck && !opts.network_fee_CustomCheck(o.network_fee)) return new Error(`${path}.network_fee: custom check failed`) - - return null -} - -export type AuthApp = { - app: Application - auth_token: string -} -export const AuthAppOptionalFields: [] = [] -export type AuthAppOptions = OptionsBaseMessage & { - checkOptionalsAreSet?: [] - app_Options?: ApplicationOptions - auth_token_CustomCheck?: (v: string) => boolean -} -export const AuthAppValidate = (o?: AuthApp, opts: AuthAppOptions = {}, path: string = 'AuthApp::root.'): Error | null => { - if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') - if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') - - const appErr = ApplicationValidate(o.app, opts.app_Options, `${path}.app`) - if (appErr !== null) return appErr - - - if (typeof o.auth_token !== 'string') return new Error(`${path}.auth_token: is not a string`) - if (opts.auth_token_CustomCheck && !opts.auth_token_CustomCheck(o.auth_token)) return new Error(`${path}.auth_token: custom check failed`) - - return null -} - -export type AppMetrics = { - app: Application - users: UsersInfo - received: number - spent: number - available: number - fees: number - invoices: number - total_fees: number - operations: UserOperation[] -} -export const AppMetricsOptionalFields: [] = [] -export type AppMetricsOptions = OptionsBaseMessage & { - checkOptionalsAreSet?: [] - app_Options?: ApplicationOptions - users_Options?: UsersInfoOptions - received_CustomCheck?: (v: number) => boolean - spent_CustomCheck?: (v: number) => boolean - available_CustomCheck?: (v: number) => boolean - fees_CustomCheck?: (v: number) => boolean - invoices_CustomCheck?: (v: number) => boolean - total_fees_CustomCheck?: (v: number) => boolean - operations_ItemOptions?: UserOperationOptions - operations_CustomCheck?: (v: UserOperation[]) => boolean -} -export const AppMetricsValidate = (o?: AppMetrics, opts: AppMetricsOptions = {}, path: string = 'AppMetrics::root.'): Error | null => { - if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') - if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') - - const appErr = ApplicationValidate(o.app, opts.app_Options, `${path}.app`) - if (appErr !== null) return appErr - - - const usersErr = UsersInfoValidate(o.users, opts.users_Options, `${path}.users`) - if (usersErr !== null) return usersErr - - - if (typeof o.received !== 'number') return new Error(`${path}.received: is not a number`) - if (opts.received_CustomCheck && !opts.received_CustomCheck(o.received)) return new Error(`${path}.received: custom check failed`) - - if (typeof o.spent !== 'number') return new Error(`${path}.spent: is not a number`) - if (opts.spent_CustomCheck && !opts.spent_CustomCheck(o.spent)) return new Error(`${path}.spent: custom check failed`) - - if (typeof o.available !== 'number') return new Error(`${path}.available: is not a number`) - if (opts.available_CustomCheck && !opts.available_CustomCheck(o.available)) return new Error(`${path}.available: custom check failed`) - - if (typeof o.fees !== 'number') return new Error(`${path}.fees: is not a number`) - if (opts.fees_CustomCheck && !opts.fees_CustomCheck(o.fees)) return new Error(`${path}.fees: custom check failed`) - - if (typeof o.invoices !== 'number') return new Error(`${path}.invoices: is not a number`) - if (opts.invoices_CustomCheck && !opts.invoices_CustomCheck(o.invoices)) return new Error(`${path}.invoices: custom check failed`) - - if (typeof o.total_fees !== 'number') return new Error(`${path}.total_fees: is not a number`) - if (opts.total_fees_CustomCheck && !opts.total_fees_CustomCheck(o.total_fees)) return new Error(`${path}.total_fees: custom check failed`) - - if (!Array.isArray(o.operations)) return new Error(`${path}.operations: is not an array`) - for (let index = 0; index < o.operations.length; index++) { - const operationsErr = UserOperationValidate(o.operations[index], opts.operations_ItemOptions, `${path}.operations[${index}]`) - if (operationsErr !== null) return operationsErr - } - if (opts.operations_CustomCheck && !opts.operations_CustomCheck(o.operations)) return new Error(`${path}.operations: custom check failed`) - - return null -} - -export type BanUserResponse = { - balance_sats: number - banned_app_users: BannedAppUser[] -} -export const BanUserResponseOptionalFields: [] = [] -export type BanUserResponseOptions = OptionsBaseMessage & { - checkOptionalsAreSet?: [] - balance_sats_CustomCheck?: (v: number) => boolean - banned_app_users_ItemOptions?: BannedAppUserOptions - banned_app_users_CustomCheck?: (v: BannedAppUser[]) => boolean -} -export const BanUserResponseValidate = (o?: BanUserResponse, opts: BanUserResponseOptions = {}, path: string = 'BanUserResponse::root.'): Error | null => { - if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') - if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') - - if (typeof o.balance_sats !== 'number') return new Error(`${path}.balance_sats: is not a number`) - if (opts.balance_sats_CustomCheck && !opts.balance_sats_CustomCheck(o.balance_sats)) return new Error(`${path}.balance_sats: custom check failed`) - - if (!Array.isArray(o.banned_app_users)) return new Error(`${path}.banned_app_users: is not an array`) - for (let index = 0; index < o.banned_app_users.length; index++) { - const banned_app_usersErr = BannedAppUserValidate(o.banned_app_users[index], opts.banned_app_users_ItemOptions, `${path}.banned_app_users[${index}]`) - if (banned_app_usersErr !== null) return banned_app_usersErr - } - if (opts.banned_app_users_CustomCheck && !opts.banned_app_users_CustomCheck(o.banned_app_users)) return new Error(`${path}.banned_app_users: custom check failed`) - - return null -} - -export type GetAppUserRequest = { - user_identifier: string -} -export const GetAppUserRequestOptionalFields: [] = [] -export type GetAppUserRequestOptions = OptionsBaseMessage & { - checkOptionalsAreSet?: [] - user_identifier_CustomCheck?: (v: string) => boolean -} -export const GetAppUserRequestValidate = (o?: GetAppUserRequest, opts: GetAppUserRequestOptions = {}, path: string = 'GetAppUserRequest::root.'): Error | null => { - if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') - if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') - - if (typeof o.user_identifier !== 'string') return new Error(`${path}.user_identifier: is not a string`) - if (opts.user_identifier_CustomCheck && !opts.user_identifier_CustomCheck(o.user_identifier)) return new Error(`${path}.user_identifier: custom check failed`) - - return null -} - -export type SetMockAppBalanceRequest = { - amount: number -} -export const SetMockAppBalanceRequestOptionalFields: [] = [] -export type SetMockAppBalanceRequestOptions = OptionsBaseMessage & { - checkOptionalsAreSet?: [] - amount_CustomCheck?: (v: number) => boolean -} -export const SetMockAppBalanceRequestValidate = (o?: SetMockAppBalanceRequest, opts: SetMockAppBalanceRequestOptions = {}, path: string = 'SetMockAppBalanceRequest::root.'): Error | null => { - if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') - if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') - - if (typeof o.amount !== 'number') return new Error(`${path}.amount: is not a number`) - if (opts.amount_CustomCheck && !opts.amount_CustomCheck(o.amount)) return new Error(`${path}.amount: custom check failed`) - - return null -} - -export type DecodeInvoiceRequest = { - invoice: string -} -export const DecodeInvoiceRequestOptionalFields: [] = [] -export type DecodeInvoiceRequestOptions = OptionsBaseMessage & { - checkOptionalsAreSet?: [] - invoice_CustomCheck?: (v: string) => boolean -} -export const DecodeInvoiceRequestValidate = (o?: DecodeInvoiceRequest, opts: DecodeInvoiceRequestOptions = {}, path: string = 'DecodeInvoiceRequest::root.'): Error | null => { - if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') - if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') - - if (typeof o.invoice !== 'string') return new Error(`${path}.invoice: is not a string`) - if (opts.invoice_CustomCheck && !opts.invoice_CustomCheck(o.invoice)) return new Error(`${path}.invoice: custom check failed`) - - return null -} - -export type RequestNPubLinkingTokenResponse = { - token: string -} -export const RequestNPubLinkingTokenResponseOptionalFields: [] = [] -export type RequestNPubLinkingTokenResponseOptions = OptionsBaseMessage & { - checkOptionalsAreSet?: [] - token_CustomCheck?: (v: string) => boolean -} -export const RequestNPubLinkingTokenResponseValidate = (o?: RequestNPubLinkingTokenResponse, opts: RequestNPubLinkingTokenResponseOptions = {}, path: string = 'RequestNPubLinkingTokenResponse::root.'): Error | null => { - if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') - if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') - - if (typeof o.token !== 'string') return new Error(`${path}.token: is not a string`) - if (opts.token_CustomCheck && !opts.token_CustomCheck(o.token)) return new Error(`${path}.token: custom check failed`) - - return null -} - -export type LndMetricsRequest = { - from_unix?: number - to_unix?: number -} -export type LndMetricsRequestOptionalField = 'from_unix' | 'to_unix' -export const LndMetricsRequestOptionalFields: LndMetricsRequestOptionalField[] = ['from_unix', 'to_unix'] -export type LndMetricsRequestOptions = OptionsBaseMessage & { - checkOptionalsAreSet?: LndMetricsRequestOptionalField[] - from_unix_CustomCheck?: (v?: number) => boolean - to_unix_CustomCheck?: (v?: number) => boolean -} -export const LndMetricsRequestValidate = (o?: LndMetricsRequest, opts: LndMetricsRequestOptions = {}, path: string = 'LndMetricsRequest::root.'): Error | null => { - if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') - if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') - - if ((o.from_unix || opts.allOptionalsAreSet || opts.checkOptionalsAreSet?.includes('from_unix')) && typeof o.from_unix !== 'number') return new Error(`${path}.from_unix: is not a number`) - if (opts.from_unix_CustomCheck && !opts.from_unix_CustomCheck(o.from_unix)) return new Error(`${path}.from_unix: custom check failed`) - - if ((o.to_unix || opts.allOptionalsAreSet || opts.checkOptionalsAreSet?.includes('to_unix')) && typeof o.to_unix !== 'number') return new Error(`${path}.to_unix: is not a number`) - if (opts.to_unix_CustomCheck && !opts.to_unix_CustomCheck(o.to_unix)) return new Error(`${path}.to_unix: custom check failed`) - - return null -} - -export type BannedAppUser = { - app_name: string - app_id: string - user_identifier: string - nostr_pub: string -} -export const BannedAppUserOptionalFields: [] = [] -export type BannedAppUserOptions = OptionsBaseMessage & { - checkOptionalsAreSet?: [] - app_name_CustomCheck?: (v: string) => boolean - app_id_CustomCheck?: (v: string) => boolean - user_identifier_CustomCheck?: (v: string) => boolean - nostr_pub_CustomCheck?: (v: string) => boolean -} -export const BannedAppUserValidate = (o?: BannedAppUser, opts: BannedAppUserOptions = {}, path: string = 'BannedAppUser::root.'): Error | null => { - if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') - if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') - - if (typeof o.app_name !== 'string') return new Error(`${path}.app_name: is not a string`) - if (opts.app_name_CustomCheck && !opts.app_name_CustomCheck(o.app_name)) return new Error(`${path}.app_name: custom check failed`) - - if (typeof o.app_id !== 'string') return new Error(`${path}.app_id: is not a string`) - if (opts.app_id_CustomCheck && !opts.app_id_CustomCheck(o.app_id)) return new Error(`${path}.app_id: custom check failed`) - - if (typeof o.user_identifier !== 'string') return new Error(`${path}.user_identifier: is not a string`) - if (opts.user_identifier_CustomCheck && !opts.user_identifier_CustomCheck(o.user_identifier)) return new Error(`${path}.user_identifier: custom check failed`) - - if (typeof o.nostr_pub !== 'string') return new Error(`${path}.nostr_pub: is not a string`) - if (opts.nostr_pub_CustomCheck && !opts.nostr_pub_CustomCheck(o.nostr_pub)) return new Error(`${path}.nostr_pub: custom check failed`) - - return null -} - -export type SetMockAppUserBalanceRequest = { - user_identifier: string - amount: number -} -export const SetMockAppUserBalanceRequestOptionalFields: [] = [] -export type SetMockAppUserBalanceRequestOptions = OptionsBaseMessage & { - checkOptionalsAreSet?: [] - user_identifier_CustomCheck?: (v: string) => boolean - amount_CustomCheck?: (v: number) => boolean -} -export const SetMockAppUserBalanceRequestValidate = (o?: SetMockAppUserBalanceRequest, opts: SetMockAppUserBalanceRequestOptions = {}, path: string = 'SetMockAppUserBalanceRequest::root.'): Error | null => { - if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') - if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') - - if (typeof o.user_identifier !== 'string') return new Error(`${path}.user_identifier: is not a string`) - if (opts.user_identifier_CustomCheck && !opts.user_identifier_CustomCheck(o.user_identifier)) return new Error(`${path}.user_identifier: custom check failed`) - - if (typeof o.amount !== 'number') return new Error(`${path}.amount: is not a number`) - if (opts.amount_CustomCheck && !opts.amount_CustomCheck(o.amount)) return new Error(`${path}.amount: custom check failed`) - - return null -} - -export type PayInvoiceRequest = { - invoice: string - amount: number -} -export const PayInvoiceRequestOptionalFields: [] = [] -export type PayInvoiceRequestOptions = OptionsBaseMessage & { - checkOptionalsAreSet?: [] - invoice_CustomCheck?: (v: string) => boolean - amount_CustomCheck?: (v: number) => boolean -} -export const PayInvoiceRequestValidate = (o?: PayInvoiceRequest, opts: PayInvoiceRequestOptions = {}, path: string = 'PayInvoiceRequest::root.'): Error | null => { - if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') - if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') - - if (typeof o.invoice !== 'string') return new Error(`${path}.invoice: is not a string`) - if (opts.invoice_CustomCheck && !opts.invoice_CustomCheck(o.invoice)) return new Error(`${path}.invoice: custom check failed`) - - if (typeof o.amount !== 'number') return new Error(`${path}.amount: is not a number`) - if (opts.amount_CustomCheck && !opts.amount_CustomCheck(o.amount)) return new Error(`${path}.amount: custom check failed`) - - return null -} - -export type LndGetInfoRequest = { - nodeId: number -} -export const LndGetInfoRequestOptionalFields: [] = [] -export type LndGetInfoRequestOptions = OptionsBaseMessage & { - checkOptionalsAreSet?: [] - nodeId_CustomCheck?: (v: number) => boolean -} -export const LndGetInfoRequestValidate = (o?: LndGetInfoRequest, opts: LndGetInfoRequestOptions = {}, path: string = 'LndGetInfoRequest::root.'): Error | null => { - if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') - if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') - - if (typeof o.nodeId !== 'number') return new Error(`${path}.nodeId: is not a number`) - if (opts.nodeId_CustomCheck && !opts.nodeId_CustomCheck(o.nodeId)) return new Error(`${path}.nodeId: custom check failed`) - - return null -} - -export type AppUser = { - identifier: string - info: UserInfo - max_withdrawable: number -} -export const AppUserOptionalFields: [] = [] -export type AppUserOptions = OptionsBaseMessage & { - checkOptionalsAreSet?: [] - identifier_CustomCheck?: (v: string) => boolean - info_Options?: UserInfoOptions - max_withdrawable_CustomCheck?: (v: number) => boolean -} -export const AppUserValidate = (o?: AppUser, opts: AppUserOptions = {}, path: string = 'AppUser::root.'): Error | null => { - if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') - if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') - - if (typeof o.identifier !== 'string') return new Error(`${path}.identifier: is not a string`) - if (opts.identifier_CustomCheck && !opts.identifier_CustomCheck(o.identifier)) return new Error(`${path}.identifier: custom check failed`) - - const infoErr = UserInfoValidate(o.info, opts.info_Options, `${path}.info`) - if (infoErr !== null) return infoErr - - - if (typeof o.max_withdrawable !== 'number') return new Error(`${path}.max_withdrawable: is not a number`) - if (opts.max_withdrawable_CustomCheck && !opts.max_withdrawable_CustomCheck(o.max_withdrawable)) return new Error(`${path}.max_withdrawable: custom check failed`) - - return null -} - -export type AddAppUserRequest = { - identifier: string - fail_if_exists: boolean - balance: number -} -export const AddAppUserRequestOptionalFields: [] = [] -export type AddAppUserRequestOptions = OptionsBaseMessage & { - checkOptionalsAreSet?: [] - identifier_CustomCheck?: (v: string) => boolean - fail_if_exists_CustomCheck?: (v: boolean) => boolean - balance_CustomCheck?: (v: number) => boolean -} -export const AddAppUserRequestValidate = (o?: AddAppUserRequest, opts: AddAppUserRequestOptions = {}, path: string = 'AddAppUserRequest::root.'): Error | null => { - if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') - if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') - - if (typeof o.identifier !== 'string') return new Error(`${path}.identifier: is not a string`) - if (opts.identifier_CustomCheck && !opts.identifier_CustomCheck(o.identifier)) return new Error(`${path}.identifier: custom check failed`) - - if (typeof o.fail_if_exists !== 'boolean') return new Error(`${path}.fail_if_exists: is not a boolean`) - if (opts.fail_if_exists_CustomCheck && !opts.fail_if_exists_CustomCheck(o.fail_if_exists)) return new Error(`${path}.fail_if_exists: custom check failed`) - - if (typeof o.balance !== 'number') return new Error(`${path}.balance: is not a number`) - if (opts.balance_CustomCheck && !opts.balance_CustomCheck(o.balance)) return new Error(`${path}.balance: custom check failed`) - - return null -} - -export type NewInvoiceResponse = { - invoice: string -} -export const NewInvoiceResponseOptionalFields: [] = [] -export type NewInvoiceResponseOptions = OptionsBaseMessage & { - checkOptionalsAreSet?: [] - invoice_CustomCheck?: (v: string) => boolean -} -export const NewInvoiceResponseValidate = (o?: NewInvoiceResponse, opts: NewInvoiceResponseOptions = {}, path: string = 'NewInvoiceResponse::root.'): Error | null => { - if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') - if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') - - if (typeof o.invoice !== 'string') return new Error(`${path}.invoice: is not a string`) - if (opts.invoice_CustomCheck && !opts.invoice_CustomCheck(o.invoice)) return new Error(`${path}.invoice: custom check failed`) - - return null -} - -export type NewAddressResponse = { - address: string -} -export const NewAddressResponseOptionalFields: [] = [] -export type NewAddressResponseOptions = OptionsBaseMessage & { - checkOptionalsAreSet?: [] - address_CustomCheck?: (v: string) => boolean -} -export const NewAddressResponseValidate = (o?: NewAddressResponse, opts: NewAddressResponseOptions = {}, path: string = 'NewAddressResponse::root.'): Error | null => { - if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') - if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') - - if (typeof o.address !== 'string') return new Error(`${path}.address: is not a string`) - if (opts.address_CustomCheck && !opts.address_CustomCheck(o.address)) return new Error(`${path}.address: custom check failed`) - - return null -} - -export type AppsMetrics = { - apps: AppMetrics[] -} -export const AppsMetricsOptionalFields: [] = [] -export type AppsMetricsOptions = OptionsBaseMessage & { - checkOptionalsAreSet?: [] - apps_ItemOptions?: AppMetricsOptions - apps_CustomCheck?: (v: AppMetrics[]) => boolean -} -export const AppsMetricsValidate = (o?: AppsMetrics, opts: AppsMetricsOptions = {}, path: string = 'AppsMetrics::root.'): Error | null => { - if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') - if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') - - if (!Array.isArray(o.apps)) return new Error(`${path}.apps: is not an array`) - for (let index = 0; index < o.apps.length; index++) { - const appsErr = AppMetricsValidate(o.apps[index], opts.apps_ItemOptions, `${path}.apps[${index}]`) - if (appsErr !== null) return appsErr - } - if (opts.apps_CustomCheck && !opts.apps_CustomCheck(o.apps)) return new Error(`${path}.apps: custom check failed`) - - return null -} - -export type LndGetInfoResponse = { - alias: string -} -export const LndGetInfoResponseOptionalFields: [] = [] -export type LndGetInfoResponseOptions = OptionsBaseMessage & { - checkOptionalsAreSet?: [] - alias_CustomCheck?: (v: string) => boolean -} -export const LndGetInfoResponseValidate = (o?: LndGetInfoResponse, opts: LndGetInfoResponseOptions = {}, path: string = 'LndGetInfoResponse::root.'): Error | null => { - if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') - if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') - - if (typeof o.alias !== 'string') return new Error(`${path}.alias: is not a string`) - if (opts.alias_CustomCheck && !opts.alias_CustomCheck(o.alias)) return new Error(`${path}.alias: custom check failed`) - - return null -} - -export type SendAppUserToAppPaymentRequest = { - from_user_identifier: string - amount: number -} -export const SendAppUserToAppPaymentRequestOptionalFields: [] = [] -export type SendAppUserToAppPaymentRequestOptions = OptionsBaseMessage & { - checkOptionalsAreSet?: [] - from_user_identifier_CustomCheck?: (v: string) => boolean - amount_CustomCheck?: (v: number) => boolean -} -export const SendAppUserToAppPaymentRequestValidate = (o?: SendAppUserToAppPaymentRequest, opts: SendAppUserToAppPaymentRequestOptions = {}, path: string = 'SendAppUserToAppPaymentRequest::root.'): Error | null => { - if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') - if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') - - if (typeof o.from_user_identifier !== 'string') return new Error(`${path}.from_user_identifier: is not a string`) - if (opts.from_user_identifier_CustomCheck && !opts.from_user_identifier_CustomCheck(o.from_user_identifier)) return new Error(`${path}.from_user_identifier: custom check failed`) - - if (typeof o.amount !== 'number') return new Error(`${path}.amount: is not a number`) - if (opts.amount_CustomCheck && !opts.amount_CustomCheck(o.amount)) return new Error(`${path}.amount: custom check failed`) - - return null -} - -export type GetUserOperationsRequest = { - latestIncomingInvoice: number - latestOutgoingInvoice: number - latestIncomingTx: number - latestOutgoingTx: number - latestIncomingUserToUserPayment: number - latestOutgoingUserToUserPayment: number - max_size: number -} -export const GetUserOperationsRequestOptionalFields: [] = [] -export type GetUserOperationsRequestOptions = OptionsBaseMessage & { - checkOptionalsAreSet?: [] - latestIncomingInvoice_CustomCheck?: (v: number) => boolean - latestOutgoingInvoice_CustomCheck?: (v: number) => boolean - latestIncomingTx_CustomCheck?: (v: number) => boolean - latestOutgoingTx_CustomCheck?: (v: number) => boolean - latestIncomingUserToUserPayment_CustomCheck?: (v: number) => boolean - latestOutgoingUserToUserPayment_CustomCheck?: (v: number) => boolean - max_size_CustomCheck?: (v: number) => boolean -} -export const GetUserOperationsRequestValidate = (o?: GetUserOperationsRequest, opts: GetUserOperationsRequestOptions = {}, path: string = 'GetUserOperationsRequest::root.'): Error | null => { - if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') - if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') - - if (typeof o.latestIncomingInvoice !== 'number') return new Error(`${path}.latestIncomingInvoice: is not a number`) - if (opts.latestIncomingInvoice_CustomCheck && !opts.latestIncomingInvoice_CustomCheck(o.latestIncomingInvoice)) return new Error(`${path}.latestIncomingInvoice: custom check failed`) - - if (typeof o.latestOutgoingInvoice !== 'number') return new Error(`${path}.latestOutgoingInvoice: is not a number`) - if (opts.latestOutgoingInvoice_CustomCheck && !opts.latestOutgoingInvoice_CustomCheck(o.latestOutgoingInvoice)) return new Error(`${path}.latestOutgoingInvoice: custom check failed`) - - if (typeof o.latestIncomingTx !== 'number') return new Error(`${path}.latestIncomingTx: is not a number`) - if (opts.latestIncomingTx_CustomCheck && !opts.latestIncomingTx_CustomCheck(o.latestIncomingTx)) return new Error(`${path}.latestIncomingTx: custom check failed`) - - if (typeof o.latestOutgoingTx !== 'number') return new Error(`${path}.latestOutgoingTx: is not a number`) - if (opts.latestOutgoingTx_CustomCheck && !opts.latestOutgoingTx_CustomCheck(o.latestOutgoingTx)) return new Error(`${path}.latestOutgoingTx: custom check failed`) - - if (typeof o.latestIncomingUserToUserPayment !== 'number') return new Error(`${path}.latestIncomingUserToUserPayment: is not a number`) - if (opts.latestIncomingUserToUserPayment_CustomCheck && !opts.latestIncomingUserToUserPayment_CustomCheck(o.latestIncomingUserToUserPayment)) return new Error(`${path}.latestIncomingUserToUserPayment: custom check failed`) - - if (typeof o.latestOutgoingUserToUserPayment !== 'number') return new Error(`${path}.latestOutgoingUserToUserPayment: is not a number`) - if (opts.latestOutgoingUserToUserPayment_CustomCheck && !opts.latestOutgoingUserToUserPayment_CustomCheck(o.latestOutgoingUserToUserPayment)) return new Error(`${path}.latestOutgoingUserToUserPayment: custom check failed`) - - if (typeof o.max_size !== 'number') return new Error(`${path}.max_size: is not a number`) - if (opts.max_size_CustomCheck && !opts.max_size_CustomCheck(o.max_size)) return new Error(`${path}.max_size: custom check failed`) - - return null -} - -export type GetUserOperationsResponse = { - latestOutgoingInvoiceOperations: UserOperations - latestIncomingInvoiceOperations: UserOperations - latestOutgoingTxOperations: UserOperations - latestIncomingTxOperations: UserOperations - latestOutgoingUserToUserPayemnts: UserOperations - latestIncomingUserToUserPayemnts: UserOperations -} -export const GetUserOperationsResponseOptionalFields: [] = [] -export type GetUserOperationsResponseOptions = OptionsBaseMessage & { - checkOptionalsAreSet?: [] - latestOutgoingInvoiceOperations_Options?: UserOperationsOptions - latestIncomingInvoiceOperations_Options?: UserOperationsOptions - latestOutgoingTxOperations_Options?: UserOperationsOptions - latestIncomingTxOperations_Options?: UserOperationsOptions - latestOutgoingUserToUserPayemnts_Options?: UserOperationsOptions - latestIncomingUserToUserPayemnts_Options?: UserOperationsOptions -} -export const GetUserOperationsResponseValidate = (o?: GetUserOperationsResponse, opts: GetUserOperationsResponseOptions = {}, path: string = 'GetUserOperationsResponse::root.'): Error | null => { - if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') - if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') - - const latestOutgoingInvoiceOperationsErr = UserOperationsValidate(o.latestOutgoingInvoiceOperations, opts.latestOutgoingInvoiceOperations_Options, `${path}.latestOutgoingInvoiceOperations`) - if (latestOutgoingInvoiceOperationsErr !== null) return latestOutgoingInvoiceOperationsErr - - - const latestIncomingInvoiceOperationsErr = UserOperationsValidate(o.latestIncomingInvoiceOperations, opts.latestIncomingInvoiceOperations_Options, `${path}.latestIncomingInvoiceOperations`) - if (latestIncomingInvoiceOperationsErr !== null) return latestIncomingInvoiceOperationsErr - - - const latestOutgoingTxOperationsErr = UserOperationsValidate(o.latestOutgoingTxOperations, opts.latestOutgoingTxOperations_Options, `${path}.latestOutgoingTxOperations`) - if (latestOutgoingTxOperationsErr !== null) return latestOutgoingTxOperationsErr - - - const latestIncomingTxOperationsErr = UserOperationsValidate(o.latestIncomingTxOperations, opts.latestIncomingTxOperations_Options, `${path}.latestIncomingTxOperations`) - if (latestIncomingTxOperationsErr !== null) return latestIncomingTxOperationsErr - - - const latestOutgoingUserToUserPayemntsErr = UserOperationsValidate(o.latestOutgoingUserToUserPayemnts, opts.latestOutgoingUserToUserPayemnts_Options, `${path}.latestOutgoingUserToUserPayemnts`) - if (latestOutgoingUserToUserPayemntsErr !== null) return latestOutgoingUserToUserPayemntsErr - - - const latestIncomingUserToUserPayemntsErr = UserOperationsValidate(o.latestIncomingUserToUserPayemnts, opts.latestIncomingUserToUserPayemnts_Options, `${path}.latestIncomingUserToUserPayemnts`) - if (latestIncomingUserToUserPayemntsErr !== null) return latestIncomingUserToUserPayemntsErr - - - return null -} - -export type BanUserRequest = { - user_id: string -} -export const BanUserRequestOptionalFields: [] = [] -export type BanUserRequestOptions = OptionsBaseMessage & { - checkOptionalsAreSet?: [] - user_id_CustomCheck?: (v: string) => boolean -} -export const BanUserRequestValidate = (o?: BanUserRequest, opts: BanUserRequestOptions = {}, path: string = 'BanUserRequest::root.'): Error | null => { - if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') - if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') - - if (typeof o.user_id !== 'string') return new Error(`${path}.user_id: is not a string`) - if (opts.user_id_CustomCheck && !opts.user_id_CustomCheck(o.user_id)) return new Error(`${path}.user_id: custom check failed`) - - return null -} - -export type SendAppUserToAppUserPaymentRequest = { - from_user_identifier: string - to_user_identifier: string - amount: number -} -export const SendAppUserToAppUserPaymentRequestOptionalFields: [] = [] -export type SendAppUserToAppUserPaymentRequestOptions = OptionsBaseMessage & { - checkOptionalsAreSet?: [] - from_user_identifier_CustomCheck?: (v: string) => boolean - to_user_identifier_CustomCheck?: (v: string) => boolean - amount_CustomCheck?: (v: number) => boolean -} -export const SendAppUserToAppUserPaymentRequestValidate = (o?: SendAppUserToAppUserPaymentRequest, opts: SendAppUserToAppUserPaymentRequestOptions = {}, path: string = 'SendAppUserToAppUserPaymentRequest::root.'): Error | null => { - if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') - if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') - - if (typeof o.from_user_identifier !== 'string') return new Error(`${path}.from_user_identifier: is not a string`) - if (opts.from_user_identifier_CustomCheck && !opts.from_user_identifier_CustomCheck(o.from_user_identifier)) return new Error(`${path}.from_user_identifier: custom check failed`) - - if (typeof o.to_user_identifier !== 'string') return new Error(`${path}.to_user_identifier: is not a string`) - if (opts.to_user_identifier_CustomCheck && !opts.to_user_identifier_CustomCheck(o.to_user_identifier)) return new Error(`${path}.to_user_identifier: custom check failed`) - - if (typeof o.amount !== 'number') return new Error(`${path}.amount: is not a number`) - if (opts.amount_CustomCheck && !opts.amount_CustomCheck(o.amount)) return new Error(`${path}.amount: custom check failed`) - - return null -} - -export type AddAppInvoiceRequest = { - payer_identifier: string - http_callback_url: string - invoice_req: NewInvoiceRequest -} -export const AddAppInvoiceRequestOptionalFields: [] = [] -export type AddAppInvoiceRequestOptions = OptionsBaseMessage & { - checkOptionalsAreSet?: [] - payer_identifier_CustomCheck?: (v: string) => boolean - http_callback_url_CustomCheck?: (v: string) => boolean - invoice_req_Options?: NewInvoiceRequestOptions -} -export const AddAppInvoiceRequestValidate = (o?: AddAppInvoiceRequest, opts: AddAppInvoiceRequestOptions = {}, path: string = 'AddAppInvoiceRequest::root.'): Error | null => { - if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') - if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') - - if (typeof o.payer_identifier !== 'string') return new Error(`${path}.payer_identifier: is not a string`) - if (opts.payer_identifier_CustomCheck && !opts.payer_identifier_CustomCheck(o.payer_identifier)) return new Error(`${path}.payer_identifier: custom check failed`) - - if (typeof o.http_callback_url !== 'string') return new Error(`${path}.http_callback_url: is not a string`) - if (opts.http_callback_url_CustomCheck && !opts.http_callback_url_CustomCheck(o.http_callback_url)) return new Error(`${path}.http_callback_url: custom check failed`) - - const invoice_reqErr = NewInvoiceRequestValidate(o.invoice_req, opts.invoice_req_Options, `${path}.invoice_req`) - if (invoice_reqErr !== null) return invoice_reqErr - - - return null -} - -export type GetAppUserLNURLInfoRequest = { - user_identifier: string - base_url_override: string -} -export const GetAppUserLNURLInfoRequestOptionalFields: [] = [] -export type GetAppUserLNURLInfoRequestOptions = OptionsBaseMessage & { - checkOptionalsAreSet?: [] - user_identifier_CustomCheck?: (v: string) => boolean - base_url_override_CustomCheck?: (v: string) => boolean -} -export const GetAppUserLNURLInfoRequestValidate = (o?: GetAppUserLNURLInfoRequest, opts: GetAppUserLNURLInfoRequestOptions = {}, path: string = 'GetAppUserLNURLInfoRequest::root.'): Error | null => { - if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') - if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') - - if (typeof o.user_identifier !== 'string') return new Error(`${path}.user_identifier: is not a string`) - if (opts.user_identifier_CustomCheck && !opts.user_identifier_CustomCheck(o.user_identifier)) return new Error(`${path}.user_identifier: custom check failed`) - - if (typeof o.base_url_override !== 'string') return new Error(`${path}.base_url_override: is not a string`) - if (opts.base_url_override_CustomCheck && !opts.base_url_override_CustomCheck(o.base_url_override)) return new Error(`${path}.base_url_override: custom check failed`) - - return null -} - -export type LnurlLinkResponse = { - lnurl: string - k1: string -} -export const LnurlLinkResponseOptionalFields: [] = [] -export type LnurlLinkResponseOptions = OptionsBaseMessage & { - checkOptionalsAreSet?: [] - lnurl_CustomCheck?: (v: string) => boolean - k1_CustomCheck?: (v: string) => boolean -} -export const LnurlLinkResponseValidate = (o?: LnurlLinkResponse, opts: LnurlLinkResponseOptions = {}, path: string = 'LnurlLinkResponse::root.'): Error | null => { - if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') - if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') - - if (typeof o.lnurl !== 'string') return new Error(`${path}.lnurl: is not a string`) - if (opts.lnurl_CustomCheck && !opts.lnurl_CustomCheck(o.lnurl)) return new Error(`${path}.lnurl: custom check failed`) - - if (typeof o.k1 !== 'string') return new Error(`${path}.k1: is not a string`) - if (opts.k1_CustomCheck && !opts.k1_CustomCheck(o.k1)) return new Error(`${path}.k1: custom check failed`) - - return null -} - -export type LnurlWithdrawInfoResponse = { - tag: string - callback: string - k1: string - defaultDescription: string - minWithdrawable: number - maxWithdrawable: number - balanceCheck: string - payLink: string -} -export const LnurlWithdrawInfoResponseOptionalFields: [] = [] -export type LnurlWithdrawInfoResponseOptions = OptionsBaseMessage & { - checkOptionalsAreSet?: [] - tag_CustomCheck?: (v: string) => boolean - callback_CustomCheck?: (v: string) => boolean - k1_CustomCheck?: (v: string) => boolean - defaultDescription_CustomCheck?: (v: string) => boolean - minWithdrawable_CustomCheck?: (v: number) => boolean - maxWithdrawable_CustomCheck?: (v: number) => boolean - balanceCheck_CustomCheck?: (v: string) => boolean - payLink_CustomCheck?: (v: string) => boolean -} -export const LnurlWithdrawInfoResponseValidate = (o?: LnurlWithdrawInfoResponse, opts: LnurlWithdrawInfoResponseOptions = {}, path: string = 'LnurlWithdrawInfoResponse::root.'): Error | null => { - if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') - if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') - - if (typeof o.tag !== 'string') return new Error(`${path}.tag: is not a string`) - if (opts.tag_CustomCheck && !opts.tag_CustomCheck(o.tag)) return new Error(`${path}.tag: custom check failed`) - - if (typeof o.callback !== 'string') return new Error(`${path}.callback: is not a string`) - if (opts.callback_CustomCheck && !opts.callback_CustomCheck(o.callback)) return new Error(`${path}.callback: custom check failed`) - - if (typeof o.k1 !== 'string') return new Error(`${path}.k1: is not a string`) - if (opts.k1_CustomCheck && !opts.k1_CustomCheck(o.k1)) return new Error(`${path}.k1: custom check failed`) - - if (typeof o.defaultDescription !== 'string') return new Error(`${path}.defaultDescription: is not a string`) - if (opts.defaultDescription_CustomCheck && !opts.defaultDescription_CustomCheck(o.defaultDescription)) return new Error(`${path}.defaultDescription: custom check failed`) - - if (typeof o.minWithdrawable !== 'number') return new Error(`${path}.minWithdrawable: is not a number`) - if (opts.minWithdrawable_CustomCheck && !opts.minWithdrawable_CustomCheck(o.minWithdrawable)) return new Error(`${path}.minWithdrawable: custom check failed`) - - if (typeof o.maxWithdrawable !== 'number') return new Error(`${path}.maxWithdrawable: is not a number`) - if (opts.maxWithdrawable_CustomCheck && !opts.maxWithdrawable_CustomCheck(o.maxWithdrawable)) return new Error(`${path}.maxWithdrawable: custom check failed`) - - if (typeof o.balanceCheck !== 'string') return new Error(`${path}.balanceCheck: is not a string`) - if (opts.balanceCheck_CustomCheck && !opts.balanceCheck_CustomCheck(o.balanceCheck)) return new Error(`${path}.balanceCheck: custom check failed`) - - if (typeof o.payLink !== 'string') return new Error(`${path}.payLink: is not a string`) - if (opts.payLink_CustomCheck && !opts.payLink_CustomCheck(o.payLink)) return new Error(`${path}.payLink: custom check failed`) - - return null -} - -export type UserOperation = { - paidAtUnix: number - type: UserOperationType - inbound: boolean - amount: number - identifier: string - operationId: string - service_fee: number - network_fee: number - confirmed: boolean - tx_hash: string - internal: boolean -} -export const UserOperationOptionalFields: [] = [] -export type UserOperationOptions = OptionsBaseMessage & { - checkOptionalsAreSet?: [] - paidAtUnix_CustomCheck?: (v: number) => boolean - type_CustomCheck?: (v: UserOperationType) => boolean - inbound_CustomCheck?: (v: boolean) => boolean - amount_CustomCheck?: (v: number) => boolean - identifier_CustomCheck?: (v: string) => boolean - operationId_CustomCheck?: (v: string) => boolean - service_fee_CustomCheck?: (v: number) => boolean - network_fee_CustomCheck?: (v: number) => boolean - confirmed_CustomCheck?: (v: boolean) => boolean - tx_hash_CustomCheck?: (v: string) => boolean - internal_CustomCheck?: (v: boolean) => boolean -} -export const UserOperationValidate = (o?: UserOperation, opts: UserOperationOptions = {}, path: string = 'UserOperation::root.'): Error | null => { - if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') - if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') - - if (typeof o.paidAtUnix !== 'number') return new Error(`${path}.paidAtUnix: is not a number`) - if (opts.paidAtUnix_CustomCheck && !opts.paidAtUnix_CustomCheck(o.paidAtUnix)) return new Error(`${path}.paidAtUnix: custom check failed`) - - if (!enumCheckUserOperationType(o.type)) return new Error(`${path}.type: is not a valid UserOperationType`) - if (opts.type_CustomCheck && !opts.type_CustomCheck(o.type)) return new Error(`${path}.type: custom check failed`) - - if (typeof o.inbound !== 'boolean') return new Error(`${path}.inbound: is not a boolean`) - if (opts.inbound_CustomCheck && !opts.inbound_CustomCheck(o.inbound)) return new Error(`${path}.inbound: custom check failed`) - - if (typeof o.amount !== 'number') return new Error(`${path}.amount: is not a number`) - if (opts.amount_CustomCheck && !opts.amount_CustomCheck(o.amount)) return new Error(`${path}.amount: custom check failed`) - - if (typeof o.identifier !== 'string') return new Error(`${path}.identifier: is not a string`) - if (opts.identifier_CustomCheck && !opts.identifier_CustomCheck(o.identifier)) return new Error(`${path}.identifier: custom check failed`) - - if (typeof o.operationId !== 'string') return new Error(`${path}.operationId: is not a string`) - if (opts.operationId_CustomCheck && !opts.operationId_CustomCheck(o.operationId)) return new Error(`${path}.operationId: custom check failed`) - - if (typeof o.service_fee !== 'number') return new Error(`${path}.service_fee: is not a number`) - if (opts.service_fee_CustomCheck && !opts.service_fee_CustomCheck(o.service_fee)) return new Error(`${path}.service_fee: custom check failed`) - - if (typeof o.network_fee !== 'number') return new Error(`${path}.network_fee: is not a number`) - if (opts.network_fee_CustomCheck && !opts.network_fee_CustomCheck(o.network_fee)) return new Error(`${path}.network_fee: custom check failed`) - - if (typeof o.confirmed !== 'boolean') return new Error(`${path}.confirmed: is not a boolean`) - if (opts.confirmed_CustomCheck && !opts.confirmed_CustomCheck(o.confirmed)) return new Error(`${path}.confirmed: custom check failed`) - - if (typeof o.tx_hash !== 'string') return new Error(`${path}.tx_hash: is not a string`) - if (opts.tx_hash_CustomCheck && !opts.tx_hash_CustomCheck(o.tx_hash)) return new Error(`${path}.tx_hash: custom check failed`) - - if (typeof o.internal !== 'boolean') return new Error(`${path}.internal: is not a boolean`) - if (opts.internal_CustomCheck && !opts.internal_CustomCheck(o.internal)) return new Error(`${path}.internal: custom check failed`) - - return null -} - -export type ClosureMigration = { - closes_at_unix: number -} -export const ClosureMigrationOptionalFields: [] = [] -export type ClosureMigrationOptions = OptionsBaseMessage & { - checkOptionalsAreSet?: [] - closes_at_unix_CustomCheck?: (v: number) => boolean -} -export const ClosureMigrationValidate = (o?: ClosureMigration, opts: ClosureMigrationOptions = {}, path: string = 'ClosureMigration::root.'): Error | null => { - if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') - if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') - - if (typeof o.closes_at_unix !== 'number') return new Error(`${path}.closes_at_unix: is not a number`) - if (opts.closes_at_unix_CustomCheck && !opts.closes_at_unix_CustomCheck(o.closes_at_unix)) return new Error(`${path}.closes_at_unix: custom check failed`) - - return null -} - -export type AuthAppRequest = { - name: string - allow_user_creation?: boolean -} -export type AuthAppRequestOptionalField = 'allow_user_creation' -export const AuthAppRequestOptionalFields: AuthAppRequestOptionalField[] = ['allow_user_creation'] -export type AuthAppRequestOptions = OptionsBaseMessage & { - checkOptionalsAreSet?: AuthAppRequestOptionalField[] - name_CustomCheck?: (v: string) => boolean - allow_user_creation_CustomCheck?: (v?: boolean) => boolean -} -export const AuthAppRequestValidate = (o?: AuthAppRequest, opts: AuthAppRequestOptions = {}, path: string = 'AuthAppRequest::root.'): Error | null => { - if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') - if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') - - if (typeof o.name !== 'string') return new Error(`${path}.name: is not a string`) - if (opts.name_CustomCheck && !opts.name_CustomCheck(o.name)) return new Error(`${path}.name: custom check failed`) - - if ((o.allow_user_creation || opts.allOptionalsAreSet || opts.checkOptionalsAreSet?.includes('allow_user_creation')) && typeof o.allow_user_creation !== 'boolean') return new Error(`${path}.allow_user_creation: is not a boolean`) - if (opts.allow_user_creation_CustomCheck && !opts.allow_user_creation_CustomCheck(o.allow_user_creation)) return new Error(`${path}.allow_user_creation: custom check failed`) - - return null -} - -export type Application = { - name: string - id: string - balance: number - npub: string -} -export const ApplicationOptionalFields: [] = [] -export type ApplicationOptions = OptionsBaseMessage & { - checkOptionalsAreSet?: [] - name_CustomCheck?: (v: string) => boolean - id_CustomCheck?: (v: string) => boolean - balance_CustomCheck?: (v: number) => boolean - npub_CustomCheck?: (v: string) => boolean -} -export const ApplicationValidate = (o?: Application, opts: ApplicationOptions = {}, path: string = 'Application::root.'): Error | null => { - if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') - if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') - - if (typeof o.name !== 'string') return new Error(`${path}.name: is not a string`) - if (opts.name_CustomCheck && !opts.name_CustomCheck(o.name)) return new Error(`${path}.name: custom check failed`) - - if (typeof o.id !== 'string') return new Error(`${path}.id: is not a string`) - if (opts.id_CustomCheck && !opts.id_CustomCheck(o.id)) return new Error(`${path}.id: custom check failed`) - - if (typeof o.balance !== 'number') return new Error(`${path}.balance: is not a number`) - if (opts.balance_CustomCheck && !opts.balance_CustomCheck(o.balance)) return new Error(`${path}.balance: custom check failed`) - - if (typeof o.npub !== 'string') return new Error(`${path}.npub: is not a string`) - if (opts.npub_CustomCheck && !opts.npub_CustomCheck(o.npub)) return new Error(`${path}.npub: custom check failed`) - - return null -} - -export type RelaysMigration = { - relays: string[] -} -export const RelaysMigrationOptionalFields: [] = [] -export type RelaysMigrationOptions = OptionsBaseMessage & { - checkOptionalsAreSet?: [] - relays_CustomCheck?: (v: string[]) => boolean -} -export const RelaysMigrationValidate = (o?: RelaysMigration, opts: RelaysMigrationOptions = {}, path: string = 'RelaysMigration::root.'): Error | null => { - if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') - if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') - - if (!Array.isArray(o.relays)) return new Error(`${path}.relays: is not an array`) - for (let index = 0; index < o.relays.length; index++) { - if (typeof o.relays[index] !== 'string') return new Error(`${path}.relays[${index}]: is not a string`) - } - if (opts.relays_CustomCheck && !opts.relays_CustomCheck(o.relays)) return new Error(`${path}.relays: custom check failed`) - - return null -} - -export type RequestNPubLinkingTokenRequest = { - user_identifier: string -} -export const RequestNPubLinkingTokenRequestOptionalFields: [] = [] -export type RequestNPubLinkingTokenRequestOptions = OptionsBaseMessage & { - checkOptionalsAreSet?: [] - user_identifier_CustomCheck?: (v: string) => boolean -} -export const RequestNPubLinkingTokenRequestValidate = (o?: RequestNPubLinkingTokenRequest, opts: RequestNPubLinkingTokenRequestOptions = {}, path: string = 'RequestNPubLinkingTokenRequest::root.'): Error | null => { - if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') - if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') - - if (typeof o.user_identifier !== 'string') return new Error(`${path}.user_identifier: is not a string`) - if (opts.user_identifier_CustomCheck && !opts.user_identifier_CustomCheck(o.user_identifier)) return new Error(`${path}.user_identifier: custom check failed`) - - return null -} - -export type ClosedChannel = { - channel_id: string - capacity: number - closed_height: number -} -export const ClosedChannelOptionalFields: [] = [] -export type ClosedChannelOptions = OptionsBaseMessage & { - checkOptionalsAreSet?: [] - channel_id_CustomCheck?: (v: string) => boolean - capacity_CustomCheck?: (v: number) => boolean - closed_height_CustomCheck?: (v: number) => boolean -} -export const ClosedChannelValidate = (o?: ClosedChannel, opts: ClosedChannelOptions = {}, path: string = 'ClosedChannel::root.'): Error | null => { - if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') - if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') - - if (typeof o.channel_id !== 'string') return new Error(`${path}.channel_id: is not a string`) - if (opts.channel_id_CustomCheck && !opts.channel_id_CustomCheck(o.channel_id)) return new Error(`${path}.channel_id: custom check failed`) - - if (typeof o.capacity !== 'number') return new Error(`${path}.capacity: is not a number`) - if (opts.capacity_CustomCheck && !opts.capacity_CustomCheck(o.capacity)) return new Error(`${path}.capacity: custom check failed`) - - if (typeof o.closed_height !== 'number') return new Error(`${path}.closed_height: is not a number`) - if (opts.closed_height_CustomCheck && !opts.closed_height_CustomCheck(o.closed_height)) return new Error(`${path}.closed_height: custom check failed`) - - return null -} - -export type OpenChannelResponse = { - channelId: string -} -export const OpenChannelResponseOptionalFields: [] = [] -export type OpenChannelResponseOptions = OptionsBaseMessage & { - checkOptionalsAreSet?: [] - channelId_CustomCheck?: (v: string) => boolean -} -export const OpenChannelResponseValidate = (o?: OpenChannelResponse, opts: OpenChannelResponseOptions = {}, path: string = 'OpenChannelResponse::root.'): Error | null => { - if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') - if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') - - if (typeof o.channelId !== 'string') return new Error(`${path}.channelId: is not a string`) - if (opts.channelId_CustomCheck && !opts.channelId_CustomCheck(o.channelId)) return new Error(`${path}.channelId: custom check failed`) - - return null -} - -export type Product = { - id: string - name: string - price_sats: number -} -export const ProductOptionalFields: [] = [] -export type ProductOptions = OptionsBaseMessage & { - checkOptionalsAreSet?: [] - id_CustomCheck?: (v: string) => boolean - name_CustomCheck?: (v: string) => boolean - price_sats_CustomCheck?: (v: number) => boolean -} -export const ProductValidate = (o?: Product, opts: ProductOptions = {}, path: string = 'Product::root.'): Error | null => { - if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') - if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') - - if (typeof o.id !== 'string') return new Error(`${path}.id: is not a string`) - if (opts.id_CustomCheck && !opts.id_CustomCheck(o.id)) return new Error(`${path}.id: custom check failed`) - - if (typeof o.name !== 'string') return new Error(`${path}.name: is not a string`) - if (opts.name_CustomCheck && !opts.name_CustomCheck(o.name)) return new Error(`${path}.name: custom check failed`) - - if (typeof o.price_sats !== 'number') return new Error(`${path}.price_sats: is not a number`) - if (opts.price_sats_CustomCheck && !opts.price_sats_CustomCheck(o.price_sats)) return new Error(`${path}.price_sats: custom check failed`) - - return null -} - -export type EncryptionExchangeRequest = { - publicKey: string - deviceId: string -} -export const EncryptionExchangeRequestOptionalFields: [] = [] -export type EncryptionExchangeRequestOptions = OptionsBaseMessage & { - checkOptionalsAreSet?: [] - publicKey_CustomCheck?: (v: string) => boolean - deviceId_CustomCheck?: (v: string) => boolean -} -export const EncryptionExchangeRequestValidate = (o?: EncryptionExchangeRequest, opts: EncryptionExchangeRequestOptions = {}, path: string = 'EncryptionExchangeRequest::root.'): Error | null => { - if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') - if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') - - if (typeof o.publicKey !== 'string') return new Error(`${path}.publicKey: is not a string`) - if (opts.publicKey_CustomCheck && !opts.publicKey_CustomCheck(o.publicKey)) return new Error(`${path}.publicKey: custom check failed`) - - if (typeof o.deviceId !== 'string') return new Error(`${path}.deviceId: is not a string`) - if (opts.deviceId_CustomCheck && !opts.deviceId_CustomCheck(o.deviceId)) return new Error(`${path}.deviceId: custom check failed`) - - return null -} - -export type AppsMetricsRequest = { - from_unix?: number - to_unix?: number - include_operations?: boolean -} -export type AppsMetricsRequestOptionalField = 'from_unix' | 'to_unix' | 'include_operations' -export const AppsMetricsRequestOptionalFields: AppsMetricsRequestOptionalField[] = ['from_unix', 'to_unix', 'include_operations'] -export type AppsMetricsRequestOptions = OptionsBaseMessage & { - checkOptionalsAreSet?: AppsMetricsRequestOptionalField[] - from_unix_CustomCheck?: (v?: number) => boolean - to_unix_CustomCheck?: (v?: number) => boolean - include_operations_CustomCheck?: (v?: boolean) => boolean -} -export const AppsMetricsRequestValidate = (o?: AppsMetricsRequest, opts: AppsMetricsRequestOptions = {}, path: string = 'AppsMetricsRequest::root.'): Error | null => { - if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') - if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') - - if ((o.from_unix || opts.allOptionalsAreSet || opts.checkOptionalsAreSet?.includes('from_unix')) && typeof o.from_unix !== 'number') return new Error(`${path}.from_unix: is not a number`) - if (opts.from_unix_CustomCheck && !opts.from_unix_CustomCheck(o.from_unix)) return new Error(`${path}.from_unix: custom check failed`) - - if ((o.to_unix || opts.allOptionalsAreSet || opts.checkOptionalsAreSet?.includes('to_unix')) && typeof o.to_unix !== 'number') return new Error(`${path}.to_unix: is not a number`) - if (opts.to_unix_CustomCheck && !opts.to_unix_CustomCheck(o.to_unix)) return new Error(`${path}.to_unix: custom check failed`) - - if ((o.include_operations || opts.allOptionalsAreSet || opts.checkOptionalsAreSet?.includes('include_operations')) && typeof o.include_operations !== 'boolean') return new Error(`${path}.include_operations: is not a boolean`) - if (opts.include_operations_CustomCheck && !opts.include_operations_CustomCheck(o.include_operations)) return new Error(`${path}.include_operations: custom check failed`) - - return null -} - -export type LiveUserOperation = { - operation: UserOperation -} -export const LiveUserOperationOptionalFields: [] = [] -export type LiveUserOperationOptions = OptionsBaseMessage & { - checkOptionalsAreSet?: [] - operation_Options?: UserOperationOptions -} -export const LiveUserOperationValidate = (o?: LiveUserOperation, opts: LiveUserOperationOptions = {}, path: string = 'LiveUserOperation::root.'): Error | null => { - if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') - if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') - - const operationErr = UserOperationValidate(o.operation, opts.operation_Options, `${path}.operation`) - if (operationErr !== null) return operationErr - - - return null -} - -export type HttpCreds = { - url: string - token: string -} -export const HttpCredsOptionalFields: [] = [] -export type HttpCredsOptions = OptionsBaseMessage & { - checkOptionalsAreSet?: [] - url_CustomCheck?: (v: string) => boolean - token_CustomCheck?: (v: string) => boolean -} -export const HttpCredsValidate = (o?: HttpCreds, opts: HttpCredsOptions = {}, path: string = 'HttpCreds::root.'): Error | null => { - if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') - if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') - - if (typeof o.url !== 'string') return new Error(`${path}.url: is not a string`) - if (opts.url_CustomCheck && !opts.url_CustomCheck(o.url)) return new Error(`${path}.url: custom check failed`) - - if (typeof o.token !== 'string') return new Error(`${path}.token: is not a string`) - if (opts.token_CustomCheck && !opts.token_CustomCheck(o.token)) return new Error(`${path}.token: custom check failed`) - - return null -} - -export type PayAppUserInvoiceRequest = { - user_identifier: string - invoice: string - amount: number -} -export const PayAppUserInvoiceRequestOptionalFields: [] = [] -export type PayAppUserInvoiceRequestOptions = OptionsBaseMessage & { - checkOptionalsAreSet?: [] - user_identifier_CustomCheck?: (v: string) => boolean - invoice_CustomCheck?: (v: string) => boolean - amount_CustomCheck?: (v: number) => boolean -} -export const PayAppUserInvoiceRequestValidate = (o?: PayAppUserInvoiceRequest, opts: PayAppUserInvoiceRequestOptions = {}, path: string = 'PayAppUserInvoiceRequest::root.'): Error | null => { - if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') - if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') - - if (typeof o.user_identifier !== 'string') return new Error(`${path}.user_identifier: is not a string`) - if (opts.user_identifier_CustomCheck && !opts.user_identifier_CustomCheck(o.user_identifier)) return new Error(`${path}.user_identifier: custom check failed`) - - if (typeof o.invoice !== 'string') return new Error(`${path}.invoice: is not a string`) - if (opts.invoice_CustomCheck && !opts.invoice_CustomCheck(o.invoice)) return new Error(`${path}.invoice: custom check failed`) - - if (typeof o.amount !== 'number') return new Error(`${path}.amount: is not a number`) - if (opts.amount_CustomCheck && !opts.amount_CustomCheck(o.amount)) return new Error(`${path}.amount: custom check failed`) - - return null -} - -export type NewInvoiceRequest = { - amountSats: number - memo: string -} -export const NewInvoiceRequestOptionalFields: [] = [] -export type NewInvoiceRequestOptions = OptionsBaseMessage & { - checkOptionalsAreSet?: [] - amountSats_CustomCheck?: (v: number) => boolean - memo_CustomCheck?: (v: string) => boolean -} -export const NewInvoiceRequestValidate = (o?: NewInvoiceRequest, opts: NewInvoiceRequestOptions = {}, path: string = 'NewInvoiceRequest::root.'): Error | null => { - if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') - if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') - - if (typeof o.amountSats !== 'number') return new Error(`${path}.amountSats: is not a number`) - if (opts.amountSats_CustomCheck && !opts.amountSats_CustomCheck(o.amountSats)) return new Error(`${path}.amountSats: custom check failed`) - - if (typeof o.memo !== 'string') return new Error(`${path}.memo: is not a string`) - if (opts.memo_CustomCheck && !opts.memo_CustomCheck(o.memo)) return new Error(`${path}.memo: custom check failed`) - - return null -} - -export type ChannelBalanceEvent = { - block_height: number - channel_id: string - local_balance_sats: number - remote_balance_sats: number -} -export const ChannelBalanceEventOptionalFields: [] = [] -export type ChannelBalanceEventOptions = OptionsBaseMessage & { - checkOptionalsAreSet?: [] - block_height_CustomCheck?: (v: number) => boolean - channel_id_CustomCheck?: (v: string) => boolean - local_balance_sats_CustomCheck?: (v: number) => boolean - remote_balance_sats_CustomCheck?: (v: number) => boolean -} -export const ChannelBalanceEventValidate = (o?: ChannelBalanceEvent, opts: ChannelBalanceEventOptions = {}, path: string = 'ChannelBalanceEvent::root.'): Error | null => { - if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') - if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') - - if (typeof o.block_height !== 'number') return new Error(`${path}.block_height: is not a number`) - if (opts.block_height_CustomCheck && !opts.block_height_CustomCheck(o.block_height)) return new Error(`${path}.block_height: custom check failed`) - - if (typeof o.channel_id !== 'string') return new Error(`${path}.channel_id: is not a string`) - if (opts.channel_id_CustomCheck && !opts.channel_id_CustomCheck(o.channel_id)) return new Error(`${path}.channel_id: custom check failed`) - - if (typeof o.local_balance_sats !== 'number') return new Error(`${path}.local_balance_sats: is not a number`) - if (opts.local_balance_sats_CustomCheck && !opts.local_balance_sats_CustomCheck(o.local_balance_sats)) return new Error(`${path}.local_balance_sats: custom check failed`) - - if (typeof o.remote_balance_sats !== 'number') return new Error(`${path}.remote_balance_sats: is not a number`) - if (opts.remote_balance_sats_CustomCheck && !opts.remote_balance_sats_CustomCheck(o.remote_balance_sats)) return new Error(`${path}.remote_balance_sats: custom check failed`) - - return null -} - -export type HandleLnurlPayResponse = { - pr: string - routes: Empty[] -} -export const HandleLnurlPayResponseOptionalFields: [] = [] -export type HandleLnurlPayResponseOptions = OptionsBaseMessage & { - checkOptionalsAreSet?: [] - pr_CustomCheck?: (v: string) => boolean - routes_ItemOptions?: EmptyOptions - routes_CustomCheck?: (v: Empty[]) => boolean -} -export const HandleLnurlPayResponseValidate = (o?: HandleLnurlPayResponse, opts: HandleLnurlPayResponseOptions = {}, path: string = 'HandleLnurlPayResponse::root.'): Error | null => { - if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') - if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') - - if (typeof o.pr !== 'string') return new Error(`${path}.pr: is not a string`) - if (opts.pr_CustomCheck && !opts.pr_CustomCheck(o.pr)) return new Error(`${path}.pr: custom check failed`) - - if (!Array.isArray(o.routes)) return new Error(`${path}.routes: is not an array`) - for (let index = 0; index < o.routes.length; index++) { - const routesErr = EmptyValidate(o.routes[index], opts.routes_ItemOptions, `${path}.routes[${index}]`) - if (routesErr !== null) return routesErr - } - if (opts.routes_CustomCheck && !opts.routes_CustomCheck(o.routes)) return new Error(`${path}.routes: custom check failed`) - - return null -} - -export type UserOperations = { - fromIndex: number - toIndex: number - operations: UserOperation[] -} -export const UserOperationsOptionalFields: [] = [] -export type UserOperationsOptions = OptionsBaseMessage & { - checkOptionalsAreSet?: [] - fromIndex_CustomCheck?: (v: number) => boolean - toIndex_CustomCheck?: (v: number) => boolean - operations_ItemOptions?: UserOperationOptions - operations_CustomCheck?: (v: UserOperation[]) => boolean -} -export const UserOperationsValidate = (o?: UserOperations, opts: UserOperationsOptions = {}, path: string = 'UserOperations::root.'): Error | null => { - if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') - if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') - - if (typeof o.fromIndex !== 'number') return new Error(`${path}.fromIndex: is not a number`) - if (opts.fromIndex_CustomCheck && !opts.fromIndex_CustomCheck(o.fromIndex)) return new Error(`${path}.fromIndex: custom check failed`) - - if (typeof o.toIndex !== 'number') return new Error(`${path}.toIndex: is not a number`) - if (opts.toIndex_CustomCheck && !opts.toIndex_CustomCheck(o.toIndex)) return new Error(`${path}.toIndex: custom check failed`) - - if (!Array.isArray(o.operations)) return new Error(`${path}.operations: is not an array`) - for (let index = 0; index < o.operations.length; index++) { - const operationsErr = UserOperationValidate(o.operations[index], opts.operations_ItemOptions, `${path}.operations[${index}]`) - if (operationsErr !== null) return operationsErr - } - if (opts.operations_CustomCheck && !opts.operations_CustomCheck(o.operations)) return new Error(`${path}.operations: custom check failed`) - - return null -} - -export type UsageMetric = { - processed_at_ms: number - parsed_in_nano: number - auth_in_nano: number - validate_in_nano: number - handle_in_nano: number - rpc_name: string - batch: boolean - nostr: boolean - batch_size: number -} -export const UsageMetricOptionalFields: [] = [] -export type UsageMetricOptions = OptionsBaseMessage & { - checkOptionalsAreSet?: [] - processed_at_ms_CustomCheck?: (v: number) => boolean - parsed_in_nano_CustomCheck?: (v: number) => boolean - auth_in_nano_CustomCheck?: (v: number) => boolean - validate_in_nano_CustomCheck?: (v: number) => boolean - handle_in_nano_CustomCheck?: (v: number) => boolean - rpc_name_CustomCheck?: (v: string) => boolean - batch_CustomCheck?: (v: boolean) => boolean - nostr_CustomCheck?: (v: boolean) => boolean - batch_size_CustomCheck?: (v: number) => boolean -} -export const UsageMetricValidate = (o?: UsageMetric, opts: UsageMetricOptions = {}, path: string = 'UsageMetric::root.'): Error | null => { - if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') - if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') - - if (typeof o.processed_at_ms !== 'number') return new Error(`${path}.processed_at_ms: is not a number`) - if (opts.processed_at_ms_CustomCheck && !opts.processed_at_ms_CustomCheck(o.processed_at_ms)) return new Error(`${path}.processed_at_ms: custom check failed`) - - if (typeof o.parsed_in_nano !== 'number') return new Error(`${path}.parsed_in_nano: is not a number`) - if (opts.parsed_in_nano_CustomCheck && !opts.parsed_in_nano_CustomCheck(o.parsed_in_nano)) return new Error(`${path}.parsed_in_nano: custom check failed`) - - if (typeof o.auth_in_nano !== 'number') return new Error(`${path}.auth_in_nano: is not a number`) - if (opts.auth_in_nano_CustomCheck && !opts.auth_in_nano_CustomCheck(o.auth_in_nano)) return new Error(`${path}.auth_in_nano: custom check failed`) - - if (typeof o.validate_in_nano !== 'number') return new Error(`${path}.validate_in_nano: is not a number`) - if (opts.validate_in_nano_CustomCheck && !opts.validate_in_nano_CustomCheck(o.validate_in_nano)) return new Error(`${path}.validate_in_nano: custom check failed`) - - if (typeof o.handle_in_nano !== 'number') return new Error(`${path}.handle_in_nano: is not a number`) - if (opts.handle_in_nano_CustomCheck && !opts.handle_in_nano_CustomCheck(o.handle_in_nano)) return new Error(`${path}.handle_in_nano: custom check failed`) - - if (typeof o.rpc_name !== 'string') return new Error(`${path}.rpc_name: is not a string`) - if (opts.rpc_name_CustomCheck && !opts.rpc_name_CustomCheck(o.rpc_name)) return new Error(`${path}.rpc_name: custom check failed`) - - if (typeof o.batch !== 'boolean') return new Error(`${path}.batch: is not a boolean`) - if (opts.batch_CustomCheck && !opts.batch_CustomCheck(o.batch)) return new Error(`${path}.batch: custom check failed`) - - if (typeof o.nostr !== 'boolean') return new Error(`${path}.nostr: is not a boolean`) - if (opts.nostr_CustomCheck && !opts.nostr_CustomCheck(o.nostr)) return new Error(`${path}.nostr: custom check failed`) - - if (typeof o.batch_size !== 'number') return new Error(`${path}.batch_size: is not a number`) - if (opts.batch_size_CustomCheck && !opts.batch_size_CustomCheck(o.batch_size)) return new Error(`${path}.batch_size: custom check failed`) - - return null -} - -export type RoutingEvent = { - incoming_channel_id: number - incoming_htlc_id: number - outgoing_channel_id: number - outgoing_htlc_id: number - timestamp_ns: number - event_type: string - incoming_amt_msat: number - outgoing_amt_msat: number - failure_string: string - settled: boolean - offchain: boolean - forward_fail_event: boolean -} -export const RoutingEventOptionalFields: [] = [] -export type RoutingEventOptions = OptionsBaseMessage & { - checkOptionalsAreSet?: [] - incoming_channel_id_CustomCheck?: (v: number) => boolean - incoming_htlc_id_CustomCheck?: (v: number) => boolean - outgoing_channel_id_CustomCheck?: (v: number) => boolean - outgoing_htlc_id_CustomCheck?: (v: number) => boolean - timestamp_ns_CustomCheck?: (v: number) => boolean - event_type_CustomCheck?: (v: string) => boolean - incoming_amt_msat_CustomCheck?: (v: number) => boolean - outgoing_amt_msat_CustomCheck?: (v: number) => boolean - failure_string_CustomCheck?: (v: string) => boolean - settled_CustomCheck?: (v: boolean) => boolean - offchain_CustomCheck?: (v: boolean) => boolean - forward_fail_event_CustomCheck?: (v: boolean) => boolean -} -export const RoutingEventValidate = (o?: RoutingEvent, opts: RoutingEventOptions = {}, path: string = 'RoutingEvent::root.'): Error | null => { - if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') - if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') - - if (typeof o.incoming_channel_id !== 'number') return new Error(`${path}.incoming_channel_id: is not a number`) - if (opts.incoming_channel_id_CustomCheck && !opts.incoming_channel_id_CustomCheck(o.incoming_channel_id)) return new Error(`${path}.incoming_channel_id: custom check failed`) - - if (typeof o.incoming_htlc_id !== 'number') return new Error(`${path}.incoming_htlc_id: is not a number`) - if (opts.incoming_htlc_id_CustomCheck && !opts.incoming_htlc_id_CustomCheck(o.incoming_htlc_id)) return new Error(`${path}.incoming_htlc_id: custom check failed`) - - if (typeof o.outgoing_channel_id !== 'number') return new Error(`${path}.outgoing_channel_id: is not a number`) - if (opts.outgoing_channel_id_CustomCheck && !opts.outgoing_channel_id_CustomCheck(o.outgoing_channel_id)) return new Error(`${path}.outgoing_channel_id: custom check failed`) - - if (typeof o.outgoing_htlc_id !== 'number') return new Error(`${path}.outgoing_htlc_id: is not a number`) - if (opts.outgoing_htlc_id_CustomCheck && !opts.outgoing_htlc_id_CustomCheck(o.outgoing_htlc_id)) return new Error(`${path}.outgoing_htlc_id: custom check failed`) - - if (typeof o.timestamp_ns !== 'number') return new Error(`${path}.timestamp_ns: is not a number`) - if (opts.timestamp_ns_CustomCheck && !opts.timestamp_ns_CustomCheck(o.timestamp_ns)) return new Error(`${path}.timestamp_ns: custom check failed`) - - if (typeof o.event_type !== 'string') return new Error(`${path}.event_type: is not a string`) - if (opts.event_type_CustomCheck && !opts.event_type_CustomCheck(o.event_type)) return new Error(`${path}.event_type: custom check failed`) - - if (typeof o.incoming_amt_msat !== 'number') return new Error(`${path}.incoming_amt_msat: is not a number`) - if (opts.incoming_amt_msat_CustomCheck && !opts.incoming_amt_msat_CustomCheck(o.incoming_amt_msat)) return new Error(`${path}.incoming_amt_msat: custom check failed`) - - if (typeof o.outgoing_amt_msat !== 'number') return new Error(`${path}.outgoing_amt_msat: is not a number`) - if (opts.outgoing_amt_msat_CustomCheck && !opts.outgoing_amt_msat_CustomCheck(o.outgoing_amt_msat)) return new Error(`${path}.outgoing_amt_msat: custom check failed`) - - if (typeof o.failure_string !== 'string') return new Error(`${path}.failure_string: is not a string`) - if (opts.failure_string_CustomCheck && !opts.failure_string_CustomCheck(o.failure_string)) return new Error(`${path}.failure_string: custom check failed`) - - if (typeof o.settled !== 'boolean') return new Error(`${path}.settled: is not a boolean`) - if (opts.settled_CustomCheck && !opts.settled_CustomCheck(o.settled)) return new Error(`${path}.settled: custom check failed`) - - if (typeof o.offchain !== 'boolean') return new Error(`${path}.offchain: is not a boolean`) - if (opts.offchain_CustomCheck && !opts.offchain_CustomCheck(o.offchain)) return new Error(`${path}.offchain: custom check failed`) - - if (typeof o.forward_fail_event !== 'boolean') return new Error(`${path}.forward_fail_event: is not a boolean`) - if (opts.forward_fail_event_CustomCheck && !opts.forward_fail_event_CustomCheck(o.forward_fail_event)) return new Error(`${path}.forward_fail_event: custom check failed`) - - return null -} - -export type SetMockInvoiceAsPaidRequest = { - invoice: string - amount: number -} -export const SetMockInvoiceAsPaidRequestOptionalFields: [] = [] -export type SetMockInvoiceAsPaidRequestOptions = OptionsBaseMessage & { - checkOptionalsAreSet?: [] - invoice_CustomCheck?: (v: string) => boolean - amount_CustomCheck?: (v: number) => boolean -} -export const SetMockInvoiceAsPaidRequestValidate = (o?: SetMockInvoiceAsPaidRequest, opts: SetMockInvoiceAsPaidRequestOptions = {}, path: string = 'SetMockInvoiceAsPaidRequest::root.'): Error | null => { - if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') - if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') - - if (typeof o.invoice !== 'string') return new Error(`${path}.invoice: is not a string`) - if (opts.invoice_CustomCheck && !opts.invoice_CustomCheck(o.invoice)) return new Error(`${path}.invoice: custom check failed`) - - if (typeof o.amount !== 'number') return new Error(`${path}.amount: is not a number`) - if (opts.amount_CustomCheck && !opts.amount_CustomCheck(o.amount)) return new Error(`${path}.amount: custom check failed`) - - return null -} - -export type AddAppUserInvoiceRequest = { - receiver_identifier: string - payer_identifier: string - http_callback_url: string - invoice_req: NewInvoiceRequest -} -export const AddAppUserInvoiceRequestOptionalFields: [] = [] -export type AddAppUserInvoiceRequestOptions = OptionsBaseMessage & { - checkOptionalsAreSet?: [] - receiver_identifier_CustomCheck?: (v: string) => boolean - payer_identifier_CustomCheck?: (v: string) => boolean - http_callback_url_CustomCheck?: (v: string) => boolean - invoice_req_Options?: NewInvoiceRequestOptions -} -export const AddAppUserInvoiceRequestValidate = (o?: AddAppUserInvoiceRequest, opts: AddAppUserInvoiceRequestOptions = {}, path: string = 'AddAppUserInvoiceRequest::root.'): Error | null => { - if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') - if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') - - if (typeof o.receiver_identifier !== 'string') return new Error(`${path}.receiver_identifier: is not a string`) - if (opts.receiver_identifier_CustomCheck && !opts.receiver_identifier_CustomCheck(o.receiver_identifier)) return new Error(`${path}.receiver_identifier: custom check failed`) - - if (typeof o.payer_identifier !== 'string') return new Error(`${path}.payer_identifier: is not a string`) - if (opts.payer_identifier_CustomCheck && !opts.payer_identifier_CustomCheck(o.payer_identifier)) return new Error(`${path}.payer_identifier: custom check failed`) - - if (typeof o.http_callback_url !== 'string') return new Error(`${path}.http_callback_url: is not a string`) - if (opts.http_callback_url_CustomCheck && !opts.http_callback_url_CustomCheck(o.http_callback_url)) return new Error(`${path}.http_callback_url: custom check failed`) - - const invoice_reqErr = NewInvoiceRequestValidate(o.invoice_req, opts.invoice_req_Options, `${path}.invoice_req`) - if (invoice_reqErr !== null) return invoice_reqErr - - - return null -} - -export type OpenChannelRequest = { - destination: string - fundingAmount: number - pushAmount: number - closeAddress: string -} -export const OpenChannelRequestOptionalFields: [] = [] -export type OpenChannelRequestOptions = OptionsBaseMessage & { - checkOptionalsAreSet?: [] - destination_CustomCheck?: (v: string) => boolean - fundingAmount_CustomCheck?: (v: number) => boolean - pushAmount_CustomCheck?: (v: number) => boolean - closeAddress_CustomCheck?: (v: string) => boolean -} -export const OpenChannelRequestValidate = (o?: OpenChannelRequest, opts: OpenChannelRequestOptions = {}, path: string = 'OpenChannelRequest::root.'): Error | null => { - if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') - if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') - - if (typeof o.destination !== 'string') return new Error(`${path}.destination: is not a string`) - if (opts.destination_CustomCheck && !opts.destination_CustomCheck(o.destination)) return new Error(`${path}.destination: custom check failed`) - - if (typeof o.fundingAmount !== 'number') return new Error(`${path}.fundingAmount: is not a number`) - if (opts.fundingAmount_CustomCheck && !opts.fundingAmount_CustomCheck(o.fundingAmount)) return new Error(`${path}.fundingAmount: custom check failed`) - - if (typeof o.pushAmount !== 'number') return new Error(`${path}.pushAmount: is not a number`) - if (opts.pushAmount_CustomCheck && !opts.pushAmount_CustomCheck(o.pushAmount)) return new Error(`${path}.pushAmount: custom check failed`) - - if (typeof o.closeAddress !== 'string') return new Error(`${path}.closeAddress: is not a string`) - if (opts.closeAddress_CustomCheck && !opts.closeAddress_CustomCheck(o.closeAddress)) return new Error(`${path}.closeAddress: custom check failed`) - - return null -} - -export type ChainBalanceEvent = { - block_height: number - confirmed_balance: number - unconfirmed_balance: number - total_balance: number -} -export const ChainBalanceEventOptionalFields: [] = [] -export type ChainBalanceEventOptions = OptionsBaseMessage & { - checkOptionalsAreSet?: [] - block_height_CustomCheck?: (v: number) => boolean - confirmed_balance_CustomCheck?: (v: number) => boolean - unconfirmed_balance_CustomCheck?: (v: number) => boolean - total_balance_CustomCheck?: (v: number) => boolean -} -export const ChainBalanceEventValidate = (o?: ChainBalanceEvent, opts: ChainBalanceEventOptions = {}, path: string = 'ChainBalanceEvent::root.'): Error | null => { - if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') - if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') - - if (typeof o.block_height !== 'number') return new Error(`${path}.block_height: is not a number`) - if (opts.block_height_CustomCheck && !opts.block_height_CustomCheck(o.block_height)) return new Error(`${path}.block_height: custom check failed`) - - if (typeof o.confirmed_balance !== 'number') return new Error(`${path}.confirmed_balance: is not a number`) - if (opts.confirmed_balance_CustomCheck && !opts.confirmed_balance_CustomCheck(o.confirmed_balance)) return new Error(`${path}.confirmed_balance: custom check failed`) - - if (typeof o.unconfirmed_balance !== 'number') return new Error(`${path}.unconfirmed_balance: is not a number`) - if (opts.unconfirmed_balance_CustomCheck && !opts.unconfirmed_balance_CustomCheck(o.unconfirmed_balance)) return new Error(`${path}.unconfirmed_balance: custom check failed`) - - if (typeof o.total_balance !== 'number') return new Error(`${path}.total_balance: is not a number`) - if (opts.total_balance_CustomCheck && !opts.total_balance_CustomCheck(o.total_balance)) return new Error(`${path}.total_balance: custom check failed`) - - return null -} - -export type LndNodeMetrics = { - channels_balance_events: ChannelBalanceEvent[] - chain_balance_events: ChainBalanceEvent[] - offline_channels: number - online_channels: number - pending_channels: number - closing_channels: number - open_channels: OpenChannel[] - closed_channels: ClosedChannel[] - channel_routing: ChannelRouting[] -} -export const LndNodeMetricsOptionalFields: [] = [] -export type LndNodeMetricsOptions = OptionsBaseMessage & { - checkOptionalsAreSet?: [] - channels_balance_events_ItemOptions?: ChannelBalanceEventOptions - channels_balance_events_CustomCheck?: (v: ChannelBalanceEvent[]) => boolean - chain_balance_events_ItemOptions?: ChainBalanceEventOptions - chain_balance_events_CustomCheck?: (v: ChainBalanceEvent[]) => boolean - offline_channels_CustomCheck?: (v: number) => boolean - online_channels_CustomCheck?: (v: number) => boolean - pending_channels_CustomCheck?: (v: number) => boolean - closing_channels_CustomCheck?: (v: number) => boolean - open_channels_ItemOptions?: OpenChannelOptions - open_channels_CustomCheck?: (v: OpenChannel[]) => boolean - closed_channels_ItemOptions?: ClosedChannelOptions - closed_channels_CustomCheck?: (v: ClosedChannel[]) => boolean - channel_routing_ItemOptions?: ChannelRoutingOptions - channel_routing_CustomCheck?: (v: ChannelRouting[]) => boolean -} -export const LndNodeMetricsValidate = (o?: LndNodeMetrics, opts: LndNodeMetricsOptions = {}, path: string = 'LndNodeMetrics::root.'): Error | null => { - if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') - if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') - - if (!Array.isArray(o.channels_balance_events)) return new Error(`${path}.channels_balance_events: is not an array`) - for (let index = 0; index < o.channels_balance_events.length; index++) { - const channels_balance_eventsErr = ChannelBalanceEventValidate(o.channels_balance_events[index], opts.channels_balance_events_ItemOptions, `${path}.channels_balance_events[${index}]`) - if (channels_balance_eventsErr !== null) return channels_balance_eventsErr - } - if (opts.channels_balance_events_CustomCheck && !opts.channels_balance_events_CustomCheck(o.channels_balance_events)) return new Error(`${path}.channels_balance_events: custom check failed`) - - if (!Array.isArray(o.chain_balance_events)) return new Error(`${path}.chain_balance_events: is not an array`) - for (let index = 0; index < o.chain_balance_events.length; index++) { - const chain_balance_eventsErr = ChainBalanceEventValidate(o.chain_balance_events[index], opts.chain_balance_events_ItemOptions, `${path}.chain_balance_events[${index}]`) - if (chain_balance_eventsErr !== null) return chain_balance_eventsErr - } - if (opts.chain_balance_events_CustomCheck && !opts.chain_balance_events_CustomCheck(o.chain_balance_events)) return new Error(`${path}.chain_balance_events: custom check failed`) - - if (typeof o.offline_channels !== 'number') return new Error(`${path}.offline_channels: is not a number`) - if (opts.offline_channels_CustomCheck && !opts.offline_channels_CustomCheck(o.offline_channels)) return new Error(`${path}.offline_channels: custom check failed`) - - if (typeof o.online_channels !== 'number') return new Error(`${path}.online_channels: is not a number`) - if (opts.online_channels_CustomCheck && !opts.online_channels_CustomCheck(o.online_channels)) return new Error(`${path}.online_channels: custom check failed`) - - if (typeof o.pending_channels !== 'number') return new Error(`${path}.pending_channels: is not a number`) - if (opts.pending_channels_CustomCheck && !opts.pending_channels_CustomCheck(o.pending_channels)) return new Error(`${path}.pending_channels: custom check failed`) - - if (typeof o.closing_channels !== 'number') return new Error(`${path}.closing_channels: is not a number`) - if (opts.closing_channels_CustomCheck && !opts.closing_channels_CustomCheck(o.closing_channels)) return new Error(`${path}.closing_channels: custom check failed`) - - if (!Array.isArray(o.open_channels)) return new Error(`${path}.open_channels: is not an array`) - for (let index = 0; index < o.open_channels.length; index++) { - const open_channelsErr = OpenChannelValidate(o.open_channels[index], opts.open_channels_ItemOptions, `${path}.open_channels[${index}]`) - if (open_channelsErr !== null) return open_channelsErr - } - if (opts.open_channels_CustomCheck && !opts.open_channels_CustomCheck(o.open_channels)) return new Error(`${path}.open_channels: custom check failed`) - - if (!Array.isArray(o.closed_channels)) return new Error(`${path}.closed_channels: is not an array`) - for (let index = 0; index < o.closed_channels.length; index++) { - const closed_channelsErr = ClosedChannelValidate(o.closed_channels[index], opts.closed_channels_ItemOptions, `${path}.closed_channels[${index}]`) - if (closed_channelsErr !== null) return closed_channelsErr - } - if (opts.closed_channels_CustomCheck && !opts.closed_channels_CustomCheck(o.closed_channels)) return new Error(`${path}.closed_channels: custom check failed`) - - if (!Array.isArray(o.channel_routing)) return new Error(`${path}.channel_routing: is not an array`) - for (let index = 0; index < o.channel_routing.length; index++) { - const channel_routingErr = ChannelRoutingValidate(o.channel_routing[index], opts.channel_routing_ItemOptions, `${path}.channel_routing[${index}]`) - if (channel_routingErr !== null) return channel_routingErr - } - if (opts.channel_routing_CustomCheck && !opts.channel_routing_CustomCheck(o.channel_routing)) return new Error(`${path}.channel_routing: custom check failed`) - - return null -} - +// This file was autogenerated from a .proto file, DO NOT EDIT! + +export type ResultError = { status: 'ERROR', reason: string } +export type RequestInfo = { rpcName: string, batch: boolean, nostr: boolean, batchSize: number } +export type RequestStats = { startMs:number, start:bigint, parse: bigint, guard: bigint, validate: bigint, handle: bigint } +export type RequestMetric = AuthContext & RequestInfo & RequestStats & { error?: string } +export type GuestContext = { +} +export type GuestMethodInputs = Health_Input | EncryptionExchange_Input | SetMockInvoiceAsPaid_Input | GetLnurlWithdrawInfo_Input | HandleLnurlWithdraw_Input | GetLnurlPayInfo_Input | HandleLnurlPay_Input | HandleLnurlAddress_Input +export type GuestMethodOutputs = Health_Output | EncryptionExchange_Output | SetMockInvoiceAsPaid_Output | GetLnurlWithdrawInfo_Output | HandleLnurlWithdraw_Output | GetLnurlPayInfo_Output | HandleLnurlPay_Output | HandleLnurlAddress_Output +export type UserContext = { + app_user_id: string + user_id: string + app_id: string +} +export type UserMethodInputs = LinkNPubThroughToken_Input | EnrollAdminToken_Input | UserHealth_Input | GetUserInfo_Input | AddProduct_Input | NewProductInvoice_Input | GetUserOperations_Input | NewAddress_Input | PayAddress_Input | NewInvoice_Input | DecodeInvoice_Input | PayInvoice_Input | OpenChannel_Input | GetLnurlWithdrawLink_Input | GetLnurlPayLink_Input | GetLNURLChannelLink_Input +export type UserMethodOutputs = LinkNPubThroughToken_Output | EnrollAdminToken_Output | UserHealth_Output | GetUserInfo_Output | AddProduct_Output | NewProductInvoice_Output | GetUserOperations_Output | NewAddress_Output | PayAddress_Output | NewInvoice_Output | DecodeInvoice_Output | PayInvoice_Output | OpenChannel_Output | GetLnurlWithdrawLink_Output | GetLnurlPayLink_Output | GetLNURLChannelLink_Output +export type AdminContext = { + admin_id: string +} +export type AdminMethodInputs = LndGetInfo_Input | AddApp_Input | AuthApp_Input | BanUser_Input +export type AdminMethodOutputs = LndGetInfo_Output | AddApp_Output | AuthApp_Output | BanUser_Output +export type MetricsContext = { + operator_id: string +} +export type MetricsMethodInputs = GetUsageMetrics_Input | GetAppsMetrics_Input | GetLndMetrics_Input +export type MetricsMethodOutputs = GetUsageMetrics_Output | GetAppsMetrics_Output | GetLndMetrics_Output +export type AppContext = { + app_id: string +} +export type AppMethodInputs = GetApp_Input | AddAppUser_Input | AddAppInvoice_Input | AddAppUserInvoice_Input | GetAppUser_Input | PayAppUserInvoice_Input | SendAppUserToAppUserPayment_Input | SendAppUserToAppPayment_Input | GetAppUserLNURLInfo_Input | SetMockAppUserBalance_Input | SetMockAppBalance_Input | RequestNPubLinkingToken_Input +export type AppMethodOutputs = GetApp_Output | AddAppUser_Output | AddAppInvoice_Output | AddAppUserInvoice_Output | GetAppUser_Output | PayAppUserInvoice_Output | SendAppUserToAppUserPayment_Output | SendAppUserToAppPayment_Output | GetAppUserLNURLInfo_Output | SetMockAppUserBalance_Output | SetMockAppBalance_Output | RequestNPubLinkingToken_Output +export type AuthContext = GuestContext | UserContext | AdminContext | MetricsContext | AppContext + +export type LndGetInfo_Input = {rpcName:'LndGetInfo', req: LndGetInfoRequest} +export type LndGetInfo_Output = ResultError | ({ status: 'OK' } & LndGetInfoResponse) + +export type AddApp_Input = {rpcName:'AddApp', req: AddAppRequest} +export type AddApp_Output = ResultError | ({ status: 'OK' } & AuthApp) + +export type AuthApp_Input = {rpcName:'AuthApp', req: AuthAppRequest} +export type AuthApp_Output = ResultError | ({ status: 'OK' } & AuthApp) + +export type BanUser_Input = {rpcName:'BanUser', req: BanUserRequest} +export type BanUser_Output = ResultError | ({ status: 'OK' } & BanUserResponse) + +export type GetUsageMetrics_Input = {rpcName:'GetUsageMetrics'} +export type GetUsageMetrics_Output = ResultError | ({ status: 'OK' } & UsageMetrics) + +export type GetAppsMetrics_Input = {rpcName:'GetAppsMetrics', req: AppsMetricsRequest} +export type GetAppsMetrics_Output = ResultError | ({ status: 'OK' } & AppsMetrics) + +export type GetLndMetrics_Input = {rpcName:'GetLndMetrics', req: LndMetricsRequest} +export type GetLndMetrics_Output = ResultError | ({ status: 'OK' } & LndMetrics) + +export type Health_Input = {rpcName:'Health'} +export type Health_Output = ResultError | { status: 'OK' } + +export type EncryptionExchange_Input = {rpcName:'EncryptionExchange', req: EncryptionExchangeRequest} +export type EncryptionExchange_Output = ResultError | { status: 'OK' } + +export type SetMockInvoiceAsPaid_Input = {rpcName:'SetMockInvoiceAsPaid', req: SetMockInvoiceAsPaidRequest} +export type SetMockInvoiceAsPaid_Output = ResultError | { status: 'OK' } + +export type GetLnurlWithdrawInfo_Query = { + k1?: string +} +export type GetLnurlWithdrawInfo_Input = {rpcName:'GetLnurlWithdrawInfo', query: GetLnurlWithdrawInfo_Query} +export type GetLnurlWithdrawInfo_Output = ResultError | ({ status: 'OK' } & LnurlWithdrawInfoResponse) + +export type HandleLnurlWithdraw_Query = { + k1?: string + pr?: string +} +export type HandleLnurlWithdraw_Input = {rpcName:'HandleLnurlWithdraw', query: HandleLnurlWithdraw_Query} +export type HandleLnurlWithdraw_Output = ResultError | { status: 'OK' } + +export type GetLnurlPayInfo_Query = { + k1?: string +} +export type GetLnurlPayInfo_Input = {rpcName:'GetLnurlPayInfo', query: GetLnurlPayInfo_Query} +export type GetLnurlPayInfo_Output = ResultError | ({ status: 'OK' } & LnurlPayInfoResponse) + +export type HandleLnurlPay_Query = { + k1?: string + amount?: string + nostr?: string + lnurl?: string +} +export type HandleLnurlPay_Input = {rpcName:'HandleLnurlPay', query: HandleLnurlPay_Query} +export type HandleLnurlPay_Output = ResultError | ({ status: 'OK' } & HandleLnurlPayResponse) + +export type HandleLnurlAddress_RouteParams = { + address_name: string +} +export type HandleLnurlAddress_Input = {rpcName:'HandleLnurlAddress', params: HandleLnurlAddress_RouteParams} +export type HandleLnurlAddress_Output = ResultError | ({ status: 'OK' } & LnurlPayInfoResponse) + +export type LinkNPubThroughToken_Input = {rpcName:'LinkNPubThroughToken', req: LinkNPubThroughTokenRequest} +export type LinkNPubThroughToken_Output = ResultError | { status: 'OK' } + +export type EnrollAdminToken_Input = {rpcName:'EnrollAdminToken', req: EnrollAdminTokenRequest} +export type EnrollAdminToken_Output = ResultError | { status: 'OK' } + +export type GetApp_Input = {rpcName:'GetApp'} +export type GetApp_Output = ResultError | ({ status: 'OK' } & Application) + +export type AddAppUser_Input = {rpcName:'AddAppUser', req: AddAppUserRequest} +export type AddAppUser_Output = ResultError | ({ status: 'OK' } & AppUser) + +export type AddAppInvoice_Input = {rpcName:'AddAppInvoice', req: AddAppInvoiceRequest} +export type AddAppInvoice_Output = ResultError | ({ status: 'OK' } & NewInvoiceResponse) + +export type AddAppUserInvoice_Input = {rpcName:'AddAppUserInvoice', req: AddAppUserInvoiceRequest} +export type AddAppUserInvoice_Output = ResultError | ({ status: 'OK' } & NewInvoiceResponse) + +export type GetAppUser_Input = {rpcName:'GetAppUser', req: GetAppUserRequest} +export type GetAppUser_Output = ResultError | ({ status: 'OK' } & AppUser) + +export type PayAppUserInvoice_Input = {rpcName:'PayAppUserInvoice', req: PayAppUserInvoiceRequest} +export type PayAppUserInvoice_Output = ResultError | ({ status: 'OK' } & PayInvoiceResponse) + +export type SendAppUserToAppUserPayment_Input = {rpcName:'SendAppUserToAppUserPayment', req: SendAppUserToAppUserPaymentRequest} +export type SendAppUserToAppUserPayment_Output = ResultError | { status: 'OK' } + +export type SendAppUserToAppPayment_Input = {rpcName:'SendAppUserToAppPayment', req: SendAppUserToAppPaymentRequest} +export type SendAppUserToAppPayment_Output = ResultError | { status: 'OK' } + +export type GetAppUserLNURLInfo_Input = {rpcName:'GetAppUserLNURLInfo', req: GetAppUserLNURLInfoRequest} +export type GetAppUserLNURLInfo_Output = ResultError | ({ status: 'OK' } & LnurlPayInfoResponse) + +export type SetMockAppUserBalance_Input = {rpcName:'SetMockAppUserBalance', req: SetMockAppUserBalanceRequest} +export type SetMockAppUserBalance_Output = ResultError | { status: 'OK' } + +export type SetMockAppBalance_Input = {rpcName:'SetMockAppBalance', req: SetMockAppBalanceRequest} +export type SetMockAppBalance_Output = ResultError | { status: 'OK' } + +export type RequestNPubLinkingToken_Input = {rpcName:'RequestNPubLinkingToken', req: RequestNPubLinkingTokenRequest} +export type RequestNPubLinkingToken_Output = ResultError | ({ status: 'OK' } & RequestNPubLinkingTokenResponse) + +export type UserHealth_Input = {rpcName:'UserHealth'} +export type UserHealth_Output = ResultError | { status: 'OK' } + +export type GetUserInfo_Input = {rpcName:'GetUserInfo'} +export type GetUserInfo_Output = ResultError | ({ status: 'OK' } & UserInfo) + +export type AddProduct_Input = {rpcName:'AddProduct', req: AddProductRequest} +export type AddProduct_Output = ResultError | ({ status: 'OK' } & Product) + +export type NewProductInvoice_Query = { + id?: string +} +export type NewProductInvoice_Input = {rpcName:'NewProductInvoice', query: NewProductInvoice_Query} +export type NewProductInvoice_Output = ResultError | ({ status: 'OK' } & NewInvoiceResponse) + +export type GetUserOperations_Input = {rpcName:'GetUserOperations', req: GetUserOperationsRequest} +export type GetUserOperations_Output = ResultError | ({ status: 'OK' } & GetUserOperationsResponse) + +export type NewAddress_Input = {rpcName:'NewAddress', req: NewAddressRequest} +export type NewAddress_Output = ResultError | ({ status: 'OK' } & NewAddressResponse) + +export type PayAddress_Input = {rpcName:'PayAddress', req: PayAddressRequest} +export type PayAddress_Output = ResultError | ({ status: 'OK' } & PayAddressResponse) + +export type NewInvoice_Input = {rpcName:'NewInvoice', req: NewInvoiceRequest} +export type NewInvoice_Output = ResultError | ({ status: 'OK' } & NewInvoiceResponse) + +export type DecodeInvoice_Input = {rpcName:'DecodeInvoice', req: DecodeInvoiceRequest} +export type DecodeInvoice_Output = ResultError | ({ status: 'OK' } & DecodeInvoiceResponse) + +export type PayInvoice_Input = {rpcName:'PayInvoice', req: PayInvoiceRequest} +export type PayInvoice_Output = ResultError | ({ status: 'OK' } & PayInvoiceResponse) + +export type OpenChannel_Input = {rpcName:'OpenChannel', req: OpenChannelRequest} +export type OpenChannel_Output = ResultError | ({ status: 'OK' } & OpenChannelResponse) + +export type GetLnurlWithdrawLink_Input = {rpcName:'GetLnurlWithdrawLink'} +export type GetLnurlWithdrawLink_Output = ResultError | ({ status: 'OK' } & LnurlLinkResponse) + +export type GetLnurlPayLink_Input = {rpcName:'GetLnurlPayLink'} +export type GetLnurlPayLink_Output = ResultError | ({ status: 'OK' } & LnurlLinkResponse) + +export type GetLNURLChannelLink_Input = {rpcName:'GetLNURLChannelLink'} +export type GetLNURLChannelLink_Output = ResultError | ({ status: 'OK' } & LnurlLinkResponse) + +export type GetLiveUserOperations_Input = {rpcName:'GetLiveUserOperations', cb:(res: LiveUserOperation, err:Error|null)=> void} +export type GetLiveUserOperations_Output = ResultError | { status: 'OK' } + +export type GetMigrationUpdate_Input = {rpcName:'GetMigrationUpdate', cb:(res: MigrationUpdate, err:Error|null)=> void} +export type GetMigrationUpdate_Output = ResultError | { status: 'OK' } + +export type GetHttpCreds_Input = {rpcName:'GetHttpCreds', cb:(res: HttpCreds, err:Error|null)=> void} +export type GetHttpCreds_Output = ResultError | { status: 'OK' } + +export type BatchUser_Input = UserMethodInputs +export type BatchUser_Output = UserMethodOutputs + +export type ServerMethods = { + LndGetInfo?: (req: LndGetInfo_Input & {ctx: AdminContext }) => Promise + AddApp?: (req: AddApp_Input & {ctx: AdminContext }) => Promise + AuthApp?: (req: AuthApp_Input & {ctx: AdminContext }) => Promise + BanUser?: (req: BanUser_Input & {ctx: AdminContext }) => Promise + GetUsageMetrics?: (req: GetUsageMetrics_Input & {ctx: MetricsContext }) => Promise + GetAppsMetrics?: (req: GetAppsMetrics_Input & {ctx: MetricsContext }) => Promise + GetLndMetrics?: (req: GetLndMetrics_Input & {ctx: MetricsContext }) => Promise + Health?: (req: Health_Input & {ctx: GuestContext }) => Promise + EncryptionExchange?: (req: EncryptionExchange_Input & {ctx: GuestContext }) => Promise + SetMockInvoiceAsPaid?: (req: SetMockInvoiceAsPaid_Input & {ctx: GuestContext }) => Promise + GetLnurlWithdrawInfo?: (req: GetLnurlWithdrawInfo_Input & {ctx: GuestContext }) => Promise + HandleLnurlWithdraw?: (req: HandleLnurlWithdraw_Input & {ctx: GuestContext }) => Promise + GetLnurlPayInfo?: (req: GetLnurlPayInfo_Input & {ctx: GuestContext }) => Promise + HandleLnurlPay?: (req: HandleLnurlPay_Input & {ctx: GuestContext }) => Promise + HandleLnurlAddress?: (req: HandleLnurlAddress_Input & {ctx: GuestContext }) => Promise + LinkNPubThroughToken?: (req: LinkNPubThroughToken_Input & {ctx: UserContext }) => Promise + EnrollAdminToken?: (req: EnrollAdminToken_Input & {ctx: UserContext }) => Promise + GetApp?: (req: GetApp_Input & {ctx: AppContext }) => Promise + AddAppUser?: (req: AddAppUser_Input & {ctx: AppContext }) => Promise + AddAppInvoice?: (req: AddAppInvoice_Input & {ctx: AppContext }) => Promise + AddAppUserInvoice?: (req: AddAppUserInvoice_Input & {ctx: AppContext }) => Promise + GetAppUser?: (req: GetAppUser_Input & {ctx: AppContext }) => Promise + PayAppUserInvoice?: (req: PayAppUserInvoice_Input & {ctx: AppContext }) => Promise + SendAppUserToAppUserPayment?: (req: SendAppUserToAppUserPayment_Input & {ctx: AppContext }) => Promise + SendAppUserToAppPayment?: (req: SendAppUserToAppPayment_Input & {ctx: AppContext }) => Promise + GetAppUserLNURLInfo?: (req: GetAppUserLNURLInfo_Input & {ctx: AppContext }) => Promise + SetMockAppUserBalance?: (req: SetMockAppUserBalance_Input & {ctx: AppContext }) => Promise + SetMockAppBalance?: (req: SetMockAppBalance_Input & {ctx: AppContext }) => Promise + RequestNPubLinkingToken?: (req: RequestNPubLinkingToken_Input & {ctx: AppContext }) => Promise + UserHealth?: (req: UserHealth_Input & {ctx: UserContext }) => Promise + GetUserInfo?: (req: GetUserInfo_Input & {ctx: UserContext }) => Promise + AddProduct?: (req: AddProduct_Input & {ctx: UserContext }) => Promise + NewProductInvoice?: (req: NewProductInvoice_Input & {ctx: UserContext }) => Promise + GetUserOperations?: (req: GetUserOperations_Input & {ctx: UserContext }) => Promise + NewAddress?: (req: NewAddress_Input & {ctx: UserContext }) => Promise + PayAddress?: (req: PayAddress_Input & {ctx: UserContext }) => Promise + NewInvoice?: (req: NewInvoice_Input & {ctx: UserContext }) => Promise + DecodeInvoice?: (req: DecodeInvoice_Input & {ctx: UserContext }) => Promise + PayInvoice?: (req: PayInvoice_Input & {ctx: UserContext }) => Promise + OpenChannel?: (req: OpenChannel_Input & {ctx: UserContext }) => Promise + GetLnurlWithdrawLink?: (req: GetLnurlWithdrawLink_Input & {ctx: UserContext }) => Promise + GetLnurlPayLink?: (req: GetLnurlPayLink_Input & {ctx: UserContext }) => Promise + GetLNURLChannelLink?: (req: GetLNURLChannelLink_Input & {ctx: UserContext }) => Promise + GetLiveUserOperations?: (req: GetLiveUserOperations_Input & {ctx: UserContext }) => Promise + GetMigrationUpdate?: (req: GetMigrationUpdate_Input & {ctx: UserContext }) => Promise + GetHttpCreds?: (req: GetHttpCreds_Input & {ctx: UserContext }) => Promise +} + +export enum AddressType { + WITNESS_PUBKEY_HASH = 'WITNESS_PUBKEY_HASH', + NESTED_PUBKEY_HASH = 'NESTED_PUBKEY_HASH', + TAPROOT_PUBKEY = 'TAPROOT_PUBKEY', +} +export const enumCheckAddressType = (e?: AddressType): boolean => { + for (const v in AddressType) if (e === v) return true + return false +} +export enum UserOperationType { + INCOMING_TX = 'INCOMING_TX', + OUTGOING_TX = 'OUTGOING_TX', + INCOMING_INVOICE = 'INCOMING_INVOICE', + OUTGOING_INVOICE = 'OUTGOING_INVOICE', + OUTGOING_USER_TO_USER = 'OUTGOING_USER_TO_USER', + INCOMING_USER_TO_USER = 'INCOMING_USER_TO_USER', +} +export const enumCheckUserOperationType = (e?: UserOperationType): boolean => { + for (const v in UserOperationType) if (e === v) return true + return false +} + +export type OptionsBaseMessage = { + allOptionalsAreSet?: true +} + +export type AppMetrics = { + fees: number + invoices: number + total_fees: number + app: Application + users: UsersInfo + spent: number + available: number + received: number + operations: UserOperation[] +} +export const AppMetricsOptionalFields: [] = [] +export type AppMetricsOptions = OptionsBaseMessage & { + checkOptionalsAreSet?: [] + received_CustomCheck?: (v: number) => boolean + operations_ItemOptions?: UserOperationOptions + operations_CustomCheck?: (v: UserOperation[]) => boolean + total_fees_CustomCheck?: (v: number) => boolean + app_Options?: ApplicationOptions + users_Options?: UsersInfoOptions + spent_CustomCheck?: (v: number) => boolean + available_CustomCheck?: (v: number) => boolean + fees_CustomCheck?: (v: number) => boolean + invoices_CustomCheck?: (v: number) => boolean +} +export const AppMetricsValidate = (o?: AppMetrics, opts: AppMetricsOptions = {}, path: string = 'AppMetrics::root.'): Error | null => { + if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') + if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') + + if (typeof o.received !== 'number') return new Error(`${path}.received: is not a number`) + if (opts.received_CustomCheck && !opts.received_CustomCheck(o.received)) return new Error(`${path}.received: custom check failed`) + + if (!Array.isArray(o.operations)) return new Error(`${path}.operations: is not an array`) + for (let index = 0; index < o.operations.length; index++) { + const operationsErr = UserOperationValidate(o.operations[index], opts.operations_ItemOptions, `${path}.operations[${index}]`) + if (operationsErr !== null) return operationsErr + } + if (opts.operations_CustomCheck && !opts.operations_CustomCheck(o.operations)) return new Error(`${path}.operations: custom check failed`) + + if (typeof o.total_fees !== 'number') return new Error(`${path}.total_fees: is not a number`) + if (opts.total_fees_CustomCheck && !opts.total_fees_CustomCheck(o.total_fees)) return new Error(`${path}.total_fees: custom check failed`) + + const appErr = ApplicationValidate(o.app, opts.app_Options, `${path}.app`) + if (appErr !== null) return appErr + + + const usersErr = UsersInfoValidate(o.users, opts.users_Options, `${path}.users`) + if (usersErr !== null) return usersErr + + + if (typeof o.spent !== 'number') return new Error(`${path}.spent: is not a number`) + if (opts.spent_CustomCheck && !opts.spent_CustomCheck(o.spent)) return new Error(`${path}.spent: custom check failed`) + + if (typeof o.available !== 'number') return new Error(`${path}.available: is not a number`) + if (opts.available_CustomCheck && !opts.available_CustomCheck(o.available)) return new Error(`${path}.available: custom check failed`) + + if (typeof o.fees !== 'number') return new Error(`${path}.fees: is not a number`) + if (opts.fees_CustomCheck && !opts.fees_CustomCheck(o.fees)) return new Error(`${path}.fees: custom check failed`) + + if (typeof o.invoices !== 'number') return new Error(`${path}.invoices: is not a number`) + if (opts.invoices_CustomCheck && !opts.invoices_CustomCheck(o.invoices)) return new Error(`${path}.invoices: custom check failed`) + + return null +} + +export type AddAppRequest = { + name: string + allow_user_creation: boolean +} +export const AddAppRequestOptionalFields: [] = [] +export type AddAppRequestOptions = OptionsBaseMessage & { + checkOptionalsAreSet?: [] + name_CustomCheck?: (v: string) => boolean + allow_user_creation_CustomCheck?: (v: boolean) => boolean +} +export const AddAppRequestValidate = (o?: AddAppRequest, opts: AddAppRequestOptions = {}, path: string = 'AddAppRequest::root.'): Error | null => { + if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') + if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') + + if (typeof o.name !== 'string') return new Error(`${path}.name: is not a string`) + if (opts.name_CustomCheck && !opts.name_CustomCheck(o.name)) return new Error(`${path}.name: custom check failed`) + + if (typeof o.allow_user_creation !== 'boolean') return new Error(`${path}.allow_user_creation: is not a boolean`) + if (opts.allow_user_creation_CustomCheck && !opts.allow_user_creation_CustomCheck(o.allow_user_creation)) return new Error(`${path}.allow_user_creation: custom check failed`) + + return null +} + +export type SendAppUserToAppUserPaymentRequest = { + from_user_identifier: string + to_user_identifier: string + amount: number +} +export const SendAppUserToAppUserPaymentRequestOptionalFields: [] = [] +export type SendAppUserToAppUserPaymentRequestOptions = OptionsBaseMessage & { + checkOptionalsAreSet?: [] + amount_CustomCheck?: (v: number) => boolean + from_user_identifier_CustomCheck?: (v: string) => boolean + to_user_identifier_CustomCheck?: (v: string) => boolean +} +export const SendAppUserToAppUserPaymentRequestValidate = (o?: SendAppUserToAppUserPaymentRequest, opts: SendAppUserToAppUserPaymentRequestOptions = {}, path: string = 'SendAppUserToAppUserPaymentRequest::root.'): Error | null => { + if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') + if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') + + if (typeof o.from_user_identifier !== 'string') return new Error(`${path}.from_user_identifier: is not a string`) + if (opts.from_user_identifier_CustomCheck && !opts.from_user_identifier_CustomCheck(o.from_user_identifier)) return new Error(`${path}.from_user_identifier: custom check failed`) + + if (typeof o.to_user_identifier !== 'string') return new Error(`${path}.to_user_identifier: is not a string`) + if (opts.to_user_identifier_CustomCheck && !opts.to_user_identifier_CustomCheck(o.to_user_identifier)) return new Error(`${path}.to_user_identifier: custom check failed`) + + if (typeof o.amount !== 'number') return new Error(`${path}.amount: is not a number`) + if (opts.amount_CustomCheck && !opts.amount_CustomCheck(o.amount)) return new Error(`${path}.amount: custom check failed`) + + return null +} + +export type LnurlPayInfoResponse = { + nostrPubkey: string + tag: string + callback: string + maxSendable: number + minSendable: number + metadata: string + allowsNostr: boolean +} +export const LnurlPayInfoResponseOptionalFields: [] = [] +export type LnurlPayInfoResponseOptions = OptionsBaseMessage & { + checkOptionalsAreSet?: [] + nostrPubkey_CustomCheck?: (v: string) => boolean + tag_CustomCheck?: (v: string) => boolean + callback_CustomCheck?: (v: string) => boolean + maxSendable_CustomCheck?: (v: number) => boolean + minSendable_CustomCheck?: (v: number) => boolean + metadata_CustomCheck?: (v: string) => boolean + allowsNostr_CustomCheck?: (v: boolean) => boolean +} +export const LnurlPayInfoResponseValidate = (o?: LnurlPayInfoResponse, opts: LnurlPayInfoResponseOptions = {}, path: string = 'LnurlPayInfoResponse::root.'): Error | null => { + if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') + if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') + + if (typeof o.tag !== 'string') return new Error(`${path}.tag: is not a string`) + if (opts.tag_CustomCheck && !opts.tag_CustomCheck(o.tag)) return new Error(`${path}.tag: custom check failed`) + + if (typeof o.callback !== 'string') return new Error(`${path}.callback: is not a string`) + if (opts.callback_CustomCheck && !opts.callback_CustomCheck(o.callback)) return new Error(`${path}.callback: custom check failed`) + + if (typeof o.maxSendable !== 'number') return new Error(`${path}.maxSendable: is not a number`) + if (opts.maxSendable_CustomCheck && !opts.maxSendable_CustomCheck(o.maxSendable)) return new Error(`${path}.maxSendable: custom check failed`) + + if (typeof o.minSendable !== 'number') return new Error(`${path}.minSendable: is not a number`) + if (opts.minSendable_CustomCheck && !opts.minSendable_CustomCheck(o.minSendable)) return new Error(`${path}.minSendable: custom check failed`) + + if (typeof o.metadata !== 'string') return new Error(`${path}.metadata: is not a string`) + if (opts.metadata_CustomCheck && !opts.metadata_CustomCheck(o.metadata)) return new Error(`${path}.metadata: custom check failed`) + + if (typeof o.allowsNostr !== 'boolean') return new Error(`${path}.allowsNostr: is not a boolean`) + if (opts.allowsNostr_CustomCheck && !opts.allowsNostr_CustomCheck(o.allowsNostr)) return new Error(`${path}.allowsNostr: custom check failed`) + + if (typeof o.nostrPubkey !== 'string') return new Error(`${path}.nostrPubkey: is not a string`) + if (opts.nostrPubkey_CustomCheck && !opts.nostrPubkey_CustomCheck(o.nostrPubkey)) return new Error(`${path}.nostrPubkey: custom check failed`) + + return null +} + +export type HandleLnurlPayResponse = { + pr: string + routes: Empty[] +} +export const HandleLnurlPayResponseOptionalFields: [] = [] +export type HandleLnurlPayResponseOptions = OptionsBaseMessage & { + checkOptionalsAreSet?: [] + pr_CustomCheck?: (v: string) => boolean + routes_ItemOptions?: EmptyOptions + routes_CustomCheck?: (v: Empty[]) => boolean +} +export const HandleLnurlPayResponseValidate = (o?: HandleLnurlPayResponse, opts: HandleLnurlPayResponseOptions = {}, path: string = 'HandleLnurlPayResponse::root.'): Error | null => { + if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') + if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') + + if (typeof o.pr !== 'string') return new Error(`${path}.pr: is not a string`) + if (opts.pr_CustomCheck && !opts.pr_CustomCheck(o.pr)) return new Error(`${path}.pr: custom check failed`) + + if (!Array.isArray(o.routes)) return new Error(`${path}.routes: is not an array`) + for (let index = 0; index < o.routes.length; index++) { + const routesErr = EmptyValidate(o.routes[index], opts.routes_ItemOptions, `${path}.routes[${index}]`) + if (routesErr !== null) return routesErr + } + if (opts.routes_CustomCheck && !opts.routes_CustomCheck(o.routes)) return new Error(`${path}.routes: custom check failed`) + + return null +} + +export type EnrollAdminTokenRequest = { + admin_token: string +} +export const EnrollAdminTokenRequestOptionalFields: [] = [] +export type EnrollAdminTokenRequestOptions = OptionsBaseMessage & { + checkOptionalsAreSet?: [] + admin_token_CustomCheck?: (v: string) => boolean +} +export const EnrollAdminTokenRequestValidate = (o?: EnrollAdminTokenRequest, opts: EnrollAdminTokenRequestOptions = {}, path: string = 'EnrollAdminTokenRequest::root.'): Error | null => { + if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') + if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') + + if (typeof o.admin_token !== 'string') return new Error(`${path}.admin_token: is not a string`) + if (opts.admin_token_CustomCheck && !opts.admin_token_CustomCheck(o.admin_token)) return new Error(`${path}.admin_token: custom check failed`) + + return null +} + +export type UsageMetrics = { + metrics: UsageMetric[] +} +export const UsageMetricsOptionalFields: [] = [] +export type UsageMetricsOptions = OptionsBaseMessage & { + checkOptionalsAreSet?: [] + metrics_ItemOptions?: UsageMetricOptions + metrics_CustomCheck?: (v: UsageMetric[]) => boolean +} +export const UsageMetricsValidate = (o?: UsageMetrics, opts: UsageMetricsOptions = {}, path: string = 'UsageMetrics::root.'): Error | null => { + if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') + if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') + + if (!Array.isArray(o.metrics)) return new Error(`${path}.metrics: is not an array`) + for (let index = 0; index < o.metrics.length; index++) { + const metricsErr = UsageMetricValidate(o.metrics[index], opts.metrics_ItemOptions, `${path}.metrics[${index}]`) + if (metricsErr !== null) return metricsErr + } + if (opts.metrics_CustomCheck && !opts.metrics_CustomCheck(o.metrics)) return new Error(`${path}.metrics: custom check failed`) + + return null +} + +export type LnurlLinkResponse = { + lnurl: string + k1: string +} +export const LnurlLinkResponseOptionalFields: [] = [] +export type LnurlLinkResponseOptions = OptionsBaseMessage & { + checkOptionalsAreSet?: [] + lnurl_CustomCheck?: (v: string) => boolean + k1_CustomCheck?: (v: string) => boolean +} +export const LnurlLinkResponseValidate = (o?: LnurlLinkResponse, opts: LnurlLinkResponseOptions = {}, path: string = 'LnurlLinkResponse::root.'): Error | null => { + if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') + if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') + + if (typeof o.lnurl !== 'string') return new Error(`${path}.lnurl: is not a string`) + if (opts.lnurl_CustomCheck && !opts.lnurl_CustomCheck(o.lnurl)) return new Error(`${path}.lnurl: custom check failed`) + + if (typeof o.k1 !== 'string') return new Error(`${path}.k1: is not a string`) + if (opts.k1_CustomCheck && !opts.k1_CustomCheck(o.k1)) return new Error(`${path}.k1: custom check failed`) + + return null +} + +export type LiveUserOperation = { + operation: UserOperation +} +export const LiveUserOperationOptionalFields: [] = [] +export type LiveUserOperationOptions = OptionsBaseMessage & { + checkOptionalsAreSet?: [] + operation_Options?: UserOperationOptions +} +export const LiveUserOperationValidate = (o?: LiveUserOperation, opts: LiveUserOperationOptions = {}, path: string = 'LiveUserOperation::root.'): Error | null => { + if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') + if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') + + const operationErr = UserOperationValidate(o.operation, opts.operation_Options, `${path}.operation`) + if (operationErr !== null) return operationErr + + + return null +} + +export type PayInvoiceRequest = { + invoice: string + amount: number +} +export const PayInvoiceRequestOptionalFields: [] = [] +export type PayInvoiceRequestOptions = OptionsBaseMessage & { + checkOptionalsAreSet?: [] + invoice_CustomCheck?: (v: string) => boolean + amount_CustomCheck?: (v: number) => boolean +} +export const PayInvoiceRequestValidate = (o?: PayInvoiceRequest, opts: PayInvoiceRequestOptions = {}, path: string = 'PayInvoiceRequest::root.'): Error | null => { + if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') + if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') + + if (typeof o.invoice !== 'string') return new Error(`${path}.invoice: is not a string`) + if (opts.invoice_CustomCheck && !opts.invoice_CustomCheck(o.invoice)) return new Error(`${path}.invoice: custom check failed`) + + if (typeof o.amount !== 'number') return new Error(`${path}.amount: is not a number`) + if (opts.amount_CustomCheck && !opts.amount_CustomCheck(o.amount)) return new Error(`${path}.amount: custom check failed`) + + return null +} + +export type GetProductBuyLinkResponse = { + link: string +} +export const GetProductBuyLinkResponseOptionalFields: [] = [] +export type GetProductBuyLinkResponseOptions = OptionsBaseMessage & { + checkOptionalsAreSet?: [] + link_CustomCheck?: (v: string) => boolean +} +export const GetProductBuyLinkResponseValidate = (o?: GetProductBuyLinkResponse, opts: GetProductBuyLinkResponseOptions = {}, path: string = 'GetProductBuyLinkResponse::root.'): Error | null => { + if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') + if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') + + if (typeof o.link !== 'string') return new Error(`${path}.link: is not a string`) + if (opts.link_CustomCheck && !opts.link_CustomCheck(o.link)) return new Error(`${path}.link: custom check failed`) + + return null +} + +export type LndNodeMetrics = { + channel_routing: ChannelRouting[] + offline_channels: number + pending_channels: number + open_channels: OpenChannel[] + closed_channels: ClosedChannel[] + channels_balance_events: ChannelBalanceEvent[] + chain_balance_events: ChainBalanceEvent[] + online_channels: number + closing_channels: number +} +export const LndNodeMetricsOptionalFields: [] = [] +export type LndNodeMetricsOptions = OptionsBaseMessage & { + checkOptionalsAreSet?: [] + channels_balance_events_ItemOptions?: ChannelBalanceEventOptions + channels_balance_events_CustomCheck?: (v: ChannelBalanceEvent[]) => boolean + chain_balance_events_ItemOptions?: ChainBalanceEventOptions + chain_balance_events_CustomCheck?: (v: ChainBalanceEvent[]) => boolean + online_channels_CustomCheck?: (v: number) => boolean + closing_channels_CustomCheck?: (v: number) => boolean + channel_routing_ItemOptions?: ChannelRoutingOptions + channel_routing_CustomCheck?: (v: ChannelRouting[]) => boolean + offline_channels_CustomCheck?: (v: number) => boolean + pending_channels_CustomCheck?: (v: number) => boolean + open_channels_ItemOptions?: OpenChannelOptions + open_channels_CustomCheck?: (v: OpenChannel[]) => boolean + closed_channels_ItemOptions?: ClosedChannelOptions + closed_channels_CustomCheck?: (v: ClosedChannel[]) => boolean +} +export const LndNodeMetricsValidate = (o?: LndNodeMetrics, opts: LndNodeMetricsOptions = {}, path: string = 'LndNodeMetrics::root.'): Error | null => { + if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') + if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') + + if (!Array.isArray(o.channels_balance_events)) return new Error(`${path}.channels_balance_events: is not an array`) + for (let index = 0; index < o.channels_balance_events.length; index++) { + const channels_balance_eventsErr = ChannelBalanceEventValidate(o.channels_balance_events[index], opts.channels_balance_events_ItemOptions, `${path}.channels_balance_events[${index}]`) + if (channels_balance_eventsErr !== null) return channels_balance_eventsErr + } + if (opts.channels_balance_events_CustomCheck && !opts.channels_balance_events_CustomCheck(o.channels_balance_events)) return new Error(`${path}.channels_balance_events: custom check failed`) + + if (!Array.isArray(o.chain_balance_events)) return new Error(`${path}.chain_balance_events: is not an array`) + for (let index = 0; index < o.chain_balance_events.length; index++) { + const chain_balance_eventsErr = ChainBalanceEventValidate(o.chain_balance_events[index], opts.chain_balance_events_ItemOptions, `${path}.chain_balance_events[${index}]`) + if (chain_balance_eventsErr !== null) return chain_balance_eventsErr + } + if (opts.chain_balance_events_CustomCheck && !opts.chain_balance_events_CustomCheck(o.chain_balance_events)) return new Error(`${path}.chain_balance_events: custom check failed`) + + if (typeof o.online_channels !== 'number') return new Error(`${path}.online_channels: is not a number`) + if (opts.online_channels_CustomCheck && !opts.online_channels_CustomCheck(o.online_channels)) return new Error(`${path}.online_channels: custom check failed`) + + if (typeof o.closing_channels !== 'number') return new Error(`${path}.closing_channels: is not a number`) + if (opts.closing_channels_CustomCheck && !opts.closing_channels_CustomCheck(o.closing_channels)) return new Error(`${path}.closing_channels: custom check failed`) + + if (typeof o.offline_channels !== 'number') return new Error(`${path}.offline_channels: is not a number`) + if (opts.offline_channels_CustomCheck && !opts.offline_channels_CustomCheck(o.offline_channels)) return new Error(`${path}.offline_channels: custom check failed`) + + if (typeof o.pending_channels !== 'number') return new Error(`${path}.pending_channels: is not a number`) + if (opts.pending_channels_CustomCheck && !opts.pending_channels_CustomCheck(o.pending_channels)) return new Error(`${path}.pending_channels: custom check failed`) + + if (!Array.isArray(o.open_channels)) return new Error(`${path}.open_channels: is not an array`) + for (let index = 0; index < o.open_channels.length; index++) { + const open_channelsErr = OpenChannelValidate(o.open_channels[index], opts.open_channels_ItemOptions, `${path}.open_channels[${index}]`) + if (open_channelsErr !== null) return open_channelsErr + } + if (opts.open_channels_CustomCheck && !opts.open_channels_CustomCheck(o.open_channels)) return new Error(`${path}.open_channels: custom check failed`) + + if (!Array.isArray(o.closed_channels)) return new Error(`${path}.closed_channels: is not an array`) + for (let index = 0; index < o.closed_channels.length; index++) { + const closed_channelsErr = ClosedChannelValidate(o.closed_channels[index], opts.closed_channels_ItemOptions, `${path}.closed_channels[${index}]`) + if (closed_channelsErr !== null) return closed_channelsErr + } + if (opts.closed_channels_CustomCheck && !opts.closed_channels_CustomCheck(o.closed_channels)) return new Error(`${path}.closed_channels: custom check failed`) + + if (!Array.isArray(o.channel_routing)) return new Error(`${path}.channel_routing: is not an array`) + for (let index = 0; index < o.channel_routing.length; index++) { + const channel_routingErr = ChannelRoutingValidate(o.channel_routing[index], opts.channel_routing_ItemOptions, `${path}.channel_routing[${index}]`) + if (channel_routingErr !== null) return channel_routingErr + } + if (opts.channel_routing_CustomCheck && !opts.channel_routing_CustomCheck(o.channel_routing)) return new Error(`${path}.channel_routing: custom check failed`) + + return null +} + +export type AuthApp = { + app: Application + auth_token: string +} +export const AuthAppOptionalFields: [] = [] +export type AuthAppOptions = OptionsBaseMessage & { + checkOptionalsAreSet?: [] + app_Options?: ApplicationOptions + auth_token_CustomCheck?: (v: string) => boolean +} +export const AuthAppValidate = (o?: AuthApp, opts: AuthAppOptions = {}, path: string = 'AuthApp::root.'): Error | null => { + if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') + if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') + + const appErr = ApplicationValidate(o.app, opts.app_Options, `${path}.app`) + if (appErr !== null) return appErr + + + if (typeof o.auth_token !== 'string') return new Error(`${path}.auth_token: is not a string`) + if (opts.auth_token_CustomCheck && !opts.auth_token_CustomCheck(o.auth_token)) return new Error(`${path}.auth_token: custom check failed`) + + return null +} + +export type GetAppUserLNURLInfoRequest = { + user_identifier: string + base_url_override: string +} +export const GetAppUserLNURLInfoRequestOptionalFields: [] = [] +export type GetAppUserLNURLInfoRequestOptions = OptionsBaseMessage & { + checkOptionalsAreSet?: [] + user_identifier_CustomCheck?: (v: string) => boolean + base_url_override_CustomCheck?: (v: string) => boolean +} +export const GetAppUserLNURLInfoRequestValidate = (o?: GetAppUserLNURLInfoRequest, opts: GetAppUserLNURLInfoRequestOptions = {}, path: string = 'GetAppUserLNURLInfoRequest::root.'): Error | null => { + if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') + if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') + + if (typeof o.user_identifier !== 'string') return new Error(`${path}.user_identifier: is not a string`) + if (opts.user_identifier_CustomCheck && !opts.user_identifier_CustomCheck(o.user_identifier)) return new Error(`${path}.user_identifier: custom check failed`) + + if (typeof o.base_url_override !== 'string') return new Error(`${path}.base_url_override: is not a string`) + if (opts.base_url_override_CustomCheck && !opts.base_url_override_CustomCheck(o.base_url_override)) return new Error(`${path}.base_url_override: custom check failed`) + + return null +} + +export type UserInfo = { + service_fee_bps: number + network_max_fee_bps: number + network_max_fee_fixed: number + userId: string + balance: number + max_withdrawable: number + user_identifier: string +} +export const UserInfoOptionalFields: [] = [] +export type UserInfoOptions = OptionsBaseMessage & { + checkOptionalsAreSet?: [] + userId_CustomCheck?: (v: string) => boolean + balance_CustomCheck?: (v: number) => boolean + max_withdrawable_CustomCheck?: (v: number) => boolean + user_identifier_CustomCheck?: (v: string) => boolean + service_fee_bps_CustomCheck?: (v: number) => boolean + network_max_fee_bps_CustomCheck?: (v: number) => boolean + network_max_fee_fixed_CustomCheck?: (v: number) => boolean +} +export const UserInfoValidate = (o?: UserInfo, opts: UserInfoOptions = {}, path: string = 'UserInfo::root.'): Error | null => { + if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') + if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') + + if (typeof o.network_max_fee_bps !== 'number') return new Error(`${path}.network_max_fee_bps: is not a number`) + if (opts.network_max_fee_bps_CustomCheck && !opts.network_max_fee_bps_CustomCheck(o.network_max_fee_bps)) return new Error(`${path}.network_max_fee_bps: custom check failed`) + + if (typeof o.network_max_fee_fixed !== 'number') return new Error(`${path}.network_max_fee_fixed: is not a number`) + if (opts.network_max_fee_fixed_CustomCheck && !opts.network_max_fee_fixed_CustomCheck(o.network_max_fee_fixed)) return new Error(`${path}.network_max_fee_fixed: custom check failed`) + + if (typeof o.userId !== 'string') return new Error(`${path}.userId: is not a string`) + if (opts.userId_CustomCheck && !opts.userId_CustomCheck(o.userId)) return new Error(`${path}.userId: custom check failed`) + + if (typeof o.balance !== 'number') return new Error(`${path}.balance: is not a number`) + if (opts.balance_CustomCheck && !opts.balance_CustomCheck(o.balance)) return new Error(`${path}.balance: custom check failed`) + + if (typeof o.max_withdrawable !== 'number') return new Error(`${path}.max_withdrawable: is not a number`) + if (opts.max_withdrawable_CustomCheck && !opts.max_withdrawable_CustomCheck(o.max_withdrawable)) return new Error(`${path}.max_withdrawable: custom check failed`) + + if (typeof o.user_identifier !== 'string') return new Error(`${path}.user_identifier: is not a string`) + if (opts.user_identifier_CustomCheck && !opts.user_identifier_CustomCheck(o.user_identifier)) return new Error(`${path}.user_identifier: custom check failed`) + + if (typeof o.service_fee_bps !== 'number') return new Error(`${path}.service_fee_bps: is not a number`) + if (opts.service_fee_bps_CustomCheck && !opts.service_fee_bps_CustomCheck(o.service_fee_bps)) return new Error(`${path}.service_fee_bps: custom check failed`) + + return null +} + +export type UserOperation = { + confirmed: boolean + tx_hash: string + internal: boolean + paidAtUnix: number + service_fee: number + amount: number + identifier: string + operationId: string + network_fee: number + type: UserOperationType + inbound: boolean +} +export const UserOperationOptionalFields: [] = [] +export type UserOperationOptions = OptionsBaseMessage & { + checkOptionalsAreSet?: [] + amount_CustomCheck?: (v: number) => boolean + identifier_CustomCheck?: (v: string) => boolean + operationId_CustomCheck?: (v: string) => boolean + network_fee_CustomCheck?: (v: number) => boolean + type_CustomCheck?: (v: UserOperationType) => boolean + inbound_CustomCheck?: (v: boolean) => boolean + confirmed_CustomCheck?: (v: boolean) => boolean + tx_hash_CustomCheck?: (v: string) => boolean + internal_CustomCheck?: (v: boolean) => boolean + paidAtUnix_CustomCheck?: (v: number) => boolean + service_fee_CustomCheck?: (v: number) => boolean +} +export const UserOperationValidate = (o?: UserOperation, opts: UserOperationOptions = {}, path: string = 'UserOperation::root.'): Error | null => { + if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') + if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') + + if (!enumCheckUserOperationType(o.type)) return new Error(`${path}.type: is not a valid UserOperationType`) + if (opts.type_CustomCheck && !opts.type_CustomCheck(o.type)) return new Error(`${path}.type: custom check failed`) + + if (typeof o.inbound !== 'boolean') return new Error(`${path}.inbound: is not a boolean`) + if (opts.inbound_CustomCheck && !opts.inbound_CustomCheck(o.inbound)) return new Error(`${path}.inbound: custom check failed`) + + if (typeof o.amount !== 'number') return new Error(`${path}.amount: is not a number`) + if (opts.amount_CustomCheck && !opts.amount_CustomCheck(o.amount)) return new Error(`${path}.amount: custom check failed`) + + if (typeof o.identifier !== 'string') return new Error(`${path}.identifier: is not a string`) + if (opts.identifier_CustomCheck && !opts.identifier_CustomCheck(o.identifier)) return new Error(`${path}.identifier: custom check failed`) + + if (typeof o.operationId !== 'string') return new Error(`${path}.operationId: is not a string`) + if (opts.operationId_CustomCheck && !opts.operationId_CustomCheck(o.operationId)) return new Error(`${path}.operationId: custom check failed`) + + if (typeof o.network_fee !== 'number') return new Error(`${path}.network_fee: is not a number`) + if (opts.network_fee_CustomCheck && !opts.network_fee_CustomCheck(o.network_fee)) return new Error(`${path}.network_fee: custom check failed`) + + if (typeof o.paidAtUnix !== 'number') return new Error(`${path}.paidAtUnix: is not a number`) + if (opts.paidAtUnix_CustomCheck && !opts.paidAtUnix_CustomCheck(o.paidAtUnix)) return new Error(`${path}.paidAtUnix: custom check failed`) + + if (typeof o.service_fee !== 'number') return new Error(`${path}.service_fee: is not a number`) + if (opts.service_fee_CustomCheck && !opts.service_fee_CustomCheck(o.service_fee)) return new Error(`${path}.service_fee: custom check failed`) + + if (typeof o.confirmed !== 'boolean') return new Error(`${path}.confirmed: is not a boolean`) + if (opts.confirmed_CustomCheck && !opts.confirmed_CustomCheck(o.confirmed)) return new Error(`${path}.confirmed: custom check failed`) + + if (typeof o.tx_hash !== 'string') return new Error(`${path}.tx_hash: is not a string`) + if (opts.tx_hash_CustomCheck && !opts.tx_hash_CustomCheck(o.tx_hash)) return new Error(`${path}.tx_hash: custom check failed`) + + if (typeof o.internal !== 'boolean') return new Error(`${path}.internal: is not a boolean`) + if (opts.internal_CustomCheck && !opts.internal_CustomCheck(o.internal)) return new Error(`${path}.internal: custom check failed`) + + return null +} + +export type Empty = { +} +export const EmptyOptionalFields: [] = [] +export type EmptyOptions = OptionsBaseMessage & { + checkOptionalsAreSet?: [] +} +export const EmptyValidate = (o?: Empty, opts: EmptyOptions = {}, path: string = 'Empty::root.'): Error | null => { + if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') + if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') + + return null +} + +export type LndMetricsRequest = { + from_unix?: number + to_unix?: number +} +export type LndMetricsRequestOptionalField = 'from_unix' | 'to_unix' +export const LndMetricsRequestOptionalFields: LndMetricsRequestOptionalField[] = ['from_unix', 'to_unix'] +export type LndMetricsRequestOptions = OptionsBaseMessage & { + checkOptionalsAreSet?: LndMetricsRequestOptionalField[] + from_unix_CustomCheck?: (v?: number) => boolean + to_unix_CustomCheck?: (v?: number) => boolean +} +export const LndMetricsRequestValidate = (o?: LndMetricsRequest, opts: LndMetricsRequestOptions = {}, path: string = 'LndMetricsRequest::root.'): Error | null => { + if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') + if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') + + if ((o.from_unix || opts.allOptionalsAreSet || opts.checkOptionalsAreSet?.includes('from_unix')) && typeof o.from_unix !== 'number') return new Error(`${path}.from_unix: is not a number`) + if (opts.from_unix_CustomCheck && !opts.from_unix_CustomCheck(o.from_unix)) return new Error(`${path}.from_unix: custom check failed`) + + if ((o.to_unix || opts.allOptionalsAreSet || opts.checkOptionalsAreSet?.includes('to_unix')) && typeof o.to_unix !== 'number') return new Error(`${path}.to_unix: is not a number`) + if (opts.to_unix_CustomCheck && !opts.to_unix_CustomCheck(o.to_unix)) return new Error(`${path}.to_unix: custom check failed`) + + return null +} + +export type LndGetInfoResponse = { + alias: string +} +export const LndGetInfoResponseOptionalFields: [] = [] +export type LndGetInfoResponseOptions = OptionsBaseMessage & { + checkOptionalsAreSet?: [] + alias_CustomCheck?: (v: string) => boolean +} +export const LndGetInfoResponseValidate = (o?: LndGetInfoResponse, opts: LndGetInfoResponseOptions = {}, path: string = 'LndGetInfoResponse::root.'): Error | null => { + if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') + if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') + + if (typeof o.alias !== 'string') return new Error(`${path}.alias: is not a string`) + if (opts.alias_CustomCheck && !opts.alias_CustomCheck(o.alias)) return new Error(`${path}.alias: custom check failed`) + + return null +} + +export type PayAppUserInvoiceRequest = { + amount: number + user_identifier: string + invoice: string +} +export const PayAppUserInvoiceRequestOptionalFields: [] = [] +export type PayAppUserInvoiceRequestOptions = OptionsBaseMessage & { + checkOptionalsAreSet?: [] + invoice_CustomCheck?: (v: string) => boolean + amount_CustomCheck?: (v: number) => boolean + user_identifier_CustomCheck?: (v: string) => boolean +} +export const PayAppUserInvoiceRequestValidate = (o?: PayAppUserInvoiceRequest, opts: PayAppUserInvoiceRequestOptions = {}, path: string = 'PayAppUserInvoiceRequest::root.'): Error | null => { + if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') + if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') + + if (typeof o.user_identifier !== 'string') return new Error(`${path}.user_identifier: is not a string`) + if (opts.user_identifier_CustomCheck && !opts.user_identifier_CustomCheck(o.user_identifier)) return new Error(`${path}.user_identifier: custom check failed`) + + if (typeof o.invoice !== 'string') return new Error(`${path}.invoice: is not a string`) + if (opts.invoice_CustomCheck && !opts.invoice_CustomCheck(o.invoice)) return new Error(`${path}.invoice: custom check failed`) + + if (typeof o.amount !== 'number') return new Error(`${path}.amount: is not a number`) + if (opts.amount_CustomCheck && !opts.amount_CustomCheck(o.amount)) return new Error(`${path}.amount: custom check failed`) + + return null +} + +export type Product = { + id: string + name: string + price_sats: number +} +export const ProductOptionalFields: [] = [] +export type ProductOptions = OptionsBaseMessage & { + checkOptionalsAreSet?: [] + id_CustomCheck?: (v: string) => boolean + name_CustomCheck?: (v: string) => boolean + price_sats_CustomCheck?: (v: number) => boolean +} +export const ProductValidate = (o?: Product, opts: ProductOptions = {}, path: string = 'Product::root.'): Error | null => { + if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') + if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') + + if (typeof o.id !== 'string') return new Error(`${path}.id: is not a string`) + if (opts.id_CustomCheck && !opts.id_CustomCheck(o.id)) return new Error(`${path}.id: custom check failed`) + + if (typeof o.name !== 'string') return new Error(`${path}.name: is not a string`) + if (opts.name_CustomCheck && !opts.name_CustomCheck(o.name)) return new Error(`${path}.name: custom check failed`) + + if (typeof o.price_sats !== 'number') return new Error(`${path}.price_sats: is not a number`) + if (opts.price_sats_CustomCheck && !opts.price_sats_CustomCheck(o.price_sats)) return new Error(`${path}.price_sats: custom check failed`) + + return null +} + +export type LndGetInfoRequest = { + nodeId: number +} +export const LndGetInfoRequestOptionalFields: [] = [] +export type LndGetInfoRequestOptions = OptionsBaseMessage & { + checkOptionalsAreSet?: [] + nodeId_CustomCheck?: (v: number) => boolean +} +export const LndGetInfoRequestValidate = (o?: LndGetInfoRequest, opts: LndGetInfoRequestOptions = {}, path: string = 'LndGetInfoRequest::root.'): Error | null => { + if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') + if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') + + if (typeof o.nodeId !== 'number') return new Error(`${path}.nodeId: is not a number`) + if (opts.nodeId_CustomCheck && !opts.nodeId_CustomCheck(o.nodeId)) return new Error(`${path}.nodeId: custom check failed`) + + return null +} + +export type BanUserResponse = { + balance_sats: number + banned_app_users: BannedAppUser[] +} +export const BanUserResponseOptionalFields: [] = [] +export type BanUserResponseOptions = OptionsBaseMessage & { + checkOptionalsAreSet?: [] + balance_sats_CustomCheck?: (v: number) => boolean + banned_app_users_ItemOptions?: BannedAppUserOptions + banned_app_users_CustomCheck?: (v: BannedAppUser[]) => boolean +} +export const BanUserResponseValidate = (o?: BanUserResponse, opts: BanUserResponseOptions = {}, path: string = 'BanUserResponse::root.'): Error | null => { + if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') + if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') + + if (typeof o.balance_sats !== 'number') return new Error(`${path}.balance_sats: is not a number`) + if (opts.balance_sats_CustomCheck && !opts.balance_sats_CustomCheck(o.balance_sats)) return new Error(`${path}.balance_sats: custom check failed`) + + if (!Array.isArray(o.banned_app_users)) return new Error(`${path}.banned_app_users: is not an array`) + for (let index = 0; index < o.banned_app_users.length; index++) { + const banned_app_usersErr = BannedAppUserValidate(o.banned_app_users[index], opts.banned_app_users_ItemOptions, `${path}.banned_app_users[${index}]`) + if (banned_app_usersErr !== null) return banned_app_usersErr + } + if (opts.banned_app_users_CustomCheck && !opts.banned_app_users_CustomCheck(o.banned_app_users)) return new Error(`${path}.banned_app_users: custom check failed`) + + return null +} + +export type AuthAppRequest = { + name: string + allow_user_creation?: boolean +} +export type AuthAppRequestOptionalField = 'allow_user_creation' +export const AuthAppRequestOptionalFields: AuthAppRequestOptionalField[] = ['allow_user_creation'] +export type AuthAppRequestOptions = OptionsBaseMessage & { + checkOptionalsAreSet?: AuthAppRequestOptionalField[] + allow_user_creation_CustomCheck?: (v?: boolean) => boolean + name_CustomCheck?: (v: string) => boolean +} +export const AuthAppRequestValidate = (o?: AuthAppRequest, opts: AuthAppRequestOptions = {}, path: string = 'AuthAppRequest::root.'): Error | null => { + if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') + if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') + + if (typeof o.name !== 'string') return new Error(`${path}.name: is not a string`) + if (opts.name_CustomCheck && !opts.name_CustomCheck(o.name)) return new Error(`${path}.name: custom check failed`) + + if ((o.allow_user_creation || opts.allOptionalsAreSet || opts.checkOptionalsAreSet?.includes('allow_user_creation')) && typeof o.allow_user_creation !== 'boolean') return new Error(`${path}.allow_user_creation: is not a boolean`) + if (opts.allow_user_creation_CustomCheck && !opts.allow_user_creation_CustomCheck(o.allow_user_creation)) return new Error(`${path}.allow_user_creation: custom check failed`) + + return null +} + +export type PayAddressRequest = { + amoutSats: number + satsPerVByte: number + address: string +} +export const PayAddressRequestOptionalFields: [] = [] +export type PayAddressRequestOptions = OptionsBaseMessage & { + checkOptionalsAreSet?: [] + address_CustomCheck?: (v: string) => boolean + amoutSats_CustomCheck?: (v: number) => boolean + satsPerVByte_CustomCheck?: (v: number) => boolean +} +export const PayAddressRequestValidate = (o?: PayAddressRequest, opts: PayAddressRequestOptions = {}, path: string = 'PayAddressRequest::root.'): Error | null => { + if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') + if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') + + if (typeof o.address !== 'string') return new Error(`${path}.address: is not a string`) + if (opts.address_CustomCheck && !opts.address_CustomCheck(o.address)) return new Error(`${path}.address: custom check failed`) + + if (typeof o.amoutSats !== 'number') return new Error(`${path}.amoutSats: is not a number`) + if (opts.amoutSats_CustomCheck && !opts.amoutSats_CustomCheck(o.amoutSats)) return new Error(`${path}.amoutSats: custom check failed`) + + if (typeof o.satsPerVByte !== 'number') return new Error(`${path}.satsPerVByte: is not a number`) + if (opts.satsPerVByte_CustomCheck && !opts.satsPerVByte_CustomCheck(o.satsPerVByte)) return new Error(`${path}.satsPerVByte: custom check failed`) + + return null +} + +export type AppsMetricsRequest = { + from_unix?: number + to_unix?: number + include_operations?: boolean +} +export type AppsMetricsRequestOptionalField = 'from_unix' | 'to_unix' | 'include_operations' +export const AppsMetricsRequestOptionalFields: AppsMetricsRequestOptionalField[] = ['from_unix', 'to_unix', 'include_operations'] +export type AppsMetricsRequestOptions = OptionsBaseMessage & { + checkOptionalsAreSet?: AppsMetricsRequestOptionalField[] + to_unix_CustomCheck?: (v?: number) => boolean + include_operations_CustomCheck?: (v?: boolean) => boolean + from_unix_CustomCheck?: (v?: number) => boolean +} +export const AppsMetricsRequestValidate = (o?: AppsMetricsRequest, opts: AppsMetricsRequestOptions = {}, path: string = 'AppsMetricsRequest::root.'): Error | null => { + if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') + if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') + + if ((o.from_unix || opts.allOptionalsAreSet || opts.checkOptionalsAreSet?.includes('from_unix')) && typeof o.from_unix !== 'number') return new Error(`${path}.from_unix: is not a number`) + if (opts.from_unix_CustomCheck && !opts.from_unix_CustomCheck(o.from_unix)) return new Error(`${path}.from_unix: custom check failed`) + + if ((o.to_unix || opts.allOptionalsAreSet || opts.checkOptionalsAreSet?.includes('to_unix')) && typeof o.to_unix !== 'number') return new Error(`${path}.to_unix: is not a number`) + if (opts.to_unix_CustomCheck && !opts.to_unix_CustomCheck(o.to_unix)) return new Error(`${path}.to_unix: custom check failed`) + + if ((o.include_operations || opts.allOptionalsAreSet || opts.checkOptionalsAreSet?.includes('include_operations')) && typeof o.include_operations !== 'boolean') return new Error(`${path}.include_operations: is not a boolean`) + if (opts.include_operations_CustomCheck && !opts.include_operations_CustomCheck(o.include_operations)) return new Error(`${path}.include_operations: custom check failed`) + + return null +} + +export type AppsMetrics = { + apps: AppMetrics[] +} +export const AppsMetricsOptionalFields: [] = [] +export type AppsMetricsOptions = OptionsBaseMessage & { + checkOptionalsAreSet?: [] + apps_ItemOptions?: AppMetricsOptions + apps_CustomCheck?: (v: AppMetrics[]) => boolean +} +export const AppsMetricsValidate = (o?: AppsMetrics, opts: AppsMetricsOptions = {}, path: string = 'AppsMetrics::root.'): Error | null => { + if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') + if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') + + if (!Array.isArray(o.apps)) return new Error(`${path}.apps: is not an array`) + for (let index = 0; index < o.apps.length; index++) { + const appsErr = AppMetricsValidate(o.apps[index], opts.apps_ItemOptions, `${path}.apps[${index}]`) + if (appsErr !== null) return appsErr + } + if (opts.apps_CustomCheck && !opts.apps_CustomCheck(o.apps)) return new Error(`${path}.apps: custom check failed`) + + return null +} + +export type RoutingEvent = { + incoming_htlc_id: number + outgoing_channel_id: number + outgoing_htlc_id: number + timestamp_ns: number + event_type: string + settled: boolean + offchain: boolean + incoming_channel_id: number + forward_fail_event: boolean + outgoing_amt_msat: number + failure_string: string + incoming_amt_msat: number +} +export const RoutingEventOptionalFields: [] = [] +export type RoutingEventOptions = OptionsBaseMessage & { + checkOptionalsAreSet?: [] + incoming_amt_msat_CustomCheck?: (v: number) => boolean + outgoing_amt_msat_CustomCheck?: (v: number) => boolean + failure_string_CustomCheck?: (v: string) => boolean + incoming_channel_id_CustomCheck?: (v: number) => boolean + incoming_htlc_id_CustomCheck?: (v: number) => boolean + outgoing_channel_id_CustomCheck?: (v: number) => boolean + outgoing_htlc_id_CustomCheck?: (v: number) => boolean + timestamp_ns_CustomCheck?: (v: number) => boolean + event_type_CustomCheck?: (v: string) => boolean + settled_CustomCheck?: (v: boolean) => boolean + offchain_CustomCheck?: (v: boolean) => boolean + forward_fail_event_CustomCheck?: (v: boolean) => boolean +} +export const RoutingEventValidate = (o?: RoutingEvent, opts: RoutingEventOptions = {}, path: string = 'RoutingEvent::root.'): Error | null => { + if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') + if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') + + if (typeof o.incoming_htlc_id !== 'number') return new Error(`${path}.incoming_htlc_id: is not a number`) + if (opts.incoming_htlc_id_CustomCheck && !opts.incoming_htlc_id_CustomCheck(o.incoming_htlc_id)) return new Error(`${path}.incoming_htlc_id: custom check failed`) + + if (typeof o.outgoing_channel_id !== 'number') return new Error(`${path}.outgoing_channel_id: is not a number`) + if (opts.outgoing_channel_id_CustomCheck && !opts.outgoing_channel_id_CustomCheck(o.outgoing_channel_id)) return new Error(`${path}.outgoing_channel_id: custom check failed`) + + if (typeof o.outgoing_htlc_id !== 'number') return new Error(`${path}.outgoing_htlc_id: is not a number`) + if (opts.outgoing_htlc_id_CustomCheck && !opts.outgoing_htlc_id_CustomCheck(o.outgoing_htlc_id)) return new Error(`${path}.outgoing_htlc_id: custom check failed`) + + if (typeof o.timestamp_ns !== 'number') return new Error(`${path}.timestamp_ns: is not a number`) + if (opts.timestamp_ns_CustomCheck && !opts.timestamp_ns_CustomCheck(o.timestamp_ns)) return new Error(`${path}.timestamp_ns: custom check failed`) + + if (typeof o.event_type !== 'string') return new Error(`${path}.event_type: is not a string`) + if (opts.event_type_CustomCheck && !opts.event_type_CustomCheck(o.event_type)) return new Error(`${path}.event_type: custom check failed`) + + if (typeof o.settled !== 'boolean') return new Error(`${path}.settled: is not a boolean`) + if (opts.settled_CustomCheck && !opts.settled_CustomCheck(o.settled)) return new Error(`${path}.settled: custom check failed`) + + if (typeof o.offchain !== 'boolean') return new Error(`${path}.offchain: is not a boolean`) + if (opts.offchain_CustomCheck && !opts.offchain_CustomCheck(o.offchain)) return new Error(`${path}.offchain: custom check failed`) + + if (typeof o.incoming_channel_id !== 'number') return new Error(`${path}.incoming_channel_id: is not a number`) + if (opts.incoming_channel_id_CustomCheck && !opts.incoming_channel_id_CustomCheck(o.incoming_channel_id)) return new Error(`${path}.incoming_channel_id: custom check failed`) + + if (typeof o.forward_fail_event !== 'boolean') return new Error(`${path}.forward_fail_event: is not a boolean`) + if (opts.forward_fail_event_CustomCheck && !opts.forward_fail_event_CustomCheck(o.forward_fail_event)) return new Error(`${path}.forward_fail_event: custom check failed`) + + if (typeof o.outgoing_amt_msat !== 'number') return new Error(`${path}.outgoing_amt_msat: is not a number`) + if (opts.outgoing_amt_msat_CustomCheck && !opts.outgoing_amt_msat_CustomCheck(o.outgoing_amt_msat)) return new Error(`${path}.outgoing_amt_msat: custom check failed`) + + if (typeof o.failure_string !== 'string') return new Error(`${path}.failure_string: is not a string`) + if (opts.failure_string_CustomCheck && !opts.failure_string_CustomCheck(o.failure_string)) return new Error(`${path}.failure_string: custom check failed`) + + if (typeof o.incoming_amt_msat !== 'number') return new Error(`${path}.incoming_amt_msat: is not a number`) + if (opts.incoming_amt_msat_CustomCheck && !opts.incoming_amt_msat_CustomCheck(o.incoming_amt_msat)) return new Error(`${path}.incoming_amt_msat: custom check failed`) + + return null +} + +export type BannedAppUser = { + app_name: string + app_id: string + user_identifier: string + nostr_pub: string +} +export const BannedAppUserOptionalFields: [] = [] +export type BannedAppUserOptions = OptionsBaseMessage & { + checkOptionalsAreSet?: [] + app_name_CustomCheck?: (v: string) => boolean + app_id_CustomCheck?: (v: string) => boolean + user_identifier_CustomCheck?: (v: string) => boolean + nostr_pub_CustomCheck?: (v: string) => boolean +} +export const BannedAppUserValidate = (o?: BannedAppUser, opts: BannedAppUserOptions = {}, path: string = 'BannedAppUser::root.'): Error | null => { + if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') + if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') + + if (typeof o.app_id !== 'string') return new Error(`${path}.app_id: is not a string`) + if (opts.app_id_CustomCheck && !opts.app_id_CustomCheck(o.app_id)) return new Error(`${path}.app_id: custom check failed`) + + if (typeof o.user_identifier !== 'string') return new Error(`${path}.user_identifier: is not a string`) + if (opts.user_identifier_CustomCheck && !opts.user_identifier_CustomCheck(o.user_identifier)) return new Error(`${path}.user_identifier: custom check failed`) + + if (typeof o.nostr_pub !== 'string') return new Error(`${path}.nostr_pub: is not a string`) + if (opts.nostr_pub_CustomCheck && !opts.nostr_pub_CustomCheck(o.nostr_pub)) return new Error(`${path}.nostr_pub: custom check failed`) + + if (typeof o.app_name !== 'string') return new Error(`${path}.app_name: is not a string`) + if (opts.app_name_CustomCheck && !opts.app_name_CustomCheck(o.app_name)) return new Error(`${path}.app_name: custom check failed`) + + return null +} + +export type GetUserOperationsResponse = { + latestIncomingInvoiceOperations: UserOperations + latestOutgoingTxOperations: UserOperations + latestIncomingTxOperations: UserOperations + latestOutgoingUserToUserPayemnts: UserOperations + latestIncomingUserToUserPayemnts: UserOperations + latestOutgoingInvoiceOperations: UserOperations +} +export const GetUserOperationsResponseOptionalFields: [] = [] +export type GetUserOperationsResponseOptions = OptionsBaseMessage & { + checkOptionalsAreSet?: [] + latestOutgoingInvoiceOperations_Options?: UserOperationsOptions + latestIncomingInvoiceOperations_Options?: UserOperationsOptions + latestOutgoingTxOperations_Options?: UserOperationsOptions + latestIncomingTxOperations_Options?: UserOperationsOptions + latestOutgoingUserToUserPayemnts_Options?: UserOperationsOptions + latestIncomingUserToUserPayemnts_Options?: UserOperationsOptions +} +export const GetUserOperationsResponseValidate = (o?: GetUserOperationsResponse, opts: GetUserOperationsResponseOptions = {}, path: string = 'GetUserOperationsResponse::root.'): Error | null => { + if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') + if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') + + const latestOutgoingInvoiceOperationsErr = UserOperationsValidate(o.latestOutgoingInvoiceOperations, opts.latestOutgoingInvoiceOperations_Options, `${path}.latestOutgoingInvoiceOperations`) + if (latestOutgoingInvoiceOperationsErr !== null) return latestOutgoingInvoiceOperationsErr + + + const latestIncomingInvoiceOperationsErr = UserOperationsValidate(o.latestIncomingInvoiceOperations, opts.latestIncomingInvoiceOperations_Options, `${path}.latestIncomingInvoiceOperations`) + if (latestIncomingInvoiceOperationsErr !== null) return latestIncomingInvoiceOperationsErr + + + const latestOutgoingTxOperationsErr = UserOperationsValidate(o.latestOutgoingTxOperations, opts.latestOutgoingTxOperations_Options, `${path}.latestOutgoingTxOperations`) + if (latestOutgoingTxOperationsErr !== null) return latestOutgoingTxOperationsErr + + + const latestIncomingTxOperationsErr = UserOperationsValidate(o.latestIncomingTxOperations, opts.latestIncomingTxOperations_Options, `${path}.latestIncomingTxOperations`) + if (latestIncomingTxOperationsErr !== null) return latestIncomingTxOperationsErr + + + const latestOutgoingUserToUserPayemntsErr = UserOperationsValidate(o.latestOutgoingUserToUserPayemnts, opts.latestOutgoingUserToUserPayemnts_Options, `${path}.latestOutgoingUserToUserPayemnts`) + if (latestOutgoingUserToUserPayemntsErr !== null) return latestOutgoingUserToUserPayemntsErr + + + const latestIncomingUserToUserPayemntsErr = UserOperationsValidate(o.latestIncomingUserToUserPayemnts, opts.latestIncomingUserToUserPayemnts_Options, `${path}.latestIncomingUserToUserPayemnts`) + if (latestIncomingUserToUserPayemntsErr !== null) return latestIncomingUserToUserPayemntsErr + + + return null +} + +export type RequestNPubLinkingTokenResponse = { + token: string +} +export const RequestNPubLinkingTokenResponseOptionalFields: [] = [] +export type RequestNPubLinkingTokenResponseOptions = OptionsBaseMessage & { + checkOptionalsAreSet?: [] + token_CustomCheck?: (v: string) => boolean +} +export const RequestNPubLinkingTokenResponseValidate = (o?: RequestNPubLinkingTokenResponse, opts: RequestNPubLinkingTokenResponseOptions = {}, path: string = 'RequestNPubLinkingTokenResponse::root.'): Error | null => { + if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') + if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') + + if (typeof o.token !== 'string') return new Error(`${path}.token: is not a string`) + if (opts.token_CustomCheck && !opts.token_CustomCheck(o.token)) return new Error(`${path}.token: custom check failed`) + + return null +} + +export type UsageMetric = { + handle_in_nano: number + batch: boolean + batch_size: number + parsed_in_nano: number + validate_in_nano: number + rpc_name: string + nostr: boolean + processed_at_ms: number + auth_in_nano: number +} +export const UsageMetricOptionalFields: [] = [] +export type UsageMetricOptions = OptionsBaseMessage & { + checkOptionalsAreSet?: [] + handle_in_nano_CustomCheck?: (v: number) => boolean + batch_CustomCheck?: (v: boolean) => boolean + batch_size_CustomCheck?: (v: number) => boolean + parsed_in_nano_CustomCheck?: (v: number) => boolean + validate_in_nano_CustomCheck?: (v: number) => boolean + rpc_name_CustomCheck?: (v: string) => boolean + nostr_CustomCheck?: (v: boolean) => boolean + processed_at_ms_CustomCheck?: (v: number) => boolean + auth_in_nano_CustomCheck?: (v: number) => boolean +} +export const UsageMetricValidate = (o?: UsageMetric, opts: UsageMetricOptions = {}, path: string = 'UsageMetric::root.'): Error | null => { + if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') + if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') + + if (typeof o.handle_in_nano !== 'number') return new Error(`${path}.handle_in_nano: is not a number`) + if (opts.handle_in_nano_CustomCheck && !opts.handle_in_nano_CustomCheck(o.handle_in_nano)) return new Error(`${path}.handle_in_nano: custom check failed`) + + if (typeof o.batch !== 'boolean') return new Error(`${path}.batch: is not a boolean`) + if (opts.batch_CustomCheck && !opts.batch_CustomCheck(o.batch)) return new Error(`${path}.batch: custom check failed`) + + if (typeof o.batch_size !== 'number') return new Error(`${path}.batch_size: is not a number`) + if (opts.batch_size_CustomCheck && !opts.batch_size_CustomCheck(o.batch_size)) return new Error(`${path}.batch_size: custom check failed`) + + if (typeof o.parsed_in_nano !== 'number') return new Error(`${path}.parsed_in_nano: is not a number`) + if (opts.parsed_in_nano_CustomCheck && !opts.parsed_in_nano_CustomCheck(o.parsed_in_nano)) return new Error(`${path}.parsed_in_nano: custom check failed`) + + if (typeof o.validate_in_nano !== 'number') return new Error(`${path}.validate_in_nano: is not a number`) + if (opts.validate_in_nano_CustomCheck && !opts.validate_in_nano_CustomCheck(o.validate_in_nano)) return new Error(`${path}.validate_in_nano: custom check failed`) + + if (typeof o.rpc_name !== 'string') return new Error(`${path}.rpc_name: is not a string`) + if (opts.rpc_name_CustomCheck && !opts.rpc_name_CustomCheck(o.rpc_name)) return new Error(`${path}.rpc_name: custom check failed`) + + if (typeof o.nostr !== 'boolean') return new Error(`${path}.nostr: is not a boolean`) + if (opts.nostr_CustomCheck && !opts.nostr_CustomCheck(o.nostr)) return new Error(`${path}.nostr: custom check failed`) + + if (typeof o.processed_at_ms !== 'number') return new Error(`${path}.processed_at_ms: is not a number`) + if (opts.processed_at_ms_CustomCheck && !opts.processed_at_ms_CustomCheck(o.processed_at_ms)) return new Error(`${path}.processed_at_ms: custom check failed`) + + if (typeof o.auth_in_nano !== 'number') return new Error(`${path}.auth_in_nano: is not a number`) + if (opts.auth_in_nano_CustomCheck && !opts.auth_in_nano_CustomCheck(o.auth_in_nano)) return new Error(`${path}.auth_in_nano: custom check failed`) + + return null +} + +export type NewInvoiceRequest = { + amountSats: number + memo: string +} +export const NewInvoiceRequestOptionalFields: [] = [] +export type NewInvoiceRequestOptions = OptionsBaseMessage & { + checkOptionalsAreSet?: [] + memo_CustomCheck?: (v: string) => boolean + amountSats_CustomCheck?: (v: number) => boolean +} +export const NewInvoiceRequestValidate = (o?: NewInvoiceRequest, opts: NewInvoiceRequestOptions = {}, path: string = 'NewInvoiceRequest::root.'): Error | null => { + if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') + if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') + + if (typeof o.amountSats !== 'number') return new Error(`${path}.amountSats: is not a number`) + if (opts.amountSats_CustomCheck && !opts.amountSats_CustomCheck(o.amountSats)) return new Error(`${path}.amountSats: custom check failed`) + + if (typeof o.memo !== 'string') return new Error(`${path}.memo: is not a string`) + if (opts.memo_CustomCheck && !opts.memo_CustomCheck(o.memo)) return new Error(`${path}.memo: custom check failed`) + + return null +} + +export type OpenChannelRequest = { + closeAddress: string + destination: string + fundingAmount: number + pushAmount: number +} +export const OpenChannelRequestOptionalFields: [] = [] +export type OpenChannelRequestOptions = OptionsBaseMessage & { + checkOptionalsAreSet?: [] + destination_CustomCheck?: (v: string) => boolean + fundingAmount_CustomCheck?: (v: number) => boolean + pushAmount_CustomCheck?: (v: number) => boolean + closeAddress_CustomCheck?: (v: string) => boolean +} +export const OpenChannelRequestValidate = (o?: OpenChannelRequest, opts: OpenChannelRequestOptions = {}, path: string = 'OpenChannelRequest::root.'): Error | null => { + if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') + if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') + + if (typeof o.destination !== 'string') return new Error(`${path}.destination: is not a string`) + if (opts.destination_CustomCheck && !opts.destination_CustomCheck(o.destination)) return new Error(`${path}.destination: custom check failed`) + + if (typeof o.fundingAmount !== 'number') return new Error(`${path}.fundingAmount: is not a number`) + if (opts.fundingAmount_CustomCheck && !opts.fundingAmount_CustomCheck(o.fundingAmount)) return new Error(`${path}.fundingAmount: custom check failed`) + + if (typeof o.pushAmount !== 'number') return new Error(`${path}.pushAmount: is not a number`) + if (opts.pushAmount_CustomCheck && !opts.pushAmount_CustomCheck(o.pushAmount)) return new Error(`${path}.pushAmount: custom check failed`) + + if (typeof o.closeAddress !== 'string') return new Error(`${path}.closeAddress: is not a string`) + if (opts.closeAddress_CustomCheck && !opts.closeAddress_CustomCheck(o.closeAddress)) return new Error(`${path}.closeAddress: custom check failed`) + + return null +} + +export type ChainBalanceEvent = { + total_balance: number + block_height: number + confirmed_balance: number + unconfirmed_balance: number +} +export const ChainBalanceEventOptionalFields: [] = [] +export type ChainBalanceEventOptions = OptionsBaseMessage & { + checkOptionalsAreSet?: [] + block_height_CustomCheck?: (v: number) => boolean + confirmed_balance_CustomCheck?: (v: number) => boolean + unconfirmed_balance_CustomCheck?: (v: number) => boolean + total_balance_CustomCheck?: (v: number) => boolean +} +export const ChainBalanceEventValidate = (o?: ChainBalanceEvent, opts: ChainBalanceEventOptions = {}, path: string = 'ChainBalanceEvent::root.'): Error | null => { + if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') + if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') + + if (typeof o.confirmed_balance !== 'number') return new Error(`${path}.confirmed_balance: is not a number`) + if (opts.confirmed_balance_CustomCheck && !opts.confirmed_balance_CustomCheck(o.confirmed_balance)) return new Error(`${path}.confirmed_balance: custom check failed`) + + if (typeof o.unconfirmed_balance !== 'number') return new Error(`${path}.unconfirmed_balance: is not a number`) + if (opts.unconfirmed_balance_CustomCheck && !opts.unconfirmed_balance_CustomCheck(o.unconfirmed_balance)) return new Error(`${path}.unconfirmed_balance: custom check failed`) + + if (typeof o.total_balance !== 'number') return new Error(`${path}.total_balance: is not a number`) + if (opts.total_balance_CustomCheck && !opts.total_balance_CustomCheck(o.total_balance)) return new Error(`${path}.total_balance: custom check failed`) + + if (typeof o.block_height !== 'number') return new Error(`${path}.block_height: is not a number`) + if (opts.block_height_CustomCheck && !opts.block_height_CustomCheck(o.block_height)) return new Error(`${path}.block_height: custom check failed`) + + return null +} + +export type GetAppUserRequest = { + user_identifier: string +} +export const GetAppUserRequestOptionalFields: [] = [] +export type GetAppUserRequestOptions = OptionsBaseMessage & { + checkOptionalsAreSet?: [] + user_identifier_CustomCheck?: (v: string) => boolean +} +export const GetAppUserRequestValidate = (o?: GetAppUserRequest, opts: GetAppUserRequestOptions = {}, path: string = 'GetAppUserRequest::root.'): Error | null => { + if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') + if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') + + if (typeof o.user_identifier !== 'string') return new Error(`${path}.user_identifier: is not a string`) + if (opts.user_identifier_CustomCheck && !opts.user_identifier_CustomCheck(o.user_identifier)) return new Error(`${path}.user_identifier: custom check failed`) + + return null +} + +export type NewAddressResponse = { + address: string +} +export const NewAddressResponseOptionalFields: [] = [] +export type NewAddressResponseOptions = OptionsBaseMessage & { + checkOptionalsAreSet?: [] + address_CustomCheck?: (v: string) => boolean +} +export const NewAddressResponseValidate = (o?: NewAddressResponse, opts: NewAddressResponseOptions = {}, path: string = 'NewAddressResponse::root.'): Error | null => { + if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') + if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') + + if (typeof o.address !== 'string') return new Error(`${path}.address: is not a string`) + if (opts.address_CustomCheck && !opts.address_CustomCheck(o.address)) return new Error(`${path}.address: custom check failed`) + + return null +} + +export type PayInvoiceResponse = { + network_fee: number + preimage: string + amount_paid: number + operation_id: string + service_fee: number +} +export const PayInvoiceResponseOptionalFields: [] = [] +export type PayInvoiceResponseOptions = OptionsBaseMessage & { + checkOptionalsAreSet?: [] + network_fee_CustomCheck?: (v: number) => boolean + preimage_CustomCheck?: (v: string) => boolean + amount_paid_CustomCheck?: (v: number) => boolean + operation_id_CustomCheck?: (v: string) => boolean + service_fee_CustomCheck?: (v: number) => boolean +} +export const PayInvoiceResponseValidate = (o?: PayInvoiceResponse, opts: PayInvoiceResponseOptions = {}, path: string = 'PayInvoiceResponse::root.'): Error | null => { + if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') + if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') + + if (typeof o.network_fee !== 'number') return new Error(`${path}.network_fee: is not a number`) + if (opts.network_fee_CustomCheck && !opts.network_fee_CustomCheck(o.network_fee)) return new Error(`${path}.network_fee: custom check failed`) + + if (typeof o.preimage !== 'string') return new Error(`${path}.preimage: is not a string`) + if (opts.preimage_CustomCheck && !opts.preimage_CustomCheck(o.preimage)) return new Error(`${path}.preimage: custom check failed`) + + if (typeof o.amount_paid !== 'number') return new Error(`${path}.amount_paid: is not a number`) + if (opts.amount_paid_CustomCheck && !opts.amount_paid_CustomCheck(o.amount_paid)) return new Error(`${path}.amount_paid: custom check failed`) + + if (typeof o.operation_id !== 'string') return new Error(`${path}.operation_id: is not a string`) + if (opts.operation_id_CustomCheck && !opts.operation_id_CustomCheck(o.operation_id)) return new Error(`${path}.operation_id: custom check failed`) + + if (typeof o.service_fee !== 'number') return new Error(`${path}.service_fee: is not a number`) + if (opts.service_fee_CustomCheck && !opts.service_fee_CustomCheck(o.service_fee)) return new Error(`${path}.service_fee: custom check failed`) + + return null +} + +export type AddProductRequest = { + name: string + price_sats: number +} +export const AddProductRequestOptionalFields: [] = [] +export type AddProductRequestOptions = OptionsBaseMessage & { + checkOptionalsAreSet?: [] + name_CustomCheck?: (v: string) => boolean + price_sats_CustomCheck?: (v: number) => boolean +} +export const AddProductRequestValidate = (o?: AddProductRequest, opts: AddProductRequestOptions = {}, path: string = 'AddProductRequest::root.'): Error | null => { + if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') + if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') + + if (typeof o.name !== 'string') return new Error(`${path}.name: is not a string`) + if (opts.name_CustomCheck && !opts.name_CustomCheck(o.name)) return new Error(`${path}.name: custom check failed`) + + if (typeof o.price_sats !== 'number') return new Error(`${path}.price_sats: is not a number`) + if (opts.price_sats_CustomCheck && !opts.price_sats_CustomCheck(o.price_sats)) return new Error(`${path}.price_sats: custom check failed`) + + return null +} + +export type EncryptionExchangeRequest = { + deviceId: string + publicKey: string +} +export const EncryptionExchangeRequestOptionalFields: [] = [] +export type EncryptionExchangeRequestOptions = OptionsBaseMessage & { + checkOptionalsAreSet?: [] + publicKey_CustomCheck?: (v: string) => boolean + deviceId_CustomCheck?: (v: string) => boolean +} +export const EncryptionExchangeRequestValidate = (o?: EncryptionExchangeRequest, opts: EncryptionExchangeRequestOptions = {}, path: string = 'EncryptionExchangeRequest::root.'): Error | null => { + if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') + if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') + + if (typeof o.publicKey !== 'string') return new Error(`${path}.publicKey: is not a string`) + if (opts.publicKey_CustomCheck && !opts.publicKey_CustomCheck(o.publicKey)) return new Error(`${path}.publicKey: custom check failed`) + + if (typeof o.deviceId !== 'string') return new Error(`${path}.deviceId: is not a string`) + if (opts.deviceId_CustomCheck && !opts.deviceId_CustomCheck(o.deviceId)) return new Error(`${path}.deviceId: custom check failed`) + + return null +} + +export type UsersInfo = { + negative_balance: number + always_been_inactive: number + balance_avg: number + balance_median: number + total: number + no_balance: number +} +export const UsersInfoOptionalFields: [] = [] +export type UsersInfoOptions = OptionsBaseMessage & { + checkOptionalsAreSet?: [] + no_balance_CustomCheck?: (v: number) => boolean + negative_balance_CustomCheck?: (v: number) => boolean + always_been_inactive_CustomCheck?: (v: number) => boolean + balance_avg_CustomCheck?: (v: number) => boolean + balance_median_CustomCheck?: (v: number) => boolean + total_CustomCheck?: (v: number) => boolean +} +export const UsersInfoValidate = (o?: UsersInfo, opts: UsersInfoOptions = {}, path: string = 'UsersInfo::root.'): Error | null => { + if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') + if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') + + if (typeof o.total !== 'number') return new Error(`${path}.total: is not a number`) + if (opts.total_CustomCheck && !opts.total_CustomCheck(o.total)) return new Error(`${path}.total: custom check failed`) + + if (typeof o.no_balance !== 'number') return new Error(`${path}.no_balance: is not a number`) + if (opts.no_balance_CustomCheck && !opts.no_balance_CustomCheck(o.no_balance)) return new Error(`${path}.no_balance: custom check failed`) + + if (typeof o.negative_balance !== 'number') return new Error(`${path}.negative_balance: is not a number`) + if (opts.negative_balance_CustomCheck && !opts.negative_balance_CustomCheck(o.negative_balance)) return new Error(`${path}.negative_balance: custom check failed`) + + if (typeof o.always_been_inactive !== 'number') return new Error(`${path}.always_been_inactive: is not a number`) + if (opts.always_been_inactive_CustomCheck && !opts.always_been_inactive_CustomCheck(o.always_been_inactive)) return new Error(`${path}.always_been_inactive: custom check failed`) + + if (typeof o.balance_avg !== 'number') return new Error(`${path}.balance_avg: is not a number`) + if (opts.balance_avg_CustomCheck && !opts.balance_avg_CustomCheck(o.balance_avg)) return new Error(`${path}.balance_avg: custom check failed`) + + if (typeof o.balance_median !== 'number') return new Error(`${path}.balance_median: is not a number`) + if (opts.balance_median_CustomCheck && !opts.balance_median_CustomCheck(o.balance_median)) return new Error(`${path}.balance_median: custom check failed`) + + return null +} + +export type ChannelBalanceEvent = { + block_height: number + channel_id: string + local_balance_sats: number + remote_balance_sats: number +} +export const ChannelBalanceEventOptionalFields: [] = [] +export type ChannelBalanceEventOptions = OptionsBaseMessage & { + checkOptionalsAreSet?: [] + block_height_CustomCheck?: (v: number) => boolean + channel_id_CustomCheck?: (v: string) => boolean + local_balance_sats_CustomCheck?: (v: number) => boolean + remote_balance_sats_CustomCheck?: (v: number) => boolean +} +export const ChannelBalanceEventValidate = (o?: ChannelBalanceEvent, opts: ChannelBalanceEventOptions = {}, path: string = 'ChannelBalanceEvent::root.'): Error | null => { + if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') + if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') + + if (typeof o.local_balance_sats !== 'number') return new Error(`${path}.local_balance_sats: is not a number`) + if (opts.local_balance_sats_CustomCheck && !opts.local_balance_sats_CustomCheck(o.local_balance_sats)) return new Error(`${path}.local_balance_sats: custom check failed`) + + if (typeof o.remote_balance_sats !== 'number') return new Error(`${path}.remote_balance_sats: is not a number`) + if (opts.remote_balance_sats_CustomCheck && !opts.remote_balance_sats_CustomCheck(o.remote_balance_sats)) return new Error(`${path}.remote_balance_sats: custom check failed`) + + if (typeof o.block_height !== 'number') return new Error(`${path}.block_height: is not a number`) + if (opts.block_height_CustomCheck && !opts.block_height_CustomCheck(o.block_height)) return new Error(`${path}.block_height: custom check failed`) + + if (typeof o.channel_id !== 'string') return new Error(`${path}.channel_id: is not a string`) + if (opts.channel_id_CustomCheck && !opts.channel_id_CustomCheck(o.channel_id)) return new Error(`${path}.channel_id: custom check failed`) + + return null +} + +export type ChannelRouting = { + channel_id: string + receive_errors: number + forward_errors_as_output: number + missed_forward_fee_as_output: number + events_number: number + send_errors: number + forward_errors_as_input: number + missed_forward_fee_as_input: number + forward_fee_as_input: number + forward_fee_as_output: number +} +export const ChannelRoutingOptionalFields: [] = [] +export type ChannelRoutingOptions = OptionsBaseMessage & { + checkOptionalsAreSet?: [] + channel_id_CustomCheck?: (v: string) => boolean + receive_errors_CustomCheck?: (v: number) => boolean + forward_errors_as_output_CustomCheck?: (v: number) => boolean + missed_forward_fee_as_output_CustomCheck?: (v: number) => boolean + events_number_CustomCheck?: (v: number) => boolean + send_errors_CustomCheck?: (v: number) => boolean + forward_errors_as_input_CustomCheck?: (v: number) => boolean + missed_forward_fee_as_input_CustomCheck?: (v: number) => boolean + forward_fee_as_input_CustomCheck?: (v: number) => boolean + forward_fee_as_output_CustomCheck?: (v: number) => boolean +} +export const ChannelRoutingValidate = (o?: ChannelRouting, opts: ChannelRoutingOptions = {}, path: string = 'ChannelRouting::root.'): Error | null => { + if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') + if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') + + if (typeof o.send_errors !== 'number') return new Error(`${path}.send_errors: is not a number`) + if (opts.send_errors_CustomCheck && !opts.send_errors_CustomCheck(o.send_errors)) return new Error(`${path}.send_errors: custom check failed`) + + if (typeof o.forward_errors_as_input !== 'number') return new Error(`${path}.forward_errors_as_input: is not a number`) + if (opts.forward_errors_as_input_CustomCheck && !opts.forward_errors_as_input_CustomCheck(o.forward_errors_as_input)) return new Error(`${path}.forward_errors_as_input: custom check failed`) + + if (typeof o.missed_forward_fee_as_input !== 'number') return new Error(`${path}.missed_forward_fee_as_input: is not a number`) + if (opts.missed_forward_fee_as_input_CustomCheck && !opts.missed_forward_fee_as_input_CustomCheck(o.missed_forward_fee_as_input)) return new Error(`${path}.missed_forward_fee_as_input: custom check failed`) + + if (typeof o.forward_fee_as_input !== 'number') return new Error(`${path}.forward_fee_as_input: is not a number`) + if (opts.forward_fee_as_input_CustomCheck && !opts.forward_fee_as_input_CustomCheck(o.forward_fee_as_input)) return new Error(`${path}.forward_fee_as_input: custom check failed`) + + if (typeof o.forward_fee_as_output !== 'number') return new Error(`${path}.forward_fee_as_output: is not a number`) + if (opts.forward_fee_as_output_CustomCheck && !opts.forward_fee_as_output_CustomCheck(o.forward_fee_as_output)) return new Error(`${path}.forward_fee_as_output: custom check failed`) + + if (typeof o.channel_id !== 'string') return new Error(`${path}.channel_id: is not a string`) + if (opts.channel_id_CustomCheck && !opts.channel_id_CustomCheck(o.channel_id)) return new Error(`${path}.channel_id: custom check failed`) + + if (typeof o.receive_errors !== 'number') return new Error(`${path}.receive_errors: is not a number`) + if (opts.receive_errors_CustomCheck && !opts.receive_errors_CustomCheck(o.receive_errors)) return new Error(`${path}.receive_errors: custom check failed`) + + if (typeof o.forward_errors_as_output !== 'number') return new Error(`${path}.forward_errors_as_output: is not a number`) + if (opts.forward_errors_as_output_CustomCheck && !opts.forward_errors_as_output_CustomCheck(o.forward_errors_as_output)) return new Error(`${path}.forward_errors_as_output: custom check failed`) + + if (typeof o.missed_forward_fee_as_output !== 'number') return new Error(`${path}.missed_forward_fee_as_output: is not a number`) + if (opts.missed_forward_fee_as_output_CustomCheck && !opts.missed_forward_fee_as_output_CustomCheck(o.missed_forward_fee_as_output)) return new Error(`${path}.missed_forward_fee_as_output: custom check failed`) + + if (typeof o.events_number !== 'number') return new Error(`${path}.events_number: is not a number`) + if (opts.events_number_CustomCheck && !opts.events_number_CustomCheck(o.events_number)) return new Error(`${path}.events_number: custom check failed`) + + return null +} + +export type SendAppUserToAppPaymentRequest = { + from_user_identifier: string + amount: number +} +export const SendAppUserToAppPaymentRequestOptionalFields: [] = [] +export type SendAppUserToAppPaymentRequestOptions = OptionsBaseMessage & { + checkOptionalsAreSet?: [] + from_user_identifier_CustomCheck?: (v: string) => boolean + amount_CustomCheck?: (v: number) => boolean +} +export const SendAppUserToAppPaymentRequestValidate = (o?: SendAppUserToAppPaymentRequest, opts: SendAppUserToAppPaymentRequestOptions = {}, path: string = 'SendAppUserToAppPaymentRequest::root.'): Error | null => { + if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') + if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') + + if (typeof o.from_user_identifier !== 'string') return new Error(`${path}.from_user_identifier: is not a string`) + if (opts.from_user_identifier_CustomCheck && !opts.from_user_identifier_CustomCheck(o.from_user_identifier)) return new Error(`${path}.from_user_identifier: custom check failed`) + + if (typeof o.amount !== 'number') return new Error(`${path}.amount: is not a number`) + if (opts.amount_CustomCheck && !opts.amount_CustomCheck(o.amount)) return new Error(`${path}.amount: custom check failed`) + + return null +} + +export type SetMockAppBalanceRequest = { + amount: number +} +export const SetMockAppBalanceRequestOptionalFields: [] = [] +export type SetMockAppBalanceRequestOptions = OptionsBaseMessage & { + checkOptionalsAreSet?: [] + amount_CustomCheck?: (v: number) => boolean +} +export const SetMockAppBalanceRequestValidate = (o?: SetMockAppBalanceRequest, opts: SetMockAppBalanceRequestOptions = {}, path: string = 'SetMockAppBalanceRequest::root.'): Error | null => { + if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') + if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') + + if (typeof o.amount !== 'number') return new Error(`${path}.amount: is not a number`) + if (opts.amount_CustomCheck && !opts.amount_CustomCheck(o.amount)) return new Error(`${path}.amount: custom check failed`) + + return null +} + +export type MigrationUpdate = { + closure?: ClosureMigration + relays?: RelaysMigration +} +export type MigrationUpdateOptionalField = 'closure' | 'relays' +export const MigrationUpdateOptionalFields: MigrationUpdateOptionalField[] = ['closure', 'relays'] +export type MigrationUpdateOptions = OptionsBaseMessage & { + checkOptionalsAreSet?: MigrationUpdateOptionalField[] + relays_Options?: RelaysMigrationOptions + closure_Options?: ClosureMigrationOptions +} +export const MigrationUpdateValidate = (o?: MigrationUpdate, opts: MigrationUpdateOptions = {}, path: string = 'MigrationUpdate::root.'): Error | null => { + if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') + if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') + + if (typeof o.closure === 'object' || opts.allOptionalsAreSet || opts.checkOptionalsAreSet?.includes('closure')) { + const closureErr = ClosureMigrationValidate(o.closure, opts.closure_Options, `${path}.closure`) + if (closureErr !== null) return closureErr + } + + + if (typeof o.relays === 'object' || opts.allOptionalsAreSet || opts.checkOptionalsAreSet?.includes('relays')) { + const relaysErr = RelaysMigrationValidate(o.relays, opts.relays_Options, `${path}.relays`) + if (relaysErr !== null) return relaysErr + } + + + return null +} + +export type ClosureMigration = { + closes_at_unix: number +} +export const ClosureMigrationOptionalFields: [] = [] +export type ClosureMigrationOptions = OptionsBaseMessage & { + checkOptionalsAreSet?: [] + closes_at_unix_CustomCheck?: (v: number) => boolean +} +export const ClosureMigrationValidate = (o?: ClosureMigration, opts: ClosureMigrationOptions = {}, path: string = 'ClosureMigration::root.'): Error | null => { + if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') + if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') + + if (typeof o.closes_at_unix !== 'number') return new Error(`${path}.closes_at_unix: is not a number`) + if (opts.closes_at_unix_CustomCheck && !opts.closes_at_unix_CustomCheck(o.closes_at_unix)) return new Error(`${path}.closes_at_unix: custom check failed`) + + return null +} + +export type ClosedChannel = { + channel_id: string + capacity: number + closed_height: number +} +export const ClosedChannelOptionalFields: [] = [] +export type ClosedChannelOptions = OptionsBaseMessage & { + checkOptionalsAreSet?: [] + channel_id_CustomCheck?: (v: string) => boolean + capacity_CustomCheck?: (v: number) => boolean + closed_height_CustomCheck?: (v: number) => boolean +} +export const ClosedChannelValidate = (o?: ClosedChannel, opts: ClosedChannelOptions = {}, path: string = 'ClosedChannel::root.'): Error | null => { + if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') + if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') + + if (typeof o.channel_id !== 'string') return new Error(`${path}.channel_id: is not a string`) + if (opts.channel_id_CustomCheck && !opts.channel_id_CustomCheck(o.channel_id)) return new Error(`${path}.channel_id: custom check failed`) + + if (typeof o.capacity !== 'number') return new Error(`${path}.capacity: is not a number`) + if (opts.capacity_CustomCheck && !opts.capacity_CustomCheck(o.capacity)) return new Error(`${path}.capacity: custom check failed`) + + if (typeof o.closed_height !== 'number') return new Error(`${path}.closed_height: is not a number`) + if (opts.closed_height_CustomCheck && !opts.closed_height_CustomCheck(o.closed_height)) return new Error(`${path}.closed_height: custom check failed`) + + return null +} + +export type Application = { + npub: string + name: string + id: string + balance: number +} +export const ApplicationOptionalFields: [] = [] +export type ApplicationOptions = OptionsBaseMessage & { + checkOptionalsAreSet?: [] + balance_CustomCheck?: (v: number) => boolean + npub_CustomCheck?: (v: string) => boolean + name_CustomCheck?: (v: string) => boolean + id_CustomCheck?: (v: string) => boolean +} +export const ApplicationValidate = (o?: Application, opts: ApplicationOptions = {}, path: string = 'Application::root.'): Error | null => { + if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') + if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') + + if (typeof o.name !== 'string') return new Error(`${path}.name: is not a string`) + if (opts.name_CustomCheck && !opts.name_CustomCheck(o.name)) return new Error(`${path}.name: custom check failed`) + + if (typeof o.id !== 'string') return new Error(`${path}.id: is not a string`) + if (opts.id_CustomCheck && !opts.id_CustomCheck(o.id)) return new Error(`${path}.id: custom check failed`) + + if (typeof o.balance !== 'number') return new Error(`${path}.balance: is not a number`) + if (opts.balance_CustomCheck && !opts.balance_CustomCheck(o.balance)) return new Error(`${path}.balance: custom check failed`) + + if (typeof o.npub !== 'string') return new Error(`${path}.npub: is not a string`) + if (opts.npub_CustomCheck && !opts.npub_CustomCheck(o.npub)) return new Error(`${path}.npub: custom check failed`) + + return null +} + +export type AddAppUserRequest = { + identifier: string + fail_if_exists: boolean + balance: number +} +export const AddAppUserRequestOptionalFields: [] = [] +export type AddAppUserRequestOptions = OptionsBaseMessage & { + checkOptionalsAreSet?: [] + fail_if_exists_CustomCheck?: (v: boolean) => boolean + balance_CustomCheck?: (v: number) => boolean + identifier_CustomCheck?: (v: string) => boolean +} +export const AddAppUserRequestValidate = (o?: AddAppUserRequest, opts: AddAppUserRequestOptions = {}, path: string = 'AddAppUserRequest::root.'): Error | null => { + if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') + if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') + + if (typeof o.identifier !== 'string') return new Error(`${path}.identifier: is not a string`) + if (opts.identifier_CustomCheck && !opts.identifier_CustomCheck(o.identifier)) return new Error(`${path}.identifier: custom check failed`) + + if (typeof o.fail_if_exists !== 'boolean') return new Error(`${path}.fail_if_exists: is not a boolean`) + if (opts.fail_if_exists_CustomCheck && !opts.fail_if_exists_CustomCheck(o.fail_if_exists)) return new Error(`${path}.fail_if_exists: custom check failed`) + + if (typeof o.balance !== 'number') return new Error(`${path}.balance: is not a number`) + if (opts.balance_CustomCheck && !opts.balance_CustomCheck(o.balance)) return new Error(`${path}.balance: custom check failed`) + + return null +} + +export type SetMockAppUserBalanceRequest = { + user_identifier: string + amount: number +} +export const SetMockAppUserBalanceRequestOptionalFields: [] = [] +export type SetMockAppUserBalanceRequestOptions = OptionsBaseMessage & { + checkOptionalsAreSet?: [] + user_identifier_CustomCheck?: (v: string) => boolean + amount_CustomCheck?: (v: number) => boolean +} +export const SetMockAppUserBalanceRequestValidate = (o?: SetMockAppUserBalanceRequest, opts: SetMockAppUserBalanceRequestOptions = {}, path: string = 'SetMockAppUserBalanceRequest::root.'): Error | null => { + if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') + if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') + + if (typeof o.amount !== 'number') return new Error(`${path}.amount: is not a number`) + if (opts.amount_CustomCheck && !opts.amount_CustomCheck(o.amount)) return new Error(`${path}.amount: custom check failed`) + + if (typeof o.user_identifier !== 'string') return new Error(`${path}.user_identifier: is not a string`) + if (opts.user_identifier_CustomCheck && !opts.user_identifier_CustomCheck(o.user_identifier)) return new Error(`${path}.user_identifier: custom check failed`) + + return null +} + +export type PayAddressResponse = { + network_fee: number + txId: string + operation_id: string + service_fee: number +} +export const PayAddressResponseOptionalFields: [] = [] +export type PayAddressResponseOptions = OptionsBaseMessage & { + checkOptionalsAreSet?: [] + txId_CustomCheck?: (v: string) => boolean + operation_id_CustomCheck?: (v: string) => boolean + service_fee_CustomCheck?: (v: number) => boolean + network_fee_CustomCheck?: (v: number) => boolean +} +export const PayAddressResponseValidate = (o?: PayAddressResponse, opts: PayAddressResponseOptions = {}, path: string = 'PayAddressResponse::root.'): Error | null => { + if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') + if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') + + if (typeof o.txId !== 'string') return new Error(`${path}.txId: is not a string`) + if (opts.txId_CustomCheck && !opts.txId_CustomCheck(o.txId)) return new Error(`${path}.txId: custom check failed`) + + if (typeof o.operation_id !== 'string') return new Error(`${path}.operation_id: is not a string`) + if (opts.operation_id_CustomCheck && !opts.operation_id_CustomCheck(o.operation_id)) return new Error(`${path}.operation_id: custom check failed`) + + if (typeof o.service_fee !== 'number') return new Error(`${path}.service_fee: is not a number`) + if (opts.service_fee_CustomCheck && !opts.service_fee_CustomCheck(o.service_fee)) return new Error(`${path}.service_fee: custom check failed`) + + if (typeof o.network_fee !== 'number') return new Error(`${path}.network_fee: is not a number`) + if (opts.network_fee_CustomCheck && !opts.network_fee_CustomCheck(o.network_fee)) return new Error(`${path}.network_fee: custom check failed`) + + return null +} + +export type NewInvoiceResponse = { + invoice: string +} +export const NewInvoiceResponseOptionalFields: [] = [] +export type NewInvoiceResponseOptions = OptionsBaseMessage & { + checkOptionalsAreSet?: [] + invoice_CustomCheck?: (v: string) => boolean +} +export const NewInvoiceResponseValidate = (o?: NewInvoiceResponse, opts: NewInvoiceResponseOptions = {}, path: string = 'NewInvoiceResponse::root.'): Error | null => { + if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') + if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') + + if (typeof o.invoice !== 'string') return new Error(`${path}.invoice: is not a string`) + if (opts.invoice_CustomCheck && !opts.invoice_CustomCheck(o.invoice)) return new Error(`${path}.invoice: custom check failed`) + + return null +} + +export type HttpCreds = { + url: string + token: string +} +export const HttpCredsOptionalFields: [] = [] +export type HttpCredsOptions = OptionsBaseMessage & { + checkOptionalsAreSet?: [] + url_CustomCheck?: (v: string) => boolean + token_CustomCheck?: (v: string) => boolean +} +export const HttpCredsValidate = (o?: HttpCreds, opts: HttpCredsOptions = {}, path: string = 'HttpCreds::root.'): Error | null => { + if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') + if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') + + if (typeof o.url !== 'string') return new Error(`${path}.url: is not a string`) + if (opts.url_CustomCheck && !opts.url_CustomCheck(o.url)) return new Error(`${path}.url: custom check failed`) + + if (typeof o.token !== 'string') return new Error(`${path}.token: is not a string`) + if (opts.token_CustomCheck && !opts.token_CustomCheck(o.token)) return new Error(`${path}.token: custom check failed`) + + return null +} + +export type OpenChannel = { + lifetime: number + local_balance: number + remote_balance: number + channel_id: string + capacity: number + active: boolean +} +export const OpenChannelOptionalFields: [] = [] +export type OpenChannelOptions = OptionsBaseMessage & { + checkOptionalsAreSet?: [] + remote_balance_CustomCheck?: (v: number) => boolean + channel_id_CustomCheck?: (v: string) => boolean + capacity_CustomCheck?: (v: number) => boolean + active_CustomCheck?: (v: boolean) => boolean + lifetime_CustomCheck?: (v: number) => boolean + local_balance_CustomCheck?: (v: number) => boolean +} +export const OpenChannelValidate = (o?: OpenChannel, opts: OpenChannelOptions = {}, path: string = 'OpenChannel::root.'): Error | null => { + if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') + if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') + + if (typeof o.channel_id !== 'string') return new Error(`${path}.channel_id: is not a string`) + if (opts.channel_id_CustomCheck && !opts.channel_id_CustomCheck(o.channel_id)) return new Error(`${path}.channel_id: custom check failed`) + + if (typeof o.capacity !== 'number') return new Error(`${path}.capacity: is not a number`) + if (opts.capacity_CustomCheck && !opts.capacity_CustomCheck(o.capacity)) return new Error(`${path}.capacity: custom check failed`) + + if (typeof o.active !== 'boolean') return new Error(`${path}.active: is not a boolean`) + if (opts.active_CustomCheck && !opts.active_CustomCheck(o.active)) return new Error(`${path}.active: custom check failed`) + + if (typeof o.lifetime !== 'number') return new Error(`${path}.lifetime: is not a number`) + if (opts.lifetime_CustomCheck && !opts.lifetime_CustomCheck(o.lifetime)) return new Error(`${path}.lifetime: custom check failed`) + + if (typeof o.local_balance !== 'number') return new Error(`${path}.local_balance: is not a number`) + if (opts.local_balance_CustomCheck && !opts.local_balance_CustomCheck(o.local_balance)) return new Error(`${path}.local_balance: custom check failed`) + + if (typeof o.remote_balance !== 'number') return new Error(`${path}.remote_balance: is not a number`) + if (opts.remote_balance_CustomCheck && !opts.remote_balance_CustomCheck(o.remote_balance)) return new Error(`${path}.remote_balance: custom check failed`) + + return null +} + +export type SetMockInvoiceAsPaidRequest = { + invoice: string + amount: number +} +export const SetMockInvoiceAsPaidRequestOptionalFields: [] = [] +export type SetMockInvoiceAsPaidRequestOptions = OptionsBaseMessage & { + checkOptionalsAreSet?: [] + invoice_CustomCheck?: (v: string) => boolean + amount_CustomCheck?: (v: number) => boolean +} +export const SetMockInvoiceAsPaidRequestValidate = (o?: SetMockInvoiceAsPaidRequest, opts: SetMockInvoiceAsPaidRequestOptions = {}, path: string = 'SetMockInvoiceAsPaidRequest::root.'): Error | null => { + if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') + if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') + + if (typeof o.amount !== 'number') return new Error(`${path}.amount: is not a number`) + if (opts.amount_CustomCheck && !opts.amount_CustomCheck(o.amount)) return new Error(`${path}.amount: custom check failed`) + + if (typeof o.invoice !== 'string') return new Error(`${path}.invoice: is not a string`) + if (opts.invoice_CustomCheck && !opts.invoice_CustomCheck(o.invoice)) return new Error(`${path}.invoice: custom check failed`) + + return null +} + +export type AddAppUserInvoiceRequest = { + receiver_identifier: string + payer_identifier: string + http_callback_url: string + invoice_req: NewInvoiceRequest +} +export const AddAppUserInvoiceRequestOptionalFields: [] = [] +export type AddAppUserInvoiceRequestOptions = OptionsBaseMessage & { + checkOptionalsAreSet?: [] + receiver_identifier_CustomCheck?: (v: string) => boolean + payer_identifier_CustomCheck?: (v: string) => boolean + http_callback_url_CustomCheck?: (v: string) => boolean + invoice_req_Options?: NewInvoiceRequestOptions +} +export const AddAppUserInvoiceRequestValidate = (o?: AddAppUserInvoiceRequest, opts: AddAppUserInvoiceRequestOptions = {}, path: string = 'AddAppUserInvoiceRequest::root.'): Error | null => { + if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') + if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') + + if (typeof o.receiver_identifier !== 'string') return new Error(`${path}.receiver_identifier: is not a string`) + if (opts.receiver_identifier_CustomCheck && !opts.receiver_identifier_CustomCheck(o.receiver_identifier)) return new Error(`${path}.receiver_identifier: custom check failed`) + + if (typeof o.payer_identifier !== 'string') return new Error(`${path}.payer_identifier: is not a string`) + if (opts.payer_identifier_CustomCheck && !opts.payer_identifier_CustomCheck(o.payer_identifier)) return new Error(`${path}.payer_identifier: custom check failed`) + + if (typeof o.http_callback_url !== 'string') return new Error(`${path}.http_callback_url: is not a string`) + if (opts.http_callback_url_CustomCheck && !opts.http_callback_url_CustomCheck(o.http_callback_url)) return new Error(`${path}.http_callback_url: custom check failed`) + + const invoice_reqErr = NewInvoiceRequestValidate(o.invoice_req, opts.invoice_req_Options, `${path}.invoice_req`) + if (invoice_reqErr !== null) return invoice_reqErr + + + return null +} + +export type DecodeInvoiceResponse = { + amount: number +} +export const DecodeInvoiceResponseOptionalFields: [] = [] +export type DecodeInvoiceResponseOptions = OptionsBaseMessage & { + checkOptionalsAreSet?: [] + amount_CustomCheck?: (v: number) => boolean +} +export const DecodeInvoiceResponseValidate = (o?: DecodeInvoiceResponse, opts: DecodeInvoiceResponseOptions = {}, path: string = 'DecodeInvoiceResponse::root.'): Error | null => { + if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') + if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') + + if (typeof o.amount !== 'number') return new Error(`${path}.amount: is not a number`) + if (opts.amount_CustomCheck && !opts.amount_CustomCheck(o.amount)) return new Error(`${path}.amount: custom check failed`) + + return null +} + +export type OpenChannelResponse = { + channelId: string +} +export const OpenChannelResponseOptionalFields: [] = [] +export type OpenChannelResponseOptions = OptionsBaseMessage & { + checkOptionalsAreSet?: [] + channelId_CustomCheck?: (v: string) => boolean +} +export const OpenChannelResponseValidate = (o?: OpenChannelResponse, opts: OpenChannelResponseOptions = {}, path: string = 'OpenChannelResponse::root.'): Error | null => { + if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') + if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') + + if (typeof o.channelId !== 'string') return new Error(`${path}.channelId: is not a string`) + if (opts.channelId_CustomCheck && !opts.channelId_CustomCheck(o.channelId)) return new Error(`${path}.channelId: custom check failed`) + + return null +} + +export type RelaysMigration = { + relays: string[] +} +export const RelaysMigrationOptionalFields: [] = [] +export type RelaysMigrationOptions = OptionsBaseMessage & { + checkOptionalsAreSet?: [] + relays_CustomCheck?: (v: string[]) => boolean +} +export const RelaysMigrationValidate = (o?: RelaysMigration, opts: RelaysMigrationOptions = {}, path: string = 'RelaysMigration::root.'): Error | null => { + if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') + if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') + + if (!Array.isArray(o.relays)) return new Error(`${path}.relays: is not an array`) + for (let index = 0; index < o.relays.length; index++) { + if (typeof o.relays[index] !== 'string') return new Error(`${path}.relays[${index}]: is not a string`) + } + if (opts.relays_CustomCheck && !opts.relays_CustomCheck(o.relays)) return new Error(`${path}.relays: custom check failed`) + + return null +} + +export type RequestNPubLinkingTokenRequest = { + user_identifier: string +} +export const RequestNPubLinkingTokenRequestOptionalFields: [] = [] +export type RequestNPubLinkingTokenRequestOptions = OptionsBaseMessage & { + checkOptionalsAreSet?: [] + user_identifier_CustomCheck?: (v: string) => boolean +} +export const RequestNPubLinkingTokenRequestValidate = (o?: RequestNPubLinkingTokenRequest, opts: RequestNPubLinkingTokenRequestOptions = {}, path: string = 'RequestNPubLinkingTokenRequest::root.'): Error | null => { + if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') + if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') + + if (typeof o.user_identifier !== 'string') return new Error(`${path}.user_identifier: is not a string`) + if (opts.user_identifier_CustomCheck && !opts.user_identifier_CustomCheck(o.user_identifier)) return new Error(`${path}.user_identifier: custom check failed`) + + return null +} + +export type LinkNPubThroughTokenRequest = { + token: string + nostr_pub: string +} +export const LinkNPubThroughTokenRequestOptionalFields: [] = [] +export type LinkNPubThroughTokenRequestOptions = OptionsBaseMessage & { + checkOptionalsAreSet?: [] + nostr_pub_CustomCheck?: (v: string) => boolean + token_CustomCheck?: (v: string) => boolean +} +export const LinkNPubThroughTokenRequestValidate = (o?: LinkNPubThroughTokenRequest, opts: LinkNPubThroughTokenRequestOptions = {}, path: string = 'LinkNPubThroughTokenRequest::root.'): Error | null => { + if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') + if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') + + if (typeof o.token !== 'string') return new Error(`${path}.token: is not a string`) + if (opts.token_CustomCheck && !opts.token_CustomCheck(o.token)) return new Error(`${path}.token: custom check failed`) + + if (typeof o.nostr_pub !== 'string') return new Error(`${path}.nostr_pub: is not a string`) + if (opts.nostr_pub_CustomCheck && !opts.nostr_pub_CustomCheck(o.nostr_pub)) return new Error(`${path}.nostr_pub: custom check failed`) + + return null +} + +export type LndMetrics = { + nodes: LndNodeMetrics[] +} +export const LndMetricsOptionalFields: [] = [] +export type LndMetricsOptions = OptionsBaseMessage & { + checkOptionalsAreSet?: [] + nodes_ItemOptions?: LndNodeMetricsOptions + nodes_CustomCheck?: (v: LndNodeMetrics[]) => boolean +} +export const LndMetricsValidate = (o?: LndMetrics, opts: LndMetricsOptions = {}, path: string = 'LndMetrics::root.'): Error | null => { + if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') + if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') + + if (!Array.isArray(o.nodes)) return new Error(`${path}.nodes: is not an array`) + for (let index = 0; index < o.nodes.length; index++) { + const nodesErr = LndNodeMetricsValidate(o.nodes[index], opts.nodes_ItemOptions, `${path}.nodes[${index}]`) + if (nodesErr !== null) return nodesErr + } + if (opts.nodes_CustomCheck && !opts.nodes_CustomCheck(o.nodes)) return new Error(`${path}.nodes: custom check failed`) + + return null +} + +export type AppUser = { + info: UserInfo + max_withdrawable: number + identifier: string +} +export const AppUserOptionalFields: [] = [] +export type AppUserOptions = OptionsBaseMessage & { + checkOptionalsAreSet?: [] + identifier_CustomCheck?: (v: string) => boolean + info_Options?: UserInfoOptions + max_withdrawable_CustomCheck?: (v: number) => boolean +} +export const AppUserValidate = (o?: AppUser, opts: AppUserOptions = {}, path: string = 'AppUser::root.'): Error | null => { + if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') + if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') + + if (typeof o.identifier !== 'string') return new Error(`${path}.identifier: is not a string`) + if (opts.identifier_CustomCheck && !opts.identifier_CustomCheck(o.identifier)) return new Error(`${path}.identifier: custom check failed`) + + const infoErr = UserInfoValidate(o.info, opts.info_Options, `${path}.info`) + if (infoErr !== null) return infoErr + + + if (typeof o.max_withdrawable !== 'number') return new Error(`${path}.max_withdrawable: is not a number`) + if (opts.max_withdrawable_CustomCheck && !opts.max_withdrawable_CustomCheck(o.max_withdrawable)) return new Error(`${path}.max_withdrawable: custom check failed`) + + return null +} + +export type AddAppInvoiceRequest = { + payer_identifier: string + http_callback_url: string + invoice_req: NewInvoiceRequest +} +export const AddAppInvoiceRequestOptionalFields: [] = [] +export type AddAppInvoiceRequestOptions = OptionsBaseMessage & { + checkOptionalsAreSet?: [] + payer_identifier_CustomCheck?: (v: string) => boolean + http_callback_url_CustomCheck?: (v: string) => boolean + invoice_req_Options?: NewInvoiceRequestOptions +} +export const AddAppInvoiceRequestValidate = (o?: AddAppInvoiceRequest, opts: AddAppInvoiceRequestOptions = {}, path: string = 'AddAppInvoiceRequest::root.'): Error | null => { + if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') + if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') + + if (typeof o.payer_identifier !== 'string') return new Error(`${path}.payer_identifier: is not a string`) + if (opts.payer_identifier_CustomCheck && !opts.payer_identifier_CustomCheck(o.payer_identifier)) return new Error(`${path}.payer_identifier: custom check failed`) + + if (typeof o.http_callback_url !== 'string') return new Error(`${path}.http_callback_url: is not a string`) + if (opts.http_callback_url_CustomCheck && !opts.http_callback_url_CustomCheck(o.http_callback_url)) return new Error(`${path}.http_callback_url: custom check failed`) + + const invoice_reqErr = NewInvoiceRequestValidate(o.invoice_req, opts.invoice_req_Options, `${path}.invoice_req`) + if (invoice_reqErr !== null) return invoice_reqErr + + + return null +} + +export type UserOperations = { + toIndex: number + operations: UserOperation[] + fromIndex: number +} +export const UserOperationsOptionalFields: [] = [] +export type UserOperationsOptions = OptionsBaseMessage & { + checkOptionalsAreSet?: [] + fromIndex_CustomCheck?: (v: number) => boolean + toIndex_CustomCheck?: (v: number) => boolean + operations_ItemOptions?: UserOperationOptions + operations_CustomCheck?: (v: UserOperation[]) => boolean +} +export const UserOperationsValidate = (o?: UserOperations, opts: UserOperationsOptions = {}, path: string = 'UserOperations::root.'): Error | null => { + if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') + if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') + + if (typeof o.fromIndex !== 'number') return new Error(`${path}.fromIndex: is not a number`) + if (opts.fromIndex_CustomCheck && !opts.fromIndex_CustomCheck(o.fromIndex)) return new Error(`${path}.fromIndex: custom check failed`) + + if (typeof o.toIndex !== 'number') return new Error(`${path}.toIndex: is not a number`) + if (opts.toIndex_CustomCheck && !opts.toIndex_CustomCheck(o.toIndex)) return new Error(`${path}.toIndex: custom check failed`) + + if (!Array.isArray(o.operations)) return new Error(`${path}.operations: is not an array`) + for (let index = 0; index < o.operations.length; index++) { + const operationsErr = UserOperationValidate(o.operations[index], opts.operations_ItemOptions, `${path}.operations[${index}]`) + if (operationsErr !== null) return operationsErr + } + if (opts.operations_CustomCheck && !opts.operations_CustomCheck(o.operations)) return new Error(`${path}.operations: custom check failed`) + + return null +} + +export type BanUserRequest = { + user_id: string +} +export const BanUserRequestOptionalFields: [] = [] +export type BanUserRequestOptions = OptionsBaseMessage & { + checkOptionalsAreSet?: [] + user_id_CustomCheck?: (v: string) => boolean +} +export const BanUserRequestValidate = (o?: BanUserRequest, opts: BanUserRequestOptions = {}, path: string = 'BanUserRequest::root.'): Error | null => { + if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') + if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') + + if (typeof o.user_id !== 'string') return new Error(`${path}.user_id: is not a string`) + if (opts.user_id_CustomCheck && !opts.user_id_CustomCheck(o.user_id)) return new Error(`${path}.user_id: custom check failed`) + + return null +} + +export type NewAddressRequest = { + addressType: AddressType +} +export const NewAddressRequestOptionalFields: [] = [] +export type NewAddressRequestOptions = OptionsBaseMessage & { + checkOptionalsAreSet?: [] + addressType_CustomCheck?: (v: AddressType) => boolean +} +export const NewAddressRequestValidate = (o?: NewAddressRequest, opts: NewAddressRequestOptions = {}, path: string = 'NewAddressRequest::root.'): Error | null => { + if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') + if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') + + if (!enumCheckAddressType(o.addressType)) return new Error(`${path}.addressType: is not a valid AddressType`) + if (opts.addressType_CustomCheck && !opts.addressType_CustomCheck(o.addressType)) return new Error(`${path}.addressType: custom check failed`) + + return null +} + +export type DecodeInvoiceRequest = { + invoice: string +} +export const DecodeInvoiceRequestOptionalFields: [] = [] +export type DecodeInvoiceRequestOptions = OptionsBaseMessage & { + checkOptionalsAreSet?: [] + invoice_CustomCheck?: (v: string) => boolean +} +export const DecodeInvoiceRequestValidate = (o?: DecodeInvoiceRequest, opts: DecodeInvoiceRequestOptions = {}, path: string = 'DecodeInvoiceRequest::root.'): Error | null => { + if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') + if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') + + if (typeof o.invoice !== 'string') return new Error(`${path}.invoice: is not a string`) + if (opts.invoice_CustomCheck && !opts.invoice_CustomCheck(o.invoice)) return new Error(`${path}.invoice: custom check failed`) + + return null +} + +export type LnurlWithdrawInfoResponse = { + balanceCheck: string + payLink: string + tag: string + callback: string + k1: string + defaultDescription: string + minWithdrawable: number + maxWithdrawable: number +} +export const LnurlWithdrawInfoResponseOptionalFields: [] = [] +export type LnurlWithdrawInfoResponseOptions = OptionsBaseMessage & { + checkOptionalsAreSet?: [] + maxWithdrawable_CustomCheck?: (v: number) => boolean + balanceCheck_CustomCheck?: (v: string) => boolean + payLink_CustomCheck?: (v: string) => boolean + tag_CustomCheck?: (v: string) => boolean + callback_CustomCheck?: (v: string) => boolean + k1_CustomCheck?: (v: string) => boolean + defaultDescription_CustomCheck?: (v: string) => boolean + minWithdrawable_CustomCheck?: (v: number) => boolean +} +export const LnurlWithdrawInfoResponseValidate = (o?: LnurlWithdrawInfoResponse, opts: LnurlWithdrawInfoResponseOptions = {}, path: string = 'LnurlWithdrawInfoResponse::root.'): Error | null => { + if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') + if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') + + if (typeof o.k1 !== 'string') return new Error(`${path}.k1: is not a string`) + if (opts.k1_CustomCheck && !opts.k1_CustomCheck(o.k1)) return new Error(`${path}.k1: custom check failed`) + + if (typeof o.defaultDescription !== 'string') return new Error(`${path}.defaultDescription: is not a string`) + if (opts.defaultDescription_CustomCheck && !opts.defaultDescription_CustomCheck(o.defaultDescription)) return new Error(`${path}.defaultDescription: custom check failed`) + + if (typeof o.minWithdrawable !== 'number') return new Error(`${path}.minWithdrawable: is not a number`) + if (opts.minWithdrawable_CustomCheck && !opts.minWithdrawable_CustomCheck(o.minWithdrawable)) return new Error(`${path}.minWithdrawable: custom check failed`) + + if (typeof o.maxWithdrawable !== 'number') return new Error(`${path}.maxWithdrawable: is not a number`) + if (opts.maxWithdrawable_CustomCheck && !opts.maxWithdrawable_CustomCheck(o.maxWithdrawable)) return new Error(`${path}.maxWithdrawable: custom check failed`) + + if (typeof o.balanceCheck !== 'string') return new Error(`${path}.balanceCheck: is not a string`) + if (opts.balanceCheck_CustomCheck && !opts.balanceCheck_CustomCheck(o.balanceCheck)) return new Error(`${path}.balanceCheck: custom check failed`) + + if (typeof o.payLink !== 'string') return new Error(`${path}.payLink: is not a string`) + if (opts.payLink_CustomCheck && !opts.payLink_CustomCheck(o.payLink)) return new Error(`${path}.payLink: custom check failed`) + + if (typeof o.tag !== 'string') return new Error(`${path}.tag: is not a string`) + if (opts.tag_CustomCheck && !opts.tag_CustomCheck(o.tag)) return new Error(`${path}.tag: custom check failed`) + + if (typeof o.callback !== 'string') return new Error(`${path}.callback: is not a string`) + if (opts.callback_CustomCheck && !opts.callback_CustomCheck(o.callback)) return new Error(`${path}.callback: custom check failed`) + + return null +} + +export type GetUserOperationsRequest = { + latestIncomingUserToUserPayment: number + latestOutgoingUserToUserPayment: number + max_size: number + latestIncomingInvoice: number + latestOutgoingInvoice: number + latestIncomingTx: number + latestOutgoingTx: number +} +export const GetUserOperationsRequestOptionalFields: [] = [] +export type GetUserOperationsRequestOptions = OptionsBaseMessage & { + checkOptionalsAreSet?: [] + latestIncomingUserToUserPayment_CustomCheck?: (v: number) => boolean + latestOutgoingUserToUserPayment_CustomCheck?: (v: number) => boolean + max_size_CustomCheck?: (v: number) => boolean + latestIncomingInvoice_CustomCheck?: (v: number) => boolean + latestOutgoingInvoice_CustomCheck?: (v: number) => boolean + latestIncomingTx_CustomCheck?: (v: number) => boolean + latestOutgoingTx_CustomCheck?: (v: number) => boolean +} +export const GetUserOperationsRequestValidate = (o?: GetUserOperationsRequest, opts: GetUserOperationsRequestOptions = {}, path: string = 'GetUserOperationsRequest::root.'): Error | null => { + if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') + if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') + + if (typeof o.max_size !== 'number') return new Error(`${path}.max_size: is not a number`) + if (opts.max_size_CustomCheck && !opts.max_size_CustomCheck(o.max_size)) return new Error(`${path}.max_size: custom check failed`) + + if (typeof o.latestIncomingInvoice !== 'number') return new Error(`${path}.latestIncomingInvoice: is not a number`) + if (opts.latestIncomingInvoice_CustomCheck && !opts.latestIncomingInvoice_CustomCheck(o.latestIncomingInvoice)) return new Error(`${path}.latestIncomingInvoice: custom check failed`) + + if (typeof o.latestOutgoingInvoice !== 'number') return new Error(`${path}.latestOutgoingInvoice: is not a number`) + if (opts.latestOutgoingInvoice_CustomCheck && !opts.latestOutgoingInvoice_CustomCheck(o.latestOutgoingInvoice)) return new Error(`${path}.latestOutgoingInvoice: custom check failed`) + + if (typeof o.latestIncomingTx !== 'number') return new Error(`${path}.latestIncomingTx: is not a number`) + if (opts.latestIncomingTx_CustomCheck && !opts.latestIncomingTx_CustomCheck(o.latestIncomingTx)) return new Error(`${path}.latestIncomingTx: custom check failed`) + + if (typeof o.latestOutgoingTx !== 'number') return new Error(`${path}.latestOutgoingTx: is not a number`) + if (opts.latestOutgoingTx_CustomCheck && !opts.latestOutgoingTx_CustomCheck(o.latestOutgoingTx)) return new Error(`${path}.latestOutgoingTx: custom check failed`) + + if (typeof o.latestIncomingUserToUserPayment !== 'number') return new Error(`${path}.latestIncomingUserToUserPayment: is not a number`) + if (opts.latestIncomingUserToUserPayment_CustomCheck && !opts.latestIncomingUserToUserPayment_CustomCheck(o.latestIncomingUserToUserPayment)) return new Error(`${path}.latestIncomingUserToUserPayment: custom check failed`) + + if (typeof o.latestOutgoingUserToUserPayment !== 'number') return new Error(`${path}.latestOutgoingUserToUserPayment: is not a number`) + if (opts.latestOutgoingUserToUserPayment_CustomCheck && !opts.latestOutgoingUserToUserPayment_CustomCheck(o.latestOutgoingUserToUserPayment)) return new Error(`${path}.latestOutgoingUserToUserPayment: custom check failed`) + + return null +} + diff --git a/proto/lnd/walletunlocker.client.ts b/proto/lnd/walletunlocker.client.ts new file mode 100644 index 00000000..a3e3d7da --- /dev/null +++ b/proto/lnd/walletunlocker.client.ts @@ -0,0 +1,180 @@ +// @generated by protobuf-ts 2.8.1 +// @generated from protobuf file "walletunlocker.proto" (package "lnrpc", syntax proto3) +// tslint:disable +import type { RpcTransport } from "@protobuf-ts/runtime-rpc"; +import type { ServiceInfo } from "@protobuf-ts/runtime-rpc"; +import { WalletUnlocker } from "./walletunlocker.js"; +import type { ChangePasswordResponse } from "./walletunlocker.js"; +import type { ChangePasswordRequest } from "./walletunlocker.js"; +import type { UnlockWalletResponse } from "./walletunlocker.js"; +import type { UnlockWalletRequest } from "./walletunlocker.js"; +import type { InitWalletResponse } from "./walletunlocker.js"; +import type { InitWalletRequest } from "./walletunlocker.js"; +import { stackIntercept } from "@protobuf-ts/runtime-rpc"; +import type { GenSeedResponse } from "./walletunlocker.js"; +import type { GenSeedRequest } from "./walletunlocker.js"; +import type { UnaryCall } from "@protobuf-ts/runtime-rpc"; +import type { RpcOptions } from "@protobuf-ts/runtime-rpc"; +// +// Comments in this file will be directly parsed into the API +// Documentation as descriptions of the associated method, message, or field. +// These descriptions should go right above the definition of the object, and +// can be in either block or // comment format. +// +// An RPC method can be matched to an lncli command by placing a line in the +// beginning of the description in exactly the following format: +// lncli: `methodname` +// +// Failure to specify the exact name of the command will cause documentation +// generation to fail. +// +// More information on how exactly the gRPC documentation is generated from +// this proto file can be found here: +// https://github.com/lightninglabs/lightning-api + +/** + * WalletUnlocker is a service that is used to set up a wallet password for + * lnd at first startup, and unlock a previously set up wallet. + * + * @generated from protobuf service lnrpc.WalletUnlocker + */ +export interface IWalletUnlockerClient { + /** + * + * GenSeed is the first method that should be used to instantiate a new lnd + * instance. This method allows a caller to generate a new aezeed cipher seed + * given an optional passphrase. If provided, the passphrase will be necessary + * to decrypt the cipherseed to expose the internal wallet seed. + * + * Once the cipherseed is obtained and verified by the user, the InitWallet + * method should be used to commit the newly generated seed, and create the + * wallet. + * + * @generated from protobuf rpc: GenSeed(lnrpc.GenSeedRequest) returns (lnrpc.GenSeedResponse); + */ + genSeed(input: GenSeedRequest, options?: RpcOptions): UnaryCall; + /** + * + * InitWallet is used when lnd is starting up for the first time to fully + * initialize the daemon and its internal wallet. At the very least a wallet + * password must be provided. This will be used to encrypt sensitive material + * on disk. + * + * In the case of a recovery scenario, the user can also specify their aezeed + * mnemonic and passphrase. If set, then the daemon will use this prior state + * to initialize its internal wallet. + * + * Alternatively, this can be used along with the GenSeed RPC to obtain a + * seed, then present it to the user. Once it has been verified by the user, + * the seed can be fed into this RPC in order to commit the new wallet. + * + * @generated from protobuf rpc: InitWallet(lnrpc.InitWalletRequest) returns (lnrpc.InitWalletResponse); + */ + initWallet(input: InitWalletRequest, options?: RpcOptions): UnaryCall; + /** + * lncli: `unlock` + * UnlockWallet is used at startup of lnd to provide a password to unlock + * the wallet database. + * + * @generated from protobuf rpc: UnlockWallet(lnrpc.UnlockWalletRequest) returns (lnrpc.UnlockWalletResponse); + */ + unlockWallet(input: UnlockWalletRequest, options?: RpcOptions): UnaryCall; + /** + * lncli: `changepassword` + * ChangePassword changes the password of the encrypted wallet. This will + * automatically unlock the wallet database if successful. + * + * @generated from protobuf rpc: ChangePassword(lnrpc.ChangePasswordRequest) returns (lnrpc.ChangePasswordResponse); + */ + changePassword(input: ChangePasswordRequest, options?: RpcOptions): UnaryCall; +} +// +// Comments in this file will be directly parsed into the API +// Documentation as descriptions of the associated method, message, or field. +// These descriptions should go right above the definition of the object, and +// can be in either block or // comment format. +// +// An RPC method can be matched to an lncli command by placing a line in the +// beginning of the description in exactly the following format: +// lncli: `methodname` +// +// Failure to specify the exact name of the command will cause documentation +// generation to fail. +// +// More information on how exactly the gRPC documentation is generated from +// this proto file can be found here: +// https://github.com/lightninglabs/lightning-api + +/** + * WalletUnlocker is a service that is used to set up a wallet password for + * lnd at first startup, and unlock a previously set up wallet. + * + * @generated from protobuf service lnrpc.WalletUnlocker + */ +export class WalletUnlockerClient implements IWalletUnlockerClient, ServiceInfo { + typeName = WalletUnlocker.typeName; + methods = WalletUnlocker.methods; + options = WalletUnlocker.options; + constructor(private readonly _transport: RpcTransport) { + } + /** + * + * GenSeed is the first method that should be used to instantiate a new lnd + * instance. This method allows a caller to generate a new aezeed cipher seed + * given an optional passphrase. If provided, the passphrase will be necessary + * to decrypt the cipherseed to expose the internal wallet seed. + * + * Once the cipherseed is obtained and verified by the user, the InitWallet + * method should be used to commit the newly generated seed, and create the + * wallet. + * + * @generated from protobuf rpc: GenSeed(lnrpc.GenSeedRequest) returns (lnrpc.GenSeedResponse); + */ + genSeed(input: GenSeedRequest, options?: RpcOptions): UnaryCall { + const method = this.methods[0], opt = this._transport.mergeOptions(options); + return stackIntercept("unary", this._transport, method, opt, input); + } + /** + * + * InitWallet is used when lnd is starting up for the first time to fully + * initialize the daemon and its internal wallet. At the very least a wallet + * password must be provided. This will be used to encrypt sensitive material + * on disk. + * + * In the case of a recovery scenario, the user can also specify their aezeed + * mnemonic and passphrase. If set, then the daemon will use this prior state + * to initialize its internal wallet. + * + * Alternatively, this can be used along with the GenSeed RPC to obtain a + * seed, then present it to the user. Once it has been verified by the user, + * the seed can be fed into this RPC in order to commit the new wallet. + * + * @generated from protobuf rpc: InitWallet(lnrpc.InitWalletRequest) returns (lnrpc.InitWalletResponse); + */ + initWallet(input: InitWalletRequest, options?: RpcOptions): UnaryCall { + const method = this.methods[1], opt = this._transport.mergeOptions(options); + return stackIntercept("unary", this._transport, method, opt, input); + } + /** + * lncli: `unlock` + * UnlockWallet is used at startup of lnd to provide a password to unlock + * the wallet database. + * + * @generated from protobuf rpc: UnlockWallet(lnrpc.UnlockWalletRequest) returns (lnrpc.UnlockWalletResponse); + */ + unlockWallet(input: UnlockWalletRequest, options?: RpcOptions): UnaryCall { + const method = this.methods[2], opt = this._transport.mergeOptions(options); + return stackIntercept("unary", this._transport, method, opt, input); + } + /** + * lncli: `changepassword` + * ChangePassword changes the password of the encrypted wallet. This will + * automatically unlock the wallet database if successful. + * + * @generated from protobuf rpc: ChangePassword(lnrpc.ChangePasswordRequest) returns (lnrpc.ChangePasswordResponse); + */ + changePassword(input: ChangePasswordRequest, options?: RpcOptions): UnaryCall { + const method = this.methods[3], opt = this._transport.mergeOptions(options); + return stackIntercept("unary", this._transport, method, opt, input); + } +} diff --git a/proto/lnd/walletunlocker.ts b/proto/lnd/walletunlocker.ts new file mode 100644 index 00000000..a472c857 --- /dev/null +++ b/proto/lnd/walletunlocker.ts @@ -0,0 +1,991 @@ +// @generated by protobuf-ts 2.8.1 +// @generated from protobuf file "walletunlocker.proto" (package "lnrpc", syntax proto3) +// tslint:disable +import { ServiceType } from "@protobuf-ts/runtime-rpc"; +import type { BinaryWriteOptions } from "@protobuf-ts/runtime"; +import type { IBinaryWriter } from "@protobuf-ts/runtime"; +import { WireType } from "@protobuf-ts/runtime"; +import type { BinaryReadOptions } from "@protobuf-ts/runtime"; +import type { IBinaryReader } from "@protobuf-ts/runtime"; +import { UnknownFieldHandler } from "@protobuf-ts/runtime"; +import type { PartialMessage } from "@protobuf-ts/runtime"; +import { reflectionMergePartial } from "@protobuf-ts/runtime"; +import { MESSAGE_TYPE } from "@protobuf-ts/runtime"; +import { MessageType } from "@protobuf-ts/runtime"; +import { ChanBackupSnapshot } from "./lightning.js"; +/** + * @generated from protobuf message lnrpc.GenSeedRequest + */ +export interface GenSeedRequest { + /** + * + * aezeed_passphrase is an optional user provided passphrase that will be used + * to encrypt the generated aezeed cipher seed. When using REST, this field + * must be encoded as base64. + * + * @generated from protobuf field: bytes aezeed_passphrase = 1; + */ + aezeedPassphrase: Uint8Array; + /** + * + * seed_entropy is an optional 16-bytes generated via CSPRNG. If not + * specified, then a fresh set of randomness will be used to create the seed. + * When using REST, this field must be encoded as base64. + * + * @generated from protobuf field: bytes seed_entropy = 2; + */ + seedEntropy: Uint8Array; +} +/** + * @generated from protobuf message lnrpc.GenSeedResponse + */ +export interface GenSeedResponse { + /** + * + * cipher_seed_mnemonic is a 24-word mnemonic that encodes a prior aezeed + * cipher seed obtained by the user. This field is optional, as if not + * provided, then the daemon will generate a new cipher seed for the user. + * Otherwise, then the daemon will attempt to recover the wallet state linked + * to this cipher seed. + * + * @generated from protobuf field: repeated string cipher_seed_mnemonic = 1; + */ + cipherSeedMnemonic: string[]; + /** + * + * enciphered_seed are the raw aezeed cipher seed bytes. This is the raw + * cipher text before run through our mnemonic encoding scheme. + * + * @generated from protobuf field: bytes enciphered_seed = 2; + */ + encipheredSeed: Uint8Array; +} +/** + * @generated from protobuf message lnrpc.InitWalletRequest + */ +export interface InitWalletRequest { + /** + * + * wallet_password is the passphrase that should be used to encrypt the + * wallet. This MUST be at least 8 chars in length. After creation, this + * password is required to unlock the daemon. When using REST, this field + * must be encoded as base64. + * + * @generated from protobuf field: bytes wallet_password = 1; + */ + walletPassword: Uint8Array; + /** + * + * cipher_seed_mnemonic is a 24-word mnemonic that encodes a prior aezeed + * cipher seed obtained by the user. This may have been generated by the + * GenSeed method, or be an existing seed. + * + * @generated from protobuf field: repeated string cipher_seed_mnemonic = 2; + */ + cipherSeedMnemonic: string[]; + /** + * + * aezeed_passphrase is an optional user provided passphrase that will be used + * to encrypt the generated aezeed cipher seed. When using REST, this field + * must be encoded as base64. + * + * @generated from protobuf field: bytes aezeed_passphrase = 3; + */ + aezeedPassphrase: Uint8Array; + /** + * + * recovery_window is an optional argument specifying the address lookahead + * when restoring a wallet seed. The recovery window applies to each + * individual branch of the BIP44 derivation paths. Supplying a recovery + * window of zero indicates that no addresses should be recovered, such after + * the first initialization of the wallet. + * + * @generated from protobuf field: int32 recovery_window = 4; + */ + recoveryWindow: number; + /** + * + * channel_backups is an optional argument that allows clients to recover the + * settled funds within a set of channels. This should be populated if the + * user was unable to close out all channels and sweep funds before partial or + * total data loss occurred. If specified, then after on-chain recovery of + * funds, lnd begin to carry out the data loss recovery protocol in order to + * recover the funds in each channel from a remote force closed transaction. + * + * @generated from protobuf field: lnrpc.ChanBackupSnapshot channel_backups = 5; + */ + channelBackups?: ChanBackupSnapshot; + /** + * + * stateless_init is an optional argument instructing the daemon NOT to create + * any *.macaroon files in its filesystem. If this parameter is set, then the + * admin macaroon returned in the response MUST be stored by the caller of the + * RPC as otherwise all access to the daemon will be lost! + * + * @generated from protobuf field: bool stateless_init = 6; + */ + statelessInit: boolean; + /** + * + * extended_master_key is an alternative to specifying cipher_seed_mnemonic and + * aezeed_passphrase. Instead of deriving the master root key from the entropy + * of an aezeed cipher seed, the given extended master root key is used + * directly as the wallet's master key. This allows users to import/use a + * master key from another wallet. When doing so, lnd still uses its default + * SegWit only (BIP49/84) derivation paths and funds from custom/non-default + * derivation paths will not automatically appear in the on-chain wallet. Using + * an 'xprv' instead of an aezeed also has the disadvantage that the wallet's + * birthday is not known as that is an information that's only encoded in the + * aezeed, not the xprv. Therefore a birthday needs to be specified in + * extended_master_key_birthday_timestamp or a "safe" default value will be + * used. + * + * @generated from protobuf field: string extended_master_key = 7; + */ + extendedMasterKey: string; + /** + * + * extended_master_key_birthday_timestamp is the optional unix timestamp in + * seconds to use as the wallet's birthday when using an extended master key + * to restore the wallet. lnd will only start scanning for funds in blocks that + * are after the birthday which can speed up the process significantly. If the + * birthday is not known, this should be left at its default value of 0 in + * which case lnd will start scanning from the first SegWit block (481824 on + * mainnet). + * + * @generated from protobuf field: uint64 extended_master_key_birthday_timestamp = 8; + */ + extendedMasterKeyBirthdayTimestamp: bigint; + /** + * + * watch_only is the third option of initializing a wallet: by importing + * account xpubs only and therefore creating a watch-only wallet that does not + * contain any private keys. That means the wallet won't be able to sign for + * any of the keys and _needs_ to be run with a remote signer that has the + * corresponding private keys and can serve signing RPC requests. + * + * @generated from protobuf field: lnrpc.WatchOnly watch_only = 9; + */ + watchOnly?: WatchOnly; + /** + * + * macaroon_root_key is an optional 32 byte macaroon root key that can be + * provided when initializing the wallet rather than letting lnd generate one + * on its own. + * + * @generated from protobuf field: bytes macaroon_root_key = 10; + */ + macaroonRootKey: Uint8Array; +} +/** + * @generated from protobuf message lnrpc.InitWalletResponse + */ +export interface InitWalletResponse { + /** + * + * The binary serialized admin macaroon that can be used to access the daemon + * after creating the wallet. If the stateless_init parameter was set to true, + * this is the ONLY copy of the macaroon and MUST be stored safely by the + * caller. Otherwise a copy of this macaroon is also persisted on disk by the + * daemon, together with other macaroon files. + * + * @generated from protobuf field: bytes admin_macaroon = 1; + */ + adminMacaroon: Uint8Array; +} +/** + * @generated from protobuf message lnrpc.WatchOnly + */ +export interface WatchOnly { + /** + * + * The unix timestamp in seconds of when the master key was created. lnd will + * only start scanning for funds in blocks that are after the birthday which + * can speed up the process significantly. If the birthday is not known, this + * should be left at its default value of 0 in which case lnd will start + * scanning from the first SegWit block (481824 on mainnet). + * + * @generated from protobuf field: uint64 master_key_birthday_timestamp = 1; + */ + masterKeyBirthdayTimestamp: bigint; + /** + * + * The fingerprint of the root key (also known as the key with derivation path + * m/) from which the account public keys were derived from. This may be + * required by some hardware wallets for proper identification and signing. The + * bytes must be in big-endian order. + * + * @generated from protobuf field: bytes master_key_fingerprint = 2; + */ + masterKeyFingerprint: Uint8Array; + /** + * + * The list of accounts to import. There _must_ be an account for all of lnd's + * main key scopes: BIP49/BIP84 (m/49'/0'/0', m/84'/0'/0', note that the + * coin type is always 0, even for testnet/regtest) and lnd's internal key + * scope (m/1017'/'/'), where account is the key family as + * defined in `keychain/derivation.go` (currently indices 0 to 9). + * + * @generated from protobuf field: repeated lnrpc.WatchOnlyAccount accounts = 3; + */ + accounts: WatchOnlyAccount[]; +} +/** + * @generated from protobuf message lnrpc.WatchOnlyAccount + */ +export interface WatchOnlyAccount { + /** + * + * Purpose is the first number in the derivation path, must be either 49, 84 + * or 1017. + * + * @generated from protobuf field: uint32 purpose = 1; + */ + purpose: number; + /** + * + * Coin type is the second number in the derivation path, this is _always_ 0 + * for purposes 49 and 84. It only needs to be set to 1 for purpose 1017 on + * testnet or regtest. + * + * @generated from protobuf field: uint32 coin_type = 2; + */ + coinType: number; + /** + * + * Account is the third number in the derivation path. For purposes 49 and 84 + * at least the default account (index 0) needs to be created but optional + * additional accounts are allowed. For purpose 1017 there needs to be exactly + * one account for each of the key families defined in `keychain/derivation.go` + * (currently indices 0 to 9) + * + * @generated from protobuf field: uint32 account = 3; + */ + account: number; + /** + * + * The extended public key at depth 3 for the given account. + * + * @generated from protobuf field: string xpub = 4; + */ + xpub: string; +} +/** + * @generated from protobuf message lnrpc.UnlockWalletRequest + */ +export interface UnlockWalletRequest { + /** + * + * wallet_password should be the current valid passphrase for the daemon. This + * will be required to decrypt on-disk material that the daemon requires to + * function properly. When using REST, this field must be encoded as base64. + * + * @generated from protobuf field: bytes wallet_password = 1; + */ + walletPassword: Uint8Array; + /** + * + * recovery_window is an optional argument specifying the address lookahead + * when restoring a wallet seed. The recovery window applies to each + * individual branch of the BIP44 derivation paths. Supplying a recovery + * window of zero indicates that no addresses should be recovered, such after + * the first initialization of the wallet. + * + * @generated from protobuf field: int32 recovery_window = 2; + */ + recoveryWindow: number; + /** + * + * channel_backups is an optional argument that allows clients to recover the + * settled funds within a set of channels. This should be populated if the + * user was unable to close out all channels and sweep funds before partial or + * total data loss occurred. If specified, then after on-chain recovery of + * funds, lnd begin to carry out the data loss recovery protocol in order to + * recover the funds in each channel from a remote force closed transaction. + * + * @generated from protobuf field: lnrpc.ChanBackupSnapshot channel_backups = 3; + */ + channelBackups?: ChanBackupSnapshot; + /** + * + * stateless_init is an optional argument instructing the daemon NOT to create + * any *.macaroon files in its file system. + * + * @generated from protobuf field: bool stateless_init = 4; + */ + statelessInit: boolean; +} +/** + * @generated from protobuf message lnrpc.UnlockWalletResponse + */ +export interface UnlockWalletResponse { +} +/** + * @generated from protobuf message lnrpc.ChangePasswordRequest + */ +export interface ChangePasswordRequest { + /** + * + * current_password should be the current valid passphrase used to unlock the + * daemon. When using REST, this field must be encoded as base64. + * + * @generated from protobuf field: bytes current_password = 1; + */ + currentPassword: Uint8Array; + /** + * + * new_password should be the new passphrase that will be needed to unlock the + * daemon. When using REST, this field must be encoded as base64. + * + * @generated from protobuf field: bytes new_password = 2; + */ + newPassword: Uint8Array; + /** + * + * stateless_init is an optional argument instructing the daemon NOT to create + * any *.macaroon files in its filesystem. If this parameter is set, then the + * admin macaroon returned in the response MUST be stored by the caller of the + * RPC as otherwise all access to the daemon will be lost! + * + * @generated from protobuf field: bool stateless_init = 3; + */ + statelessInit: boolean; + /** + * + * new_macaroon_root_key is an optional argument instructing the daemon to + * rotate the macaroon root key when set to true. This will invalidate all + * previously generated macaroons. + * + * @generated from protobuf field: bool new_macaroon_root_key = 4; + */ + newMacaroonRootKey: boolean; +} +/** + * @generated from protobuf message lnrpc.ChangePasswordResponse + */ +export interface ChangePasswordResponse { + /** + * + * The binary serialized admin macaroon that can be used to access the daemon + * after rotating the macaroon root key. If both the stateless_init and + * new_macaroon_root_key parameter were set to true, this is the ONLY copy of + * the macaroon that was created from the new root key and MUST be stored + * safely by the caller. Otherwise a copy of this macaroon is also persisted on + * disk by the daemon, together with other macaroon files. + * + * @generated from protobuf field: bytes admin_macaroon = 1; + */ + adminMacaroon: Uint8Array; +} +// @generated message type with reflection information, may provide speed optimized methods +class GenSeedRequest$Type extends MessageType { + constructor() { + super("lnrpc.GenSeedRequest", [ + { no: 1, name: "aezeed_passphrase", kind: "scalar", T: 12 /*ScalarType.BYTES*/ }, + { no: 2, name: "seed_entropy", kind: "scalar", T: 12 /*ScalarType.BYTES*/ } + ]); + } + create(value?: PartialMessage): GenSeedRequest { + const message = { aezeedPassphrase: new Uint8Array(0), seedEntropy: new Uint8Array(0) }; + globalThis.Object.defineProperty(message, MESSAGE_TYPE, { enumerable: false, value: this }); + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: GenSeedRequest): GenSeedRequest { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* bytes aezeed_passphrase */ 1: + message.aezeedPassphrase = reader.bytes(); + break; + case /* bytes seed_entropy */ 2: + message.seedEntropy = reader.bytes(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: GenSeedRequest, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* bytes aezeed_passphrase = 1; */ + if (message.aezeedPassphrase.length) + writer.tag(1, WireType.LengthDelimited).bytes(message.aezeedPassphrase); + /* bytes seed_entropy = 2; */ + if (message.seedEntropy.length) + writer.tag(2, WireType.LengthDelimited).bytes(message.seedEntropy); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message lnrpc.GenSeedRequest + */ +export const GenSeedRequest = new GenSeedRequest$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class GenSeedResponse$Type extends MessageType { + constructor() { + super("lnrpc.GenSeedResponse", [ + { no: 1, name: "cipher_seed_mnemonic", kind: "scalar", repeat: 2 /*RepeatType.UNPACKED*/, T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "enciphered_seed", kind: "scalar", T: 12 /*ScalarType.BYTES*/ } + ]); + } + create(value?: PartialMessage): GenSeedResponse { + const message = { cipherSeedMnemonic: [], encipheredSeed: new Uint8Array(0) }; + globalThis.Object.defineProperty(message, MESSAGE_TYPE, { enumerable: false, value: this }); + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: GenSeedResponse): GenSeedResponse { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* repeated string cipher_seed_mnemonic */ 1: + message.cipherSeedMnemonic.push(reader.string()); + break; + case /* bytes enciphered_seed */ 2: + message.encipheredSeed = reader.bytes(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: GenSeedResponse, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* repeated string cipher_seed_mnemonic = 1; */ + for (let i = 0; i < message.cipherSeedMnemonic.length; i++) + writer.tag(1, WireType.LengthDelimited).string(message.cipherSeedMnemonic[i]); + /* bytes enciphered_seed = 2; */ + if (message.encipheredSeed.length) + writer.tag(2, WireType.LengthDelimited).bytes(message.encipheredSeed); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message lnrpc.GenSeedResponse + */ +export const GenSeedResponse = new GenSeedResponse$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class InitWalletRequest$Type extends MessageType { + constructor() { + super("lnrpc.InitWalletRequest", [ + { no: 1, name: "wallet_password", kind: "scalar", T: 12 /*ScalarType.BYTES*/ }, + { no: 2, name: "cipher_seed_mnemonic", kind: "scalar", repeat: 2 /*RepeatType.UNPACKED*/, T: 9 /*ScalarType.STRING*/ }, + { no: 3, name: "aezeed_passphrase", kind: "scalar", T: 12 /*ScalarType.BYTES*/ }, + { no: 4, name: "recovery_window", kind: "scalar", T: 5 /*ScalarType.INT32*/ }, + { no: 5, name: "channel_backups", kind: "message", T: () => ChanBackupSnapshot }, + { no: 6, name: "stateless_init", kind: "scalar", T: 8 /*ScalarType.BOOL*/ }, + { no: 7, name: "extended_master_key", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 8, name: "extended_master_key_birthday_timestamp", kind: "scalar", T: 4 /*ScalarType.UINT64*/, L: 0 /*LongType.BIGINT*/ }, + { no: 9, name: "watch_only", kind: "message", T: () => WatchOnly }, + { no: 10, name: "macaroon_root_key", kind: "scalar", T: 12 /*ScalarType.BYTES*/ } + ]); + } + create(value?: PartialMessage): InitWalletRequest { + const message = { walletPassword: new Uint8Array(0), cipherSeedMnemonic: [], aezeedPassphrase: new Uint8Array(0), recoveryWindow: 0, statelessInit: false, extendedMasterKey: "", extendedMasterKeyBirthdayTimestamp: 0n, macaroonRootKey: new Uint8Array(0) }; + globalThis.Object.defineProperty(message, MESSAGE_TYPE, { enumerable: false, value: this }); + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: InitWalletRequest): InitWalletRequest { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* bytes wallet_password */ 1: + message.walletPassword = reader.bytes(); + break; + case /* repeated string cipher_seed_mnemonic */ 2: + message.cipherSeedMnemonic.push(reader.string()); + break; + case /* bytes aezeed_passphrase */ 3: + message.aezeedPassphrase = reader.bytes(); + break; + case /* int32 recovery_window */ 4: + message.recoveryWindow = reader.int32(); + break; + case /* lnrpc.ChanBackupSnapshot channel_backups */ 5: + message.channelBackups = ChanBackupSnapshot.internalBinaryRead(reader, reader.uint32(), options, message.channelBackups); + break; + case /* bool stateless_init */ 6: + message.statelessInit = reader.bool(); + break; + case /* string extended_master_key */ 7: + message.extendedMasterKey = reader.string(); + break; + case /* uint64 extended_master_key_birthday_timestamp */ 8: + message.extendedMasterKeyBirthdayTimestamp = reader.uint64().toBigInt(); + break; + case /* lnrpc.WatchOnly watch_only */ 9: + message.watchOnly = WatchOnly.internalBinaryRead(reader, reader.uint32(), options, message.watchOnly); + break; + case /* bytes macaroon_root_key */ 10: + message.macaroonRootKey = reader.bytes(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: InitWalletRequest, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* bytes wallet_password = 1; */ + if (message.walletPassword.length) + writer.tag(1, WireType.LengthDelimited).bytes(message.walletPassword); + /* repeated string cipher_seed_mnemonic = 2; */ + for (let i = 0; i < message.cipherSeedMnemonic.length; i++) + writer.tag(2, WireType.LengthDelimited).string(message.cipherSeedMnemonic[i]); + /* bytes aezeed_passphrase = 3; */ + if (message.aezeedPassphrase.length) + writer.tag(3, WireType.LengthDelimited).bytes(message.aezeedPassphrase); + /* int32 recovery_window = 4; */ + if (message.recoveryWindow !== 0) + writer.tag(4, WireType.Varint).int32(message.recoveryWindow); + /* lnrpc.ChanBackupSnapshot channel_backups = 5; */ + if (message.channelBackups) + ChanBackupSnapshot.internalBinaryWrite(message.channelBackups, writer.tag(5, WireType.LengthDelimited).fork(), options).join(); + /* bool stateless_init = 6; */ + if (message.statelessInit !== false) + writer.tag(6, WireType.Varint).bool(message.statelessInit); + /* string extended_master_key = 7; */ + if (message.extendedMasterKey !== "") + writer.tag(7, WireType.LengthDelimited).string(message.extendedMasterKey); + /* uint64 extended_master_key_birthday_timestamp = 8; */ + if (message.extendedMasterKeyBirthdayTimestamp !== 0n) + writer.tag(8, WireType.Varint).uint64(message.extendedMasterKeyBirthdayTimestamp); + /* lnrpc.WatchOnly watch_only = 9; */ + if (message.watchOnly) + WatchOnly.internalBinaryWrite(message.watchOnly, writer.tag(9, WireType.LengthDelimited).fork(), options).join(); + /* bytes macaroon_root_key = 10; */ + if (message.macaroonRootKey.length) + writer.tag(10, WireType.LengthDelimited).bytes(message.macaroonRootKey); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message lnrpc.InitWalletRequest + */ +export const InitWalletRequest = new InitWalletRequest$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class InitWalletResponse$Type extends MessageType { + constructor() { + super("lnrpc.InitWalletResponse", [ + { no: 1, name: "admin_macaroon", kind: "scalar", T: 12 /*ScalarType.BYTES*/ } + ]); + } + create(value?: PartialMessage): InitWalletResponse { + const message = { adminMacaroon: new Uint8Array(0) }; + globalThis.Object.defineProperty(message, MESSAGE_TYPE, { enumerable: false, value: this }); + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: InitWalletResponse): InitWalletResponse { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* bytes admin_macaroon */ 1: + message.adminMacaroon = reader.bytes(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: InitWalletResponse, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* bytes admin_macaroon = 1; */ + if (message.adminMacaroon.length) + writer.tag(1, WireType.LengthDelimited).bytes(message.adminMacaroon); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message lnrpc.InitWalletResponse + */ +export const InitWalletResponse = new InitWalletResponse$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class WatchOnly$Type extends MessageType { + constructor() { + super("lnrpc.WatchOnly", [ + { no: 1, name: "master_key_birthday_timestamp", kind: "scalar", T: 4 /*ScalarType.UINT64*/, L: 0 /*LongType.BIGINT*/ }, + { no: 2, name: "master_key_fingerprint", kind: "scalar", T: 12 /*ScalarType.BYTES*/ }, + { no: 3, name: "accounts", kind: "message", repeat: 1 /*RepeatType.PACKED*/, T: () => WatchOnlyAccount } + ]); + } + create(value?: PartialMessage): WatchOnly { + const message = { masterKeyBirthdayTimestamp: 0n, masterKeyFingerprint: new Uint8Array(0), accounts: [] }; + globalThis.Object.defineProperty(message, MESSAGE_TYPE, { enumerable: false, value: this }); + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: WatchOnly): WatchOnly { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* uint64 master_key_birthday_timestamp */ 1: + message.masterKeyBirthdayTimestamp = reader.uint64().toBigInt(); + break; + case /* bytes master_key_fingerprint */ 2: + message.masterKeyFingerprint = reader.bytes(); + break; + case /* repeated lnrpc.WatchOnlyAccount accounts */ 3: + message.accounts.push(WatchOnlyAccount.internalBinaryRead(reader, reader.uint32(), options)); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: WatchOnly, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* uint64 master_key_birthday_timestamp = 1; */ + if (message.masterKeyBirthdayTimestamp !== 0n) + writer.tag(1, WireType.Varint).uint64(message.masterKeyBirthdayTimestamp); + /* bytes master_key_fingerprint = 2; */ + if (message.masterKeyFingerprint.length) + writer.tag(2, WireType.LengthDelimited).bytes(message.masterKeyFingerprint); + /* repeated lnrpc.WatchOnlyAccount accounts = 3; */ + for (let i = 0; i < message.accounts.length; i++) + WatchOnlyAccount.internalBinaryWrite(message.accounts[i], writer.tag(3, WireType.LengthDelimited).fork(), options).join(); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message lnrpc.WatchOnly + */ +export const WatchOnly = new WatchOnly$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class WatchOnlyAccount$Type extends MessageType { + constructor() { + super("lnrpc.WatchOnlyAccount", [ + { no: 1, name: "purpose", kind: "scalar", T: 13 /*ScalarType.UINT32*/ }, + { no: 2, name: "coin_type", kind: "scalar", T: 13 /*ScalarType.UINT32*/ }, + { no: 3, name: "account", kind: "scalar", T: 13 /*ScalarType.UINT32*/ }, + { no: 4, name: "xpub", kind: "scalar", T: 9 /*ScalarType.STRING*/ } + ]); + } + create(value?: PartialMessage): WatchOnlyAccount { + const message = { purpose: 0, coinType: 0, account: 0, xpub: "" }; + globalThis.Object.defineProperty(message, MESSAGE_TYPE, { enumerable: false, value: this }); + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: WatchOnlyAccount): WatchOnlyAccount { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* uint32 purpose */ 1: + message.purpose = reader.uint32(); + break; + case /* uint32 coin_type */ 2: + message.coinType = reader.uint32(); + break; + case /* uint32 account */ 3: + message.account = reader.uint32(); + break; + case /* string xpub */ 4: + message.xpub = reader.string(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: WatchOnlyAccount, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* uint32 purpose = 1; */ + if (message.purpose !== 0) + writer.tag(1, WireType.Varint).uint32(message.purpose); + /* uint32 coin_type = 2; */ + if (message.coinType !== 0) + writer.tag(2, WireType.Varint).uint32(message.coinType); + /* uint32 account = 3; */ + if (message.account !== 0) + writer.tag(3, WireType.Varint).uint32(message.account); + /* string xpub = 4; */ + if (message.xpub !== "") + writer.tag(4, WireType.LengthDelimited).string(message.xpub); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message lnrpc.WatchOnlyAccount + */ +export const WatchOnlyAccount = new WatchOnlyAccount$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class UnlockWalletRequest$Type extends MessageType { + constructor() { + super("lnrpc.UnlockWalletRequest", [ + { no: 1, name: "wallet_password", kind: "scalar", T: 12 /*ScalarType.BYTES*/ }, + { no: 2, name: "recovery_window", kind: "scalar", T: 5 /*ScalarType.INT32*/ }, + { no: 3, name: "channel_backups", kind: "message", T: () => ChanBackupSnapshot }, + { no: 4, name: "stateless_init", kind: "scalar", T: 8 /*ScalarType.BOOL*/ } + ]); + } + create(value?: PartialMessage): UnlockWalletRequest { + const message = { walletPassword: new Uint8Array(0), recoveryWindow: 0, statelessInit: false }; + globalThis.Object.defineProperty(message, MESSAGE_TYPE, { enumerable: false, value: this }); + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: UnlockWalletRequest): UnlockWalletRequest { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* bytes wallet_password */ 1: + message.walletPassword = reader.bytes(); + break; + case /* int32 recovery_window */ 2: + message.recoveryWindow = reader.int32(); + break; + case /* lnrpc.ChanBackupSnapshot channel_backups */ 3: + message.channelBackups = ChanBackupSnapshot.internalBinaryRead(reader, reader.uint32(), options, message.channelBackups); + break; + case /* bool stateless_init */ 4: + message.statelessInit = reader.bool(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: UnlockWalletRequest, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* bytes wallet_password = 1; */ + if (message.walletPassword.length) + writer.tag(1, WireType.LengthDelimited).bytes(message.walletPassword); + /* int32 recovery_window = 2; */ + if (message.recoveryWindow !== 0) + writer.tag(2, WireType.Varint).int32(message.recoveryWindow); + /* lnrpc.ChanBackupSnapshot channel_backups = 3; */ + if (message.channelBackups) + ChanBackupSnapshot.internalBinaryWrite(message.channelBackups, writer.tag(3, WireType.LengthDelimited).fork(), options).join(); + /* bool stateless_init = 4; */ + if (message.statelessInit !== false) + writer.tag(4, WireType.Varint).bool(message.statelessInit); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message lnrpc.UnlockWalletRequest + */ +export const UnlockWalletRequest = new UnlockWalletRequest$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class UnlockWalletResponse$Type extends MessageType { + constructor() { + super("lnrpc.UnlockWalletResponse", []); + } + create(value?: PartialMessage): UnlockWalletResponse { + const message = {}; + globalThis.Object.defineProperty(message, MESSAGE_TYPE, { enumerable: false, value: this }); + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: UnlockWalletResponse): UnlockWalletResponse { + return target ?? this.create(); + } + internalBinaryWrite(message: UnlockWalletResponse, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message lnrpc.UnlockWalletResponse + */ +export const UnlockWalletResponse = new UnlockWalletResponse$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class ChangePasswordRequest$Type extends MessageType { + constructor() { + super("lnrpc.ChangePasswordRequest", [ + { no: 1, name: "current_password", kind: "scalar", T: 12 /*ScalarType.BYTES*/ }, + { no: 2, name: "new_password", kind: "scalar", T: 12 /*ScalarType.BYTES*/ }, + { no: 3, name: "stateless_init", kind: "scalar", T: 8 /*ScalarType.BOOL*/ }, + { no: 4, name: "new_macaroon_root_key", kind: "scalar", T: 8 /*ScalarType.BOOL*/ } + ]); + } + create(value?: PartialMessage): ChangePasswordRequest { + const message = { currentPassword: new Uint8Array(0), newPassword: new Uint8Array(0), statelessInit: false, newMacaroonRootKey: false }; + globalThis.Object.defineProperty(message, MESSAGE_TYPE, { enumerable: false, value: this }); + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: ChangePasswordRequest): ChangePasswordRequest { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* bytes current_password */ 1: + message.currentPassword = reader.bytes(); + break; + case /* bytes new_password */ 2: + message.newPassword = reader.bytes(); + break; + case /* bool stateless_init */ 3: + message.statelessInit = reader.bool(); + break; + case /* bool new_macaroon_root_key */ 4: + message.newMacaroonRootKey = reader.bool(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: ChangePasswordRequest, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* bytes current_password = 1; */ + if (message.currentPassword.length) + writer.tag(1, WireType.LengthDelimited).bytes(message.currentPassword); + /* bytes new_password = 2; */ + if (message.newPassword.length) + writer.tag(2, WireType.LengthDelimited).bytes(message.newPassword); + /* bool stateless_init = 3; */ + if (message.statelessInit !== false) + writer.tag(3, WireType.Varint).bool(message.statelessInit); + /* bool new_macaroon_root_key = 4; */ + if (message.newMacaroonRootKey !== false) + writer.tag(4, WireType.Varint).bool(message.newMacaroonRootKey); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message lnrpc.ChangePasswordRequest + */ +export const ChangePasswordRequest = new ChangePasswordRequest$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class ChangePasswordResponse$Type extends MessageType { + constructor() { + super("lnrpc.ChangePasswordResponse", [ + { no: 1, name: "admin_macaroon", kind: "scalar", T: 12 /*ScalarType.BYTES*/ } + ]); + } + create(value?: PartialMessage): ChangePasswordResponse { + const message = { adminMacaroon: new Uint8Array(0) }; + globalThis.Object.defineProperty(message, MESSAGE_TYPE, { enumerable: false, value: this }); + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: ChangePasswordResponse): ChangePasswordResponse { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* bytes admin_macaroon */ 1: + message.adminMacaroon = reader.bytes(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: ChangePasswordResponse, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* bytes admin_macaroon = 1; */ + if (message.adminMacaroon.length) + writer.tag(1, WireType.LengthDelimited).bytes(message.adminMacaroon); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message lnrpc.ChangePasswordResponse + */ +export const ChangePasswordResponse = new ChangePasswordResponse$Type(); +/** + * @generated ServiceType for protobuf service lnrpc.WalletUnlocker + */ +export const WalletUnlocker = new ServiceType("lnrpc.WalletUnlocker", [ + { name: "GenSeed", options: {}, I: GenSeedRequest, O: GenSeedResponse }, + { name: "InitWallet", options: {}, I: InitWalletRequest, O: InitWalletResponse }, + { name: "UnlockWallet", options: {}, I: UnlockWalletRequest, O: UnlockWalletResponse }, + { name: "ChangePassword", options: {}, I: ChangePasswordRequest, O: ChangePasswordResponse } +]); diff --git a/proto/others/walletunlocker.proto b/proto/others/walletunlocker.proto new file mode 100644 index 00000000..7bcead54 --- /dev/null +++ b/proto/others/walletunlocker.proto @@ -0,0 +1,338 @@ +syntax = "proto3"; + +package lnrpc; + +import "lightning.proto"; + +option go_package = "github.com/lightningnetwork/lnd/lnrpc"; + +/* + * Comments in this file will be directly parsed into the API + * Documentation as descriptions of the associated method, message, or field. + * These descriptions should go right above the definition of the object, and + * can be in either block or // comment format. + * + * An RPC method can be matched to an lncli command by placing a line in the + * beginning of the description in exactly the following format: + * lncli: `methodname` + * + * Failure to specify the exact name of the command will cause documentation + * generation to fail. + * + * More information on how exactly the gRPC documentation is generated from + * this proto file can be found here: + * https://github.com/lightninglabs/lightning-api + */ + +// WalletUnlocker is a service that is used to set up a wallet password for +// lnd at first startup, and unlock a previously set up wallet. +service WalletUnlocker { + /* + GenSeed is the first method that should be used to instantiate a new lnd + instance. This method allows a caller to generate a new aezeed cipher seed + given an optional passphrase. If provided, the passphrase will be necessary + to decrypt the cipherseed to expose the internal wallet seed. + + Once the cipherseed is obtained and verified by the user, the InitWallet + method should be used to commit the newly generated seed, and create the + wallet. + */ + rpc GenSeed (GenSeedRequest) returns (GenSeedResponse); + + /* + InitWallet is used when lnd is starting up for the first time to fully + initialize the daemon and its internal wallet. At the very least a wallet + password must be provided. This will be used to encrypt sensitive material + on disk. + + In the case of a recovery scenario, the user can also specify their aezeed + mnemonic and passphrase. If set, then the daemon will use this prior state + to initialize its internal wallet. + + Alternatively, this can be used along with the GenSeed RPC to obtain a + seed, then present it to the user. Once it has been verified by the user, + the seed can be fed into this RPC in order to commit the new wallet. + */ + rpc InitWallet (InitWalletRequest) returns (InitWalletResponse); + + /* lncli: `unlock` + UnlockWallet is used at startup of lnd to provide a password to unlock + the wallet database. + */ + rpc UnlockWallet (UnlockWalletRequest) returns (UnlockWalletResponse); + + /* lncli: `changepassword` + ChangePassword changes the password of the encrypted wallet. This will + automatically unlock the wallet database if successful. + */ + rpc ChangePassword (ChangePasswordRequest) returns (ChangePasswordResponse); +} + +message GenSeedRequest { + /* + aezeed_passphrase is an optional user provided passphrase that will be used + to encrypt the generated aezeed cipher seed. When using REST, this field + must be encoded as base64. + */ + bytes aezeed_passphrase = 1; + + /* + seed_entropy is an optional 16-bytes generated via CSPRNG. If not + specified, then a fresh set of randomness will be used to create the seed. + When using REST, this field must be encoded as base64. + */ + bytes seed_entropy = 2; +} +message GenSeedResponse { + /* + cipher_seed_mnemonic is a 24-word mnemonic that encodes a prior aezeed + cipher seed obtained by the user. This field is optional, as if not + provided, then the daemon will generate a new cipher seed for the user. + Otherwise, then the daemon will attempt to recover the wallet state linked + to this cipher seed. + */ + repeated string cipher_seed_mnemonic = 1; + + /* + enciphered_seed are the raw aezeed cipher seed bytes. This is the raw + cipher text before run through our mnemonic encoding scheme. + */ + bytes enciphered_seed = 2; +} + +message InitWalletRequest { + /* + wallet_password is the passphrase that should be used to encrypt the + wallet. This MUST be at least 8 chars in length. After creation, this + password is required to unlock the daemon. When using REST, this field + must be encoded as base64. + */ + bytes wallet_password = 1; + + /* + cipher_seed_mnemonic is a 24-word mnemonic that encodes a prior aezeed + cipher seed obtained by the user. This may have been generated by the + GenSeed method, or be an existing seed. + */ + repeated string cipher_seed_mnemonic = 2; + + /* + aezeed_passphrase is an optional user provided passphrase that will be used + to encrypt the generated aezeed cipher seed. When using REST, this field + must be encoded as base64. + */ + bytes aezeed_passphrase = 3; + + /* + recovery_window is an optional argument specifying the address lookahead + when restoring a wallet seed. The recovery window applies to each + individual branch of the BIP44 derivation paths. Supplying a recovery + window of zero indicates that no addresses should be recovered, such after + the first initialization of the wallet. + */ + int32 recovery_window = 4; + + /* + channel_backups is an optional argument that allows clients to recover the + settled funds within a set of channels. This should be populated if the + user was unable to close out all channels and sweep funds before partial or + total data loss occurred. If specified, then after on-chain recovery of + funds, lnd begin to carry out the data loss recovery protocol in order to + recover the funds in each channel from a remote force closed transaction. + */ + ChanBackupSnapshot channel_backups = 5; + + /* + stateless_init is an optional argument instructing the daemon NOT to create + any *.macaroon files in its filesystem. If this parameter is set, then the + admin macaroon returned in the response MUST be stored by the caller of the + RPC as otherwise all access to the daemon will be lost! + */ + bool stateless_init = 6; + + /* + extended_master_key is an alternative to specifying cipher_seed_mnemonic and + aezeed_passphrase. Instead of deriving the master root key from the entropy + of an aezeed cipher seed, the given extended master root key is used + directly as the wallet's master key. This allows users to import/use a + master key from another wallet. When doing so, lnd still uses its default + SegWit only (BIP49/84) derivation paths and funds from custom/non-default + derivation paths will not automatically appear in the on-chain wallet. Using + an 'xprv' instead of an aezeed also has the disadvantage that the wallet's + birthday is not known as that is an information that's only encoded in the + aezeed, not the xprv. Therefore a birthday needs to be specified in + extended_master_key_birthday_timestamp or a "safe" default value will be + used. + */ + string extended_master_key = 7; + + /* + extended_master_key_birthday_timestamp is the optional unix timestamp in + seconds to use as the wallet's birthday when using an extended master key + to restore the wallet. lnd will only start scanning for funds in blocks that + are after the birthday which can speed up the process significantly. If the + birthday is not known, this should be left at its default value of 0 in + which case lnd will start scanning from the first SegWit block (481824 on + mainnet). + */ + uint64 extended_master_key_birthday_timestamp = 8; + + /* + watch_only is the third option of initializing a wallet: by importing + account xpubs only and therefore creating a watch-only wallet that does not + contain any private keys. That means the wallet won't be able to sign for + any of the keys and _needs_ to be run with a remote signer that has the + corresponding private keys and can serve signing RPC requests. + */ + WatchOnly watch_only = 9; + + /* + macaroon_root_key is an optional 32 byte macaroon root key that can be + provided when initializing the wallet rather than letting lnd generate one + on its own. + */ + bytes macaroon_root_key = 10; +} +message InitWalletResponse { + /* + The binary serialized admin macaroon that can be used to access the daemon + after creating the wallet. If the stateless_init parameter was set to true, + this is the ONLY copy of the macaroon and MUST be stored safely by the + caller. Otherwise a copy of this macaroon is also persisted on disk by the + daemon, together with other macaroon files. + */ + bytes admin_macaroon = 1; +} + +message WatchOnly { + /* + The unix timestamp in seconds of when the master key was created. lnd will + only start scanning for funds in blocks that are after the birthday which + can speed up the process significantly. If the birthday is not known, this + should be left at its default value of 0 in which case lnd will start + scanning from the first SegWit block (481824 on mainnet). + */ + uint64 master_key_birthday_timestamp = 1; + + /* + The fingerprint of the root key (also known as the key with derivation path + m/) from which the account public keys were derived from. This may be + required by some hardware wallets for proper identification and signing. The + bytes must be in big-endian order. + */ + bytes master_key_fingerprint = 2; + + /* + The list of accounts to import. There _must_ be an account for all of lnd's + main key scopes: BIP49/BIP84 (m/49'/0'/0', m/84'/0'/0', note that the + coin type is always 0, even for testnet/regtest) and lnd's internal key + scope (m/1017'/'/'), where account is the key family as + defined in `keychain/derivation.go` (currently indices 0 to 9). + */ + repeated WatchOnlyAccount accounts = 3; +} + +message WatchOnlyAccount { + /* + Purpose is the first number in the derivation path, must be either 49, 84 + or 1017. + */ + uint32 purpose = 1; + + /* + Coin type is the second number in the derivation path, this is _always_ 0 + for purposes 49 and 84. It only needs to be set to 1 for purpose 1017 on + testnet or regtest. + */ + uint32 coin_type = 2; + + /* + Account is the third number in the derivation path. For purposes 49 and 84 + at least the default account (index 0) needs to be created but optional + additional accounts are allowed. For purpose 1017 there needs to be exactly + one account for each of the key families defined in `keychain/derivation.go` + (currently indices 0 to 9) + */ + uint32 account = 3; + + /* + The extended public key at depth 3 for the given account. + */ + string xpub = 4; +} + +message UnlockWalletRequest { + /* + wallet_password should be the current valid passphrase for the daemon. This + will be required to decrypt on-disk material that the daemon requires to + function properly. When using REST, this field must be encoded as base64. + */ + bytes wallet_password = 1; + + /* + recovery_window is an optional argument specifying the address lookahead + when restoring a wallet seed. The recovery window applies to each + individual branch of the BIP44 derivation paths. Supplying a recovery + window of zero indicates that no addresses should be recovered, such after + the first initialization of the wallet. + */ + int32 recovery_window = 2; + + /* + channel_backups is an optional argument that allows clients to recover the + settled funds within a set of channels. This should be populated if the + user was unable to close out all channels and sweep funds before partial or + total data loss occurred. If specified, then after on-chain recovery of + funds, lnd begin to carry out the data loss recovery protocol in order to + recover the funds in each channel from a remote force closed transaction. + */ + ChanBackupSnapshot channel_backups = 3; + + /* + stateless_init is an optional argument instructing the daemon NOT to create + any *.macaroon files in its file system. + */ + bool stateless_init = 4; +} +message UnlockWalletResponse { +} + +message ChangePasswordRequest { + /* + current_password should be the current valid passphrase used to unlock the + daemon. When using REST, this field must be encoded as base64. + */ + bytes current_password = 1; + + /* + new_password should be the new passphrase that will be needed to unlock the + daemon. When using REST, this field must be encoded as base64. + */ + bytes new_password = 2; + + /* + stateless_init is an optional argument instructing the daemon NOT to create + any *.macaroon files in its filesystem. If this parameter is set, then the + admin macaroon returned in the response MUST be stored by the caller of the + RPC as otherwise all access to the daemon will be lost! + */ + bool stateless_init = 3; + + /* + new_macaroon_root_key is an optional argument instructing the daemon to + rotate the macaroon root key when set to true. This will invalidate all + previously generated macaroons. + */ + bool new_macaroon_root_key = 4; +} +message ChangePasswordResponse { + /* + The binary serialized admin macaroon that can be used to access the daemon + after rotating the macaroon root key. If both the stateless_init and + new_macaroon_root_key parameter were set to true, this is the ONLY copy of + the macaroon that was created from the new root key and MUST be stored + safely by the caller. Otherwise a copy of this macaroon is also persisted on + disk by the daemon, together with other macaroon files. + */ + bytes admin_macaroon = 1; +} \ No newline at end of file diff --git a/proto/protoc-gen-pub b/proto/protoc-gen-pub index a725f736..8d3c6d2b 100755 Binary files a/proto/protoc-gen-pub and b/proto/protoc-gen-pub differ diff --git a/proto/protoc-gen-pub_old b/proto/protoc-gen-pub_old new file mode 100755 index 00000000..a725f736 Binary files /dev/null and b/proto/protoc-gen-pub_old differ diff --git a/proto/service/methods.proto b/proto/service/methods.proto index 9260c4cd..ec186018 100644 --- a/proto/service/methods.proto +++ b/proto/service/methods.proto @@ -92,42 +92,49 @@ service LightningPub { option (auth_type) = "Admin"; option (http_method) = "post"; option (http_route) = "/api/admin/lnd/getinfo"; + option (nostr) = true; }; rpc AddApp(structs.AddAppRequest) returns (structs.AuthApp) { option (auth_type) = "Admin"; option (http_method) = "post"; option (http_route) = "/api/admin/app/add"; + option (nostr) = true; }; rpc AuthApp(structs.AuthAppRequest) returns (structs.AuthApp) { option (auth_type) = "Admin"; option (http_method) = "post"; option (http_route) = "/api/admin/app/auth"; + option (nostr) = true; } rpc BanUser(structs.BanUserRequest) returns (structs.BanUserResponse) { option (auth_type) = "Admin"; option (http_method) = "post"; option (http_route) = "/api/admin/user/ban"; + option (nostr) = true; } rpc GetUsageMetrics(structs.Empty) returns (structs.UsageMetrics) { option (auth_type) = "Metrics"; option (http_method) = "post"; option (http_route) = "/api/reports/usage"; + option (nostr) = true; } rpc GetAppsMetrics(structs.AppsMetricsRequest) returns (structs.AppsMetrics) { option (auth_type) = "Metrics"; option (http_method) = "post"; option (http_route) = "/api/reports/apps"; + option (nostr) = true; } rpc GetLndMetrics(structs.LndMetricsRequest) returns (structs.LndMetrics) { option (auth_type) = "Metrics"; option (http_method) = "post"; option (http_route) = "/api/reports/lnd"; + option (nostr) = true; } @@ -182,10 +189,16 @@ service LightningPub { rpc LinkNPubThroughToken(structs.LinkNPubThroughTokenRequest) returns (structs.Empty) { option (auth_type) = "User"; - option(http_method) = "post"; + option (http_method) = "post"; option (http_route) = "/api/guest/npub/link"; option (nostr) = true; } + rpc EnrollAdminToken(structs.EnrollAdminTokenRequest) returns (structs.Empty) { + option (auth_type) = "User"; + option (http_method) = "post"; + option (http_route) = "/api/guest/npub/enroll/admin"; + option (nostr) = true; + } // // diff --git a/proto/service/structs.proto b/proto/service/structs.proto index af493ab8..52c80cb2 100644 --- a/proto/service/structs.proto +++ b/proto/service/structs.proto @@ -349,6 +349,9 @@ message UserInfo{ int64 balance = 2; int64 max_withdrawable = 3; string user_identifier = 4; + int64 service_fee_bps = 5; + int64 network_max_fee_bps = 6; + int64 network_max_fee_fixed = 7; } message GetUserOperationsRequest{ @@ -446,4 +449,8 @@ message LinkNPubThroughTokenRequest { message HttpCreds { string url = 1; string token = 2; +} + +message EnrollAdminTokenRequest { + string admin_token = 1; } \ No newline at end of file diff --git a/proto/wizard/wizard_methods.proto b/proto/wizard/wizard_methods.proto new file mode 100644 index 00000000..9b6a560f --- /dev/null +++ b/proto/wizard/wizard_methods.proto @@ -0,0 +1,70 @@ +syntax = "proto3"; + +package wizard_methods; + +import "google/protobuf/descriptor.proto"; +import "wizard_structs.proto"; + +option go_package = "github.com/shocknet/lightning.pub"; +option (file_options) = { + supported_http_methods:["post", "get"]; + supported_auths:{ + id: "guest" + name: "Guest" + context:[] + }; +}; + +message MethodQueryOptions { + repeated string items = 1; +} + +extend google.protobuf.MethodOptions { // TODO: move this stuff to dep repo? + string auth_type = 50003; + string http_method = 50004; + string http_route = 50005; + MethodQueryOptions query = 50006; + bool nostr = 50007; + bool batch = 50008; + +} + +message ProtoFileOptions { + message SupportedAuth { + string id = 1; + string name = 2; + bool encrypted = 3; + map context = 4; + } + repeated SupportedAuth supported_auths = 1; + repeated string supported_http_methods = 2; +} + +extend google.protobuf.FileOptions { + ProtoFileOptions file_options = 50004; +} + +service Wizard { + // + rpc WizardState(wizard_structs.Empty) returns (wizard_structs.StateResponse){ + option (auth_type) = "Guest"; + option (http_method) = "get"; + option (http_route) = "/wizard/state"; + }; + rpc WizardConfig(wizard_structs.ConfigRequest) returns (wizard_structs.Empty){ + option (auth_type) = "Guest"; + option (http_method) = "post"; + option (http_route) = "/wizard/config"; + }; + rpc GetAdminConnectInfo(wizard_structs.Empty) returns (wizard_structs.AdminConnectInfoResponse){ + option (auth_type) = "Guest"; + option (http_method) = "get"; + option (http_route) = "/wizard/admin_connect_info"; + }; + rpc GetServiceState(wizard_structs.Empty) returns (wizard_structs.ServiceStateResponse){ + option (auth_type) = "Guest"; + option (http_method) = "get"; + option (http_route) = "/wizard/service_state"; + }; + // +} \ No newline at end of file diff --git a/proto/wizard/wizard_structs.proto b/proto/wizard/wizard_structs.proto new file mode 100644 index 00000000..e997a1b8 --- /dev/null +++ b/proto/wizard/wizard_structs.proto @@ -0,0 +1,40 @@ +syntax = "proto3"; + +package wizard_structs; + +option go_package = "github.com/shocknet/lightning.pub"; + +message Empty {} + +message StateResponse { + bool config_sent = 1; + bool admin_linked = 2; +} +message ConfigRequest { + string source_name = 1; + string relay_url = 2; + bool automate_liquidity = 3; + bool push_backups_to_nostr = 4; +} +message AdminConnectInfoResponse { + string nprofile = 1; + oneof connect_info { + string admin_token = 2; + string enrolled_npub = 3; + } +} +enum LndState { + OFFLINE = 0; + SYNCING = 1; + ONLINE = 2; +} +message ServiceStateResponse { + string provider_name = 1; + repeated string relays = 2; + string admin_npub = 3; + bool relay_connected = 4; + LndState lnd_state = 5; + bool watchdog_ok = 6; + string http_url = 7; + string nprofile = 8; +} \ No newline at end of file diff --git a/proto/wizard_service/autogenerated/client.md b/proto/wizard_service/autogenerated/client.md new file mode 100644 index 00000000..69596785 --- /dev/null +++ b/proto/wizard_service/autogenerated/client.md @@ -0,0 +1,91 @@ +# NOSTR API DEFINITION + + +A nostr request will take the same parameter and give the same response as an http request, but it will use nostr as transport, to do that it will send encrypted events to the server public key, in the event 6 thing are required: +- __rpcName__: string containing the name of the method +- __params__: a map with the all the url params for the method +- __query__: a map with the the url query for the method +- __body__: the body of the method request +- __requestId__: id of the request to be able to get a response + +The nostr server will send back a message response, and inside the body there will also be a __requestId__ to identify the request this response is answering + +## NOSTR Methods +### These are the nostr methods the client implements to communicate with the API via nostr + +# HTTP API DEFINITION + +## Supported HTTP Auths +### These are the supported http auth types, to give different type of access to the API users + +- __Guest__: + - expected context content + +## HTTP Methods +### These are the http methods the client implements to communicate with the API + +- WizardState + - auth type: __Guest__ + - http method: __get__ + - http route: __/wizard/state__ + - This methods has an __empty__ __request__ body + - output: [StateResponse](#StateResponse) + +- WizardConfig + - auth type: __Guest__ + - http method: __post__ + - http route: __/wizard/config__ + - input: [ConfigRequest](#ConfigRequest) + - This methods has an __empty__ __response__ body + +- GetAdminConnectInfo + - auth type: __Guest__ + - http method: __get__ + - http route: __/wizard/admin_connect_info__ + - This methods has an __empty__ __request__ body + - output: [AdminConnectInfoResponse](#AdminConnectInfoResponse) + +- GetServiceState + - auth type: __Guest__ + - http method: __get__ + - http route: __/wizard/service_state__ + - This methods has an __empty__ __request__ body + - output: [ServiceStateResponse](#ServiceStateResponse) + +# INPUTS AND OUTPUTS + +## Messages +### The content of requests and response from the methods + +### StateResponse + - __config_sent__: _boolean_ + - __admin_linked__: _boolean_ + +### ConfigRequest + - __source_name__: _string_ + - __relay_url__: _string_ + - __automate_liquidity__: _boolean_ + - __push_backups_to_nostr__: _boolean_ + +### AdminConnectInfoResponse + - __nprofile__: _string_ + - __connect_info__: _AdminConnectInfoResponse_connect_info_ + +### ServiceStateResponse + - __http_url__: _string_ + - __nprofile__: _string_ + - __provider_name__: _string_ + - __relays__: ARRAY of: _string_ + - __admin_npub__: _string_ + - __relay_connected__: _boolean_ + - __lnd_state__: _[LndState](#LndState)_ + - __watchdog_ok__: _boolean_ + +### Empty +## Enums +### The enumerators used in the messages + +### LndState + - __OFFLINE__ + - __SYNCING__ + - __ONLINE__ diff --git a/proto/wizard_service/autogenerated/debug.txt b/proto/wizard_service/autogenerated/debug.txt new file mode 100644 index 00000000..fd00e738 --- /dev/null +++ b/proto/wizard_service/autogenerated/debug.txt @@ -0,0 +1,359 @@ +([]*main.Method) (len=4 cap=4) { + (*main.Method)(0xc00022a280)({ + in: (main.MethodMessage) { + name: (string) (len=5) "Empty", + hasZeroFields: (bool) true + }, + name: (string) (len=11) "WizardState", + out: (main.MethodMessage) { + name: (string) (len=13) "StateResponse", + hasZeroFields: (bool) false + }, + opts: (*main.methodOptions)(0xc00009a9c0)({ + authType: (*main.supportedAuth)(0xc0003c9aa0)({ + id: (string) (len=5) "guest", + name: (string) (len=5) "Guest", + context: (map[string]string) { + } + }), + method: (string) (len=3) "get", + route: (main.decodedRoute) { + route: (string) (len=13) "/wizard/state", + params: ([]string) + }, + query: ([]string) , + nostr: (bool) false, + batch: (bool) false + }), + serverStream: (bool) false + }), + (*main.Method)(0xc00022a2d0)({ + in: (main.MethodMessage) { + name: (string) (len=13) "ConfigRequest", + hasZeroFields: (bool) false + }, + name: (string) (len=12) "WizardConfig", + out: (main.MethodMessage) { + name: (string) (len=5) "Empty", + hasZeroFields: (bool) true + }, + opts: (*main.methodOptions)(0xc00009ab40)({ + authType: (*main.supportedAuth)(0xc0003c9b60)({ + id: (string) (len=5) "guest", + name: (string) (len=5) "Guest", + context: (map[string]string) { + } + }), + method: (string) (len=4) "post", + route: (main.decodedRoute) { + route: (string) (len=14) "/wizard/config", + params: ([]string) + }, + query: ([]string) , + nostr: (bool) false, + batch: (bool) false + }), + serverStream: (bool) false + }), + (*main.Method)(0xc00022a640)({ + in: (main.MethodMessage) { + name: (string) (len=5) "Empty", + hasZeroFields: (bool) true + }, + name: (string) (len=19) "GetAdminConnectInfo", + out: (main.MethodMessage) { + name: (string) (len=24) "AdminConnectInfoResponse", + hasZeroFields: (bool) false + }, + opts: (*main.methodOptions)(0xc00009acc0)({ + authType: (*main.supportedAuth)(0xc0003c9c20)({ + id: (string) (len=5) "guest", + name: (string) (len=5) "Guest", + context: (map[string]string) { + } + }), + method: (string) (len=3) "get", + route: (main.decodedRoute) { + route: (string) (len=26) "/wizard/admin_connect_info", + params: ([]string) + }, + query: ([]string) , + nostr: (bool) false, + batch: (bool) false + }), + serverStream: (bool) false + }), + (*main.Method)(0xc00022a690)({ + in: (main.MethodMessage) { + name: (string) (len=5) "Empty", + hasZeroFields: (bool) true + }, + name: (string) (len=15) "GetServiceState", + out: (main.MethodMessage) { + name: (string) (len=20) "ServiceStateResponse", + hasZeroFields: (bool) false + }, + opts: (*main.methodOptions)(0xc00009ae40)({ + authType: (*main.supportedAuth)(0xc0003c9ce0)({ + id: (string) (len=5) "guest", + name: (string) (len=5) "Guest", + context: (map[string]string) { + } + }), + method: (string) (len=3) "get", + route: (main.decodedRoute) { + route: (string) (len=21) "/wizard/service_state", + params: ([]string) + }, + query: ([]string) , + nostr: (bool) false, + batch: (bool) false + }), + serverStream: (bool) false + }) +} + +([]*main.Enum) (len=1 cap=1) { + (*main.Enum)(0xc0003c9680)({ + name: (string) (len=8) "LndState", + values: ([]main.EnumValue) (len=3 cap=4) { + (main.EnumValue) { + number: (int64) 0, + name: (string) (len=7) "OFFLINE" + }, + (main.EnumValue) { + number: (int64) 1, + name: (string) (len=7) "SYNCING" + }, + (main.EnumValue) { + number: (int64) 2, + name: (string) (len=6) "ONLINE" + } + } + }) +} + +(map[string]*main.Message) (len=5) { + (string) (len=5) "Empty": (*main.Message)(0xc0003c94a0)({ + fullName: (string) (len=5) "Empty", + name: (string) (len=5) "Empty", + fields: (map[string]*main.Field) { + } + }), + (string) (len=13) "StateResponse": (*main.Message)(0xc0003c9500)({ + fullName: (string) (len=13) "StateResponse", + name: (string) (len=13) "StateResponse", + fields: (map[string]*main.Field) (len=2) { + (string) (len=11) "config_sent": (*main.Field)(0xc0003ee440)({ + name: (string) (len=11) "config_sent", + kind: (string) (len=4) "bool", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=12) "admin_linked": (*main.Field)(0xc0003ee480)({ + name: (string) (len=12) "admin_linked", + kind: (string) (len=4) "bool", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }) + } + }), + (string) (len=13) "ConfigRequest": (*main.Message)(0xc0003c9560)({ + fullName: (string) (len=13) "ConfigRequest", + name: (string) (len=13) "ConfigRequest", + fields: (map[string]*main.Field) (len=4) { + (string) (len=9) "relay_url": (*main.Field)(0xc0003ee500)({ + name: (string) (len=9) "relay_url", + kind: (string) (len=6) "string", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=18) "automate_liquidity": (*main.Field)(0xc0003ee540)({ + name: (string) (len=18) "automate_liquidity", + kind: (string) (len=4) "bool", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=21) "push_backups_to_nostr": (*main.Field)(0xc0003ee580)({ + name: (string) (len=21) "push_backups_to_nostr", + kind: (string) (len=4) "bool", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=11) "source_name": (*main.Field)(0xc0003ee4c0)({ + name: (string) (len=11) "source_name", + kind: (string) (len=6) "string", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }) + } + }), + (string) (len=24) "AdminConnectInfoResponse": (*main.Message)(0xc0003c95c0)({ + fullName: (string) (len=24) "AdminConnectInfoResponse", + name: (string) (len=24) "AdminConnectInfoResponse", + fields: (map[string]*main.Field) (len=2) { + (string) (len=8) "nprofile": (*main.Field)(0xc0003ee5c0)({ + name: (string) (len=8) "nprofile", + kind: (string) (len=6) "string", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=37) "AdminConnectInfoResponse_connect_info": (*main.Field)(0xc0003eea80)({ + name: (string) (len=12) "connect_info", + kind: (string) (len=37) "AdminConnectInfoResponse_connect_info", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) (len=12) "connect_info" + }) + } + }), + (string) (len=20) "ServiceStateResponse": (*main.Message)(0xc0003c9620)({ + fullName: (string) (len=20) "ServiceStateResponse", + name: (string) (len=20) "ServiceStateResponse", + fields: (map[string]*main.Field) (len=8) { + (string) (len=10) "admin_npub": (*main.Field)(0xc0003ee700)({ + name: (string) (len=10) "admin_npub", + kind: (string) (len=6) "string", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=15) "relay_connected": (*main.Field)(0xc0003ee740)({ + name: (string) (len=15) "relay_connected", + kind: (string) (len=4) "bool", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=9) "lnd_state": (*main.Field)(0xc0003ee780)({ + name: (string) (len=9) "lnd_state", + kind: (string) (len=8) "LndState", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) true, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=11) "watchdog_ok": (*main.Field)(0xc0003ee7c0)({ + name: (string) (len=11) "watchdog_ok", + kind: (string) (len=4) "bool", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=8) "http_url": (*main.Field)(0xc0003ee800)({ + name: (string) (len=8) "http_url", + kind: (string) (len=6) "string", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=8) "nprofile": (*main.Field)(0xc0003ee840)({ + name: (string) (len=8) "nprofile", + kind: (string) (len=6) "string", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=13) "provider_name": (*main.Field)(0xc0003ee680)({ + name: (string) (len=13) "provider_name", + kind: (string) (len=6) "string", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (string) (len=6) "relays": (*main.Field)(0xc0003ee6c0)({ + name: (string) (len=6) "relays", + kind: (string) (len=6) "string", + isMap: (bool) false, + isArray: (bool) true, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }) + } + }) +} + +(map[string][]*main.Field) (len=1) { + (string) (len=37) "AdminConnectInfoResponse_connect_info": ([]*main.Field) (len=2 cap=2) { + (*main.Field)(0xc0003ee600)({ + name: (string) (len=11) "admin_token", + kind: (string) (len=6) "string", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) (len=12) "connect_info" + }), + (*main.Field)(0xc0003ee640)({ + name: (string) (len=13) "enrolled_npub", + kind: (string) (len=6) "string", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) (len=12) "connect_info" + }) + } +} + +parsing file: wizard_structs 5 +parsing file: wizard_methods 2 +-> [{guest Guest map[]}] + +([]interface {}) + diff --git a/proto/wizard_service/autogenerated/ts/express_server.ts b/proto/wizard_service/autogenerated/ts/express_server.ts new file mode 100644 index 00000000..7dd26057 --- /dev/null +++ b/proto/wizard_service/autogenerated/ts/express_server.ts @@ -0,0 +1,120 @@ +// This file was autogenerated from a .proto file, DO NOT EDIT! + +import express, { Response, json, urlencoded } from 'express' +import cors from 'cors' +import * as Types from './types.js' +export type Logger = { log: (v: any) => void, error: (v: any) => void } +export type ServerOptions = { + allowCors?: true + staticFiles?: string + allowNotImplementedMethods?: true + logger?: Logger + throwErrors?: true + logMethod?: true + logBody?: true + metricsCallback: (metrics: Types.RequestMetric[]) => void + GuestAuthGuard: (authorizationHeader?: string) => Promise +} +declare module 'express-serve-static-core' { interface Request { startTime?: bigint, bodySize?: number, startTimeMs: number } } +const logErrorAndReturnResponse = (error: Error, response: string, res: Response, logger: Logger, metric: Types.RequestMetric, metricsCallback: (metrics: Types.RequestMetric[]) => void) => { + logger.error(error.message || error); metricsCallback([{ ...metric, error: response }]); res.json({ status: 'ERROR', reason: response }) +} +export default (methods: Types.ServerMethods, opts: ServerOptions) => { + const logger = opts.logger || { log: console.log, error: console.error } + const app = express() + if (opts.allowCors) { + app.use(cors()) + } + app.use((req, _, next) => { req.startTime = process.hrtime.bigint(); req.startTimeMs = Date.now(); next() }) + app.use(json()) + app.use(urlencoded({ extended: true })) + if (opts.logMethod) app.use((req, _, next) => { console.log(req.method, req.path); if (opts.logBody) console.log(req.body); next() }) + if (!opts.allowNotImplementedMethods && !methods.WizardState) throw new Error('method: WizardState is not implemented') + app.get('/wizard/state', async (req, res) => { + const info: Types.RequestInfo = { rpcName: 'WizardState', batch: false, nostr: false, batchSize: 0} + const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } + let authCtx: Types.AuthContext = {} + try { + if (!methods.WizardState) throw new Error('method: WizardState is not implemented') + const authContext = await opts.GuestAuthGuard(req.headers['authorization']) + authCtx = authContext + stats.guard = process.hrtime.bigint() + stats.validate = stats.guard + const query = req.query + const params = req.params + const response = await methods.WizardState({rpcName:'WizardState', ctx:authContext }) + stats.handle = process.hrtime.bigint() + res.json({status: 'OK', ...response}) + opts.metricsCallback([{ ...info, ...stats, ...authContext }]) + } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } + }) + if (!opts.allowNotImplementedMethods && !methods.WizardConfig) throw new Error('method: WizardConfig is not implemented') + app.post('/wizard/config', async (req, res) => { + const info: Types.RequestInfo = { rpcName: 'WizardConfig', batch: false, nostr: false, batchSize: 0} + const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } + let authCtx: Types.AuthContext = {} + try { + if (!methods.WizardConfig) throw new Error('method: WizardConfig is not implemented') + const authContext = await opts.GuestAuthGuard(req.headers['authorization']) + authCtx = authContext + stats.guard = process.hrtime.bigint() + const request = req.body + const error = Types.ConfigRequestValidate(request) + stats.validate = process.hrtime.bigint() + if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authContext }, opts.metricsCallback) + const query = req.query + const params = req.params + await methods.WizardConfig({rpcName:'WizardConfig', ctx:authContext , req: request}) + stats.handle = process.hrtime.bigint() + res.json({status: 'OK'}) + opts.metricsCallback([{ ...info, ...stats, ...authContext }]) + } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } + }) + if (!opts.allowNotImplementedMethods && !methods.GetAdminConnectInfo) throw new Error('method: GetAdminConnectInfo is not implemented') + app.get('/wizard/admin_connect_info', async (req, res) => { + const info: Types.RequestInfo = { rpcName: 'GetAdminConnectInfo', batch: false, nostr: false, batchSize: 0} + const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } + let authCtx: Types.AuthContext = {} + try { + if (!methods.GetAdminConnectInfo) throw new Error('method: GetAdminConnectInfo is not implemented') + const authContext = await opts.GuestAuthGuard(req.headers['authorization']) + authCtx = authContext + stats.guard = process.hrtime.bigint() + stats.validate = stats.guard + const query = req.query + const params = req.params + const response = await methods.GetAdminConnectInfo({rpcName:'GetAdminConnectInfo', ctx:authContext }) + stats.handle = process.hrtime.bigint() + res.json({status: 'OK', ...response}) + opts.metricsCallback([{ ...info, ...stats, ...authContext }]) + } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } + }) + if (!opts.allowNotImplementedMethods && !methods.GetServiceState) throw new Error('method: GetServiceState is not implemented') + app.get('/wizard/service_state', async (req, res) => { + const info: Types.RequestInfo = { rpcName: 'GetServiceState', batch: false, nostr: false, batchSize: 0} + const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } + let authCtx: Types.AuthContext = {} + try { + if (!methods.GetServiceState) throw new Error('method: GetServiceState is not implemented') + const authContext = await opts.GuestAuthGuard(req.headers['authorization']) + authCtx = authContext + stats.guard = process.hrtime.bigint() + stats.validate = stats.guard + const query = req.query + const params = req.params + const response = await methods.GetServiceState({rpcName:'GetServiceState', ctx:authContext }) + stats.handle = process.hrtime.bigint() + res.json({status: 'OK', ...response}) + opts.metricsCallback([{ ...info, ...stats, ...authContext }]) + } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } + }) + if (opts.staticFiles) { + app.use(express.static(opts.staticFiles)) + app.get('*', function (_, res) { res.sendFile('index.html', { root: opts.staticFiles })}) + } + var server: { close: () => void } | undefined + return { + Close: () => { if (!server) { throw new Error('tried closing server before starting') } else server.close() }, + Listen: (port: number) => { server = app.listen(port, () => logger.log('Wizard listening on port ' + port)) } + } +} diff --git a/proto/wizard_service/autogenerated/ts/http_client.ts b/proto/wizard_service/autogenerated/ts/http_client.ts new file mode 100644 index 00000000..8d949b84 --- /dev/null +++ b/proto/wizard_service/autogenerated/ts/http_client.ts @@ -0,0 +1,68 @@ +// This file was autogenerated from a .proto file, DO NOT EDIT! +import axios from 'axios' +import * as Types from './types.js' +export type ResultError = { status: 'ERROR', reason: string } + +export type ClientParams = { + baseUrl: string + retrieveGuestAuth: () => Promise + encryptCallback: (plain: any) => Promise + decryptCallback: (encrypted: any) => Promise + deviceId: string + checkResult?: true +} +export default (params: ClientParams) => ({ + WizardState: async (): Promise => { + const auth = await params.retrieveGuestAuth() + if (auth === null) throw new Error('retrieveGuestAuth() returned null') + let finalRoute = '/wizard/state' + const { data } = await axios.get(params.baseUrl + finalRoute, { headers: { 'authorization': auth } }) + if (data.status === 'ERROR' && typeof data.reason === 'string') return data + if (data.status === 'OK') { + const result = data + if(!params.checkResult) return { status: 'OK', ...result } + const error = Types.StateResponseValidate(result) + if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } + } + return { status: 'ERROR', reason: 'invalid response' } + }, + WizardConfig: async (request: Types.ConfigRequest): Promise => { + const auth = await params.retrieveGuestAuth() + if (auth === null) throw new Error('retrieveGuestAuth() returned null') + let finalRoute = '/wizard/config' + const { data } = await axios.post(params.baseUrl + finalRoute, request, { headers: { 'authorization': auth } }) + if (data.status === 'ERROR' && typeof data.reason === 'string') return data + if (data.status === 'OK') { + return data + } + return { status: 'ERROR', reason: 'invalid response' } + }, + GetAdminConnectInfo: async (): Promise => { + const auth = await params.retrieveGuestAuth() + if (auth === null) throw new Error('retrieveGuestAuth() returned null') + let finalRoute = '/wizard/admin_connect_info' + const { data } = await axios.get(params.baseUrl + finalRoute, { headers: { 'authorization': auth } }) + if (data.status === 'ERROR' && typeof data.reason === 'string') return data + if (data.status === 'OK') { + const result = data + if(!params.checkResult) return { status: 'OK', ...result } + const error = Types.AdminConnectInfoResponseValidate(result) + if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } + } + return { status: 'ERROR', reason: 'invalid response' } + }, + GetServiceState: async (): Promise => { + const auth = await params.retrieveGuestAuth() + if (auth === null) throw new Error('retrieveGuestAuth() returned null') + let finalRoute = '/wizard/service_state' + const { data } = await axios.get(params.baseUrl + finalRoute, { headers: { 'authorization': auth } }) + if (data.status === 'ERROR' && typeof data.reason === 'string') return data + if (data.status === 'OK') { + const result = data + if(!params.checkResult) return { status: 'OK', ...result } + const error = Types.ServiceStateResponseValidate(result) + if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } + } + return { status: 'ERROR', reason: 'invalid response' } + }, +}) diff --git a/proto/wizard_service/autogenerated/ts/nostr_client.ts b/proto/wizard_service/autogenerated/ts/nostr_client.ts new file mode 100644 index 00000000..2d7e666b --- /dev/null +++ b/proto/wizard_service/autogenerated/ts/nostr_client.ts @@ -0,0 +1,11 @@ +// This file was autogenerated from a .proto file, DO NOT EDIT! +import { NostrRequest } from './nostr_transport.js' +import * as Types from './types.js' +export type ResultError = { status: 'ERROR', reason: string } + +export type NostrClientParams = { + pubDestination: string + checkResult?: true +} +export default (params: NostrClientParams, send: (to:string, message: NostrRequest) => Promise, subscribe: (to:string, message: NostrRequest, cb:(res:any)=> void) => void) => ({ +}) diff --git a/proto/wizard_service/autogenerated/ts/nostr_transport.ts b/proto/wizard_service/autogenerated/ts/nostr_transport.ts new file mode 100644 index 00000000..85249e68 --- /dev/null +++ b/proto/wizard_service/autogenerated/ts/nostr_transport.ts @@ -0,0 +1,34 @@ +// This file was autogenerated from a .proto file, DO NOT EDIT! + +import * as Types from './types.js' +export type Logger = { log: (v: any) => void, error: (v: any) => void } +type NostrResponse = (message: object) => void +export type NostrRequest = { + rpcName?: string + params?: Record + query?: Record + body?: any + authIdentifier?: string + requestId?: string + appId?: string +} +export type NostrOptions = { + logger?: Logger + throwErrors?: true + metricsCallback: (metrics: Types.RequestMetric[]) => void +} +const logErrorAndReturnResponse = (error: Error, response: string, res: NostrResponse, logger: Logger, metric: Types.RequestMetric, metricsCallback: (metrics: Types.RequestMetric[]) => void) => { + logger.error(error.message || error); metricsCallback([{ ...metric, error: response }]); res({ status: 'ERROR', reason: response }) +} +export default (methods: Types.ServerMethods, opts: NostrOptions) => { + const logger = opts.logger || { log: console.log, error: console.error } + return async (req: NostrRequest, res: NostrResponse, startString: string, startMs: number) => { + const startTime = BigInt(startString) + const info: Types.RequestInfo = { rpcName: req.rpcName || 'unkown', batch: false, nostr: true, batchSize: 0 } + const stats: Types.RequestStats = { startMs, start: startTime, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } + let authCtx: Types.AuthContext = {} + switch (req.rpcName) { + default: logger.error('unknown rpc call name from nostr event:'+req.rpcName) + } + } +} diff --git a/proto/wizard_service/autogenerated/ts/types.ts b/proto/wizard_service/autogenerated/ts/types.ts new file mode 100644 index 00000000..43927811 --- /dev/null +++ b/proto/wizard_service/autogenerated/ts/types.ts @@ -0,0 +1,214 @@ +// This file was autogenerated from a .proto file, DO NOT EDIT! + +export type ResultError = { status: 'ERROR', reason: string } +export type RequestInfo = { rpcName: string, batch: boolean, nostr: boolean, batchSize: number } +export type RequestStats = { startMs:number, start:bigint, parse: bigint, guard: bigint, validate: bigint, handle: bigint } +export type RequestMetric = AuthContext & RequestInfo & RequestStats & { error?: string } +export type GuestContext = { +} +export type GuestMethodInputs = WizardState_Input | WizardConfig_Input | GetAdminConnectInfo_Input | GetServiceState_Input +export type GuestMethodOutputs = WizardState_Output | WizardConfig_Output | GetAdminConnectInfo_Output | GetServiceState_Output +export type AuthContext = GuestContext + +export type WizardState_Input = {rpcName:'WizardState'} +export type WizardState_Output = ResultError | ({ status: 'OK' } & StateResponse) + +export type WizardConfig_Input = {rpcName:'WizardConfig', req: ConfigRequest} +export type WizardConfig_Output = ResultError | { status: 'OK' } + +export type GetAdminConnectInfo_Input = {rpcName:'GetAdminConnectInfo'} +export type GetAdminConnectInfo_Output = ResultError | ({ status: 'OK' } & AdminConnectInfoResponse) + +export type GetServiceState_Input = {rpcName:'GetServiceState'} +export type GetServiceState_Output = ResultError | ({ status: 'OK' } & ServiceStateResponse) + +export type ServerMethods = { + WizardState?: (req: WizardState_Input & {ctx: GuestContext }) => Promise + WizardConfig?: (req: WizardConfig_Input & {ctx: GuestContext }) => Promise + GetAdminConnectInfo?: (req: GetAdminConnectInfo_Input & {ctx: GuestContext }) => Promise + GetServiceState?: (req: GetServiceState_Input & {ctx: GuestContext }) => Promise +} + +export enum LndState { + OFFLINE = 'OFFLINE', + SYNCING = 'SYNCING', + ONLINE = 'ONLINE', +} +export const enumCheckLndState = (e?: LndState): boolean => { + for (const v in LndState) if (e === v) return true + return false +} + +export type OptionsBaseMessage = { + allOptionalsAreSet?: true +} + +export type Empty = { +} +export const EmptyOptionalFields: [] = [] +export type EmptyOptions = OptionsBaseMessage & { + checkOptionalsAreSet?: [] +} +export const EmptyValidate = (o?: Empty, opts: EmptyOptions = {}, path: string = 'Empty::root.'): Error | null => { + if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') + if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') + + return null +} + +export type StateResponse = { + config_sent: boolean + admin_linked: boolean +} +export const StateResponseOptionalFields: [] = [] +export type StateResponseOptions = OptionsBaseMessage & { + checkOptionalsAreSet?: [] + config_sent_CustomCheck?: (v: boolean) => boolean + admin_linked_CustomCheck?: (v: boolean) => boolean +} +export const StateResponseValidate = (o?: StateResponse, opts: StateResponseOptions = {}, path: string = 'StateResponse::root.'): Error | null => { + if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') + if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') + + if (typeof o.config_sent !== 'boolean') return new Error(`${path}.config_sent: is not a boolean`) + if (opts.config_sent_CustomCheck && !opts.config_sent_CustomCheck(o.config_sent)) return new Error(`${path}.config_sent: custom check failed`) + + if (typeof o.admin_linked !== 'boolean') return new Error(`${path}.admin_linked: is not a boolean`) + if (opts.admin_linked_CustomCheck && !opts.admin_linked_CustomCheck(o.admin_linked)) return new Error(`${path}.admin_linked: custom check failed`) + + return null +} + +export type ConfigRequest = { + source_name: string + relay_url: string + automate_liquidity: boolean + push_backups_to_nostr: boolean +} +export const ConfigRequestOptionalFields: [] = [] +export type ConfigRequestOptions = OptionsBaseMessage & { + checkOptionalsAreSet?: [] + push_backups_to_nostr_CustomCheck?: (v: boolean) => boolean + source_name_CustomCheck?: (v: string) => boolean + relay_url_CustomCheck?: (v: string) => boolean + automate_liquidity_CustomCheck?: (v: boolean) => boolean +} +export const ConfigRequestValidate = (o?: ConfigRequest, opts: ConfigRequestOptions = {}, path: string = 'ConfigRequest::root.'): Error | null => { + if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') + if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') + + if (typeof o.source_name !== 'string') return new Error(`${path}.source_name: is not a string`) + if (opts.source_name_CustomCheck && !opts.source_name_CustomCheck(o.source_name)) return new Error(`${path}.source_name: custom check failed`) + + if (typeof o.relay_url !== 'string') return new Error(`${path}.relay_url: is not a string`) + if (opts.relay_url_CustomCheck && !opts.relay_url_CustomCheck(o.relay_url)) return new Error(`${path}.relay_url: custom check failed`) + + if (typeof o.automate_liquidity !== 'boolean') return new Error(`${path}.automate_liquidity: is not a boolean`) + if (opts.automate_liquidity_CustomCheck && !opts.automate_liquidity_CustomCheck(o.automate_liquidity)) return new Error(`${path}.automate_liquidity: custom check failed`) + + if (typeof o.push_backups_to_nostr !== 'boolean') return new Error(`${path}.push_backups_to_nostr: is not a boolean`) + if (opts.push_backups_to_nostr_CustomCheck && !opts.push_backups_to_nostr_CustomCheck(o.push_backups_to_nostr)) return new Error(`${path}.push_backups_to_nostr: custom check failed`) + + return null +} + +export type AdminConnectInfoResponse = { + nprofile: string + connect_info: AdminConnectInfoResponse_connect_info +} +export const AdminConnectInfoResponseOptionalFields: [] = [] +export type AdminConnectInfoResponseOptions = OptionsBaseMessage & { + checkOptionalsAreSet?: [] + nprofile_CustomCheck?: (v: string) => boolean + connect_info_CustomCheck?: (v: AdminConnectInfoResponse_connect_info) => boolean +} +export const AdminConnectInfoResponseValidate = (o?: AdminConnectInfoResponse, opts: AdminConnectInfoResponseOptions = {}, path: string = 'AdminConnectInfoResponse::root.'): Error | null => { + if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') + if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') + + if (typeof o.nprofile !== 'string') return new Error(`${path}.nprofile: is not a string`) + if (opts.nprofile_CustomCheck && !opts.nprofile_CustomCheck(o.nprofile)) return new Error(`${path}.nprofile: custom check failed`) + + const connect_infoErr = AdminConnectInfoResponse_connect_infoValidate(o.connect_info,{}, `${path}.connect_info`) + if (connect_infoErr !== null) return connect_infoErr + + + return null +} + +export type ServiceStateResponse = { + http_url: string + nprofile: string + provider_name: string + relays: string[] + admin_npub: string + relay_connected: boolean + lnd_state: LndState + watchdog_ok: boolean +} +export const ServiceStateResponseOptionalFields: [] = [] +export type ServiceStateResponseOptions = OptionsBaseMessage & { + checkOptionalsAreSet?: [] + http_url_CustomCheck?: (v: string) => boolean + nprofile_CustomCheck?: (v: string) => boolean + provider_name_CustomCheck?: (v: string) => boolean + relays_CustomCheck?: (v: string[]) => boolean + admin_npub_CustomCheck?: (v: string) => boolean + relay_connected_CustomCheck?: (v: boolean) => boolean + lnd_state_CustomCheck?: (v: LndState) => boolean + watchdog_ok_CustomCheck?: (v: boolean) => boolean +} +export const ServiceStateResponseValidate = (o?: ServiceStateResponse, opts: ServiceStateResponseOptions = {}, path: string = 'ServiceStateResponse::root.'): Error | null => { + if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') + if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') + + if (!Array.isArray(o.relays)) return new Error(`${path}.relays: is not an array`) + for (let index = 0; index < o.relays.length; index++) { + if (typeof o.relays[index] !== 'string') return new Error(`${path}.relays[${index}]: is not a string`) + } + if (opts.relays_CustomCheck && !opts.relays_CustomCheck(o.relays)) return new Error(`${path}.relays: custom check failed`) + + if (typeof o.admin_npub !== 'string') return new Error(`${path}.admin_npub: is not a string`) + if (opts.admin_npub_CustomCheck && !opts.admin_npub_CustomCheck(o.admin_npub)) return new Error(`${path}.admin_npub: custom check failed`) + + if (typeof o.relay_connected !== 'boolean') return new Error(`${path}.relay_connected: is not a boolean`) + if (opts.relay_connected_CustomCheck && !opts.relay_connected_CustomCheck(o.relay_connected)) return new Error(`${path}.relay_connected: custom check failed`) + + if (!enumCheckLndState(o.lnd_state)) return new Error(`${path}.lnd_state: is not a valid LndState`) + if (opts.lnd_state_CustomCheck && !opts.lnd_state_CustomCheck(o.lnd_state)) return new Error(`${path}.lnd_state: custom check failed`) + + if (typeof o.watchdog_ok !== 'boolean') return new Error(`${path}.watchdog_ok: is not a boolean`) + if (opts.watchdog_ok_CustomCheck && !opts.watchdog_ok_CustomCheck(o.watchdog_ok)) return new Error(`${path}.watchdog_ok: custom check failed`) + + if (typeof o.http_url !== 'string') return new Error(`${path}.http_url: is not a string`) + if (opts.http_url_CustomCheck && !opts.http_url_CustomCheck(o.http_url)) return new Error(`${path}.http_url: custom check failed`) + + if (typeof o.nprofile !== 'string') return new Error(`${path}.nprofile: is not a string`) + if (opts.nprofile_CustomCheck && !opts.nprofile_CustomCheck(o.nprofile)) return new Error(`${path}.nprofile: custom check failed`) + + if (typeof o.provider_name !== 'string') return new Error(`${path}.provider_name: is not a string`) + if (opts.provider_name_CustomCheck && !opts.provider_name_CustomCheck(o.provider_name)) return new Error(`${path}.provider_name: custom check failed`) + + return null +} + +export enum AdminConnectInfoResponse_connect_info_type { + ADMIN_TOKEN = 'admin_token', + ENROLLED_NPUB = 'enrolled_npub', +} +export type AdminConnectInfoResponse_connect_info = + {type:AdminConnectInfoResponse_connect_info_type.ADMIN_TOKEN, admin_token:string}| + {type:AdminConnectInfoResponse_connect_info_type.ENROLLED_NPUB, enrolled_npub:string} + +export const AdminConnectInfoResponse_connect_infoValidate = (o?: AdminConnectInfoResponse_connect_info, opts = {}, path: string = 'AdminConnectInfoResponse_connect_info::root.'): Error | null => { + if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') + switch (o.type) { + case 'admin_token': + if (typeof o.admin_token !== 'string') return new Error(`${path}.admin_token: is not a string`) + break + case 'enrolled_npub': + if (typeof o.enrolled_npub !== 'string') return new Error(`${path}.enrolled_npub: is not a string`) + break + } + return new Error(path + ': unknown type'+ o.type) +} diff --git a/scripts/check_homebrew.sh b/scripts/check_homebrew.sh new file mode 100755 index 00000000..fd58489e --- /dev/null +++ b/scripts/check_homebrew.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +check_homebrew() { + if ! command -v brew &> /dev/null; then + log "${PRIMARY_COLOR}Homebrew not found. Installing Homebrew...${RESET_COLOR}" + /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" || { + log "${PRIMARY_COLOR}Failed to install Homebrew.${RESET_COLOR}" + exit 1 + } + fi +} diff --git a/scripts/create_launchd_plist.sh b/scripts/create_launchd_plist.sh new file mode 100755 index 00000000..9964a1fe --- /dev/null +++ b/scripts/create_launchd_plist.sh @@ -0,0 +1,43 @@ +#!/bin/bash + +create_launchd_plist() { + create_plist() { + local plist_path=$1 + local label=$2 + local program_args=$3 + local working_dir=$4 + + if [ -f "$plist_path" ]; then + log "${PRIMARY_COLOR}${label} already exists. Skipping creation.${RESET_COLOR}" + else + cat < "$plist_path" + + + + + Label + ${label} + ProgramArguments + + ${program_args} + + WorkingDirectory + ${working_dir} + RunAtLoad + + KeepAlive + + + +EOF + fi + } + USER_HOME=$(eval echo ~$(whoami)) + NVM_DIR="$([ -z "${XDG_CONFIG_HOME-}" ] && printf %s "${USER_HOME}/.nvm" || printf %s "${XDG_CONFIG_HOME}/nvm")" + LAUNCH_AGENTS_DIR="${USER_HOME}/Library/LaunchAgents" + + create_plist "${LAUNCH_AGENTS_DIR}/local.lnd.plist" "local.lnd" "${USER_HOME}/lnd/lnd" "" + create_plist "${LAUNCH_AGENTS_DIR}/local.lightning_pub.plist" "local.lightning_pub" "/bin/bash-csource ${NVM_DIR}/nvm.sh && npm start" "${USER_HOME}/lightning_pub" + + log "${PRIMARY_COLOR}Created launchd plists. Please load them using launchctl.${RESET_COLOR}" +} diff --git a/scripts/extract_nprofile.sh b/scripts/extract_nprofile.sh new file mode 100644 index 00000000..57eb9f10 --- /dev/null +++ b/scripts/extract_nprofile.sh @@ -0,0 +1,80 @@ +#!/bin/bash + +get_log_info() { + if [ "$EUID" -eq 0 ]; then + USER_HOME=$(getent passwd ${SUDO_USER} | cut -d: -f6) + USER_NAME=$SUDO_USER + else + USER_HOME=$HOME + USER_NAME=$(whoami) + fi + + LOG_DIR="$USER_HOME/lightning_pub/logs" + MAX_ATTEMPTS=4 + ATTEMPT=0 + + find_latest_log() { + ls -1t ${LOG_DIR}/components/nostrMiddleware_*.log 2>/dev/null | head -n 1 + } + + TIMEOUT=180 + while [ ! -f ${LOG_DIR}/components/unlocker_*.log ] && [ $TIMEOUT -gt 0 ]; do + log "Waiting for build..." + sleep 10 + TIMEOUT=$((TIMEOUT - 10)) + done + if [ $TIMEOUT -le 0 ]; then + log "Timeout waiting for unlocker log file, make sure the system has adequate resources." + exit 1 + fi + + TIMEOUT=45 + while [ $TIMEOUT -gt 0 ]; do + if grep -q -e "unlocker >> macaroon not found, creating wallet..." -e "unlocker >> the wallet is already unlocked" -e "unlocker >> wallet is locked, unlocking" ${LOG_DIR}/components/unlocker_*.log; then + break + fi + sleep 1 + TIMEOUT=$((TIMEOUT - 1)) + done + if [ $TIMEOUT -le 0 ]; then + log "Timeout waiting for wallet status message." + exit 1 + fi + + latest_unlocker_log=$(ls -1t ${LOG_DIR}/components/unlocker_*.log 2>/dev/null | head -n 1) + + latest_entry=$(grep -E "unlocker >> macaroon not found, creating wallet|unlocker >> wallet is locked, unlocking|unlocker >> the wallet is already unlocked" "$latest_unlocker_log" | tail -n 1) + + if echo "$latest_entry" | grep -q "unlocker >> macaroon not found, creating wallet"; then + log "Creating wallet..." + elif echo "$latest_entry" | grep -q "unlocker >> wallet is locked, unlocking"; then + log "Unlocking wallet..." + else + log "Wallet is already unlocked." + fi + + while [ $ATTEMPT -lt $MAX_ATTEMPTS ]; do + LATEST_LOG=$(find_latest_log) + if [ -n "$LATEST_LOG" ]; then + break + fi + log "Awaiting connection details..." + sleep 4 + ATTEMPT=$((ATTEMPT + 1)) + done + + if [ -z "$LATEST_LOG" ]; then + log "Failed to find the log file, check service status" + exit 1 + fi + + LATEST_LOG=$(find_latest_log) + latest_nprofile_key=$(grep -oP 'nprofile: \K\w+' "$LATEST_LOG" | tail -n 1) + + if [ -z "$latest_nprofile_key" ]; then + log "There was a problem fetching the connection details." + exit 1 + fi + + log "Paste this string into ShockWallet to connect to the node: $latest_nprofile_key" +} \ No newline at end of file diff --git a/scripts/install.sh b/scripts/install.sh new file mode 100755 index 00000000..246ad988 --- /dev/null +++ b/scripts/install.sh @@ -0,0 +1,44 @@ +#!/bin/bash +set -e + +BASE_URL="https://bolt12.info/deploy/" +modules=( + "utils" + "check_homebrew" + "install_rsync_mac" + "create_launchd_plist" + "start_services_mac" + "install_lnd" + "install_nodejs" + "install_lightning_pub" + "start_services" + "extract_nprofile" +) + +for module in "${modules[@]}"; do + wget -q "${BASE_URL}/${module}.sh" -O "/tmp/${module}.sh" + source "/tmp/${module}.sh" +done + +# Upgrade flag +SKIP_PROMPT=false +for arg in "$@"; do + case $arg in + --yes) + SKIP_PROMPT=true + shift + ;; + esac +done + +detect_os_arch + +if [ "$OS" = "Mac" ]; then + handle_macos +else + install_lnd + install_nodejs + install_lightning_pub + start_services + get_log_info +fi \ No newline at end of file diff --git a/scripts/install_lightning_pub.sh b/scripts/install_lightning_pub.sh new file mode 100755 index 00000000..c82be736 --- /dev/null +++ b/scripts/install_lightning_pub.sh @@ -0,0 +1,65 @@ +#!/bin/bash + +install_lightning_pub() { + if [ "$EUID" -eq 0 ]; then + USER_HOME=$(getent passwd ${SUDO_USER} | cut -d: -f6) + USER_NAME=$SUDO_USER + else + USER_HOME=$HOME + USER_NAME=$(whoami) + fi + + log "${PRIMARY_COLOR}Installing${RESET_COLOR} ${SECONDARY_COLOR}Lightning.Pub${RESET_COLOR}..." + REPO_URL="https://github.com/shocknet/Lightning.Pub/tarball/fix/bootstrap" + + sudo -u $USER_NAME wget $REPO_URL -O $USER_HOME/lightning_pub.tar.gz > /dev/null 2>&1 || { + log "${PRIMARY_COLOR}Failed to download Lightning.Pub.${RESET_COLOR}" + exit 1 + } + + sudo -u $USER_NAME mkdir -p $USER_HOME/lightning_pub_temp + sudo -u $USER_NAME tar -xvzf $USER_HOME/lightning_pub.tar.gz -C $USER_HOME/lightning_pub_temp --strip-components=1 > /dev/null 2>&1 || { + log "${PRIMARY_COLOR}Failed to extract Lightning.Pub.${RESET_COLOR}" + exit 1 + } + rm $USER_HOME/lightning_pub.tar.gz + + if ! command -v rsync &> /dev/null; then + log "${PRIMARY_COLOR}rsync not found, installing...${RESET_COLOR}" + if [ "$OS" = "Mac" ]; then + brew install rsync + elif [ "$OS" = "Linux" ]; then + if [ -x "$(command -v apt-get)" ]; then + sudo apt-get update > /dev/null 2>&1 + sudo apt-get install -y rsync > /dev/null 2>&1 + elif [ -x "$(command -v yum)" ]; then + sudo yum install -y rsync > /dev/null 2>&1 + else + log "${PRIMARY_COLOR}Package manager not found. Please install rsync manually.${RESET_COLOR}" + exit 1 + fi + else + log "${PRIMARY_COLOR}Package manager not found. Please install rsync manually.${RESET_COLOR}" + exit 1 + fi + fi + + # Merge if upgrade + rsync -av --exclude='*.sqlite' --exclude='.env' --exclude='logs' --exclude='node_modules' lightning_pub_temp/ lightning_pub/ > /dev/null 2>&1 + rm -rf lightning_pub_temp + + # Load nvm and npm + export NVM_DIR="${NVM_DIR}" + [ -s "${NVM_DIR}/nvm.sh" ] && \. "${NVM_DIR}/nvm.sh" + + cd lightning_pub + + log "${PRIMARY_COLOR}Installing${RESET_COLOR} npm dependencies..." + + npm install > npm_install.log 2>&1 || { + log "${PRIMARY_COLOR}Failed to install npm dependencies.${RESET_COLOR}" + exit 1 + } + + log "${SECONDARY_COLOR}Lightning.Pub${RESET_COLOR} installation completed." +} \ No newline at end of file diff --git a/scripts/install_lnd.sh b/scripts/install_lnd.sh new file mode 100755 index 00000000..ac057318 --- /dev/null +++ b/scripts/install_lnd.sh @@ -0,0 +1,80 @@ +#!/bin/bash + +install_lnd() { + if [ "$EUID" -eq 0 ]; then + USER_HOME=$(getent passwd ${SUDO_USER} | cut -d: -f6) + USER_NAME=$SUDO_USER + else + USER_HOME=$HOME + USER_NAME=$(whoami) + fi + + LND_VERSION=$(wget -qO- https://api.github.com/repos/lightningnetwork/lnd/releases/latest | grep -oP '"tag_name": "\K(.*)(?=")') + LND_URL="https://github.com/lightningnetwork/lnd/releases/download/${LND_VERSION}/lnd-${OS}-${ARCH}-${LND_VERSION}.tar.gz" + + # Check if LND is already installed + if [ -d "$USER_HOME/lnd" ]; then + CURRENT_VERSION=$("$USER_HOME/lnd/lnd" --version | grep -oP 'version \K[^\s]+') + if [ "$CURRENT_VERSION" == "${LND_VERSION#v}" ]; then + log "${SECONDARY_COLOR}LND${RESET_COLOR} is already up-to-date (version $CURRENT_VERSION)." + return + else + if [ "$SKIP_PROMPT" != true ]; then + read -p "LND version $CURRENT_VERSION is installed. Do you want to upgrade to version $LND_VERSION? (y/N): " response + case "$response" in + [yY][eE][sS]|[yY]) + log "${PRIMARY_COLOR}Upgrading${RESET_COLOR} ${SECONDARY_COLOR}LND${RESET_COLOR} from version $CURRENT_VERSION to $LND_VERSION..." + ;; + *) + log "$(date '+%Y-%m-%d %H:%M:%S') Upgrade cancelled." + return + ;; + esac + else + log "${PRIMARY_COLOR}Upgrading${RESET_COLOR} ${SECONDARY_COLOR}LND${RESET_COLOR} from version $CURRENT_VERSION to $LND_VERSION..." + fi + fi + fi + + log "${PRIMARY_COLOR}Downloading${RESET_COLOR} ${SECONDARY_COLOR}LND${RESET_COLOR}..." + + # Start the download + sudo -u $USER_NAME wget -q $LND_URL -O $USER_HOME/lnd.tar.gz || { + log "${PRIMARY_COLOR}Failed to download LND.${RESET_COLOR}" + exit 1 + } + + # Check if LND is already running and stop it if necessary (Linux) + if [ "$OS" = "Linux" ] && [ "$SYSTEMCTL_AVAILABLE" = true ]; then + if systemctl is-active --quiet lnd; then + log "${PRIMARY_COLOR}Stopping${RESET_COLOR} ${SECONDARY_COLOR}LND${RESET_COLOR} service..." + sudo systemctl stop lnd + fi + else + log "${PRIMARY_COLOR}systemctl not found. Please stop ${SECONDARY_COLOR}LND${RESET_COLOR} manually if it is running.${RESET_COLOR}" + fi + + sudo -u $USER_NAME tar -xzf $USER_HOME/lnd.tar.gz -C $USER_HOME > /dev/null || { + log "${PRIMARY_COLOR}Failed to extract LND.${RESET_COLOR}" + exit 1 + } + rm $USER_HOME/lnd.tar.gz + sudo -u $USER_NAME mv $USER_HOME/lnd-* $USER_HOME/lnd + + # Create .lnd directory if it doesn't exist + sudo -u $USER_NAME mkdir -p $USER_HOME/.lnd + + # Check if lnd.conf already exists and avoid overwriting it + if [ -f $USER_HOME/.lnd/lnd.conf ]; then + log "${PRIMARY_COLOR}lnd.conf already exists. Skipping creation of new lnd.conf file.${RESET_COLOR}" + else + sudo -u $USER_NAME bash -c "cat < $USER_HOME/.lnd/lnd.conf +bitcoin.mainnet=true +bitcoin.node=neutrino +neutrino.addpeer=neutrino.shock.network +feeurl=https://nodes.lightning.computer/fees/v1/btc-fee-estimates.json +EOF" + fi + + log "${SECONDARY_COLOR}LND${RESET_COLOR} installation and configuration completed." +} \ No newline at end of file diff --git a/scripts/install_nodejs.sh b/scripts/install_nodejs.sh new file mode 100755 index 00000000..b4053854 --- /dev/null +++ b/scripts/install_nodejs.sh @@ -0,0 +1,45 @@ +#!/bin/bash + +install_nodejs() { + if [ "$EUID" -eq 0 ] && [ -n "$SUDO_USER" ]; then + USER_HOME=$(getent passwd ${SUDO_USER} | cut -d: -f6) + USER_NAME=${SUDO_USER} + else + USER_HOME=$HOME + USER_NAME=$(whoami) + fi + + NVM_DIR="$USER_HOME/.nvm" + log "${PRIMARY_COLOR}Checking${RESET_COLOR} for Node.js..." + MINIMUM_VERSION="18.0.0" + + # Load nvm if it already exists + export NVM_DIR="${NVM_DIR}" + [ -s "${NVM_DIR}/nvm.sh" ] && \. "${NVM_DIR}/nvm.sh" + + if ! command -v nvm &> /dev/null; then + NVM_VERSION=$(wget -qO- https://api.github.com/repos/nvm-sh/nvm/releases/latest | grep -oP '"tag_name": "\K(.*)(?=")') + sudo -u $USER_NAME bash -c "wget -qO- https://raw.githubusercontent.com/nvm-sh/nvm/${NVM_VERSION}/install.sh | bash > /dev/null 2>&1" + export NVM_DIR="${NVM_DIR}" + [ -s "${NVM_DIR}/nvm.sh" ] && \. "${NVM_DIR}/nvm.sh" + fi + + if command -v node &> /dev/null; then + NODE_VERSION=$(node -v | sed 's/v//') + if [ "$(printf '%s\n' "$MINIMUM_VERSION" "$NODE_VERSION" | sort -V | head -n1)" = "$MINIMUM_VERSION" ]; then + log "Node.js is already installed and meets the minimum version requirement." + return + else + log "${PRIMARY_COLOR}Updating${RESET_COLOR} Node.js to the LTS version..." + fi + else + log "Node.js is not installed. ${PRIMARY_COLOR}Installing the LTS version...${RESET_COLOR}" + fi + + sudo -u $USER_NAME bash -c "source ${NVM_DIR}/nvm.sh && nvm install --lts" || { + log "${PRIMARY_COLOR}Failed to install Node.js.${RESET_COLOR}" + exit 1 + } + + log "Node.js LTS installation completed." +} \ No newline at end of file diff --git a/scripts/install_rsync_mac.sh b/scripts/install_rsync_mac.sh new file mode 100755 index 00000000..f1973a76 --- /dev/null +++ b/scripts/install_rsync_mac.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +install_rsync_mac() { + check_homebrew + log "${PRIMARY_COLOR}Installing${RESET_COLOR} rsync using Homebrew..." + brew install rsync || { + log "${PRIMARY_COLOR}Failed to install rsync.${RESET_COLOR}" + exit 1 + } +} diff --git a/scripts/start_services.sh b/scripts/start_services.sh new file mode 100755 index 00000000..d73cb968 --- /dev/null +++ b/scripts/start_services.sh @@ -0,0 +1,100 @@ +#!/bin/bash + +start_services() { + if [ "$EUID" -eq 0 ]; then + USER_HOME=$(getent passwd ${SUDO_USER} | cut -d: -f6) + USER_NAME=$SUDO_USER + else + USER_HOME=$HOME + USER_NAME=$(whoami) + fi + + if [ "$OS" = "Linux" ]; then + if [ "$SYSTEMCTL_AVAILABLE" = true ]; then + sudo bash -c "cat > /etc/systemd/system/lnd.service < /etc/systemd/system/lightning_pub.service </dev/null 2>&1 + sudo systemctl enable lightning_pub >/dev/null 2>&1 + + log "${PRIMARY_COLOR}Starting${RESET_COLOR} ${SECONDARY_COLOR}LND${RESET_COLOR} service..." + sudo systemctl start lnd & + lnd_pid=$! + wait $lnd_pid + if systemctl is-active --quiet lnd; then + log "${SECONDARY_COLOR}LND${RESET_COLOR} started successfully using systemd." + else + log "Failed to start ${SECONDARY_COLOR}LND${RESET_COLOR} using systemd." + exit 1 + fi + + log "Giving ${SECONDARY_COLOR}LND${RESET_COLOR} a few seconds to start before starting ${SECONDARY_COLOR}Lightning.Pub${RESET_COLOR}..." + sleep 10 + + log "${PRIMARY_COLOR}Starting${RESET_COLOR} ${SECONDARY_COLOR}Lightning.Pub${RESET_COLOR} service..." + sudo systemctl start lightning_pub & + lightning_pub_pid=$! + wait $lightning_pub_pid + if systemctl is-active --quiet lightning_pub; then + log "${SECONDARY_COLOR}Lightning.Pub${RESET_COLOR} started successfully using systemd." + else + log "Failed to start ${SECONDARY_COLOR}Lightning.Pub${RESET_COLOR} using systemd." + exit 1 + fi + else + create_start_script + log "systemctl not available. Created start.sh. Please use this script to start the services manually." + fi + elif [ "$OS" = "Mac" ]; then + log "macOS detected. Please configure launchd manually to start ${SECONDARY_COLOR}LND${RESET_COLOR} and ${SECONDARY_COLOR}Lightning.Pub${RESET_COLOR} at startup." + create_start_script + elif [ "$OS" = "Cygwin" ] || [ "$OS" = "MinGw" ]; then + log "Windows detected. Please configure your startup scripts manually to start ${SECONDARY_COLOR}LND${RESET_COLOR} and ${SECONDARY_COLOR}Lightning.Pub${RESET_COLOR} at startup." + create_start_script + else + log "Unsupported OS detected. Please configure your startup scripts manually." + create_start_script + fi +} + +create_start_script() { + cat < start.sh +#!/bin/bash +${USER_HOME}/lnd/lnd & +LND_PID=\$! +sleep 10 +npm start & +NODE_PID=\$! +wait \$LND_PID +wait \$NODE_PID +EOF + chmod +x start.sh + log "systemctl not available. Created start.sh. Please use this script to start the services manually." +} \ No newline at end of file diff --git a/scripts/start_services_mac.sh b/scripts/start_services_mac.sh new file mode 100755 index 00000000..81f817c1 --- /dev/null +++ b/scripts/start_services_mac.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +start_services_mac() { + create_launchd_plist + launchctl load "${LAUNCH_AGENTS_DIR}/local.lnd.plist" + launchctl load "${LAUNCH_AGENTS_DIR}/local.lightning_pub.plist" + log "${SECONDARY_COLOR}LND${RESET_COLOR} and ${SECONDARY_COLOR}Lightning.Pub${RESET_COLOR} services started using launchd." +} + +handle_macos() { + check_homebrew + install_rsync_mac + install_nodejs + install_lightning_pub + create_launchd_plist + start_services_mac +} diff --git a/scripts/utils.sh b/scripts/utils.sh new file mode 100755 index 00000000..bee666e2 --- /dev/null +++ b/scripts/utils.sh @@ -0,0 +1,40 @@ +#!/bin/bash + +PRIMARY_COLOR="\e[38;5;208m" +SECONDARY_COLOR="\e[38;5;165m" +RESET_COLOR="\e[0m" +LOG_FILE="/var/log/pubdeploy.log" + +touch $LOG_FILE +chmod 644 $LOG_FILE + +log() { + local message="$(date '+%Y-%m-%d %H:%M:%S') $1" + if [ -t 1 ]; then + echo -e "$message" + fi + echo -e "$(echo $message | sed 's/\\e\[[0-9;]*m//g')" >> $LOG_FILE +} + +detect_os_arch() { + OS="$(uname -s)" + ARCH="$(uname -m)" + case "$OS" in + Linux*) OS=Linux;; + Darwin*) OS=Mac;; + CYGWIN*) OS=Cygwin;; + MINGW*) OS=MinGw;; + *) OS="UNKNOWN" + esac + case "$ARCH" in + x86_64) ARCH=amd64;; + arm64) ARCH=arm64;; + *) ARCH="UNKNOWN" + esac + + if [ "$OS" = "Linux" ] && command -v systemctl &> /dev/null; then + SYSTEMCTL_AVAILABLE=true + else + SYSTEMCTL_AVAILABLE=false + fi +} diff --git a/src/auth.ts b/src/auth.ts index 492526ab..b5fa93dd 100644 --- a/src/auth.ts +++ b/src/auth.ts @@ -1,5 +1,5 @@ import express from 'express'; -import path from 'path'; + import { ServerOptions } from "../proto/autogenerated/ts/express_server"; import { AdminContext, MetricsContext } from "../proto/autogenerated/ts/types"; import Main from './services/main' @@ -8,7 +8,6 @@ const serverOptions = (mainHandler: Main): ServerOptions => { const log = getLogger({}) return { logger: { log, error: err => log(ERROR, err) }, - staticFiles: path.resolve('static'), AdminAuthGuard: adminAuth, MetricsAuthGuard: metricsAuth, AppAuthGuard: async (authHeader) => { return { app_id: mainHandler.applicationManager.DecodeAppToken(stripBearer(authHeader)) } }, diff --git a/src/index.ts b/src/index.ts index 9a248900..d5f30bdb 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,31 +1,37 @@ -import 'dotenv/config' -import NewServer from '../proto/autogenerated/ts/express_server.js' -import GetServerMethods from './services/serverMethods/index.js' -import serverOptions from './auth.js'; -import { LoadNosrtSettingsFromEnv } from './services/nostr/index.js' -import nostrMiddleware from './nostrMiddleware.js' -import { getLogger } from './services/helpers/logger.js'; -import { initMainHandler } from './services/main/init.js'; -import { LoadMainSettingsFromEnv } from './services/main/settings.js'; - -const start = async () => { - const log = getLogger({}) - const mainSettings = LoadMainSettingsFromEnv() - const keepOn = await initMainHandler(log, mainSettings) - if (!keepOn) { - log("manual process ended") - return - } - const { apps, mainHandler, liquidityProviderInfo } = keepOn - const serverMethods = GetServerMethods(mainHandler) - const nostrSettings = LoadNosrtSettingsFromEnv() - const { Send } = nostrMiddleware(serverMethods, mainHandler, - { ...nostrSettings, apps, clients: [liquidityProviderInfo] }, - (e, p) => mainHandler.liquidProvider.onEvent(e, p) - ) - mainHandler.attachNostrSend(Send) - mainHandler.StartBeacons() - const Server = NewServer(serverMethods, serverOptions(mainHandler)) - Server.Listen(mainSettings.servicePort) -} -start() +import 'dotenv/config' +import NewServer from '../proto/autogenerated/ts/express_server.js' +import GetServerMethods from './services/serverMethods/index.js' +import serverOptions from './auth.js'; +import { LoadNosrtSettingsFromEnv } from './services/nostr/index.js' +import nostrMiddleware from './nostrMiddleware.js' +import { getLogger } from './services/helpers/logger.js'; +import { initMainHandler } from './services/main/init.js'; +import { LoadMainSettingsFromEnv } from './services/main/settings.js'; +import { encodeNprofile } from './custom-nip19.js'; + +const start = async () => { + const log = getLogger({}) + const mainSettings = LoadMainSettingsFromEnv() + const keepOn = await initMainHandler(log, mainSettings) + if (!keepOn) { + log("manual process ended") + return + } + const { apps, mainHandler, liquidityProviderInfo, wizard } = keepOn + const serverMethods = GetServerMethods(mainHandler) + const nostrSettings = LoadNosrtSettingsFromEnv() + log("initializing nostr middleware") + const { Send } = nostrMiddleware(serverMethods, mainHandler, + { ...nostrSettings, apps, clients: [liquidityProviderInfo] }, + (e, p) => mainHandler.liquidityProvider.onEvent(e, p) + ) + log("starting server") + mainHandler.attachNostrSend(Send) + mainHandler.StartBeacons() + if (wizard) { + wizard.AddConnectInfo(encodeNprofile({ pubkey: liquidityProviderInfo.publicKey, relays: nostrSettings.relays }), nostrSettings.relays) + } + const Server = NewServer(serverMethods, serverOptions(mainHandler)) + Server.Listen(mainSettings.servicePort) +} +start() diff --git a/src/nostrMiddleware.ts b/src/nostrMiddleware.ts index a8d6e82c..021266ef 100644 --- a/src/nostrMiddleware.ts +++ b/src/nostrMiddleware.ts @@ -13,6 +13,20 @@ export default (serverMethods: Types.ServerMethods, mainHandler: Main, nostrSett const nostrUser = await mainHandler.storage.applicationStorage.GetOrCreateNostrAppUser(app, pub || "") return { user_id: nostrUser.user.user_id, app_user_id: nostrUser.identifier, app_id: appId || "" } }, + NostrAdminAuthGuard: async (appId, pub) => { + const adminNpub = mainHandler.adminManager.GetAdminNpub() + if (!adminNpub) { throw new Error("admin access not configured") } + if (pub !== adminNpub) { throw new Error("admin access denied") } + log("admin access from", pub) + return { admin_id: pub } + }, + NostrMetricsAuthGuard: async (appId, pub) => { + const adminNpub = mainHandler.adminManager.GetAdminNpub() + if (!adminNpub) { throw new Error("admin access not configured") } + if (pub !== adminNpub) { throw new Error("admin access denied") } + log("operator access from", pub) + return { operator_id: pub } + }, metricsCallback: metrics => mainHandler.settings.recordPerformance ? mainHandler.metricsManager.AddMetrics(metrics) : null, logger: { log: console.log, error: err => log(ERROR, err) } }) @@ -20,7 +34,7 @@ export default (serverMethods: Types.ServerMethods, mainHandler: Main, nostrSett let j: NostrRequest try { j = JSON.parse(event.content) - log("nostr event", j.rpcName || 'no rpc name') + //log("nostr event", j.rpcName || 'no rpc name') } catch { log(ERROR, "invalid json event received", event.content) return diff --git a/src/services/helpers/logger.ts b/src/services/helpers/logger.ts index 83d73785..b4cffc73 100644 --- a/src/services/helpers/logger.ts +++ b/src/services/helpers/logger.ts @@ -1,105 +1,114 @@ -import fs from 'fs' -export const DEBUG = Symbol("DEBUG") -export const ERROR = Symbol("ERROR") -export const WARN = Symbol("WARN") -type LoggerParams = { appName?: string, userId?: string, component?: string } -export type PubLogger = (...message: (string | number | object | symbol)[]) => void -type Writer = (message: string) => void -const logsDir = process.env.LOGS_DIR || "logs" -const logLevel = process.env.LOG_LEVEL || "DEBUG" -try { - fs.mkdirSync(logsDir) -} catch { } -if (logLevel !== "DEBUG" && logLevel !== "WARN" && logLevel !== "ERROR") { - throw new Error("Invalid log level " + logLevel + " must be one of (DEBUG, WARN, ERROR)") -} -const z = (n: number) => n < 10 ? `0${n}` : `${n}` -const openWriter = (fileName: string): Writer => { - const now = new Date() - const date = `${now.getFullYear()}-${z(now.getMonth() + 1)}-${z(now.getDate())}` - const logStream = fs.createWriteStream(`${logsDir}/${fileName}_${date}.log`, { flags: 'a' }); - return (message) => { - logStream.write(message + "\n") - } -} -const rootWriter = openWriter("ROOT.log") -if (!fs.existsSync(`${logsDir}/apps`)) { - fs.mkdirSync(`${logsDir}/apps`, { recursive: true }); -} -if (!fs.existsSync(`${logsDir}/users`)) { - fs.mkdirSync(`${logsDir}/users`, { recursive: true }); -} -if (!fs.existsSync(`${logsDir}/components`)) { - fs.mkdirSync(`${logsDir}/components`, { recursive: true }); -} -export const getLogger = (params: LoggerParams): PubLogger => { - const writers: Writer[] = [] - if (params.appName) { - writers.push(openWriter(`apps/${params.appName}`)) - } - if (params.userId) { - writers.push(openWriter(`users/${params.userId}`)) - } - if (params.component) { - writers.push(openWriter(`components/${params.component}`)) - } - if (writers.length === 0) { - writers.push(rootWriter) - } - - return (...message) => { - switch (message[0]) { - case DEBUG: - if (logLevel !== "DEBUG") { - return - } - message[0] = "DEBUG" - break; - case WARN: - if (logLevel === "ERROR") { - return - } - message[0] = "WARN" - break; - case ERROR: - message[0] = "ERROR" - break; - default: - if (logLevel !== "DEBUG") { - return - } - } - const now = new Date() - const timestamp = `${now.getFullYear()}-${z(now.getMonth() + 1)}-${z(now.getDate())} ${z(now.getHours())}:${z(now.getMinutes())}:${z(now.getSeconds())}` - const toLog = [timestamp] - if (params.appName) { - if (disabledApps.includes(params.appName)) { - return - } - toLog.push(params.appName) - } - if (params.component) { - if (disabledComponents.includes(params.component)) { - return - } - toLog.push(params.component) - } - if (params.userId) { - toLog.push(params.userId) - } - const parsed = message.map(m => typeof m === 'object' ? JSON.stringify(m, (_, v) => typeof v === 'bigint' ? v.toString() : v) : m) - const final = `${toLog.join(" ")} >> ${parsed.join(" ")}` - console.log(final) - writers.forEach(w => w(final)) - } -} -let disabledApps: string[] = [] -let disabledComponents: string[] = [] -export const resetDisabledLoggers = () => { - disabledApps = [] - disabledComponents = [] -} -export const disableLoggers = (appNamesToDisable: string[], componentsToDisable: string[]) => { - disabledApps.push(...appNamesToDisable) - disabledComponents.push(...componentsToDisable) -} \ No newline at end of file +import fs from 'fs' +export const DEBUG = Symbol("DEBUG") +export const ERROR = Symbol("ERROR") +export const WARN = Symbol("WARN") +type LoggerParams = { appName?: string, userId?: string, component?: string } +export type PubLogger = (...message: (string | number | object | symbol)[]) => void +type Writer = (message: string) => void +const logsDir = process.env.LOGS_DIR || "logs" +const logLevel = process.env.LOG_LEVEL || "DEBUG" +try { + fs.mkdirSync(logsDir) +} catch { } +if (logLevel !== "DEBUG" && logLevel !== "WARN" && logLevel !== "ERROR") { + throw new Error("Invalid log level " + logLevel + " must be one of (DEBUG, WARN, ERROR)") +} +const z = (n: number) => n < 10 ? `0${n}` : `${n}` +const openWriter = (fileName: string): Writer => { + const now = new Date() + const date = `${now.getFullYear()}-${z(now.getMonth() + 1)}-${z(now.getDate())}` + const logStream = fs.createWriteStream(`${logsDir}/${fileName}_${date}.log`, { flags: 'a' }); + return (message) => { + logStream.write(message + "\n") + } +} +const rootWriter = openWriter("ROOT.log") +if (!fs.existsSync(`${logsDir}/apps`)) { + fs.mkdirSync(`${logsDir}/apps`, { recursive: true }); +} +if (!fs.existsSync(`${logsDir}/users`)) { + fs.mkdirSync(`${logsDir}/users`, { recursive: true }); +} +if (!fs.existsSync(`${logsDir}/components`)) { + fs.mkdirSync(`${logsDir}/components`, { recursive: true }); +} +export const getLogger = (params: LoggerParams): PubLogger => { + const writers: Writer[] = [] + if (params.appName) { + writers.push(openWriter(`apps/${params.appName}`)) + } + if (params.userId) { + writers.push(openWriter(`users/${params.userId}`)) + } + if (params.component) { + writers.push(openWriter(`components/${params.component}`)) + } + if (writers.length === 0) { + writers.push(rootWriter) + } + + return (...message) => { + switch (message[0]) { + case DEBUG: + if (logLevel !== "DEBUG") { + return + } + message[0] = "DEBUG" + break; + case WARN: + if (logLevel === "ERROR") { + return + } + message[0] = "WARN" + break; + case ERROR: + message[0] = "ERROR" + break; + default: + if (logLevel !== "DEBUG") { + return + } + } + const now = new Date() + const timestamp = `${now.getFullYear()}-${z(now.getMonth() + 1)}-${z(now.getDate())} ${z(now.getHours())}:${z(now.getMinutes())}:${z(now.getSeconds())}` + const toLog = [timestamp] + if (params.appName) { + if (disabledApps.includes(params.appName)) { + return + } + toLog.push(params.appName) + } + if (params.component) { + if (disabledComponents.includes(params.component)) { + return + } + toLog.push(params.component) + } + if (params.userId) { + toLog.push(params.userId) + } + const parsed = message.map(m => typeof m === 'object' ? JSON.stringify(m, (_, v) => typeof v === 'bigint' ? v.toString() : v) : m) + const final = `${toLog.join(" ")} >> ${parsed.join(" ")}` + console.log(final) + writers.forEach(w => w(final)) + } +} +let disabledApps: string[] = [] +let disabledComponents: string[] = [] +export const resetDisabledLoggers = () => { + disabledApps = [] + disabledComponents = [] +} +export const disableLoggers = (appNamesToDisable: string[], componentsToDisable: string[]) => { + disabledApps.push(...appNamesToDisable) + disabledComponents.push(...componentsToDisable) +} +const disableFromEnv = () => { + const disabledApps = process.env.HIDE_LOGS + if (disabledApps) { + const loggers = disabledApps.split(" ") + resetDisabledLoggers() + disableLoggers(loggers, loggers) + } +} +disableFromEnv() diff --git a/src/services/helpers/utilsWrapper.ts b/src/services/helpers/utilsWrapper.ts new file mode 100644 index 00000000..f00626e0 --- /dev/null +++ b/src/services/helpers/utilsWrapper.ts @@ -0,0 +1,11 @@ +import { MainSettings } from "../main/settings.js"; +import { StateBundler } from "../storage/stateBundler.js"; + +export class Utils { + stateBundler: StateBundler + settings: MainSettings + constructor(settings: MainSettings) { + this.settings = settings + this.stateBundler = new StateBundler() + } +} \ No newline at end of file diff --git a/src/services/lnd/index.ts b/src/services/lnd/index.ts index 0d671ef6..2525503c 100644 --- a/src/services/lnd/index.ts +++ b/src/services/lnd/index.ts @@ -4,18 +4,22 @@ import os from 'os' import path from 'path' const resolveHome = (filepath: string) => { - if (filepath[0] === '~') { - return path.join(os.homedir(), filepath.slice(1)) + let homeDir; + if (process.env.SUDO_USER) { + homeDir = path.join('/home', process.env.SUDO_USER); + } else { + homeDir = os.homedir(); } - return filepath + return path.join(homeDir, filepath); } export const LoadLndSettingsFromEnv = (): LndSettings => { - const lndAddr = process.env.LND_ADDRESS || "127.0.0.1:10009" - const lndCertPath = process.env.LND_CERT_PATH || resolveHome("~/.lnd/tls.cert") - const lndMacaroonPath = process.env.LND_MACAROON_PATH || resolveHome("~/.lnd/data/chain/bitcoin/mainnet/admin.macaroon") - const feeRateLimit = EnvCanBeInteger("OUTBOUND_MAX_FEE_BPS", 60) / 10000 - const feeFixedLimit = EnvCanBeInteger("OUTBOUND_MAX_FEE_EXTRA_SATS", 100) - const mockLnd = EnvCanBeBoolean("MOCK_LND") - return { mainNode: { lndAddr, lndCertPath, lndMacaroonPath }, feeRateLimit, feeFixedLimit, mockLnd } + const lndAddr = process.env.LND_ADDRESS || "127.0.0.1:10009" + const lndCertPath = process.env.LND_CERT_PATH || resolveHome("/.lnd/tls.cert") + const lndMacaroonPath = process.env.LND_MACAROON_PATH || resolveHome("/.lnd/data/chain/bitcoin/mainnet/admin.macaroon") + const feeRateBps = EnvCanBeInteger("OUTBOUND_MAX_FEE_BPS", 60) + const feeRateLimit = feeRateBps / 10000 + const feeFixedLimit = EnvCanBeInteger("OUTBOUND_MAX_FEE_EXTRA_SATS", 100) + const mockLnd = EnvCanBeBoolean("MOCK_LND") + return { mainNode: { lndAddr, lndCertPath, lndMacaroonPath }, feeRateLimit, feeFixedLimit, feeRateBps, mockLnd } } diff --git a/src/services/lnd/initWalletReq.ts b/src/services/lnd/initWalletReq.ts new file mode 100644 index 00000000..e76617d1 --- /dev/null +++ b/src/services/lnd/initWalletReq.ts @@ -0,0 +1,15 @@ +import { InitWalletRequest } from "../../../proto/lnd/walletunlocker"; + + +export const InitWalletReq = (walletPw: Buffer, cipherSeedMnemonic: string[]): InitWalletRequest => ({ + aezeedPassphrase: Buffer.alloc(0), + walletPassword: walletPw, + cipherSeedMnemonic, + extendedMasterKey: "", + extendedMasterKeyBirthdayTimestamp: 0n, + macaroonRootKey: Buffer.alloc(0), + recoveryWindow: 0, + statelessInit: false, + channelBackups: undefined, + watchOnly: undefined, +}) \ No newline at end of file diff --git a/src/services/lnd/liquidityProvider.ts b/src/services/lnd/liquidityProvider.ts deleted file mode 100644 index 295d3bf9..00000000 --- a/src/services/lnd/liquidityProvider.ts +++ /dev/null @@ -1,252 +0,0 @@ -import newNostrClient from '../../../proto/autogenerated/ts/nostr_client.js' -import { NostrRequest } from '../../../proto/autogenerated/ts/nostr_transport.js' -import * as Types from '../../../proto/autogenerated/ts/types.js' -import { decodeNprofile } from '../../custom-nip19.js' -import { getLogger } from '../helpers/logger.js' -import { NostrEvent, NostrSend } from '../nostr/handler.js' -import { relayInit } from '../nostr/tools/relay.js' -import { InvoicePaidCb } from './settings.js' - -export type LiquidityRequest = { action: 'spend' | 'receive', amount: number } - -export type nostrCallback = { startedAtMillis: number, type: 'single' | 'stream', f: (res: T) => void } -export class LiquidityProvider { - client: ReturnType - clientCbs: Record> = {} - clientId: string = "" - myPub: string = "" - log = getLogger({ component: 'liquidityProvider' }) - nostrSend: NostrSend | null = null - ready = false - pubDestination: string - latestMaxWithdrawable: number | null = null - latestBalance: number | null = null - invoicePaidCb: InvoicePaidCb - connecting = false - readyInterval: NodeJS.Timeout - // make the sub process accept client - constructor(pubDestination: string, invoicePaidCb: InvoicePaidCb) { - if (!pubDestination) { - this.log("No pub provider to liquidity provider, will not be initialized") - return - } - this.log("connecting to liquidity provider", pubDestination) - this.pubDestination = pubDestination - this.invoicePaidCb = invoicePaidCb - this.client = newNostrClient({ - pubDestination: this.pubDestination, - retrieveNostrUserAuth: async () => this.myPub, - }, this.clientSend, this.clientSub) - - this.readyInterval = setInterval(() => { - if (this.ready) { - clearInterval(this.readyInterval) - this.Connect() - } - }, 1000) - } - - Stop = () => { - clearInterval(this.readyInterval) - } - - Connect = async () => { - await new Promise(res => setTimeout(res, 2000)) - this.log("ready") - await this.CheckUserState() - if (this.latestMaxWithdrawable === null) { - return - } - this.log("subbing to user operations") - this.client.GetLiveUserOperations(res => { - console.log("got user operation", res) - if (res.status === 'ERROR') { - this.log("error getting user operations", res.reason) - return - } - this.log("got user operation", res.operation) - if (res.operation.type === Types.UserOperationType.INCOMING_INVOICE) { - this.log("invoice was paid", res.operation.identifier) - this.invoicePaidCb(res.operation.identifier, res.operation.amount, false) - } - }) - } - - GetLatestMaxWithdrawable = async (fetch = false) => { - if (this.latestMaxWithdrawable === null) { - this.log("liquidity provider is not ready yet") - return 0 - } - if (fetch) { - await this.CheckUserState() - } - return this.latestMaxWithdrawable || 0 - } - - GetLatestBalance = async (fetch = false) => { - if (this.latestMaxWithdrawable === null) { - this.log("liquidity provider is not ready yet") - return 0 - } - if (fetch) { - await this.CheckUserState() - } - return this.latestBalance || 0 - } - - CheckUserState = async () => { - const res = await this.client.GetUserInfo() - if (res.status === 'ERROR') { - this.log("error getting user info", res) - return - } - this.latestMaxWithdrawable = res.max_withdrawable - this.latestBalance = res.balance - this.log("latest provider balance:", res.balance, "latest max withdrawable:", res.max_withdrawable) - return res - } - - CanProviderHandle = (req: LiquidityRequest) => { - if (this.latestMaxWithdrawable === null) { - return false - } - if (req.action === 'spend') { - return this.latestMaxWithdrawable > req.amount - } - return true - } - - AddInvoice = async (amount: number, memo: string) => { - const res = await this.client.NewInvoice({ amountSats: amount, memo }) - if (res.status === 'ERROR') { - this.log("error creating invoice", res.reason) - throw new Error(res.reason) - } - this.log("new invoice", res.invoice) - this.CheckUserState() - return res.invoice - } - - PayInvoice = async (invoice: string) => { - const res = await this.client.PayInvoice({ invoice, amount: 0 }) - if (res.status === 'ERROR') { - this.log("error paying invoice", res.reason) - throw new Error(res.reason) - } - this.log("paid invoice", res) - this.CheckUserState() - return res - } - - setNostrInfo = ({ clientId, myPub }: { myPub: string, clientId: string }) => { - this.clientId = clientId - this.myPub = myPub - this.setSetIfReady() - } - - - - attachNostrSend(f: NostrSend) { - this.nostrSend = f - this.setSetIfReady() - } - - setSetIfReady = () => { - if (this.nostrSend && !!this.pubDestination && !!this.clientId && !!this.myPub) { - this.ready = true - this.log("ready to send to ", this.pubDestination) - } - } - - onEvent = async (res: { requestId: string }, fromPub: string) => { - if (fromPub !== this.pubDestination) { - this.log("got event from invalid pub", fromPub, this.pubDestination) - return false - } - if (this.clientCbs[res.requestId]) { - const cb = this.clientCbs[res.requestId] - cb.f(res) - if (cb.type === 'single') { - delete this.clientCbs[res.requestId] - this.log(this.getSingleSubs(), "single subs left") - } - return true - } - return false - } - - clientSend = (to: string, message: NostrRequest): Promise => { - if (!this.ready || !this.nostrSend) { - throw new Error("liquidity provider not initialized") - } - if (!message.requestId) { - message.requestId = makeId(16) - } - const reqId = message.requestId - if (this.clientCbs[reqId]) { - throw new Error("request was already sent") - } - this.nostrSend({ type: 'client', clientId: this.clientId }, { - type: 'content', - pub: to, - content: JSON.stringify(message) - }) - - //this.nostrSend(this.relays, to, JSON.stringify(message), this.settings) - - this.log("subbing to single send", reqId, message.rpcName || 'no rpc name') - return new Promise(res => { - this.clientCbs[reqId] = { - startedAtMillis: Date.now(), - type: 'single', - f: (response: any) => { res(response) }, - } - }) - } - - clientSub = (to: string, message: NostrRequest, cb: (res: any) => void): void => { - if (!this.ready || !this.nostrSend) { - throw new Error("liquidity provider not initialized") - } - if (!message.requestId) { - message.requestId = message.rpcName - } - const reqId = message.requestId - if (!reqId) { - throw new Error("invalid sub") - } - if (this.clientCbs[reqId]) { - this.clientCbs[reqId] = { - startedAtMillis: Date.now(), - type: 'stream', - f: (response: any) => { cb(response) }, - } - this.log("sub for", reqId, "was already registered, overriding") - return - } - this.nostrSend({ type: 'client', clientId: this.clientId }, { - type: 'content', - pub: to, - content: JSON.stringify(message) - }) - this.log("subbing to stream", reqId) - this.clientCbs[reqId] = { - startedAtMillis: Date.now(), - type: 'stream', - f: (response: any) => { cb(response) } - } - } - getSingleSubs = () => { - return Object.entries(this.clientCbs).filter(([_, cb]) => cb.type === 'single') - } -} - -export const makeId = (length: number) => { - let result = ''; - const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; - const charactersLength = characters.length; - for (let i = 0; i < length; i++) { - result += characters.charAt(Math.floor(Math.random() * charactersLength)); - } - return result; -} \ No newline at end of file diff --git a/src/services/lnd/lnd.ts b/src/services/lnd/lnd.ts index 67063a14..d5ec2778 100644 --- a/src/services/lnd/lnd.ts +++ b/src/services/lnd/lnd.ts @@ -16,9 +16,12 @@ import { SendCoinsReq } from './sendCoinsReq.js'; import { LndSettings, AddressPaidCb, InvoicePaidCb, NodeInfo, Invoice, DecodedInvoice, PaidInvoice, NewBlockCb, HtlcCb, BalanceInfo } from './settings.js'; import { getLogger } from '../helpers/logger.js'; import { HtlcEvent_EventType } from '../../../proto/lnd/router.js'; -import { LiquidityProvider, LiquidityRequest } from './liquidityProvider.js'; +import { LiquidityProvider, LiquidityRequest } from '../main/liquidityProvider.js'; +import { Utils } from '../helpers/utilsWrapper.js'; +import { TxPointSettings } from '../storage/stateBundler.js'; const DeadLineMetadata = (deadline = 10 * 1000) => ({ deadline: Date.now() + deadline }) const deadLndRetrySeconds = 5 +type TxActionOptions = { useProvider: boolean, from: 'user' | 'system' } export default class { lightning: LightningClient invoices: InvoicesClient @@ -36,9 +39,10 @@ export default class { log = getLogger({ component: 'lndManager' }) outgoingOpsLocked = false liquidProvider: LiquidityProvider - useOnlyLiquidityProvider = false - constructor(settings: LndSettings, provider: { liquidProvider: LiquidityProvider, useOnly?: boolean }, addressPaidCb: AddressPaidCb, invoicePaidCb: InvoicePaidCb, newBlockCb: NewBlockCb, htlcCb: HtlcCb) { + utils: Utils + constructor(settings: LndSettings, liquidProvider: LiquidityProvider, utils: Utils, addressPaidCb: AddressPaidCb, invoicePaidCb: InvoicePaidCb, newBlockCb: NewBlockCb, htlcCb: HtlcCb) { this.settings = settings + this.utils = utils this.addressPaidCb = addressPaidCb this.invoicePaidCb = invoicePaidCb this.newBlockCb = newBlockCb @@ -63,8 +67,7 @@ export default class { this.invoices = new InvoicesClient(transport) this.router = new RouterClient(transport) this.chainNotifier = new ChainNotifierClient(transport) - this.liquidProvider = provider.liquidProvider - this.useOnlyLiquidityProvider = !!provider.useOnly + this.liquidProvider = liquidProvider } LockOutgoingOperations(): void { @@ -82,20 +85,6 @@ export default class { this.liquidProvider.Stop() } - async ShouldUseLiquidityProvider(req: LiquidityRequest): Promise { - if (this.useOnlyLiquidityProvider) { - return true - } - if (!this.liquidProvider.CanProviderHandle(req)) { - return false - } - const channels = await this.ListChannels() - if (channels.channels.length === 0) { - this.log("no channels, will use liquidity provider") - return true - } - return false - } async Warmup() { this.SubscribeAddressPaid() this.SubscribeInvoicePaid() @@ -212,8 +201,7 @@ export default class { if (tx.numConfirmations === 0) { // only process pending transactions, confirmed transaction are processed by the newBlock CB tx.outputDetails.forEach(output => { if (output.isOurAddress) { - this.log("received chan TX", Number(output.amount), "sats", "for", output.address) - this.addressPaidCb({ hash: tx.txHash, index: Number(output.outputIndex) }, output.address, Number(output.amount), false) + this.addressPaidCb({ hash: tx.txHash, index: Number(output.outputIndex) }, output.address, Number(output.amount), 'lnd') } }) } @@ -233,9 +221,8 @@ export default class { }, { abort: this.abortController.signal }) stream.responses.onMessage(invoice => { if (invoice.state === Invoice_InvoiceState.SETTLED) { - this.log("An invoice was paid for", Number(invoice.amtPaidSat), "sats", invoice.paymentRequest) this.latestKnownSettleIndex = Number(invoice.settleIndex) - this.invoicePaidCb(invoice.paymentRequest, Number(invoice.amtPaidSat), false) + this.invoicePaidCb(invoice.paymentRequest, Number(invoice.amtPaidSat), 'lnd') } }) stream.responses.onError(error => { @@ -247,8 +234,8 @@ export default class { }) } - async NewAddress(addressType: Types.AddressType): Promise { - this.log("generating new address") + async NewAddress(addressType: Types.AddressType, { useProvider, from }: TxActionOptions): Promise { + await this.Health() let lndAddressType: AddressType switch (addressType) { @@ -264,22 +251,34 @@ export default class { default: throw new Error("unknown address type " + addressType) } - const res = await this.lightning.newAddress({ account: "", type: lndAddressType }, DeadLineMetadata()) - this.log("new address", res.response.address) - return res.response + if (useProvider) { + throw new Error("provider payments not support chain payments yet") + } + try { + const res = await this.lightning.newAddress({ account: "", type: lndAddressType }, DeadLineMetadata()) + this.utils.stateBundler.AddTxPoint('addedAddress', 1, { from, used: 'lnd' }) + return res.response + } catch (err) { + this.utils.stateBundler.AddTxPointFailed('addedAddress', 1, { from, used: 'lnd' }) + throw err + } } - async NewInvoice(value: number, memo: string, expiry: number, useProvider = false): Promise { - this.log("generating new invoice for", value, "sats") + async NewInvoice(value: number, memo: string, expiry: number, { useProvider, from }: TxActionOptions): Promise { await this.Health() - const shouldUseLiquidityProvider = await this.ShouldUseLiquidityProvider({ action: 'receive', amount: value }) - if (shouldUseLiquidityProvider || useProvider) { - const invoice = await this.liquidProvider.AddInvoice(value, memo) - return { payRequest: invoice } + if (useProvider) { + const invoice = await this.liquidProvider.AddInvoice(value, memo, from) + const providerDst = this.liquidProvider.GetProviderDestination() + return { payRequest: invoice, providerDst } + } + try { + const res = await this.lightning.addInvoice(AddInvoiceReq(value, expiry, true, memo), DeadLineMetadata()) + this.utils.stateBundler.AddTxPoint('addedInvoice', value, { from, used: 'lnd' }) + return { payRequest: res.response.paymentRequest } + } catch (err) { + this.utils.stateBundler.AddTxPointFailed('addedInvoice', value, { from, used: 'lnd' }) + throw err } - const res = await this.lightning.addInvoice(AddInvoiceReq(value, expiry, false, memo), DeadLineMetadata()) - this.log("new invoice", res.response.paymentRequest) - return { payRequest: res.response.paymentRequest } } async DecodeInvoice(paymentRequest: string): Promise { @@ -300,39 +299,44 @@ export default class { const r = res.response return { local: r.localBalance ? Number(r.localBalance.sat) : 0, remote: r.remoteBalance ? Number(r.remoteBalance.sat) : 0 } } - async PayInvoice(invoice: string, amount: number, feeLimit: number, useProvider = false): Promise { + async PayInvoice(invoice: string, amount: number, feeLimit: number, decodedAmount: number, { useProvider, from }: TxActionOptions): Promise { if (this.outgoingOpsLocked) { this.log("outgoing ops locked, rejecting payment request") throw new Error("lnd node is currently out of sync") } await this.Health() - this.log("paying invoice", invoice, "for", amount, "sats") - const shouldUseLiquidityProvider = await this.ShouldUseLiquidityProvider({ action: 'spend', amount }) - if (shouldUseLiquidityProvider || useProvider) { - const res = await this.liquidProvider.PayInvoice(invoice) - return { feeSat: res.network_fee + res.service_fee, valueSat: res.amount_paid, paymentPreimage: res.preimage } + if (useProvider) { + const res = await this.liquidProvider.PayInvoice(invoice, decodedAmount, from) + const providerDst = this.liquidProvider.GetProviderDestination() + return { feeSat: res.network_fee + res.service_fee, valueSat: res.amount_paid, paymentPreimage: res.preimage, providerDst } } - const abortController = new AbortController() - const req = PayInvoiceReq(invoice, amount, feeLimit) - const stream = this.router.sendPaymentV2(req, { abort: abortController.signal }) - return new Promise((res, rej) => { - stream.responses.onError(error => { - this.log("invoice payment failed", error) - rej(error) + try { + const abortController = new AbortController() + const req = PayInvoiceReq(invoice, amount, feeLimit) + const stream = this.router.sendPaymentV2(req, { abort: abortController.signal }) + return new Promise((res, rej) => { + stream.responses.onError(error => { + this.log("invoice payment failed", error) + rej(error) + }) + stream.responses.onMessage(payment => { + switch (payment.status) { + case Payment_PaymentStatus.FAILED: + this.log("invoice payment failed", payment.failureReason) + rej(PaymentFailureReason[payment.failureReason]) + return + case Payment_PaymentStatus.SUCCEEDED: + this.utils.stateBundler.AddTxPoint('paidAnInvoice', Number(payment.valueSat), { from, used: 'lnd', timeDiscount: true }) + res({ feeSat: Math.ceil(Number(payment.feeMsat) / 1000), valueSat: Number(payment.valueSat), paymentPreimage: payment.paymentPreimage }) + return + } + }) }) - stream.responses.onMessage(payment => { - switch (payment.status) { - case Payment_PaymentStatus.FAILED: - console.log(payment) - this.log("invoice payment failed", payment.failureReason) - rej(PaymentFailureReason[payment.failureReason]) - return - case Payment_PaymentStatus.SUCCEEDED: - this.log("invoice payment succeded", Number(payment.valueSat)) - res({ feeSat: Math.ceil(Number(payment.feeMsat) / 1000), valueSat: Number(payment.valueSat), paymentPreimage: payment.paymentPreimage }) - } - }) - }) + } catch (err) { + this.utils.stateBundler.AddTxPointFailed('paidAnInvoice', decodedAmount, { from, used: 'lnd' }) + throw err + } + } async EstimateChainFees(address: string, amount: number, targetConf: number): Promise { @@ -346,16 +350,23 @@ export default class { return res.response } - async PayAddress(address: string, amount: number, satPerVByte: number, label = ""): Promise { + async PayAddress(address: string, amount: number, satPerVByte: number, label = "", { useProvider, from }: TxActionOptions): Promise { if (this.outgoingOpsLocked) { this.log("outgoing ops locked, rejecting payment request") throw new Error("lnd node is currently out of sync") } - await this.Health() - this.log("sending chain TX for", amount, "sats", "to", address) - const res = await this.lightning.sendCoins(SendCoinsReq(address, amount, satPerVByte, label), DeadLineMetadata()) - this.log("sent chain TX for", amount, "sats", "to", address) - return res.response + if (useProvider) { + throw new Error("provider payments not support chain payments yet") + } + try { + await this.Health() + const res = await this.lightning.sendCoins(SendCoinsReq(address, amount, satPerVByte, label), DeadLineMetadata()) + this.utils.stateBundler.AddTxPoint('paidAnAddress', amount, { from, used: 'lnd', timeDiscount: true }) + return res.response + } catch (err) { + this.utils.stateBundler.AddTxPointFailed('paidAnAddress', amount, { from, used: 'lnd' }) + throw err + } } async GetTransactions(startHeight: number): Promise { @@ -374,7 +385,20 @@ export default class { return res.response } - async GetBalance(): Promise { + async GetTotalBalace() { + const walletBalance = await this.GetWalletBalance() + const confirmedWalletBalance = Number(walletBalance.confirmedBalance) + this.utils.stateBundler.AddBalancePoint('walletBalance', confirmedWalletBalance) + const channelsBalance = await this.GetChannelBalance() + const totalLightningBalanceMsats = (channelsBalance.localBalance?.msat || 0n) + (channelsBalance.unsettledLocalBalance?.msat || 0n) + const totalLightningBalance = Math.ceil(Number(totalLightningBalanceMsats) / 1000) + this.utils.stateBundler.AddBalancePoint('channelBalance', totalLightningBalance) + const totalLndBalance = confirmedWalletBalance + totalLightningBalance + this.utils.stateBundler.AddBalancePoint('totalLndBalance', totalLndBalance) + return totalLndBalance + } + + async GetBalance(): Promise { // TODO: remove this const wRes = await this.lightning.walletBalance({}, DeadLineMetadata()) const { confirmedBalance, unconfirmedBalance, totalBalance } = wRes.response const { response } = await this.lightning.listChannels({ diff --git a/src/services/lnd/lsp.ts b/src/services/lnd/lsp.ts index 63d6bedf..6f654a27 100644 --- a/src/services/lnd/lsp.ts +++ b/src/services/lnd/lsp.ts @@ -1,5 +1,5 @@ import fetch from "node-fetch" -import { LiquidityProvider } from "./liquidityProvider.js" +import { LiquidityProvider } from "../main/liquidityProvider.js" import { getLogger, PubLogger } from '../helpers/logger.js' import LND from "./lnd.js" import { AddressType } from "../../../proto/autogenerated/ts/types.js" @@ -61,29 +61,6 @@ class LSP { this.log = getLogger({ component: serviceName }) } - shouldOpenChannel = async (): Promise<{ shouldOpen: false } | { shouldOpen: true, maxSpendable: number }> => { - if (this.settings.channelThreshold === 0) { - this.log("channel threshold is 0") - return { shouldOpen: false } - } - const channels = await this.lnd.ListChannels() - if (channels.channels.length > 0) { - this.log("this node already has open channels") - return { shouldOpen: false } - } - const pendingChannels = await this.lnd.ListPendingChannels() - if (pendingChannels.pendingOpenChannels.length > 0) { - this.log("this node already has pending channels") - return { shouldOpen: false } - } - const userState = await this.liquidityProvider.CheckUserState() - if (!userState || userState.max_withdrawable < this.settings.channelThreshold) { - this.log("balance of", userState?.max_withdrawable || 0, "is lower than channel threshold of", this.settings.channelThreshold) - return { shouldOpen: false } - } - return { shouldOpen: true, maxSpendable: userState.max_withdrawable } - } - addPeer = async (pubKey: string, host: string) => { const { peers } = await this.lnd.ListPeers() if (!peers.find(p => p.pubKey === pubKey)) { @@ -98,18 +75,14 @@ export class FlashsatsLSP extends LSP { super("FlashsatsLSP", settings, lnd, liquidityProvider) } - openChannelIfReady = async (): Promise => { - const shouldOpen = await this.shouldOpenChannel() - if (!shouldOpen.shouldOpen) { - return null - } + requestChannel = async (maxSpendable: number): Promise => { if (!this.settings.flashsatsServiceUrl) { this.log("no flashsats service url provided") return null } const serviceInfo = await this.getInfo() - if (+serviceInfo.options.min_initial_client_balance_sat > shouldOpen.maxSpendable) { - this.log("balance of", shouldOpen.maxSpendable, "is lower than service minimum of", serviceInfo.options.min_initial_client_balance_sat) + if (+serviceInfo.options.min_initial_client_balance_sat > maxSpendable) { + this.log("balance of", maxSpendable, "is lower than service minimum of", serviceInfo.options.min_initial_client_balance_sat) return null } const lndInfo = await this.lnd.GetInfo() @@ -118,7 +91,8 @@ export class FlashsatsLSP extends LSP { this.log("no uri found for this node,uri is required to use flashsats") return null } - const lspBalance = (this.settings.channelThreshold * 2).toString() + const channelSize = Math.floor(maxSpendable * (1 - this.settings.maxRelativeFee)) * 2 + const lspBalance = channelSize.toString() const chanExpiryBlocks = serviceInfo.options.max_channel_expiry_blocks const order = await this.createOrder({ nodeUri: myUri, lspBalance, clientBalance: "0", chanExpiryBlocks }) if (order.payment.state !== 'EXPECT_PAYMENT') { @@ -130,18 +104,19 @@ export class FlashsatsLSP extends LSP { this.log("invoice of amount", decoded.numSatoshis, "does not match order total of", order.payment.order_total_sat) return null } - if (decoded.numSatoshis > shouldOpen.maxSpendable) { - this.log("invoice of amount", decoded.numSatoshis, "exceeds user balance of", shouldOpen.maxSpendable) + if (decoded.numSatoshis > maxSpendable) { + this.log("invoice of amount", decoded.numSatoshis, "exceeds user balance of", maxSpendable) return null } - const relativeFee = +order.payment.fee_total_sat / this.settings.channelThreshold + const relativeFee = +order.payment.fee_total_sat / channelSize if (relativeFee > this.settings.maxRelativeFee) { this.log("invoice relative fee of", relativeFee, "exceeds max relative fee of", this.settings.maxRelativeFee) return null } - const res = await this.liquidityProvider.PayInvoice(order.payment.bolt11_invoice) - this.log("paid", res.amount_paid, "to open channel") - return { orderId: order.order_id, invoice: order.payment.bolt11_invoice, totalSats: +order.payment.order_total_sat, fees: +order.payment.fee_total_sat } + const res = await this.liquidityProvider.PayInvoice(order.payment.bolt11_invoice, decoded.numSatoshis, 'system') + const fees = +order.payment.fee_total_sat + res.network_fee + res.service_fee + this.log("paid", res.amount_paid, "to open channel, and a fee of", fees) + return { orderId: order.order_id, invoice: order.payment.bolt11_invoice, totalSats: +order.payment.order_total_sat, fees } } getInfo = async () => { @@ -174,54 +149,52 @@ export class OlympusLSP extends LSP { super("OlympusLSP", settings, lnd, liquidityProvider) } - openChannelIfReady = async (): Promise => { - const shouldOpen = await this.shouldOpenChannel() - if (!shouldOpen.shouldOpen) { - return null - } + requestChannel = async (maxSpendable: number): Promise => { if (!this.settings.olympusServiceUrl) { this.log("no olympus service url provided") return null } const serviceInfo = await this.getInfo() - if (+serviceInfo.options.min_initial_client_balance_sat > shouldOpen.maxSpendable) { - this.log("balance of", shouldOpen.maxSpendable, "is lower than service minimum of", serviceInfo.options.min_initial_client_balance_sat) + if (+serviceInfo.min_initial_client_balance_sat > maxSpendable) { + this.log("balance of", maxSpendable, "is lower than service minimum of", serviceInfo.min_initial_client_balance_sat) return null } const [servicePub, host] = serviceInfo.uris[0].split('@') await this.addPeer(servicePub, host) const lndInfo = await this.lnd.GetInfo() const myPub = lndInfo.identityPubkey - const refundAddr = await this.lnd.NewAddress(AddressType.WITNESS_PUBKEY_HASH) - const lspBalance = (this.settings.channelThreshold * 2).toString() - const chanExpiryBlocks = serviceInfo.options.max_channel_expiry_blocks + const refundAddr = await this.lnd.NewAddress(AddressType.WITNESS_PUBKEY_HASH, { useProvider: false, from: 'system' }) + const channelSize = Math.floor(maxSpendable * (1 - this.settings.maxRelativeFee)) * 2 + const lspBalance = channelSize.toString() + const chanExpiryBlocks = serviceInfo.max_channel_expiry_blocks const order = await this.createOrder({ pubKey: myPub, refundAddr: refundAddr.address, lspBalance, clientBalance: "0", chanExpiryBlocks }) - if (order.payment.state !== 'EXPECT_PAYMENT') { + if (order.payment.bolt11.state !== 'EXPECT_PAYMENT') { this.log("order not in expect payment state") return null } - const decoded = await this.lnd.DecodeInvoice(order.payment.bolt11_invoice) - if (decoded.numSatoshis !== +order.payment.order_total_sat) { - this.log("invoice of amount", decoded.numSatoshis, "does not match order total of", order.payment.order_total_sat) + const decoded = await this.lnd.DecodeInvoice(order.payment.bolt11.invoice) + if (decoded.numSatoshis !== +order.payment.bolt11.order_total_sat) { + this.log("invoice of amount", decoded.numSatoshis, "does not match order total of", order.payment.bolt11.order_total_sat) return null } - if (decoded.numSatoshis > shouldOpen.maxSpendable) { - this.log("invoice of amount", decoded.numSatoshis, "exceeds user balance of", shouldOpen.maxSpendable) + if (decoded.numSatoshis > maxSpendable) { + this.log("invoice of amount", decoded.numSatoshis, "exceeds user balance of", maxSpendable) return null } - const relativeFee = +order.payment.fee_total_sat / this.settings.channelThreshold + const relativeFee = +order.payment.bolt11.fee_total_sat / channelSize if (relativeFee > this.settings.maxRelativeFee) { this.log("invoice relative fee of", relativeFee, "exceeds max relative fee of", this.settings.maxRelativeFee) return null } - const res = await this.liquidityProvider.PayInvoice(order.payment.bolt11_invoice) - this.log("paid", res.amount_paid, "to open channel") - return { orderId: order.order_id, invoice: order.payment.bolt11_invoice, totalSats: +order.payment.order_total_sat, fees: +order.payment.fee_total_sat } + const res = await this.liquidityProvider.PayInvoice(order.payment.bolt11.invoice, decoded.numSatoshis, 'system') + const fees = +order.payment.bolt11.fee_total_sat + res.network_fee + res.service_fee + this.log("paid", res.amount_paid, "to open channel, and a fee of", fees) + return { orderId: order.order_id, invoice: order.payment.bolt11.invoice, totalSats: +order.payment.bolt11.order_total_sat, fees } } getInfo = async () => { const res = await fetch(`${this.settings.olympusServiceUrl}/get_info`) - const json = await res.json() as { options: { min_initial_client_balance_sat: string, max_channel_expiry_blocks: number }, uris: string[] } + const json = await res.json() as { min_initial_client_balance_sat: string, max_channel_expiry_blocks: number, uris: string[] } return json } @@ -241,7 +214,7 @@ export class OlympusLSP extends LSP { body: JSON.stringify(req), headers: { "Content-Type": "application/json" } }) - const json = await res.json() as { order_id: string, payment: { state: 'EXPECT_PAYMENT', bolt11_invoice: string, fee_total_sat: string, order_total_sat: string } } + const json = await res.json() as { order_id: string, payment: { bolt11: { state: 'EXPECT_PAYMENT', invoice: string, fee_total_sat: string, order_total_sat: string } } } return json } @@ -275,12 +248,7 @@ export class VoltageLSP extends LSP { return json } - openChannelIfReady = async (): Promise => { - const shouldOpen = await this.shouldOpenChannel() - if (!shouldOpen.shouldOpen) { - return null - } - + requestChannel = async (maxSpendable: number): Promise => { if (!this.settings.voltageServiceUrl) { this.log("no voltage service url provided") return null @@ -288,10 +256,11 @@ export class VoltageLSP extends LSP { const lndInfo = await this.lnd.GetInfo() const myPub = lndInfo.identityPubkey - const amtMsats = this.settings.channelThreshold * 1000 + const amtSats = Math.floor(maxSpendable * 0.9) + const amtMsats = Math.floor(maxSpendable * 0.9) * 1000 const fee = await this.getFees(amtMsats, myPub) const feeSats = fee.fee_amount_msat / 1000 - const relativeFee = feeSats / this.settings.channelThreshold + const relativeFee = feeSats / (amtSats * 1.1) if (relativeFee > this.settings.maxRelativeFee) { this.log("relative fee of", relativeFee, "exceeds max relative fee of", this.settings.maxRelativeFee) @@ -306,17 +275,22 @@ export class VoltageLSP extends LSP { } await this.addPeer(info.pubkey, `${ipv4.address}:${ipv4.port}`) - const invoice = await this.lnd.NewInvoice(this.settings.channelThreshold, "open channel", 60 * 60) - const res = await this.proposal(invoice.payRequest, fee.id) - const decoded = await this.lnd.DecodeInvoice(res.jit_bolt11) - if (decoded.numSatoshis !== this.settings.channelThreshold + feeSats) { - this.log("invoice of amount", decoded.numSatoshis, "does not match expected amount of", this.settings.channelThreshold + feeSats) + const invoice = await this.lnd.NewInvoice(amtSats, "open channel", 60 * 60, { from: 'system', useProvider: false }) + const proposalRes = await this.proposal(invoice.payRequest, fee.id) + this.log("proposal res", proposalRes, fee.id) + const decoded = await this.lnd.DecodeInvoice(proposalRes.jit_bolt11) + if (decoded.numSatoshis !== amtSats + feeSats) { + this.log("invoice of amount", decoded.numSatoshis, "does not match expected amount of", amtSats + feeSats) return null } - - const invoiceRes = await this.liquidityProvider.PayInvoice(res.jit_bolt11) - this.log("paid", invoiceRes.amount_paid, "to open channel") - return { orderId: fee.id, invoice: res.jit_bolt11, totalSats: decoded.numSatoshis, fees: feeSats } + if (decoded.numSatoshis > maxSpendable) { + this.log("invoice of amount", decoded.numSatoshis, "exceeds user balance of", maxSpendable) + return null + } + const res = await this.liquidityProvider.PayInvoice(proposalRes.jit_bolt11, decoded.numSatoshis, 'system') + const fees = feeSats + res.network_fee + res.service_fee + this.log("paid", res.amount_paid, "to open channel, and a fee of", fees) + return { orderId: fee.id, invoice: proposalRes.jit_bolt11, totalSats: decoded.numSatoshis, fees } } proposal = async (bolt11: string, feeId: string) => { diff --git a/src/services/lnd/payInvoiceReq.ts b/src/services/lnd/payInvoiceReq.ts index 6192ee92..323448e0 100644 --- a/src/services/lnd/payInvoiceReq.ts +++ b/src/services/lnd/payInvoiceReq.ts @@ -1,30 +1,29 @@ -import { OpenChannelRequest } from "../../../proto/lnd/lightning"; -import { SendPaymentRequest } from "../../../proto/lnd/router"; - -export const PayInvoiceReq = (invoice: string, amount: number, feeLimit: number): SendPaymentRequest => ({ - amt: BigInt(amount), - feeLimitSat: BigInt(feeLimit), - noInflightUpdates: true, - paymentRequest: invoice, - maxParts: 3, - timeoutSeconds: 50, - - allowSelfPayment: false, - amp: false, - amtMsat: 0n, - cltvLimit: 0, - dest: Buffer.alloc(0), - destCustomRecords: {}, - destFeatures: [], - feeLimitMsat: 0n, - finalCltvDelta: 0, - lastHopPubkey: Buffer.alloc(0), - maxShardSizeMsat: 0n, - outgoingChanIds: [], - paymentAddr: Buffer.alloc(0), - paymentHash: Buffer.alloc(0), - routeHints: [], - timePref: 0, - - outgoingChanId: '0' +import { OpenChannelRequest } from "../../../proto/lnd/lightning"; +import { SendPaymentRequest } from "../../../proto/lnd/router"; + +export const PayInvoiceReq = (invoice: string, amount: number, feeLimit: number): SendPaymentRequest => ({ + amt: BigInt(amount), + feeLimitSat: BigInt(feeLimit), + noInflightUpdates: false, + paymentRequest: invoice, + maxParts: 3, + timeoutSeconds: 50, + + allowSelfPayment: false, + amp: false, + amtMsat: 0n, + cltvLimit: 0, + dest: Buffer.alloc(0), + destCustomRecords: {}, + destFeatures: [], + feeLimitMsat: 0n, + finalCltvDelta: 0, + lastHopPubkey: Buffer.alloc(0), + maxShardSizeMsat: 0n, + outgoingChanIds: [], + paymentAddr: Buffer.alloc(0), + paymentHash: Buffer.alloc(0), + routeHints: [], + timePref: 0, + outgoingChanId: '0' }) \ No newline at end of file diff --git a/src/services/lnd/settings.ts b/src/services/lnd/settings.ts index 3d4c97f1..04f31c91 100644 --- a/src/services/lnd/settings.ts +++ b/src/services/lnd/settings.ts @@ -8,6 +8,7 @@ export type LndSettings = { mainNode: NodeSettings feeRateLimit: number feeFixedLimit: number + feeRateBps: number mockLnd: boolean otherNode?: NodeSettings @@ -30,8 +31,8 @@ export type BalanceInfo = { channelsBalance: ChannelBalance[]; } -export type AddressPaidCb = (txOutput: TxOutput, address: string, amount: number, internal: boolean) => void -export type InvoicePaidCb = (paymentRequest: string, amount: number, internal: boolean) => void +export type AddressPaidCb = (txOutput: TxOutput, address: string, amount: number, used: 'lnd' | 'provider' | 'internal') => Promise +export type InvoicePaidCb = (paymentRequest: string, amount: number, used: 'lnd' | 'provider' | 'internal') => Promise export type NewBlockCb = (height: number) => void export type HtlcCb = (event: HtlcEvent) => void @@ -46,6 +47,7 @@ export type NodeInfo = { } export type Invoice = { payRequest: string + providerDst?: string } export type DecodedInvoice = { numSatoshis: number @@ -55,4 +57,5 @@ export type PaidInvoice = { feeSat: number valueSat: number paymentPreimage: string + providerDst?: string } \ No newline at end of file diff --git a/src/services/main/adminManager.ts b/src/services/main/adminManager.ts new file mode 100644 index 00000000..906c652f --- /dev/null +++ b/src/services/main/adminManager.ts @@ -0,0 +1,97 @@ +import fs, { watchFile } from "fs"; +import crypto from 'crypto' +import { getLogger } from "../helpers/logger.js"; +import { MainSettings, getDataPath } from "./settings.js"; +import Storage from "../storage/index.js"; +export class AdminManager { + storage: Storage + log = getLogger({ component: "adminManager" }) + adminNpub = "" + dataDir: string + adminNpubPath: string + adminEnrollTokenPath: string + interval: NodeJS.Timer + constructor(mainSettings: MainSettings, storage: Storage) { + this.storage = storage + this.dataDir = mainSettings.storageSettings.dataDir + this.adminNpubPath = getDataPath(this.dataDir, 'admin.npub') + this.adminEnrollTokenPath = getDataPath(this.dataDir, '.admin_enroll') + this.start() + } + Stop = () => { + clearInterval(this.interval) + } + + GenerateAdminEnrollToken = async () => { + const token = crypto.randomBytes(32).toString('hex') + fs.writeFileSync(this.adminEnrollTokenPath, token) + return token + } + + start = () => { + const adminNpub = this.ReadAdminNpub() + if (adminNpub) { + this.adminNpub = adminNpub + } else if (!fs.existsSync(this.adminEnrollTokenPath)) { + this.GenerateAdminEnrollToken() + } + this.interval = setInterval(() => { + if (!this.adminNpub) { + return + } + const deleted = !fs.existsSync(this.adminNpubPath) + if (deleted) { + this.adminNpub = "" + this.log("admin npub file deleted") + this.GenerateAdminEnrollToken() + } + }) + } + + ReadAdminEnrollToken = () => { + try { + return fs.readFileSync(this.adminEnrollTokenPath, 'utf8').trim() + } catch (err: any) { + return "" + } + } + + ReadAdminNpub = () => { + try { + return fs.readFileSync(this.adminNpubPath, 'utf8').trim() + } catch (err: any) { + return "" + } + } + + GetAdminNpub = () => { + return this.adminNpub + } + + ClearExistingAdmin = () => { + try { + fs.unlinkSync(this.adminNpubPath) + } catch (err: any) { } + } + + PromoteUserToAdmin = async (appId: string, appUserId: string, token: string) => { + const app = await this.storage.applicationStorage.GetApplication(appId) + const appUser = await this.storage.applicationStorage.GetApplicationUser(app, appUserId) + const npub = appUser.nostr_public_key + if (!npub) { + throw new Error("no npub found for user") + } + let actualToken + try { + actualToken = fs.readFileSync(this.adminEnrollTokenPath, 'utf8').trim() + } catch (err: any) { + throw new Error("invalid enroll token") + } + if (token !== actualToken) { + throw new Error("invalid enroll token") + } + fs.writeFileSync(this.adminNpubPath, npub) + fs.unlinkSync(this.adminEnrollTokenPath) + this.adminNpub = npub + } +} \ No newline at end of file diff --git a/src/services/main/appUserManager.ts b/src/services/main/appUserManager.ts index 680718a9..6da520ae 100644 --- a/src/services/main/appUserManager.ts +++ b/src/services/main/appUserManager.ts @@ -56,7 +56,10 @@ export default class { userId: ctx.user_id, balance: user.balance_sats, max_withdrawable: this.applicationManager.paymentManager.GetMaxPayableInvoice(user.balance_sats, true), - user_identifier: appUser.identifier + user_identifier: appUser.identifier, + network_max_fee_bps: this.settings.lndSettings.feeRateBps, + network_max_fee_fixed: this.settings.lndSettings.feeFixedLimit, + service_fee_bps: this.settings.outgoingAppUserInvoiceFeeBps } } diff --git a/src/services/main/applicationManager.ts b/src/services/main/applicationManager.ts index ff97e6a4..a75a591c 100644 --- a/src/services/main/applicationManager.ts +++ b/src/services/main/applicationManager.ts @@ -154,7 +154,11 @@ export default class { userId: u.user.user_id, balance: u.user.balance_sats, max_withdrawable: this.paymentManager.GetMaxPayableInvoice(u.user.balance_sats, true), - user_identifier: u.identifier + user_identifier: u.identifier, + network_max_fee_bps: this.settings.lndSettings.feeRateBps, + network_max_fee_fixed: this.settings.lndSettings.feeFixedLimit, + service_fee_bps: this.settings.outgoingAppUserInvoiceFeeBps + }, max_withdrawable: this.paymentManager.GetMaxPayableInvoice(u.user.balance_sats, true) } @@ -175,9 +179,7 @@ export default class { const receiver = await this.storage.applicationStorage.GetApplicationUser(app, req.receiver_identifier) const { user: payer } = await this.storage.applicationStorage.GetOrCreateApplicationUser(app, req.payer_identifier, 0) const opts: InboundOptionals = { callbackUrl: req.http_callback_url, expiry: defaultInvoiceExpiry, expectedPayer: payer.user, linkedApplication: app } - log("generating invoice...") const appUserInvoice = await this.paymentManager.NewInvoice(receiver.user.user_id, req.invoice_req, opts) - log(receiver.identifier, "invoice created to be paid by", payer.identifier) return { invoice: appUserInvoice.invoice } @@ -191,7 +193,10 @@ export default class { max_withdrawable: max, identifier: req.user_identifier, info: { userId: user.user.user_id, balance: user.user.balance_sats, max_withdrawable: this.paymentManager.GetMaxPayableInvoice(user.user.balance_sats, true), - user_identifier: user.identifier + user_identifier: user.identifier, + network_max_fee_bps: this.settings.lndSettings.feeRateBps, + network_max_fee_fixed: this.settings.lndSettings.feeFixedLimit, + service_fee_bps: this.settings.outgoingAppUserInvoiceFeeBps } } } diff --git a/src/services/main/index.ts b/src/services/main/index.ts index 20d4c7be..c6bb8d68 100644 --- a/src/services/main/index.ts +++ b/src/services/main/index.ts @@ -15,8 +15,11 @@ import { UnsignedEvent } from '../nostr/tools/event.js' import { NostrSend } from '../nostr/handler.js' import MetricsManager from '../metrics/index.js' import { LoggedEvent } from '../storage/eventsLog.js' -import { LiquidityProvider } from "../lnd/liquidityProvider.js" +import { LiquidityProvider } from "./liquidityProvider.js" import { LiquidityManager } from "./liquidityManager.js" +import { Utils } from "../helpers/utilsWrapper.js" +import { RugPullTracker } from "./rugPullTracker.js" +import { AdminManager } from "./adminManager.js" type UserOperationsSub = { id: string @@ -31,25 +34,31 @@ export default class { lnd: LND settings: MainSettings userOperationsSub: UserOperationsSub | null = null + adminManager: AdminManager productManager: ProductManager applicationManager: ApplicationManager appUserManager: AppUserManager paymentManager: PaymentManager paymentSubs: Record void) | null> = {} metricsManager: MetricsManager - liquidProvider: LiquidityProvider liquidityManager: LiquidityManager + liquidityProvider: LiquidityProvider + utils: Utils + rugPullTracker: RugPullTracker nostrSend: NostrSend = () => { getLogger({})("nostr send not initialized yet") } - constructor(settings: MainSettings, storage: Storage) { + constructor(settings: MainSettings, storage: Storage, adminManager: AdminManager, utils: Utils) { this.settings = settings this.storage = storage - this.liquidProvider = new LiquidityProvider(settings.liquiditySettings.liquidityProviderPub, this.invoicePaidCb) - const provider = { liquidProvider: this.liquidProvider, useOnly: settings.liquiditySettings.useOnlyLiquidityProvider } - this.lnd = new LND(settings.lndSettings, provider, this.addressPaidCb, this.invoicePaidCb, this.newBlockCb, this.htlcCb) - this.liquidityManager = new LiquidityManager(this.settings.liquiditySettings, this.storage, this.liquidProvider, this.lnd) + this.utils = utils + this.adminManager = adminManager + const updateProviderBalance = (b: number) => this.storage.liquidityStorage.IncrementTrackedProviderBalance('lnPub', settings.liquiditySettings.liquidityProviderPub, b) + this.liquidityProvider = new LiquidityProvider(settings.liquiditySettings.liquidityProviderPub, this.utils, this.invoicePaidCb, updateProviderBalance) + this.rugPullTracker = new RugPullTracker(this.storage, this.liquidityProvider) + this.lnd = new LND(settings.lndSettings, this.liquidityProvider, this.utils, this.addressPaidCb, this.invoicePaidCb, this.newBlockCb, this.htlcCb) + this.liquidityManager = new LiquidityManager(this.settings.liquiditySettings, this.storage, this.utils, this.liquidityProvider, this.lnd, this.rugPullTracker) this.metricsManager = new MetricsManager(this.storage, this.lnd) - this.paymentManager = new PaymentManager(this.storage, this.lnd, this.settings, this.liquidityManager, this.addressPaidCb, this.invoicePaidCb) + this.paymentManager = new PaymentManager(this.storage, this.lnd, this.settings, this.liquidityManager, this.utils, this.addressPaidCb, this.invoicePaidCb) this.productManager = new ProductManager(this.storage, this.paymentManager, this.settings) this.applicationManager = new ApplicationManager(this.storage, this.settings, this.paymentManager) this.appUserManager = new AppUserManager(this.storage, this.settings, this.applicationManager) @@ -69,7 +78,7 @@ export default class { attachNostrSend(f: NostrSend) { this.nostrSend = f - this.liquidProvider.attachNostrSend(f) + this.liquidityProvider.attachNostrSend(f) } htlcCb: HtlcCb = (e) => { @@ -88,7 +97,7 @@ export default class { const balanceEvents = await this.paymentManager.GetLndBalance() await this.metricsManager.NewBlockCb(height, balanceEvents) confirmed = await this.paymentManager.CheckNewlyConfirmedTxs(height) - this.liquidityManager.onNewBlock() + await this.liquidityManager.onNewBlock() } catch (err: any) { log(ERROR, "failed to check transactions after new block", err.message || err) return @@ -125,11 +134,12 @@ export default class { })) } - addressPaidCb: AddressPaidCb = (txOutput, address, amount, internal) => { - this.storage.StartTransaction(async tx => { + addressPaidCb: AddressPaidCb = (txOutput, address, amount, used) => { + return this.storage.StartTransaction(async tx => { const { blockHeight } = await this.lnd.GetInfo() const userAddress = await this.storage.paymentStorage.GetAddressOwner(address, tx) if (!userAddress) { return } + const internal = used === 'internal' let log = getLogger({}) if (!userAddress.linkedApplication) { log(ERROR, "an address was paid, that has no linked application") @@ -156,17 +166,20 @@ export default class { const operationId = `${Types.UserOperationType.INCOMING_TX}-${addedTx.serial_id}` const op = { amount, paidAtUnix: Date.now() / 1000, inbound: true, type: Types.UserOperationType.INCOMING_TX, identifier: userAddress.address, operationId, network_fee: 0, service_fee: fee, confirmed: internal, tx_hash: txOutput.hash, internal: false } this.sendOperationToNostr(userAddress.linkedApplication, userAddress.user.user_id, op) - } catch { + this.utils.stateBundler.AddTxPoint('addressWasPaid', amount, { used, from: 'system', timeDiscount: true }) + } catch (err: any) { + this.utils.stateBundler.AddTxPointFailed('addressWasPaid', amount, { used, from: 'system' }) log(ERROR, "cannot process address paid transaction, already registered") } }) } - invoicePaidCb: InvoicePaidCb = (paymentRequest, amount, internal) => { - this.storage.StartTransaction(async tx => { + invoicePaidCb: InvoicePaidCb = (paymentRequest, amount, used) => { + return this.storage.StartTransaction(async tx => { let log = getLogger({}) const userInvoice = await this.storage.paymentStorage.GetInvoiceOwner(paymentRequest, tx) if (!userInvoice) { return } + const internal = used === 'internal' if (userInvoice.paid_at_unix > 0 && internal) { log("cannot pay internally, invoice already paid"); return } if (userInvoice.paid_at_unix > 0 && !internal && userInvoice.paidByLnd) { log("invoice already paid by lnd"); return } if (!userInvoice.linkedApplication) { @@ -191,9 +204,10 @@ export default class { const op = { amount, paidAtUnix: Date.now() / 1000, inbound: true, type: Types.UserOperationType.INCOMING_INVOICE, identifier: userInvoice.invoice, operationId, network_fee: 0, service_fee: fee, confirmed: true, tx_hash: "", internal } this.sendOperationToNostr(userInvoice.linkedApplication, userInvoice.user.user_id, op) this.createZapReceipt(log, userInvoice) - log("paid invoice processed successfully") this.liquidityManager.afterInInvoicePaid() + this.utils.stateBundler.AddTxPoint('invoiceWasPaid', amount, { used, from: 'system', timeDiscount: true }) } catch (err: any) { + this.utils.stateBundler.AddTxPointFailed('invoiceWasPaid', amount, { used, from: 'system' }) log(ERROR, "cannot process paid invoice", err.message || "") } }) @@ -239,7 +253,6 @@ export default class { async createZapReceipt(log: PubLogger, invoice: UserReceivingInvoice) { const zapInfo = invoice.zap_info if (!zapInfo || !invoice.linkedApplication || !invoice.linkedApplication.nostr_public_key) { - log(ERROR, "no zap info linked to payment") return } const tags = [["p", zapInfo.pub], ["bolt11", invoice.invoice], ["description", zapInfo.description]] diff --git a/src/services/main/init.ts b/src/services/main/init.ts index 5dbf31be..e47b55c9 100644 --- a/src/services/main/init.ts +++ b/src/services/main/init.ts @@ -1,73 +1,92 @@ -import { PubLogger, getLogger } from "../helpers/logger.js" -import { LiquidityProvider } from "../lnd/liquidityProvider.js" -import Storage from "../storage/index.js" -import { TypeOrmMigrationRunner } from "../storage/migrations/runner.js" -import Main from "./index.js" -import SanityChecker from "./sanityChecker.js" -import { MainSettings } from "./settings.js" -export type AppData = { - privateKey: string; - publicKey: string; - appId: string; - name: string; -} -export const initMainHandler = async (log: PubLogger, mainSettings: MainSettings) => { - const storageManager = new Storage(mainSettings.storageSettings) - const manualMigration = await TypeOrmMigrationRunner(log, storageManager, mainSettings.storageSettings.dbSettings, process.argv[2]) - if (manualMigration) { - return - } - - const mainHandler = new Main(mainSettings, storageManager) - await mainHandler.lnd.Warmup() - if (!mainSettings.skipSanityCheck) { - const sanityChecker = new SanityChecker(storageManager, mainHandler.lnd) - await sanityChecker.VerifyEventsLog() - } - await mainHandler.paymentManager.watchDog.Start() - const appsData = await mainHandler.storage.applicationStorage.GetApplications() - const existingWalletApp = await appsData.find(app => app.name === 'wallet' || app.name === 'wallet-test') - if (!existingWalletApp) { - log("no default wallet app found, creating one...") - const newWalletApp = await mainHandler.storage.applicationStorage.AddApplication('wallet', true) - appsData.push(newWalletApp) - } - const apps: AppData[] = await Promise.all(appsData.map(app => { - if (!app.nostr_private_key || !app.nostr_public_key) { // TMP -- - return mainHandler.storage.applicationStorage.GenerateApplicationKeys(app); - } // -- - else { - return { privateKey: app.nostr_private_key, publicKey: app.nostr_public_key, appId: app.app_id, name: app.name } - } - })) - const liquidityProviderApp = apps.find(app => app.name === 'wallet' || app.name === 'wallet-test') - if (!liquidityProviderApp) { - throw new Error("wallet app not initialized correctly") - } - const liquidityProviderInfo = { - privateKey: liquidityProviderApp.privateKey, - publicKey: liquidityProviderApp.publicKey, - name: "liquidity_provider", clientId: `client_${liquidityProviderApp.appId}` - } - mainHandler.liquidProvider.setNostrInfo({ clientId: liquidityProviderInfo.clientId, myPub: liquidityProviderInfo.publicKey }) - const stop = await processArgs(mainHandler) - if (stop) { - return - } - return { mainHandler, apps, liquidityProviderInfo, liquidityProviderApp } -} - -const processArgs = async (mainHandler: Main) => { - switch (process.argv[2]) { - case 'updateUserBalance': - await mainHandler.storage.userStorage.UpdateUser(process.argv[3], { balance_sats: +process.argv[4] }) - getLogger({ userId: process.argv[3] })(`user balance updated correctly`) - return false - case 'unlock': - await mainHandler.storage.userStorage.UnbanUser(process.argv[3]) - getLogger({ userId: process.argv[3] })(`user unlocked`) - return false - default: - return false - } +import { PubLogger, getLogger } from "../helpers/logger.js" +import { LiquidityProvider } from "./liquidityProvider.js" +import { Unlocker } from "./unlocker.js" +import Storage from "../storage/index.js" +import { TypeOrmMigrationRunner } from "../storage/migrations/runner.js" +import Main from "./index.js" +import SanityChecker from "./sanityChecker.js" +import { LoadMainSettingsFromEnv, MainSettings } from "./settings.js" +import { Utils } from "../helpers/utilsWrapper.js" +import { Wizard } from "../wizard/index.js" +import { AdminManager } from "./adminManager.js" +import { encodeNprofile } from "../../custom-nip19.js" +export type AppData = { + privateKey: string; + publicKey: string; + appId: string; + name: string; +} +export const initMainHandler = async (log: PubLogger, mainSettings: MainSettings) => { + const utils = new Utils(mainSettings) + const storageManager = new Storage(mainSettings.storageSettings) + const manualMigration = await TypeOrmMigrationRunner(log, storageManager, mainSettings.storageSettings.dbSettings, process.argv[2]) + if (manualMigration) { + return + } + const unlocker = new Unlocker(mainSettings, storageManager) + await unlocker.Unlock() + const adminManager = new AdminManager(mainSettings, storageManager) + let reloadedSettings = mainSettings + let wizard: Wizard | null = null + if (mainSettings.wizard) { + wizard = new Wizard(mainSettings, storageManager, adminManager) + const reload = await wizard.Configure() + if (reload) { + reloadedSettings = LoadMainSettingsFromEnv() + } + } + + const mainHandler = new Main(reloadedSettings, storageManager, adminManager, utils) + await mainHandler.lnd.Warmup() + if (!reloadedSettings.skipSanityCheck) { + const sanityChecker = new SanityChecker(storageManager, mainHandler.lnd) + await sanityChecker.VerifyEventsLog() + } + const appsData = await mainHandler.storage.applicationStorage.GetApplications() + const defaultNames = ['wallet', 'wallet-test', reloadedSettings.defaultAppName] + const existingWalletApp = await appsData.find(app => defaultNames.includes(app.name)) + if (!existingWalletApp) { + log("no default wallet app found, creating one...") + const newWalletApp = await mainHandler.storage.applicationStorage.AddApplication(reloadedSettings.defaultAppName, true) + appsData.push(newWalletApp) + } + const apps: AppData[] = await Promise.all(appsData.map(app => { + if (!app.nostr_private_key || !app.nostr_public_key) { // TMP -- + return mainHandler.storage.applicationStorage.GenerateApplicationKeys(app); + } // -- + else { + return { privateKey: app.nostr_private_key, publicKey: app.nostr_public_key, appId: app.app_id, name: app.name } + } + })) + const liquidityProviderApp = apps.find(app => defaultNames.includes(app.name)) + if (!liquidityProviderApp) { + throw new Error("wallet app not initialized correctly") + } + const liquidityProviderInfo = { + privateKey: liquidityProviderApp.privateKey, + publicKey: liquidityProviderApp.publicKey, + name: "liquidity_provider", clientId: `client_${liquidityProviderApp.appId}` + } + mainHandler.liquidityProvider.setNostrInfo({ clientId: liquidityProviderInfo.clientId, myPub: liquidityProviderInfo.publicKey }) + const stop = await processArgs(mainHandler) + if (stop) { + return + } + mainHandler.paymentManager.watchDog.Start() + return { mainHandler, apps, liquidityProviderInfo, liquidityProviderApp, wizard, adminManager } +} + +const processArgs = async (mainHandler: Main) => { + switch (process.argv[2]) { + case 'updateUserBalance': + await mainHandler.storage.userStorage.UpdateUser(process.argv[3], { balance_sats: +process.argv[4] }) + getLogger({ userId: process.argv[3] })(`user balance updated correctly`) + return false + case 'unlock': + await mainHandler.storage.userStorage.UnbanUser(process.argv[3]) + getLogger({ userId: process.argv[3] })(`user unlocked`) + return false + default: + return false + } } \ No newline at end of file diff --git a/src/services/main/liquidityManager.ts b/src/services/main/liquidityManager.ts index c583e149..71fd87b7 100644 --- a/src/services/main/liquidityManager.ts +++ b/src/services/main/liquidityManager.ts @@ -1,9 +1,11 @@ import { getLogger } from "../helpers/logger.js" -import { LiquidityProvider } from "../lnd/liquidityProvider.js" +import { Utils } from "../helpers/utilsWrapper.js" +import { LiquidityProvider } from "./liquidityProvider.js" import LND from "../lnd/lnd.js" import { FlashsatsLSP, LoadLSPSettingsFromEnv, LSPSettings, OlympusLSP, VoltageLSP } from "../lnd/lsp.js" import Storage from '../storage/index.js' import { defaultInvoiceExpiry } from "../storage/paymentStorage.js" +import { RugPullTracker } from "./rugPullTracker.js" export type LiquiditySettings = { lspSettings: LSPSettings liquidityProviderPub: string @@ -18,6 +20,7 @@ export class LiquidityManager { settings: LiquiditySettings storage: Storage liquidityProvider: LiquidityProvider + rugPullTracker: RugPullTracker lnd: LND olympusLSP: OlympusLSP voltageLSP: VoltageLSP @@ -25,82 +28,196 @@ export class LiquidityManager { log = getLogger({ component: "liquidityManager" }) channelRequested = false channelRequesting = false - constructor(settings: LiquiditySettings, storage: Storage, liquidityProvider: LiquidityProvider, lnd: LND) { + feesPaid = 0 + utils: Utils + latestDrain: ({ success: true, amt: number } | { success: false, amt: number, attempt: number, at: Date }) = { success: true, amt: 0 } + drainsSkipped = 0 + constructor(settings: LiquiditySettings, storage: Storage, utils: Utils, liquidityProvider: LiquidityProvider, lnd: LND, rugPullTracker: RugPullTracker) { this.settings = settings this.storage = storage this.liquidityProvider = liquidityProvider this.lnd = lnd + this.rugPullTracker = rugPullTracker + this.utils = utils this.olympusLSP = new OlympusLSP(settings.lspSettings, lnd, liquidityProvider) this.voltageLSP = new VoltageLSP(settings.lspSettings, lnd, liquidityProvider) this.flashsatsLSP = new FlashsatsLSP(settings.lspSettings, lnd, liquidityProvider) } + + GetPaidFees = () => { + this.utils.stateBundler.AddBalancePoint('feesPaidForLiquidity', this.feesPaid) + return this.feesPaid + } + onNewBlock = async () => { - const balance = await this.liquidityProvider.GetLatestMaxWithdrawable() - const { remote } = await this.lnd.ChannelBalance() - if (remote > balance) { - this.log("draining provider balance to channel") - const invoice = await this.lnd.NewInvoice(balance, "liqudity provider drain", defaultInvoiceExpiry) - const res = await this.liquidityProvider.PayInvoice(invoice.payRequest) - this.log("drained provider balance to channel", res.amount_paid) + try { + await this.shouldDrainProvider() + } catch (err: any) { + this.log("error in onNewBlock", err.message || err) } } beforeInvoiceCreation = async (amount: number): Promise<'lnd' | 'provider'> => { - const { remote } = await this.lnd.ChannelBalance() - if (remote > amount) { - this.log("channel has enough balance for invoice") + if (this.settings.useOnlyLiquidityProvider) { + return 'provider' + } + + if (this.rugPullTracker.HasProviderRugPulled()) { + return 'lnd' + } + + const { remote } = await this.lnd.ChannelBalance() + if (remote > amount) { + return 'lnd' + } + const providerCanHandle = this.liquidityProvider.CanProviderHandle({ action: 'receive', amount }) + if (!providerCanHandle) { return 'lnd' } - this.log("channel does not have enough balance for invoice,suggesting provider") return 'provider' } + afterInInvoicePaid = async () => { + try { + await this.orderChannelIfNeeded() + } catch (e: any) { + this.log("error ordering channel", e) + } + } + + beforeOutInvoicePayment = async (amount: number): Promise<'lnd' | 'provider'> => { + if (this.settings.useOnlyLiquidityProvider) { + return 'provider' + } + const canHandle = await this.liquidityProvider.CanProviderHandle({ action: 'spend', amount }) + if (canHandle) { + return 'provider' + } + return 'lnd' + } + afterOutInvoicePaid = async () => { } + + shouldDrainProvider = async () => { + const maxW = await this.liquidityProvider.GetLatestMaxWithdrawable() + const { remote } = await this.lnd.ChannelBalance() + const drainable = Math.min(maxW, remote) + if (drainable < 500) { + return + } + if (this.latestDrain.success) { + if (this.latestDrain.amt === 0) { + await this.drainProvider(drainable) + } else { + await this.drainProvider(Math.min(drainable, this.latestDrain.amt * 2)) + } + } else if (this.latestDrain.attempt * 10 < this.drainsSkipped) { + const drain = Math.min(drainable, Math.ceil(this.latestDrain.amt / 2)) + this.drainsSkipped = 0 + if (drain < 500) { + this.log("drain attempt went below 500 sats, will start again") + this.updateLatestDrain(true, 0) + } else { + await this.drainProvider(drain) + } + } else { + this.drainsSkipped += 1 + } + } + + drainProvider = async (amt: number) => { + try { + const invoice = await this.lnd.NewInvoice(amt, "liqudity provider drain", defaultInvoiceExpiry, { from: 'system', useProvider: false }) + const res = await this.liquidityProvider.PayInvoice(invoice.payRequest, amt, 'system') + const fees = res.network_fee + res.service_fee + this.feesPaid += fees + this.updateLatestDrain(true, amt) + } catch (err: any) { + this.log("error draining provider balance", err.message || err) + this.updateLatestDrain(false, amt) + } + } + + updateLatestDrain = (success: boolean, amt: number) => { + if (this.latestDrain.success) { + if (success) { + this.latestDrain = { success: true, amt } + } else { + this.latestDrain = { success: false, amt, attempt: 1, at: new Date() } + } + } else { + if (success) { + this.latestDrain = { success: true, amt } + } else { + this.latestDrain = { success: false, amt, attempt: this.latestDrain.attempt + 1, at: new Date() } + } + } + } + + + shouldOpenChannel = async (): Promise<{ shouldOpen: false } | { shouldOpen: true, maxSpendable: number }> => { + const threshold = this.settings.lspSettings.channelThreshold + if (threshold === 0) { + return { shouldOpen: false } + } + const { remote } = await this.lnd.ChannelBalance() + if (remote > threshold) { + return { shouldOpen: false } + } + const pendingChannels = await this.lnd.ListPendingChannels() + if (pendingChannels.pendingOpenChannels.length > 0) { + return { shouldOpen: false } + } + const maxW = await this.liquidityProvider.GetLatestMaxWithdrawable() + if (maxW < threshold) { + return { shouldOpen: false } + } + return { shouldOpen: true, maxSpendable: maxW } + } + + orderChannelIfNeeded = async () => { const existingOrder = await this.storage.liquidityStorage.GetLatestLspOrder() - if (existingOrder) { + if (existingOrder && existingOrder.created_at > new Date(Date.now() - 20 * 60 * 1000)) { + this.log("most recent lsp order is less than 20 minutes old") + return + } + const shouldOpen = await this.shouldOpenChannel() + if (!shouldOpen.shouldOpen) { return } if (this.channelRequested || this.channelRequesting) { return } this.channelRequesting = true - this.log("checking if channel should be requested") - const olympusOk = await this.olympusLSP.openChannelIfReady() + this.log("requesting channel from lsp") + const olympusOk = await this.olympusLSP.requestChannel(shouldOpen.maxSpendable) if (olympusOk) { this.log("requested channel from olympus") this.channelRequested = true this.channelRequesting = false + this.feesPaid += olympusOk.fees await this.storage.liquidityStorage.SaveLspOrder({ service_name: 'olympus', invoice: olympusOk.invoice, total_paid: olympusOk.totalSats, order_id: olympusOk.orderId, fees: olympusOk.fees }) return } - const voltageOk = await this.voltageLSP.openChannelIfReady() + const voltageOk = await this.voltageLSP.requestChannel(shouldOpen.maxSpendable) if (voltageOk) { this.log("requested channel from voltage") this.channelRequested = true this.channelRequesting = false + this.feesPaid += voltageOk.fees await this.storage.liquidityStorage.SaveLspOrder({ service_name: 'voltage', invoice: voltageOk.invoice, total_paid: voltageOk.totalSats, order_id: voltageOk.orderId, fees: voltageOk.fees }) return } - const flashsatsOk = await this.flashsatsLSP.openChannelIfReady() + const flashsatsOk = await this.flashsatsLSP.requestChannel(shouldOpen.maxSpendable) if (flashsatsOk) { this.log("requested channel from flashsats") this.channelRequested = true this.channelRequesting = false + this.feesPaid += flashsatsOk.fees await this.storage.liquidityStorage.SaveLspOrder({ service_name: 'flashsats', invoice: flashsatsOk.invoice, total_paid: flashsatsOk.totalSats, order_id: flashsatsOk.orderId, fees: flashsatsOk.fees }) return } this.channelRequesting = false this.log("no channel requested") } - - beforeOutInvoicePayment = async (amount: number): Promise<'lnd' | 'provider'> => { - const balance = await this.liquidityProvider.GetLatestMaxWithdrawable(true) - if (balance > amount) { - this.log("provider has enough balance for payment") - return 'provider' - } - this.log("provider does not have enough balance for payment, suggesting lnd") - return 'lnd' - } - afterOutInvoicePaid = async () => { } } \ No newline at end of file diff --git a/src/services/main/liquidityProvider.ts b/src/services/main/liquidityProvider.ts new file mode 100644 index 00000000..47f44b17 --- /dev/null +++ b/src/services/main/liquidityProvider.ts @@ -0,0 +1,338 @@ +import newNostrClient from '../../../proto/autogenerated/ts/nostr_client.js' +import { NostrRequest } from '../../../proto/autogenerated/ts/nostr_transport.js' +import * as Types from '../../../proto/autogenerated/ts/types.js' +import { decodeNprofile } from '../../custom-nip19.js' +import { getLogger } from '../helpers/logger.js' +import { Utils } from '../helpers/utilsWrapper.js' +import { NostrEvent, NostrSend } from '../nostr/handler.js' +import { relayInit } from '../nostr/tools/relay.js' +import { InvoicePaidCb } from '../lnd/settings.js' +import Storage from '../storage/index.js' +export type LiquidityRequest = { action: 'spend' | 'receive', amount: number } + +export type nostrCallback = { startedAtMillis: number, type: 'single' | 'stream', f: (res: T) => void } +export class LiquidityProvider { + + client: ReturnType + clientCbs: Record> = {} + clientId: string = "" + myPub: string = "" + log = getLogger({ component: 'liquidityProvider' }) + nostrSend: NostrSend | null = null + configured = false + pubDestination: string + ready: boolean + invoicePaidCb: InvoicePaidCb + connecting = false + configuredInterval: NodeJS.Timeout + queue: ((state: 'ready') => void)[] = [] + utils: Utils + pendingPayments: Record = {} + incrementProviderBalance: (balance: number) => Promise + // make the sub process accept client + constructor(pubDestination: string, utils: Utils, invoicePaidCb: InvoicePaidCb, incrementProviderBalance: (balance: number) => Promise) { + this.utils = utils + if (!pubDestination) { + this.log("No pub provider to liquidity provider, will not be initialized") + return + } + this.log("connecting to liquidity provider:", pubDestination) + this.pubDestination = pubDestination + this.invoicePaidCb = invoicePaidCb + this.incrementProviderBalance = incrementProviderBalance + this.client = newNostrClient({ + pubDestination: this.pubDestination, + retrieveNostrUserAuth: async () => this.myPub, + retrieveNostrAdminAuth: async () => this.myPub, + retrieveNostrMetricsAuth: async () => this.myPub, + }, this.clientSend, this.clientSub) + + this.configuredInterval = setInterval(() => { + if (this.configured) { + clearInterval(this.configuredInterval) + this.Connect() + } + }, 1000) + } + + GetProviderDestination() { + return this.pubDestination + } + + IsReady = () => { + return this.ready + } + + AwaitProviderReady = async (): Promise<'inactive' | 'ready'> => { + if (!this.pubDestination) { + return 'inactive' + } + if (this.ready) { + return 'ready' + } + return new Promise<'ready'>(res => { + this.queue.push(res) + }) + } + + Stop = () => { + clearInterval(this.configuredInterval) + } + + Connect = async () => { + await new Promise(res => setTimeout(res, 2000)) + const res = await this.GetUserState() + if (res.status === 'ERROR' && res.reason !== 'timeout') { + return + } + this.log("provider ready with balance:", res.status === 'OK' ? res.balance : 0) + this.ready = true + this.queue.forEach(q => q('ready')) + this.log("subbing to user operations") + this.client.GetLiveUserOperations(res => { + if (res.status === 'ERROR') { + this.log("error getting user operations", res.reason) + return + } + //this.log("got user operation", res.operation) + if (res.operation.type === Types.UserOperationType.INCOMING_INVOICE) { + this.incrementProviderBalance(res.operation.amount) + this.invoicePaidCb(res.operation.identifier, res.operation.amount, 'provider') + } + }) + } + + GetUserState = async () => { + const res = await Promise.race([this.client.GetUserInfo(), new Promise(res => setTimeout(() => res({ status: 'ERROR', reason: 'timeout' }), 10 * 1000))]) + if (res.status === 'ERROR') { + this.log("error getting user info", res.reason) + return res + } + this.utils.stateBundler.AddBalancePoint('providerBalance', res.balance) + this.utils.stateBundler.AddBalancePoint('providerMaxWithdrawable', res.max_withdrawable) + return res + } + + GetLatestMaxWithdrawable = async () => { + if (!this.ready) { + return 0 + } + const res = await this.GetUserState() + if (res.status === 'ERROR') { + this.log("error getting user info", res.reason) + return 0 + } + return res.max_withdrawable + } + + GetLatestBalance = async () => { + if (!this.ready) { + return 0 + } + const res = await this.GetUserState() + if (res.status === 'ERROR') { + this.log("error getting user info", res.reason) + return 0 + } + return res.balance + } + + GetPendingBalance = async () => { + return Object.values(this.pendingPayments).reduce((a, b) => a + b, 0) + } + + CalculateExpectedFeeLimit = (amount: number, info: Types.UserInfo) => { + const serviceFeeRate = info.service_fee_bps / 10000 + const serviceFee = Math.ceil(serviceFeeRate * amount) + const networkMaxFeeRate = info.network_max_fee_bps / 10000 + const networkFeeLimit = Math.ceil(amount * networkMaxFeeRate + info.network_max_fee_fixed) + return serviceFee + networkFeeLimit + } + + CanProviderHandle = async (req: LiquidityRequest) => { + if (!this.ready) { + return false + } + const maxW = await this.GetLatestMaxWithdrawable() + if (req.action === 'spend') { + return maxW > req.amount + } + return true + } + + AddInvoice = async (amount: number, memo: string, from: 'user' | 'system') => { + try { + if (!this.ready) { + throw new Error("liquidity provider is not ready yet") + } + const res = await this.client.NewInvoice({ amountSats: amount, memo }) + if (res.status === 'ERROR') { + this.log("error creating invoice", res.reason) + throw new Error(res.reason) + } + this.utils.stateBundler.AddTxPoint('addedInvoice', amount, { used: 'provider', from }) + return res.invoice + } catch (err) { + this.utils.stateBundler.AddTxPointFailed('addedInvoice', amount, { used: 'provider', from }) + throw err + } + + } + + PayInvoice = async (invoice: string, decodedAmount: number, from: 'user' | 'system') => { + try { + if (!this.ready) { + throw new Error("liquidity provider is not ready yet") + } + const userInfo = await this.GetUserState() + if (userInfo.status === 'ERROR') { + throw new Error(userInfo.reason) + } + this.pendingPayments[invoice] = decodedAmount + this.CalculateExpectedFeeLimit(decodedAmount, userInfo) + const res = await this.client.PayInvoice({ invoice, amount: 0 }) + if (res.status === 'ERROR') { + this.log("error paying invoice", res.reason) + throw new Error(res.reason) + } + const totalPaid = res.amount_paid + res.network_fee + res.service_fee + this.incrementProviderBalance(-totalPaid).then(() => { delete this.pendingPayments[invoice] }) + this.utils.stateBundler.AddTxPoint('paidAnInvoice', decodedAmount, { used: 'provider', from, timeDiscount: true }) + return res + } catch (err) { + delete this.pendingPayments[invoice] + this.utils.stateBundler.AddTxPointFailed('paidAnInvoice', decodedAmount, { used: 'provider', from }) + throw err + } + } + + GetOperations = async () => { + if (!this.ready) { + throw new Error("liquidity provider is not ready yet") + } + const res = await this.client.GetUserOperations({ + latestIncomingInvoice: 0, latestOutgoingInvoice: 0, + latestIncomingTx: 0, latestOutgoingTx: 0, latestIncomingUserToUserPayment: 0, + latestOutgoingUserToUserPayment: 0, max_size: 200 + }) + if (res.status === 'ERROR') { + this.log("error getting operations", res.reason) + throw new Error(res.reason) + } + return res + } + + setNostrInfo = ({ clientId, myPub }: { myPub: string, clientId: string }) => { + this.log("setting nostr info") + this.clientId = clientId + this.myPub = myPub + this.setSetIfConfigured() + } + + + + attachNostrSend(f: NostrSend) { + this.log("attaching nostrSend action") + this.nostrSend = f + this.setSetIfConfigured() + } + + setSetIfConfigured = () => { + if (this.nostrSend && !!this.pubDestination && !!this.clientId && !!this.myPub) { + this.configured = true + this.log("configured to send to ", this.pubDestination) + } + } + + onEvent = async (res: { requestId: string }, fromPub: string) => { + if (fromPub !== this.pubDestination) { + this.log("got event from invalid pub", fromPub, this.pubDestination) + return false + } + if (this.clientCbs[res.requestId]) { + const cb = this.clientCbs[res.requestId] + + cb.f(res) + if (cb.type === 'single') { + delete this.clientCbs[res.requestId] + this.utils.stateBundler.AddMaxPoint('maxProviderRespTime', Date.now() - cb.startedAtMillis) + } + return true + } + return false + } + + clientSend = (to: string, message: NostrRequest): Promise => { + if (!this.configured || !this.nostrSend) { + throw new Error("liquidity provider not initialized") + } + if (!message.requestId) { + message.requestId = makeId(16) + } + const reqId = message.requestId + if (this.clientCbs[reqId]) { + throw new Error("request was already sent") + } + this.nostrSend({ type: 'client', clientId: this.clientId }, { + type: 'content', + pub: to, + content: JSON.stringify(message) + }) + + //this.nostrSend(this.relays, to, JSON.stringify(message), this.settings) + + // this.log("subbing to single send", reqId, message.rpcName || 'no rpc name') + return new Promise(res => { + this.clientCbs[reqId] = { + startedAtMillis: Date.now(), + type: 'single', + f: (response: any) => { res(response) }, + } + }) + } + + clientSub = (to: string, message: NostrRequest, cb: (res: any) => void): void => { + if (!this.configured || !this.nostrSend) { + throw new Error("liquidity provider not initialized") + } + if (!message.requestId) { + message.requestId = message.rpcName + } + const reqId = message.requestId + if (!reqId) { + throw new Error("invalid sub") + } + if (this.clientCbs[reqId]) { + this.clientCbs[reqId] = { + startedAtMillis: Date.now(), + type: 'stream', + f: (response: any) => { cb(response) }, + } + this.log("sub for", reqId, "was already registered, overriding") + return + } + this.nostrSend({ type: 'client', clientId: this.clientId }, { + type: 'content', + pub: to, + content: JSON.stringify(message) + }) + this.log("subbing to stream", reqId) + this.clientCbs[reqId] = { + startedAtMillis: Date.now(), + type: 'stream', + f: (response: any) => { cb(response) } + } + } + getSingleSubs = () => { + return Object.entries(this.clientCbs).filter(([_, cb]) => cb.type === 'single') + } +} + +export const makeId = (length: number) => { + let result = ''; + const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; + const charactersLength = characters.length; + for (let i = 0; i < length; i++) { + result += characters.charAt(Math.floor(Math.random() * charactersLength)); + } + return result; +} \ No newline at end of file diff --git a/src/services/main/paymentManager.ts b/src/services/main/paymentManager.ts index 77144209..8cfc56b0 100644 --- a/src/services/main/paymentManager.ts +++ b/src/services/main/paymentManager.ts @@ -15,8 +15,10 @@ import { Event, verifiedSymbol, verifySignature } from '../nostr/tools/event.js' import { AddressReceivingTransaction } from '../storage/entity/AddressReceivingTransaction.js' import { UserTransactionPayment } from '../storage/entity/UserTransactionPayment.js' import { Watchdog } from './watchdog.js' -import { LiquidityProvider } from '../lnd/liquidityProvider.js' +import { LiquidityProvider } from './liquidityProvider.js' import { LiquidityManager } from './liquidityManager.js' +import { Utils } from '../helpers/utilsWrapper.js' +import { UserInvoicePayment } from '../storage/entity/UserInvoicePayment.js' interface UserOperationInfo { serial_id: number paid_amount: number @@ -49,12 +51,14 @@ export default class { log = getLogger({ component: "PaymentManager" }) watchDog: Watchdog liquidityManager: LiquidityManager - constructor(storage: Storage, lnd: LND, settings: MainSettings, liquidityManager: LiquidityManager, addressPaidCb: AddressPaidCb, invoicePaidCb: InvoicePaidCb) { + utils: Utils + constructor(storage: Storage, lnd: LND, settings: MainSettings, liquidityManager: LiquidityManager, utils: Utils, addressPaidCb: AddressPaidCb, invoicePaidCb: InvoicePaidCb) { this.storage = storage this.settings = settings this.lnd = lnd - this.watchDog = new Watchdog(settings.watchDogSettings, lnd, storage) this.liquidityManager = liquidityManager + this.utils = utils + this.watchDog = new Watchdog(settings.watchDogSettings, this.liquidityManager, this.lnd, this.storage, this.utils, this.liquidityManager.rugPullTracker) this.addressPaidCb = addressPaidCb this.invoicePaidCb = invoicePaidCb } @@ -113,7 +117,7 @@ export default class { if (existingAddress) { return { address: existingAddress.address } } - const res = await this.lnd.NewAddress(req.addressType) + const res = await this.lnd.NewAddress(req.addressType, { useProvider: false, from: 'user' }) const userAddress = await this.storage.paymentStorage.AddUserAddress(user, res.address, { linkedApplication: app }) this.storage.eventsLog.LogEvent({ type: 'new_address', userId: user.user_id, appUserId: "", appId: app.app_id, balance: user.balance_sats, data: res.address, amount: 0 }) return { address: userAddress.address } @@ -125,8 +129,8 @@ export default class { throw new Error("user is banned, cannot generate invoice") } const use = await this.liquidityManager.beforeInvoiceCreation(req.amountSats) - const res = await this.lnd.NewInvoice(req.amountSats, req.memo, options.expiry, use === 'provider') - const userInvoice = await this.storage.paymentStorage.AddUserInvoice(user, res.payRequest, options) + const res = await this.lnd.NewInvoice(req.amountSats, req.memo, options.expiry, { useProvider: use === 'provider', from: 'user' }) + const userInvoice = await this.storage.paymentStorage.AddUserInvoice(user, res.payRequest, options, res.providerDst) const appId = options.linkedApplication ? options.linkedApplication.app_id : "" this.storage.eventsLog.LogEvent({ type: 'new_invoice', userId: user.user_id, appUserId: "", appId, balance: user.balance_sats, data: userInvoice.invoice, amount: req.amountSats }) return { @@ -151,7 +155,6 @@ export default class { } async PayInvoice(userId: string, req: Types.PayInvoiceRequest, linkedApplication: Application): Promise { - this.log("paying invoice", req.invoice, "for user", userId, "with amount", req.amount) await this.watchDog.PaymentRequested() const maybeBanned = await this.storage.userStorage.GetUser(userId) if (maybeBanned.locked) { @@ -191,7 +194,7 @@ export default class { amount_paid: paymentInfo.amtPaid, operation_id: `${Types.UserOperationType.OUTGOING_INVOICE}-${paymentInfo.serialId}`, network_fee: paymentInfo.networkFee, - service_fee: serviceFee + service_fee: serviceFee, } } @@ -199,42 +202,60 @@ export default class { if (this.settings.disableExternalPayments) { throw new Error("something went wrong sending payment, please try again later") } + const existingPendingPayment = await this.storage.paymentStorage.GetPaymentOwner(invoice) + if (existingPendingPayment) { + if (existingPendingPayment.paid_at_unix > 0) { + throw new Error("this invoice was already paid") + } else if (existingPendingPayment.paid_at_unix < 0) { + throw new Error("this invoice was already paid and failed, try another invoice") + } + throw new Error("payment already in progress") + } const { amountForLnd, payAmount, serviceFee } = amounts const totalAmountToDecrement = payAmount + serviceFee - this.log("paying external invoice", invoice) const routingFeeLimit = this.lnd.GetFeeLimitAmount(payAmount) await this.storage.userStorage.DecrementUserBalance(userId, totalAmountToDecrement + routingFeeLimit, invoice) - const pendingPayment = await this.storage.paymentStorage.AddPendingExternalPayment(userId, invoice, payAmount, linkedApplication) - const use = await this.liquidityManager.beforeOutInvoicePayment(payAmount) + let pendingPayment: UserInvoicePayment | null = null try { - const payment = await this.lnd.PayInvoice(invoice, amountForLnd, routingFeeLimit, use === 'provider') - + pendingPayment = await this.storage.paymentStorage.AddPendingExternalPayment(userId, invoice, payAmount, linkedApplication) + const use = await this.liquidityManager.beforeOutInvoicePayment(payAmount) + const payment = await this.lnd.PayInvoice(invoice, amountForLnd, routingFeeLimit, payAmount, { useProvider: use === 'provider', from: 'user' }) if (routingFeeLimit - payment.feeSat > 0) { this.log("refund routing fee", routingFeeLimit, payment.feeSat, "sats") await this.storage.userStorage.IncrementUserBalance(userId, routingFeeLimit - payment.feeSat, "routing_fee_refund:" + invoice) } - await this.storage.paymentStorage.UpdateExternalPayment(pendingPayment.serial_id, payment.feeSat, serviceFee, true) + await this.storage.paymentStorage.UpdateExternalPayment(pendingPayment.serial_id, payment.feeSat, serviceFee, true, payment.providerDst) return { preimage: payment.paymentPreimage, amtPaid: payment.valueSat, networkFee: payment.feeSat, serialId: pendingPayment.serial_id } } catch (err) { await this.storage.userStorage.IncrementUserBalance(userId, totalAmountToDecrement + routingFeeLimit, "payment_refund:" + invoice) - await this.storage.paymentStorage.UpdateExternalPayment(pendingPayment.serial_id, 0, 0, false) + if (pendingPayment) { + await this.storage.paymentStorage.UpdateExternalPayment(pendingPayment.serial_id, 0, 0, false) + } throw err } } async PayInternalInvoice(userId: string, internalInvoice: UserReceivingInvoice, amounts: { payAmount: number, serviceFee: number }, linkedApplication: Application) { - this.log("paying internal invoice", internalInvoice.invoice) if (internalInvoice.paid_at_unix > 0) { throw new Error("this invoice was already paid") } const { payAmount, serviceFee } = amounts const totalAmountToDecrement = payAmount + serviceFee await this.storage.userStorage.DecrementUserBalance(userId, totalAmountToDecrement, internalInvoice.invoice) - this.invoicePaidCb(internalInvoice.invoice, payAmount, true) - const newPayment = await this.storage.paymentStorage.AddInternalPayment(userId, internalInvoice.invoice, payAmount, serviceFee, linkedApplication) - return { preimage: "", amtPaid: payAmount, networkFee: 0, serialId: newPayment.serial_id } + try { + await this.invoicePaidCb(internalInvoice.invoice, payAmount, 'internal') + const newPayment = await this.storage.paymentStorage.AddInternalPayment(userId, internalInvoice.invoice, payAmount, serviceFee, linkedApplication) + this.utils.stateBundler.AddTxPoint('paidAnInvoice', payAmount, { used: 'internal', from: 'user' }) + return { preimage: "", amtPaid: payAmount, networkFee: 0, serialId: newPayment.serial_id } + } catch (err) { + await this.storage.userStorage.IncrementUserBalance(userId, totalAmountToDecrement, "internal_payment_refund:" + internalInvoice.invoice) + this.utils.stateBundler.AddTxPointFailed('paidAnInvoice', payAmount, { used: 'internal', from: 'user' }) + + throw err + } + } @@ -262,7 +283,7 @@ export default class { // WARNING, before re-enabling this, make sure to add the tx_hash to the DecrementUserBalance "reason"!! this.storage.userStorage.DecrementUserBalance(ctx.user_id, total + serviceFee, req.address) try { - const payment = await this.lnd.PayAddress(req.address, req.amoutSats, req.satsPerVByte) + const payment = await this.lnd.PayAddress(req.address, req.amoutSats, req.satsPerVByte, "", { useProvider: false, from: 'user' }) txId = payment.txid } catch (err) { // WARNING, before re-enabling this, make sure to add the tx_hash to the IncrementUserBalance "reason"!! @@ -274,7 +295,7 @@ export default class { txId = crypto.randomBytes(32).toString("hex") const addressData = `${req.address}:${txId}` await this.storage.userStorage.DecrementUserBalance(ctx.user_id, req.amoutSats + serviceFee, addressData) - this.addressPaidCb({ hash: txId, index: 0 }, req.address, req.amoutSats, true) + this.addressPaidCb({ hash: txId, index: 0 }, req.address, req.amoutSats, 'internal') } if (isAppUserPayment && serviceFee > 0) { @@ -360,11 +381,9 @@ export default class { if (this.isDefaultServiceUrl()) { throw new Error("Lnurl not enabled. Make sure to set SERVICE_URL env variable") } - getLogger({})("getting lnurl pay link") const app = await this.storage.applicationStorage.GetApplication(ctx.app_id) const key = await this.storage.paymentStorage.AddUserEphemeralKey(ctx.user_id, 'pay', app) const lnurl = this.encodeLnurl(this.lnurlPayUrl(key.key)) - getLogger({})("got lnurl pay link: ", lnurl) return { lnurl, k1: key.key diff --git a/src/services/main/rugPullTracker.ts b/src/services/main/rugPullTracker.ts new file mode 100644 index 00000000..308359d8 --- /dev/null +++ b/src/services/main/rugPullTracker.ts @@ -0,0 +1,68 @@ +import FunctionQueue from "../helpers/functionQueue.js"; +import { getLogger } from "../helpers/logger.js"; +import { Utils } from "../helpers/utilsWrapper.js"; +import { LiquidityProvider } from "./liquidityProvider.js"; +import { TrackedProvider } from "../storage/entity/TrackedProvider.js"; +import Storage from "../storage/index.js"; + +export class RugPullTracker { + liquidProvider: LiquidityProvider + storage: Storage + log = getLogger({ component: "rugPullTracker" }) + rugPulled = false + constructor(storage: Storage, liquidProvider: LiquidityProvider) { + this.liquidProvider = liquidProvider + this.storage = storage + } + + HasProviderRugPulled = () => { + return this.rugPulled + } + + CheckProviderBalance = async (): Promise<{ balance: number, prevBalance?: number }> => { + const pubDst = this.liquidProvider.GetProviderDestination() + if (!pubDst) { + return { balance: 0 } + } + const providerTracker = await this.storage.liquidityStorage.GetTrackedProvider('lnPub', pubDst) + const ready = this.liquidProvider.IsReady() + if (ready) { + const balance = await this.liquidProvider.GetLatestBalance() + const pendingBalance = await this.liquidProvider.GetPendingBalance() + const trackedBalance = balance + pendingBalance + this.log({ pendingBalance, balance, trackedBalance }) + if (!providerTracker) { + this.log("starting to track provider", this.liquidProvider.GetProviderDestination()) + await this.storage.liquidityStorage.CreateTrackedProvider('lnPub', pubDst, trackedBalance) + return { balance: trackedBalance } + } + return this.checkForDisruption(pubDst, trackedBalance, providerTracker) + } else { + return { balance: providerTracker?.latest_balance || 0 } + } + } + + checkForDisruption = async (pubDst: string, trackedBalance: number, providerTracker: TrackedProvider) => { + const diff = trackedBalance - providerTracker.latest_balance + this.log({ latestBalance: providerTracker.latest_balance, diff }) + if (diff < 0) { + this.rugPulled = true + if (providerTracker.latest_distruption_at_unix === 0) { + await this.storage.liquidityStorage.UpdateTrackedProviderDisruption('lnPub', pubDst, Math.floor(Date.now() / 1000)) + getLogger({ component: 'rugPull' })("detected rugpull from: ", pubDst, "provider balance changed from", providerTracker.latest_balance, "to", trackedBalance, "losing", diff) + } else { + getLogger({ component: 'rugPull' })("ongoing rugpull from: ", pubDst, "provider balance changed from", providerTracker.latest_balance, "to", trackedBalance, "losing", diff) + } + } else { + this.rugPulled = false + if (providerTracker.latest_distruption_at_unix !== 0) { + await this.storage.liquidityStorage.UpdateTrackedProviderDisruption('lnPub', pubDst, 0) + getLogger({ component: 'rugPull' })("rugpull from: ", pubDst, "cleared after: ", Math.floor(Date.now() / 1000) - providerTracker.latest_distruption_at_unix, "seconds") + } + if (diff > 0) { + this.log("detected excees from: ", pubDst, "provider balance changed from", providerTracker.latest_balance, "to", trackedBalance, "gaining", diff) + } + } + return { balance: trackedBalance, prevBalance: providerTracker.latest_balance } + } +} \ No newline at end of file diff --git a/src/services/main/sanityChecker.ts b/src/services/main/sanityChecker.ts index 7b4c2477..876c122e 100644 --- a/src/services/main/sanityChecker.ts +++ b/src/services/main/sanityChecker.ts @@ -1,268 +1,270 @@ -import Storage from '../storage/index.js' -import LND from "../lnd/lnd.js" -import { LoggedEvent } from '../storage/eventsLog.js' -import { Invoice, Payment } from '../../../proto/lnd/lightning'; -import { getLogger } from '../helpers/logger.js'; -const LN_INVOICE_REGEX = /^(lightning:)?(lnbc|lntb)[0-9a-zA-Z]+$/; -const BITCOIN_ADDRESS_REGEX = /^(bitcoin:)?([13][a-km-zA-HJ-NP-Z1-9]{25,34}|bc1[a-zA-HJ-NP-Z0-9]{39,59})$/; -type UniqueDecrementReasons = 'ban' -type UniqueIncrementReasons = 'fees' | 'routing_fee_refund' | 'payment_refund' -type CommonReasons = 'invoice' | 'address' | 'u2u' -type Reason = UniqueDecrementReasons | UniqueIncrementReasons | CommonReasons -const incrementTwiceAllowed = ['fees', 'ban'] -export default class SanityChecker { - storage: Storage - lnd: LND - - events: LoggedEvent[] = [] - invoices: Invoice[] = [] - payments: Payment[] = [] - incrementSources: Record = {} - decrementSources: Record = {} - decrementEvents: Record = {} - log = getLogger({ component: "SanityChecker" }) - users: Record = {} - constructor(storage: Storage, lnd: LND) { - this.storage = storage - this.lnd = lnd - } - - parseDataField(data: string): { type: Reason, data: string, txHash?: string, serialId?: number } { - const parts = data.split(":") - if (parts.length === 1) { - const [fullData] = parts - if (fullData === 'fees' || fullData === 'ban') { - return { type: fullData, data: fullData } - } else if (LN_INVOICE_REGEX.test(fullData)) { - return { type: 'invoice', data: fullData } - } else if (BITCOIN_ADDRESS_REGEX.test(fullData)) { - return { type: 'address', data: fullData } - } else { - return { type: 'u2u', data: fullData } - } - } else if (parts.length === 2) { - const [prefix, data] = parts - if (prefix === 'routing_fee_refund' || prefix === 'payment_refund') { - return { type: prefix, data } - } else if (BITCOIN_ADDRESS_REGEX.test(prefix)) { - return { type: 'address', data: prefix, txHash: data } - } else { - return { type: 'u2u', data: prefix, serialId: +data } - } - } - throw new Error("unknown data format") - } - - async verifyDecrementEvent(e: LoggedEvent) { - if (this.decrementSources[e.data]) { - throw new Error("entry decremented more that once " + e.data) - } - this.decrementSources[e.data] = !incrementTwiceAllowed.includes(e.data) - this.users[e.userId] = this.checkUserEntry(e, this.users[e.userId]) - const parsed = this.parseDataField(e.data) - switch (parsed.type) { - case 'ban': - return - case 'address': - return this.validateUserTransactionPayment({ address: parsed.data, txHash: parsed.txHash, userId: e.userId }) - case 'invoice': - return this.validateUserInvoicePayment({ invoice: parsed.data, userId: e.userId, amt: e.amount }) - case 'u2u': - return this.validateUser2UserPayment({ fromUser: e.userId, toUser: parsed.data, serialId: parsed.serialId }) - default: - throw new Error("unknown decrement type " + parsed.type) - } - } - - async validateUserTransactionPayment({ address, txHash, userId }: { userId: string, address: string, txHash?: string }) { - if (!txHash) { - throw new Error("no tx hash provided to payment for address " + address) - } - const entry = await this.storage.paymentStorage.GetUserTransactionPaymentOwner(address, txHash) - if (!entry) { - throw new Error("no payment found for tx hash " + txHash) - } - if (entry.user.user_id !== userId) { - throw new Error("payment user id mismatch for tx hash " + txHash) - } - if (entry.paid_at_unix <= 0) { - throw new Error("payment not paid for tx hash " + txHash) - } - } - - async validateUserInvoicePayment({ invoice, userId, amt }: { userId: string, invoice: string, amt: number }) { - const entry = await this.storage.paymentStorage.GetPaymentOwner(invoice) - if (!entry) { - throw new Error("no payment found for invoice " + invoice) - } - if (entry.user.user_id !== userId) { - throw new Error("payment user id mismatch for invoice " + invoice) - } - if (entry.paid_at_unix === 0) { - throw new Error("payment never settled for invoice " + invoice) // TODO: check if this is correct - } - if (entry.paid_at_unix === -1) { - this.decrementEvents[invoice] = { userId, refund: amt, failure: true } - } else { - const refund = amt - (entry.paid_amount + entry.routing_fees + entry.service_fees) - this.decrementEvents[invoice] = { userId, refund, failure: false } - } - if (!entry.internal) { - const lndEntry = this.payments.find(i => i.paymentRequest === invoice) - if (!lndEntry) { - throw new Error("payment not found in lnd for invoice " + invoice) - } - } - } - - async validateUser2UserPayment({ fromUser, toUser, serialId }: { fromUser: string, toUser: string, serialId?: number }) { - if (!serialId) { - throw new Error("no serial id provided to u2u payment") - } - const entry = await this.storage.paymentStorage.GetUser2UserPayment(serialId) - if (!entry) { - throw new Error("no payment u2u found for serial id " + serialId) - } - if (entry.from_user.user_id !== fromUser || entry.to_user.user_id !== toUser) { - throw new Error("u2u payment user id mismatch for serial id " + serialId) - } - if (entry.paid_at_unix <= 0) { - throw new Error("payment not paid for serial id " + serialId) - } - } - - async verifyIncrementEvent(e: LoggedEvent) { - if (this.incrementSources[e.data]) { - throw new Error("entry incremented more that once " + e.data) - } - this.incrementSources[e.data] = !incrementTwiceAllowed.includes(e.data) - this.users[e.userId] = this.checkUserEntry(e, this.users[e.userId]) - const parsed = this.parseDataField(e.data) - switch (parsed.type) { - case 'fees': - return - case 'address': - return this.validateAddressReceivingTransaction({ address: parsed.data, txHash: parsed.txHash, userId: e.userId }) - case 'invoice': - return this.validateReceivingInvoice({ invoice: parsed.data, userId: e.userId }) - case 'u2u': - return this.validateUser2UserPayment({ fromUser: parsed.data, toUser: e.userId, serialId: parsed.serialId }) - case 'routing_fee_refund': - return this.validateRoutingFeeRefund({ amt: e.amount, invoice: parsed.data, userId: e.userId }) - case 'payment_refund': - return this.validatePaymentRefund({ amt: e.amount, invoice: parsed.data, userId: e.userId }) - default: - throw new Error("unknown increment type " + parsed.type) - } - } - - async validateAddressReceivingTransaction({ userId, address, txHash }: { userId: string, address: string, txHash?: string }) { - if (!txHash) { - throw new Error("no tx hash provided to address " + address) - } - const entry = await this.storage.paymentStorage.GetAddressReceivingTransactionOwner(address, txHash) - if (!entry) { - throw new Error("no tx found for tx hash " + txHash) - } - if (entry.user_address.user.user_id !== userId) { - throw new Error("tx user id mismatch for tx hash " + txHash) - } - if (entry.paid_at_unix <= 0) { - throw new Error("tx not paid for tx hash " + txHash) - } - } - - async validateReceivingInvoice({ userId, invoice }: { userId: string, invoice: string }) { - const entry = await this.storage.paymentStorage.GetInvoiceOwner(invoice) - if (!entry) { - throw new Error("no invoice found for invoice " + invoice) - } - if (entry.user.user_id !== userId) { - throw new Error("invoice user id mismatch for invoice " + invoice) - } - if (entry.paid_at_unix <= 0) { - throw new Error("invoice not paid for invoice " + invoice) - } - if (!entry.internal) { - const entry = this.invoices.find(i => i.paymentRequest === invoice) - if (!entry) { - throw new Error("invoice not found in lnd " + invoice) - } - } - } - - async validateRoutingFeeRefund({ amt, invoice, userId }: { userId: string, invoice: string, amt: number }) { - const entry = this.decrementEvents[invoice] - if (!entry) { - throw new Error("no decrement event found for invoice routing fee refound " + invoice) - } - if (entry.userId !== userId) { - throw new Error("user id mismatch for routing fee refund " + invoice) - } - if (entry.failure) { - throw new Error("payment failled, should not refund routing fees " + invoice) - } - if (entry.refund !== amt) { - throw new Error("refund amount mismatch for routing fee refund " + invoice) - } - } - - async validatePaymentRefund({ amt, invoice, userId }: { userId: string, invoice: string, amt: number }) { - const entry = this.decrementEvents[invoice] - if (!entry) { - throw new Error("no decrement event found for invoice payment refund " + invoice) - } - if (entry.userId !== userId) { - throw new Error("user id mismatch for payment refund " + invoice) - } - if (!entry.failure) { - throw new Error("payment did not fail, should not refund payment " + invoice) - } - if (entry.refund !== amt) { - throw new Error("refund amount mismatch for payment refund " + invoice) - } - } - - async VerifyEventsLog() { - this.events = await this.storage.eventsLog.GetAllLogs() - this.invoices = (await this.lnd.GetAllPaidInvoices(1000)).invoices - this.payments = (await this.lnd.GetAllPayments(1000)).payments - this.incrementSources = {} - this.decrementSources = {} - this.users = {} - this.users = {} - this.decrementEvents = {} - for (let i = 0; i < this.events.length; i++) { - const e = this.events[i] - if (e.type === 'balance_decrement') { - await this.verifyDecrementEvent(e) - } else if (e.type === 'balance_increment') { - await this.verifyIncrementEvent(e) - } else { - await this.storage.paymentStorage.VerifyDbEvent(e) - } - } - await Promise.all(Object.entries(this.users).map(async ([userId, u]) => { - const user = await this.storage.userStorage.GetUser(userId) - if (user.balance_sats !== u.updatedBalance) { - throw new Error("sanity check on balance failed, expected: " + u.updatedBalance + " found: " + user.balance_sats) - } - })) - } - - checkUserEntry(e: LoggedEvent, u: { ts: number, updatedBalance: number } | undefined) { - const newEntry = { ts: e.timestampMs, updatedBalance: e.balance + e.amount * (e.type === 'balance_decrement' ? -1 : 1) } - if (!u) { - this.log(e.userId, "balance starts at", e.balance, "sats and moves by", e.amount * (e.type === 'balance_decrement' ? -1 : 1), "sats, resulting in", newEntry.updatedBalance, "sats") - return newEntry - } - if (e.timestampMs < u.ts) { - throw new Error("entry out of order " + e.timestampMs + " " + u.ts) - } - if (e.balance !== u.updatedBalance) { - throw new Error("inconsistent balance update got: " + e.balance + " expected " + u.updatedBalance) - } - this.log(e.userId, "balance updates from", e.balance, "sats and moves by", e.amount * (e.type === 'balance_decrement' ? -1 : 1), "sats, resulting in", newEntry.updatedBalance, "sats") - return newEntry - } +import Storage from '../storage/index.js' +import LND from "../lnd/lnd.js" +import { LoggedEvent } from '../storage/eventsLog.js' +import { Invoice, Payment } from '../../../proto/lnd/lightning'; +import { getLogger } from '../helpers/logger.js'; +import * as Types from '../../../proto/autogenerated/ts/types.js' +const LN_INVOICE_REGEX = /^(lightning:)?(lnbc|lntb)[0-9a-zA-Z]+$/; +const BITCOIN_ADDRESS_REGEX = /^(bitcoin:)?([13][a-km-zA-HJ-NP-Z1-9]{25,34}|bc1[a-zA-HJ-NP-Z0-9]{39,59})$/; +type UniqueDecrementReasons = 'ban' +type UniqueIncrementReasons = 'fees' | 'routing_fee_refund' | 'payment_refund' +type CommonReasons = 'invoice' | 'address' | 'u2u' +type Reason = UniqueDecrementReasons | UniqueIncrementReasons | CommonReasons +const incrementTwiceAllowed = ['fees', 'ban'] +export default class SanityChecker { + storage: Storage + lnd: LND + + events: LoggedEvent[] = [] + invoices: Invoice[] = [] + payments: Payment[] = [] + incrementSources: Record = {} + decrementSources: Record = {} + decrementEvents: Record = {} + log = getLogger({ component: "SanityChecker" }) + users: Record = {} + constructor(storage: Storage, lnd: LND) { + this.storage = storage + this.lnd = lnd + } + + parseDataField(data: string): { type: Reason, data: string, txHash?: string, serialId?: number } { + const parts = data.split(":") + if (parts.length === 1) { + const [fullData] = parts + if (fullData === 'fees' || fullData === 'ban') { + return { type: fullData, data: fullData } + } else if (LN_INVOICE_REGEX.test(fullData)) { + return { type: 'invoice', data: fullData } + } else if (BITCOIN_ADDRESS_REGEX.test(fullData)) { + return { type: 'address', data: fullData } + } else { + return { type: 'u2u', data: fullData } + } + } else if (parts.length === 2) { + const [prefix, data] = parts + if (prefix === 'routing_fee_refund' || prefix === 'payment_refund') { + return { type: prefix, data } + } else if (BITCOIN_ADDRESS_REGEX.test(prefix)) { + return { type: 'address', data: prefix, txHash: data } + } else { + return { type: 'u2u', data: prefix, serialId: +data } + } + } + throw new Error("unknown data format") + } + + async verifyDecrementEvent(e: LoggedEvent) { + if (this.decrementSources[e.data]) { + throw new Error("entry decremented more that once " + e.data) + } + this.decrementSources[e.data] = !incrementTwiceAllowed.includes(e.data) + this.users[e.userId] = this.checkUserEntry(e, this.users[e.userId]) + const parsed = this.parseDataField(e.data) + switch (parsed.type) { + case 'ban': + return + case 'address': + return this.validateUserTransactionPayment({ address: parsed.data, txHash: parsed.txHash, userId: e.userId }) + case 'invoice': + return this.validateUserInvoicePayment({ invoice: parsed.data, userId: e.userId, amt: e.amount }) + case 'u2u': + return this.validateUser2UserPayment({ fromUser: e.userId, toUser: parsed.data, serialId: parsed.serialId }) + default: + throw new Error("unknown decrement type " + parsed.type) + } + } + + async validateUserTransactionPayment({ address, txHash, userId }: { userId: string, address: string, txHash?: string }) { + if (!txHash) { + throw new Error("no tx hash provided to payment for address " + address) + } + const entry = await this.storage.paymentStorage.GetUserTransactionPaymentOwner(address, txHash) + if (!entry) { + throw new Error("no payment found for tx hash " + txHash) + } + if (entry.user.user_id !== userId) { + throw new Error("payment user id mismatch for tx hash " + txHash) + } + if (entry.paid_at_unix <= 0) { + throw new Error("payment not paid for tx hash " + txHash) + } + } + + async validateUserInvoicePayment({ invoice, userId, amt }: { userId: string, invoice: string, amt: number }) { + const entry = await this.storage.paymentStorage.GetPaymentOwner(invoice) + if (!entry) { + throw new Error("no payment found for invoice " + invoice) + } + if (entry.user.user_id !== userId) { + throw new Error("payment user id mismatch for invoice " + invoice) + } + if (entry.paid_at_unix === 0) { + throw new Error("payment never settled for invoice " + invoice) // TODO: check if this is correct + } + if (entry.paid_at_unix === -1) { + this.decrementEvents[invoice] = { userId, refund: amt, failure: true } + return + } + const refund = amt - (entry.paid_amount + entry.routing_fees + entry.service_fees) + this.decrementEvents[invoice] = { userId, refund, failure: false } + if (!entry.internal && !entry.liquidityProvider) { + const lndEntry = this.payments.find(i => i.paymentRequest === invoice) + if (!lndEntry) { + throw new Error("payment not found in lnd for invoice " + invoice) + } + } + } + + async validateUser2UserPayment({ fromUser, toUser, serialId }: { fromUser: string, toUser: string, serialId?: number }) { + if (!serialId) { + throw new Error("no serial id provided to u2u payment") + } + const entry = await this.storage.paymentStorage.GetUser2UserPayment(serialId) + if (!entry) { + throw new Error("no payment u2u found for serial id " + serialId) + } + if (entry.from_user.user_id !== fromUser || entry.to_user.user_id !== toUser) { + throw new Error("u2u payment user id mismatch for serial id " + serialId) + } + if (entry.paid_at_unix <= 0) { + throw new Error("payment not paid for serial id " + serialId) + } + } + + async verifyIncrementEvent(e: LoggedEvent) { + if (this.incrementSources[e.data]) { + throw new Error("entry incremented more that once " + e.data) + } + this.incrementSources[e.data] = !incrementTwiceAllowed.includes(e.data) + this.users[e.userId] = this.checkUserEntry(e, this.users[e.userId]) + const parsed = this.parseDataField(e.data) + switch (parsed.type) { + case 'fees': + return + case 'address': + return this.validateAddressReceivingTransaction({ address: parsed.data, txHash: parsed.txHash, userId: e.userId }) + case 'invoice': + return this.validateReceivingInvoice({ invoice: parsed.data, userId: e.userId }) + case 'u2u': + return this.validateUser2UserPayment({ fromUser: parsed.data, toUser: e.userId, serialId: parsed.serialId }) + case 'routing_fee_refund': + return this.validateRoutingFeeRefund({ amt: e.amount, invoice: parsed.data, userId: e.userId }) + case 'payment_refund': + return this.validatePaymentRefund({ amt: e.amount, invoice: parsed.data, userId: e.userId }) + default: + throw new Error("unknown increment type " + parsed.type) + } + } + + async validateAddressReceivingTransaction({ userId, address, txHash }: { userId: string, address: string, txHash?: string }) { + if (!txHash) { + throw new Error("no tx hash provided to address " + address) + } + const entry = await this.storage.paymentStorage.GetAddressReceivingTransactionOwner(address, txHash) + if (!entry) { + throw new Error("no tx found for tx hash " + txHash) + } + if (entry.user_address.user.user_id !== userId) { + throw new Error("tx user id mismatch for tx hash " + txHash) + } + if (entry.paid_at_unix <= 0) { + throw new Error("tx not paid for tx hash " + txHash) + } + } + + async validateReceivingInvoice({ userId, invoice }: { userId: string, invoice: string }) { + const entry = await this.storage.paymentStorage.GetInvoiceOwner(invoice) + if (!entry) { + throw new Error("no invoice found for invoice " + invoice) + } + if (entry.user.user_id !== userId) { + throw new Error("invoice user id mismatch for invoice " + invoice) + } + if (entry.paid_at_unix <= 0) { + throw new Error("invoice not paid for invoice " + invoice) + } + if (!entry.internal && !entry.liquidityProvider) { + const entry = this.invoices.find(i => i.paymentRequest === invoice) + if (!entry) { + throw new Error("invoice not found in lnd " + invoice) + } + } + } + + async validateRoutingFeeRefund({ amt, invoice, userId }: { userId: string, invoice: string, amt: number }) { + const entry = this.decrementEvents[invoice] + if (!entry) { + throw new Error("no decrement event found for invoice routing fee refound " + invoice) + } + if (entry.userId !== userId) { + throw new Error("user id mismatch for routing fee refund " + invoice) + } + if (entry.failure) { + throw new Error("payment failled, should not refund routing fees " + invoice) + } + if (entry.refund !== amt) { + throw new Error("refund amount mismatch for routing fee refund " + invoice) + } + } + + async validatePaymentRefund({ amt, invoice, userId }: { userId: string, invoice: string, amt: number }) { + const entry = this.decrementEvents[invoice] + if (!entry) { + throw new Error("no decrement event found for invoice payment refund " + invoice) + } + if (entry.userId !== userId) { + throw new Error("user id mismatch for payment refund " + invoice) + } + if (!entry.failure) { + throw new Error("payment did not fail, should not refund payment " + invoice) + } + if (entry.refund !== amt) { + throw new Error("refund amount mismatch for payment refund " + invoice) + } + } + + async VerifyEventsLog() { + this.events = await this.storage.eventsLog.GetAllLogs() + this.invoices = (await this.lnd.GetAllPaidInvoices(1000)).invoices + this.payments = (await this.lnd.GetAllPayments(1000)).payments + + this.incrementSources = {} + this.decrementSources = {} + this.users = {} + this.users = {} + this.decrementEvents = {} + for (let i = 0; i < this.events.length; i++) { + const e = this.events[i] + if (e.type === 'balance_decrement') { + await this.verifyDecrementEvent(e) + } else if (e.type === 'balance_increment') { + await this.verifyIncrementEvent(e) + } else { + await this.storage.paymentStorage.VerifyDbEvent(e) + } + } + await Promise.all(Object.entries(this.users).map(async ([userId, u]) => { + const user = await this.storage.userStorage.GetUser(userId) + if (user.balance_sats !== u.updatedBalance) { + throw new Error("sanity check on balance failed, expected: " + u.updatedBalance + " found: " + user.balance_sats) + } + })) + } + + checkUserEntry(e: LoggedEvent, u: { ts: number, updatedBalance: number } | undefined) { + const newEntry = { ts: e.timestampMs, updatedBalance: e.balance + e.amount * (e.type === 'balance_decrement' ? -1 : 1) } + if (!u) { + this.log(e.userId, "balance starts at", e.balance, "sats and moves by", e.amount * (e.type === 'balance_decrement' ? -1 : 1), "sats, resulting in", newEntry.updatedBalance, "sats") + return newEntry + } + if (e.timestampMs < u.ts) { + throw new Error("entry out of order " + e.timestampMs + " " + u.ts) + } + if (e.balance !== u.updatedBalance) { + throw new Error("inconsistent balance update got: " + e.balance + " expected " + u.updatedBalance) + } + this.log(e.userId, "balance updates from", e.balance, "sats and moves by", e.amount * (e.type === 'balance_decrement' ? -1 : 1), "sats, resulting in", newEntry.updatedBalance, "sats") + return newEntry + } } \ No newline at end of file diff --git a/src/services/main/settings.ts b/src/services/main/settings.ts index 5ae32474..9b50ae67 100644 --- a/src/services/main/settings.ts +++ b/src/services/main/settings.ts @@ -7,18 +7,22 @@ import { getLogger } from '../helpers/logger.js' import fs from 'fs' import crypto from 'crypto'; import { LiquiditySettings, LoadLiquiditySettingsFromEnv } from './liquidityManager.js' + export type MainSettings = { storageSettings: StorageSettings, lndSettings: LndSettings, watchDogSettings: WatchdogSettings, liquiditySettings: LiquiditySettings, jwtSecret: string + walletPasswordPath: string + walletSecretPath: string incomingTxFee: number outgoingTxFee: number incomingAppInvoiceFee: number incomingAppUserInvoiceFee: number outgoingAppInvoiceFee: number outgoingAppUserInvoiceFee: number + outgoingAppUserInvoiceFeeBps: number userToUserFee: number appToUserFee: number serviceUrl: string @@ -26,27 +30,37 @@ export type MainSettings = { recordPerformance: boolean skipSanityCheck: boolean disableExternalPayments: boolean + wizard: boolean + defaultAppName: string + pushBackupsToNostr: boolean } + export type BitcoinCoreSettings = { port: number user: string pass: string } + export type TestSettings = MainSettings & { lndSettings: { otherNode: NodeSettings, thirdNode: NodeSettings, fourthNode: NodeSettings }, bitcoinCoreSettings: BitcoinCoreSettings } export const LoadMainSettingsFromEnv = (): MainSettings => { const storageSettings = LoadStorageSettingsFromEnv() + const outgoingAppUserInvoiceFeeBps = EnvCanBeInteger("OUTGOING_INVOICE_FEE_USER_BPS", 0) + return { watchDogSettings: LoadWatchdogSettingsFromEnv(), lndSettings: LoadLndSettingsFromEnv(), storageSettings: storageSettings, liquiditySettings: LoadLiquiditySettingsFromEnv(), jwtSecret: loadJwtSecret(storageSettings.dataDir), + walletSecretPath: process.env.WALLET_SECRET_PATH || getDataPath(storageSettings.dataDir, ".wallet_secret"), + walletPasswordPath: process.env.WALLET_PASSWORD_PATH || getDataPath(storageSettings.dataDir, ".wallet_password"), incomingTxFee: EnvCanBeInteger("INCOMING_CHAIN_FEE_ROOT_BPS", 0) / 10000, outgoingTxFee: EnvCanBeInteger("OUTGOING_CHAIN_FEE_ROOT_BPS", 60) / 10000, incomingAppInvoiceFee: EnvCanBeInteger("INCOMING_INVOICE_FEE_ROOT_BPS", 0) / 10000, outgoingAppInvoiceFee: EnvCanBeInteger("OUTGOING_INVOICE_FEE_ROOT_BPS", 60) / 10000, incomingAppUserInvoiceFee: EnvCanBeInteger("INCOMING_INVOICE_FEE_USER_BPS", 0) / 10000, - outgoingAppUserInvoiceFee: EnvCanBeInteger("OUTGOING_INVOICE_FEE_USER_BPS", 0) / 10000, + outgoingAppUserInvoiceFeeBps, + outgoingAppUserInvoiceFee: outgoingAppUserInvoiceFeeBps / 10000, userToUserFee: EnvCanBeInteger("TX_FEE_INTERNAL_USER_BPS", 0) / 10000, appToUserFee: EnvCanBeInteger("TX_FEE_INTERNAL_ROOT_BPS", 0) / 10000, serviceUrl: process.env.SERVICE_URL || `http://localhost:${EnvCanBeInteger("PORT", 1776)}`, @@ -54,11 +68,14 @@ export const LoadMainSettingsFromEnv = (): MainSettings => { recordPerformance: process.env.RECORD_PERFORMANCE === 'true' || false, skipSanityCheck: process.env.SKIP_SANITY_CHECK === 'true' || false, disableExternalPayments: process.env.DISABLE_EXTERNAL_PAYMENTS === 'true' || false, + wizard: process.env.WIZARD === 'true' || false, + defaultAppName: process.env.DEFAULT_APP_NAME || "wallet", + pushBackupsToNostr: process.env.PUSH_BACKUPS_TO_NOSTR === 'true' || false } } export const LoadTestSettingsFromEnv = (): TestSettings => { - const eventLogPath = `logs/eventLogV2Test${Date.now()}.csv` + const eventLogPath = `logs/eventLogV3Test${Date.now()}.csv` const settings = LoadMainSettingsFromEnv() return { ...settings, @@ -101,7 +118,7 @@ export const loadJwtSecret = (dataDir: string): string => { return secret } log("JWT_SECRET not set in env, checking .jwt_secret file") - const secretPath = dataDir !== "" ? `${dataDir}/.jwt_secret` : ".jwt_secret" + const secretPath = getDataPath(dataDir, ".jwt_secret") try { const fileContent = fs.readFileSync(secretPath, "utf-8") return fileContent.trim() @@ -111,4 +128,8 @@ export const loadJwtSecret = (dataDir: string): string => { fs.writeFileSync(secretPath, secret) return secret } +} + +export const getDataPath = (dataDir: string, dataPath: string) => { + return dataDir !== "" ? `${dataDir}/${dataPath}` : dataPath } \ No newline at end of file diff --git a/src/services/main/unlocker.ts b/src/services/main/unlocker.ts new file mode 100644 index 00000000..6dbe0ecc --- /dev/null +++ b/src/services/main/unlocker.ts @@ -0,0 +1,275 @@ +import fs from 'fs' +import crypto from 'crypto' +import { GrpcTransport } from "@protobuf-ts/grpc-transport"; +import { credentials, Metadata } from '@grpc/grpc-js' +import { getLogger } from '../helpers/logger.js'; +import { WalletUnlockerClient } from '../../../proto/lnd/walletunlocker.client.js'; +import { MainSettings } from '../main/settings.js'; +import { InitWalletReq } from '../lnd/initWalletReq.js'; +import Storage from '../storage/index.js' +import { LightningClient } from '../../../proto/lnd/lightning.client.js'; +const DeadLineMetadata = (deadline = 10 * 1000) => ({ deadline: Date.now() + deadline }) +type EncryptedData = { iv: string, encrypted: string } +type Seed = { plaintextSeed: string[], encryptedSeed: EncryptedData } +export class Unlocker { + settings: MainSettings + storage: Storage + abortController = new AbortController() + subbedToBackups = false + log = getLogger({ component: "unlocker" }) + constructor(settings: MainSettings, storage: Storage) { + this.settings = settings + this.storage = storage + } + + Stop = () => { + this.abortController.abort() + } + + getCreds = () => { + const macroonPath = this.settings.lndSettings.mainNode.lndMacaroonPath + const certPath = this.settings.lndSettings.mainNode.lndCertPath + let macaroon = "" + let lndCert: Buffer + try { + lndCert = fs.readFileSync(certPath) + } catch (err: any) { + throw new Error("failed to access lnd cert, make sure to set LND_CERT_PATH in .env, that the path is correct, and that lnd is running") + } + try { + macaroon = fs.readFileSync(macroonPath).toString('hex'); + } catch (err: any) { + if (err.code !== 'ENOENT') { + throw err + } + } + return { lndCert, macaroon } + } + + IsInitialized = () => { + const { macaroon } = this.getCreds() + return macaroon !== '' + } + + Unlock = async (): Promise<'created' | 'unlocked' | 'noaction'> => { + const { lndCert, macaroon } = this.getCreds() + if (macaroon === "") { + const { ln, pub } = await this.InitFlow(lndCert) + this.subscribeToBackups(ln, pub) + return 'created' + } + const { ln, pub, action } = await this.UnlockFlow(lndCert, macaroon) + this.subscribeToBackups(ln, pub) + return action + } + + UnlockFlow = async (lndCert: Buffer, macaroon: string): Promise<{ ln: LightningClient, pub: string, action: 'unlocked' | 'noaction' }> => { + const ln = this.GetLightningClient(lndCert, macaroon) + const info = await this.GetLndInfo(ln) + if (info.ok) { + this.log("the wallet is already unlocked with pub:", info.pub) + return { ln, pub: info.pub, action: 'noaction' } + } + if (info.failure !== 'locked') { + throw new Error("failed to get lnd info for reason: " + info.failure) + } + this.log("wallet is locked, unlocking...") + const unlocker = this.GetUnlockerClient(lndCert) + const walletPassword = this.GetWalletPassword() + await unlocker.unlockWallet({ walletPassword, recoveryWindow: 0, statelessInit: false, channelBackups: undefined }, DeadLineMetadata()) + const infoAfter = await this.GetLndInfo(ln) + if (!infoAfter.ok) { + throw new Error("failed to unlock lnd wallet " + infoAfter.failure) + } + this.log("unlocked wallet with pub:", infoAfter.pub) + return { ln, pub: infoAfter.pub, action: 'unlocked' } + } + + InitFlow = async (lndCert: Buffer) => { + this.log("macaroon not found, creating wallet...") + const unlocker = this.GetUnlockerClient(lndCert) + const { plaintextSeed, encryptedSeed } = await this.genSeed(unlocker) + return this.initWallet(lndCert, unlocker, { plaintextSeed, encryptedSeed }) + } + + genSeed = async (unlocker: WalletUnlockerClient): Promise => { + const entropy = crypto.randomBytes(16) + const seedRes = await unlocker.genSeed({ + aezeedPassphrase: Buffer.alloc(0), + seedEntropy: entropy + }, DeadLineMetadata()) + this.log("seed created") + const { encryptedData } = this.EncryptWalletSeed(seedRes.response.cipherSeedMnemonic) + return { plaintextSeed: seedRes.response.cipherSeedMnemonic, encryptedSeed: encryptedData } + } + + initWallet = async (lndCert: Buffer, unlocker: WalletUnlockerClient, seed: Seed) => { + const walletPw = this.GetWalletPassword() + const req = InitWalletReq(walletPw, seed.plaintextSeed) + const initRes = await unlocker.initWallet(req, DeadLineMetadata(60 * 1000)) + const adminMacaroon = Buffer.from(initRes.response.adminMacaroon).toString('hex') + const ln = this.GetLightningClient(lndCert, adminMacaroon) + + // Retry mechanism to ensure LND is ready + let info; + for (let i = 0; i < 10; i++) { + info = await this.GetLndInfo(ln); + if (info.ok) break; + this.log("LND not ready, retrying in 5 seconds..."); + await new Promise(res => setTimeout(res, 5000)); + } + + if (!info || !info.ok) { + throw new Error("failed to init lnd wallet " + (info ? info.failure : "unknown error")) + } + await this.storage.liquidityStorage.SaveNodeSeed(info.pub, JSON.stringify(seed.encryptedSeed)) + this.log("created wallet with pub:", info.pub) + return { ln, pub: info.pub } + } + + + + GetLndInfo = async (ln: LightningClient): Promise<{ ok: false, failure: 'locked' | 'unknown' } | { ok: true, pub: string }> => { + while (true) { + try { + const info = await ln.getInfo({}, DeadLineMetadata()) + return { ok: true, pub: info.response.identityPubkey } + } catch (err: any) { + if (err.message === '2 UNKNOWN: wallet locked, unlock it to enable full RPC access') { + this.log("wallet is locked") + return { ok: false, failure: 'locked' } + } else if (err.message === '2 UNKNOWN: the RPC server is in the process of starting up, but not yet ready to accept calls') { + this.log("lnd is not ready yet, waiting...") + await new Promise((res) => setTimeout(res, 1000)) + } else { + this.log("failed to get lnd info", err.message) + return { ok: false, failure: 'unknown' } + } + } + } + } + + EncryptWalletSeed = (seed: string[]) => { + return this.encrypt(seed.join('+'), true) + } + + DecryptWalletSeed = (data: { iv: string, encrypted: string }) => { + return this.decrypt(data).split('+') + } + EncryptBackup = (backup: Buffer) => { + return this.encrypt(backup.toString('hex')) + } + + DecryptBackup = (data: { iv: string, encrypted: string }) => { + return Buffer.from(this.decrypt(data), 'hex') + } + + encrypt = (text: string, must = false) => { + const sec = this.GetWalletSecret(must) + if (!sec) { + throw new Error("wallet secret not found to encrypt") + } + const secret = Buffer.from(sec, 'hex') + const iv = crypto.randomBytes(16) + const cipher = crypto.createCipheriv('aes-256-cbc', secret, iv) + const rawData = Buffer.from(text, 'utf-8') + const cyData = cipher.update(rawData) + const encrypted = Buffer.concat([cyData, cipher.final()]) + const encryptedData = { iv: iv.toString('hex'), encrypted: encrypted.toString('hex') } + return { encryptedData } + } + + decrypt = (data: { iv: string, encrypted: string }) => { + const sec = this.GetWalletSecret(false) + if (!sec) { + throw new Error("wallet secret not found to decrypt") + } + const secret = Buffer.from(sec, 'hex') + const iv = Buffer.from(data.iv, 'hex') + const encrypted = Buffer.from(data.encrypted, 'hex') + const decipher = crypto.createDecipheriv('aes-256-cbc', secret, iv) + const decrypted = decipher.update(encrypted) + const raw = Buffer.concat([decrypted, decipher.final()]) + return raw.toString('utf-8') + } + + GetWalletSecret = (create: boolean) => { + const path = this.settings.walletSecretPath + let secret = "" + try { + secret = fs.readFileSync(path, 'utf-8') + } catch { + this.log("the wallet secret file was not found") + } + if (secret === "" && create) { + this.log("creating wallet secret file") + secret = crypto.randomBytes(32).toString('hex') + fs.writeFileSync(path, secret) + } + return secret + } + + GetWalletPassword = () => { + const path = this.settings.walletPasswordPath + let password = Buffer.alloc(0) + try { + password = fs.readFileSync(path) + } catch { + } + if (password.length === 0) { + this.log("no wallet password configured, using wallet secret") + const secret = this.GetWalletSecret(false) + if (secret === "") { + throw new Error("no usable password found") + } + password = Buffer.from(secret, 'hex') + } + return password + } + + subscribeToBackups = async (ln: LightningClient, pub: string) => { + if (this.subbedToBackups) { + return + } + this.subbedToBackups = true + this.log("subscribing to channel backups for: ", pub) + const stream = ln.subscribeChannelBackups({}, { abort: this.abortController.signal }) + stream.responses.onMessage(async (msg) => { + if (msg.multiChanBackup) { + this.log("received backup, saving") + try { + const { encryptedData } = this.EncryptBackup(Buffer.from(msg.multiChanBackup.multiChanBackup)) + await this.storage.liquidityStorage.SaveNodeBackup(pub, JSON.stringify(encryptedData)) + } catch (err: any) { + this.log("failed to save backup", err.message) + } + } + }) + } + + GetUnlockerClient = (cert: Buffer) => { + const host = this.settings.lndSettings.mainNode.lndAddr + const channelCredentials = credentials.createSsl(cert) + const transport = new GrpcTransport({ host, channelCredentials }) + const client = new WalletUnlockerClient(transport) + return client + } + GetLightningClient = (cert: Buffer, macaroon: string) => { + const host = this.settings.lndSettings.mainNode.lndAddr + const sslCreds = credentials.createSsl(cert) + const macaroonCreds = credentials.createFromMetadataGenerator( + function (args: any, callback: any) { + let metadata = new Metadata(); + metadata.add('macaroon', macaroon); + callback(null, metadata); + }, + ); + const channelCredentials = credentials.combineChannelCredentials( + sslCreds, + macaroonCreds, + ); + const transport = new GrpcTransport({ host, channelCredentials }) + const client = new LightningClient(transport) + return client + } +} \ No newline at end of file diff --git a/src/services/main/watchdog.ts b/src/services/main/watchdog.ts index 07605a75..a534505a 100644 --- a/src/services/main/watchdog.ts +++ b/src/services/main/watchdog.ts @@ -1,10 +1,13 @@ import { EnvCanBeInteger } from "../helpers/envParser.js"; import FunctionQueue from "../helpers/functionQueue.js"; import { getLogger } from "../helpers/logger.js"; -import { LiquidityProvider } from "../lnd/liquidityProvider.js"; +import { Utils } from "../helpers/utilsWrapper.js"; +import { LiquidityProvider } from "./liquidityProvider.js"; import LND from "../lnd/lnd.js"; import { ChannelBalance } from "../lnd/settings.js"; import Storage from '../storage/index.js' +import { LiquidityManager } from "./liquidityManager.js"; +import { RugPullTracker } from "./rugPullTracker.js"; export type WatchdogSettings = { maxDiffSats: number } @@ -22,17 +25,24 @@ export class Watchdog { accumulatedHtlcFees: number; lnd: LND; liquidProvider: LiquidityProvider; + liquidityManager: LiquidityManager; settings: WatchdogSettings; storage: Storage; + rugPullTracker: RugPullTracker + utils: Utils latestCheckStart = 0 log = getLogger({ component: "watchdog" }) ready = false interval: NodeJS.Timer; - constructor(settings: WatchdogSettings, lnd: LND, storage: Storage) { + lndPubKey: string; + constructor(settings: WatchdogSettings, liquidityManager: LiquidityManager, lnd: LND, storage: Storage, utils: Utils, rugPullTracker: RugPullTracker) { this.lnd = lnd; this.settings = settings; this.storage = storage; this.liquidProvider = lnd.liquidProvider + this.liquidityManager = liquidityManager + this.utils = utils + this.rugPullTracker = rugPullTracker this.queue = new FunctionQueue("watchdog_queue", () => this.StartCheck()) } @@ -41,19 +51,30 @@ export class Watchdog { clearInterval(this.interval) } } - Start = async () => { + try { + await this.StartWatching() + } catch (err: any) { + this.log("Failed to start watchdog", err.message || err) + throw err + } + } + StartWatching = async () => { + this.log("Starting watchdog") this.startedAtUnix = Math.floor(Date.now() / 1000) + const info = await this.lnd.GetInfo() + this.lndPubKey = info.identityPubkey + await this.getTracker() const totalUsersBalance = await this.storage.paymentStorage.GetTotalUsersBalance() - this.initialLndBalance = await this.getTotalLndBalance(totalUsersBalance) + this.utils.stateBundler.AddBalancePoint('usersBalance', totalUsersBalance) + this.initialLndBalance = await this.getAggregatedExternalBalance() this.initialUsersBalance = totalUsersBalance const fwEvents = await this.lnd.GetForwardingHistory(0, this.startedAtUnix) this.latestIndexOffset = fwEvents.lastOffsetIndex this.accumulatedHtlcFees = 0 this.interval = setInterval(() => { - if (this.latestCheckStart + (1000 * 60) < Date.now()) { - this.log("No balance check was made in the last minute, checking now") + if (this.latestCheckStart + (1000 * 58) < Date.now()) { this.PaymentRequested() } }, 1000 * 60) @@ -70,49 +91,42 @@ export class Watchdog { } - - - getTotalLndBalance = async (usersTotal: number) => { - const walletBalance = await this.lnd.GetWalletBalance() - this.log(Number(walletBalance.confirmedBalance), "sats in chain wallet") - const channelsBalance = await this.lnd.GetChannelBalance() - getLogger({ component: "debugLndBalancev3" })({ w: walletBalance, c: channelsBalance, u: usersTotal, f: this.accumulatedHtlcFees }) - const totalLightningBalanceMsats = (channelsBalance.localBalance?.msat || 0n) + (channelsBalance.unsettledLocalBalance?.msat || 0n) - const totalLightningBalance = Math.ceil(Number(totalLightningBalanceMsats) / 1000) - const providerBalance = await this.liquidProvider.GetLatestBalance() - return Number(walletBalance.confirmedBalance) + totalLightningBalance + providerBalance + getAggregatedExternalBalance = async () => { + const totalLndBalance = await this.lnd.GetTotalBalace() + const feesPaidForLiquidity = this.liquidityManager.GetPaidFees() + const pb = await this.rugPullTracker.CheckProviderBalance() + const providerBalance = pb.prevBalance || pb.balance + return totalLndBalance + providerBalance + feesPaidForLiquidity } - checkBalanceUpdate = (deltaLnd: number, deltaUsers: number) => { - this.log("LND balance update:", deltaLnd, "sats since app startup") - this.log("Users balance update:", deltaUsers, "sats since app startup") + checkBalanceUpdate = async (deltaLnd: number, deltaUsers: number) => { + this.utils.stateBundler.AddBalancePoint('deltaExternal', deltaLnd) + this.utils.stateBundler.AddBalancePoint('deltaUsers', deltaUsers) const result = this.checkDeltas(deltaLnd, deltaUsers) switch (result.type) { case 'mismatch': if (deltaLnd < 0) { - this.log("WARNING! LND balance decreased while users balance increased creating a difference of", result.absoluteDiff, "sats") if (result.absoluteDiff > this.settings.maxDiffSats) { - this.log("Difference is too big for an update, locking outgoing operations") + await this.updateDisruption(true, result.absoluteDiff) return true } } else { - this.log("LND balance increased while users balance decreased creating a difference of", result.absoluteDiff, "sats, could be caused by data loss, or liquidity injection") + this.updateDisruption(false, result.absoluteDiff) return false } break case 'negative': if (Math.abs(deltaLnd) > Math.abs(deltaUsers)) { - this.log("WARNING! LND balance decreased more than users balance with a difference of", result.absoluteDiff, "sats") if (result.absoluteDiff > this.settings.maxDiffSats) { - this.log("Difference is too big for an update, locking outgoing operations") + await this.updateDisruption(true, result.absoluteDiff) return true } } else if (deltaLnd === deltaUsers) { - this.log("LND and users balance went both DOWN consistently") + await this.updateDisruption(false, 0) return false } else { - this.log("LND balance decreased less than users balance with a difference of", result.absoluteDiff, "sats, could be caused by data loss, or liquidity injection") + await this.updateDisruption(false, result.absoluteDiff) return false } break @@ -120,28 +134,49 @@ export class Watchdog { if (deltaLnd < deltaUsers) { this.log("WARNING! LND balance increased less than users balance with a difference of", result.absoluteDiff, "sats") if (result.absoluteDiff > this.settings.maxDiffSats) { - this.log("Difference is too big for an update, locking outgoing operations") + await this.updateDisruption(true, result.absoluteDiff) return true } } else if (deltaLnd === deltaUsers) { - this.log("LND and users balance went both UP consistently") + await this.updateDisruption(false, 0) return false } else { - this.log("LND balance increased more than users balance with a difference of", result.absoluteDiff, "sats, could be caused by data loss, or liquidity injection") + await this.updateDisruption(false, result.absoluteDiff) return false } } return false } + updateDisruption = async (isDisrupted: boolean, absoluteDiff: number) => { + const tracker = await this.getTracker() + if (isDisrupted) { + if (tracker.latest_distruption_at_unix === 0) { + await this.storage.liquidityStorage.UpdateTrackedProviderDisruption('lnd', this.lndPubKey, Math.floor(Date.now() / 1000)) + getLogger({ component: 'bark' })("detected lnd loss of", absoluteDiff, "sats,", absoluteDiff - this.settings.maxDiffSats, "above the max allowed") + } else { + getLogger({ component: 'bark' })("ongoing lnd loss of", absoluteDiff, "sats,", absoluteDiff - this.settings.maxDiffSats, "above the max allowed") + } + } else { + if (tracker.latest_distruption_at_unix !== 0) { + await this.storage.liquidityStorage.UpdateTrackedProviderDisruption('lnd', this.lndPubKey, 0) + getLogger({ component: 'bark' })("loss cleared after: ", Math.floor(Date.now() / 1000) - tracker.latest_distruption_at_unix, "seconds") + } else if (absoluteDiff > 0) { + this.log("lnd balance increased more than users balance by", absoluteDiff) + } + } + } + StartCheck = async () => { this.latestCheckStart = Date.now() await this.updateAccumulatedHtlcFees() const totalUsersBalance = await this.storage.paymentStorage.GetTotalUsersBalance() - const totalLndBalance = await this.getTotalLndBalance(totalUsersBalance) + this.utils.stateBundler.AddBalancePoint('usersBalance', totalUsersBalance) + const totalLndBalance = await this.getAggregatedExternalBalance() + this.utils.stateBundler.AddBalancePoint('accumulatedHtlcFees', this.accumulatedHtlcFees) const deltaLnd = totalLndBalance - (this.initialLndBalance + this.accumulatedHtlcFees) const deltaUsers = totalUsersBalance - this.initialUsersBalance - const deny = this.checkBalanceUpdate(deltaLnd, deltaUsers) + const deny = await this.checkBalanceUpdate(deltaLnd, deltaUsers) if (deny) { this.log("Balance mismatch detected in absolute update, locking outgoing operations") this.lnd.LockOutgoingOperations() @@ -151,7 +186,6 @@ export class Watchdog { } PaymentRequested = async () => { - this.log("Payment requested, checking balance") if (!this.ready) { throw new Error("Watchdog not ready") } @@ -179,5 +213,13 @@ export class Watchdog { } } } + + getTracker = async () => { + const tracker = await this.storage.liquidityStorage.GetTrackedProvider('lnd', this.lndPubKey) + if (!tracker) { + return this.storage.liquidityStorage.CreateTrackedProvider('lnd', this.lndPubKey, 0) + } + return tracker + } } type DeltaCheckResult = { type: 'negative' | 'positive', absoluteDiff: number, relativeDiff: number } | { type: 'mismatch', absoluteDiff: number } \ No newline at end of file diff --git a/src/services/metrics/htlcTracker.ts b/src/services/metrics/htlcTracker.ts index 420aa2e5..edbbe15e 100644 --- a/src/services/metrics/htlcTracker.ts +++ b/src/services/metrics/htlcTracker.ts @@ -18,10 +18,9 @@ export default class HtlcTracker { } log = getLogger({ component: 'htlcTracker' }) onHtlcEvent = async (htlc: HtlcEvent) => { - getLogger({ component: 'debugHtlcs' })(htlc) + //getLogger({ component: 'debugHtlcs' })(htlc) const htlcEvent = htlc.event if (htlcEvent.oneofKind === 'subscribedEvent') { - this.log("htlc subscribed") return } const outgoingHtlcId = Number(htlc.outgoingHtlcId) @@ -45,12 +44,11 @@ export default class HtlcTracker { case 'settleEvent': return this.handleSuccess(info) default: - this.log("unknown htlc event type") + //this.log("unknown htlc event type") } } handleForward = (fwe: ForwardEvent, { eventType, outgoingHtlcId, incomingHtlcId }: EventInfo) => { - this.log("new forward event, currently tracked htlcs: (s,r,f)", this.pendingSendHtlcs.size, this.pendingReceiveHtlcs.size, this.pendingForwardHtlcs.size) const { info } = fwe const incomingAmtMsat = info ? Number(info.incomingAmtMsat) : 0 const outgoingAmtMsat = info ? Number(info.outgoingAmtMsat) : 0 @@ -60,8 +58,6 @@ export default class HtlcTracker { this.pendingReceiveHtlcs.set(incomingHtlcId, incomingAmtMsat - outgoingAmtMsat) } else if (eventType === HtlcEvent_EventType.FORWARD) { this.pendingForwardHtlcs.set(outgoingHtlcId, outgoingAmtMsat - incomingAmtMsat) - } else { - this.log("unknown htlc event type for forward event") } } @@ -90,7 +86,6 @@ export default class HtlcTracker { return this.incrementReceiveFailures(incomingChannelId) } } - this.log("unknown htlc event type for failure event", eventType) } handleSuccess = ({ eventType, outgoingHtlcId, incomingHtlcId }: EventInfo) => { @@ -104,8 +99,6 @@ export default class HtlcTracker { if (this.deleteMapEntry(outgoingHtlcId, this.pendingSendHtlcs) !== null) return if (this.deleteMapEntry(incomingHtlcId, this.pendingReceiveHtlcs) !== null) return if (this.deleteMapEntry(outgoingHtlcId, this.pendingForwardHtlcs) !== null) return - } else { - this.log("unknown htlc event type for success event", eventType) } } diff --git a/src/services/nostr/handler.ts b/src/services/nostr/handler.ts index 084963ff..e3fcdf59 100644 --- a/src/services/nostr/handler.ts +++ b/src/services/nostr/handler.ts @@ -1,226 +1,224 @@ -//import { SimplePool, Sub, Event, UnsignedEvent, getEventHash, signEvent } from 'nostr-tools' -import { SimplePool, Sub, Event, UnsignedEvent, getEventHash, finishEvent, relayInit } from './tools/index.js' -import { encryptData, decryptData, getSharedSecret, decodePayload, encodePayload } from './nip44.js' -import { ERROR, getLogger } from '../helpers/logger.js' -import { encodeNprofile } from '../../custom-nip19.js' -const handledEvents: string[] = [] // TODO: - big memory leak here, add TTL -type AppInfo = { appId: string, publicKey: string, privateKey: string, name: string } -type ClientInfo = { clientId: string, publicKey: string, privateKey: string, name: string } -export type SendData = { type: "content", content: string, pub: string } | { type: "event", event: UnsignedEvent } -export type SendInitiator = { type: 'app', appId: string } | { type: 'client', clientId: string } -export type NostrSend = (initiator: SendInitiator, data: SendData, relays?: string[] | undefined) => void - -export type NostrSettings = { - apps: AppInfo[] - relays: string[] - clients: ClientInfo[] -} -export type NostrEvent = { - id: string - pub: string - content: string - appId: string - startAtNano: string - startAtMs: number -} - -type SettingsRequest = { - type: 'settings' - settings: NostrSettings -} - -type SendRequest = { - type: 'send' - initiator: SendInitiator - data: SendData - relays?: string[] -} -type ReadyResponse = { - type: 'ready' -} -type EventResponse = { - type: 'event' - event: NostrEvent -} - -export type ChildProcessRequest = SettingsRequest | SendRequest -export type ChildProcessResponse = ReadyResponse | EventResponse -const send = (message: ChildProcessResponse) => { - if (process.send) { - process.send(message) - } -} -let subProcessHandler: Handler | undefined -process.on("message", (message: ChildProcessRequest) => { - switch (message.type) { - case 'settings': - initSubprocessHandler(message.settings) - break - case 'send': - sendToNostr(message.initiator, message.data, message.relays) - break - default: - getLogger({ component: "nostrMiddleware" })(ERROR, "unknown nostr request", message) - break - } -}) -const initSubprocessHandler = (settings: NostrSettings) => { - if (subProcessHandler) { - getLogger({ component: "nostrMiddleware" })(ERROR, "nostr settings ignored since handler already exists") - return - } - subProcessHandler = new Handler(settings, event => { - send({ - type: 'event', - event: event - }) - }) -} -const sendToNostr: NostrSend = (initiator, data, relays) => { - if (!subProcessHandler) { - getLogger({ component: "nostrMiddleware" })(ERROR, "nostr was not initialized") - return - } - subProcessHandler.Send(initiator, data, relays) -} -send({ type: 'ready' }) - -export default class Handler { - pool = new SimplePool() - settings: NostrSettings - subs: Sub[] = [] - apps: Record = {} - eventCallback: (event: NostrEvent) => void - log = getLogger({ component: "nostrMiddleware" }) - constructor(settings: NostrSettings, eventCallback: (event: NostrEvent) => void) { - this.settings = settings - this.log( - { - ...settings, - apps: settings.apps.map(app => { - const { privateKey, ...rest } = app; - return { - ...rest, - nprofile: encodeNprofile({ pubkey: rest.publicKey, relays: settings.relays }) - } - }) - } - ) - this.eventCallback = eventCallback - this.settings.apps.forEach(app => { - this.apps[app.publicKey] = app - }) - this.Connect() - } - - async Connect() { - const log = getLogger({}) - log("conneting to relay...", this.settings.relays[0]) - const relay = relayInit(this.settings.relays[0]) // TODO: create multiple conns for multiple relays - try { - await relay.connect() - } catch (err) { - log("failed to connect to relay, will try again in 2 seconds") - setTimeout(() => { - this.Connect() - }, 2000) - return - } - log("connected, subbing...") - relay.on('disconnect', () => { - log("relay disconnected, will try to reconnect") - relay.close() - this.Connect() - }) - const sub = relay.sub([ - { - since: Math.ceil(Date.now() / 1000), - kinds: [21000], - '#p': Object.keys(this.apps), - } - ]) - sub.on('eose', () => { - log("up to date with nostr events") - }) - sub.on('event', async (e) => { - if (e.kind !== 21000 || !e.pubkey) { - return - } - const pubTags = e.tags.find(tags => tags && tags.length > 1 && tags[0] === 'p') - if (!pubTags) { - return - } - const app = this.apps[pubTags[1]] - if (app) { - await this.processEvent(e, app) - return - } - }) - } - - async processEvent(e: Event<21000>, app: AppInfo) { - const eventId = e.id - if (handledEvents.includes(eventId)) { - this.log("event already handled") - return - } - handledEvents.push(eventId) - const startAtMs = Date.now() - const startAtNano = process.hrtime.bigint().toString() - const decoded = decodePayload(e.content) - const content = await decryptData(decoded, getSharedSecret(app.privateKey, e.pubkey)) - this.eventCallback({ id: eventId, content, pub: e.pubkey, appId: app.appId, startAtNano, startAtMs }) - } - - async Send(initiator: SendInitiator, data: SendData, relays?: string[]) { - const keys = this.GetSendKeys(initiator) - let toSign: UnsignedEvent - if (data.type === 'content') { - const decoded = await encryptData(data.content, getSharedSecret(keys.privateKey, data.pub)) - const content = encodePayload(decoded) - toSign = { - content, - created_at: Math.floor(Date.now() / 1000), - kind: 21000, - pubkey: keys.publicKey, - tags: [['p', data.pub]], - } - } else { - toSign = data.event - } - - const signed = finishEvent(toSign, keys.privateKey) - let sent = false - const log = getLogger({ appName: keys.name }) - await Promise.all(this.pool.publish(relays || this.settings.relays, signed).map(async p => { - try { - await p - sent = true - } catch (e: any) { - log(e) - } - })) - if (!sent) { - log("failed to send event") - } - } - - GetSendKeys(initiator: SendInitiator) { - if (initiator.type === 'app') { - const { appId } = initiator - const found = this.settings.apps.find((info: AppInfo) => info.appId === appId) - if (!found) { - throw new Error("unkown app") - } - return found - } else if (initiator.type === 'client') { - const { clientId } = initiator - const found = this.settings.clients.find((info: ClientInfo) => info.clientId === clientId) - if (!found) { - throw new Error("unkown client") - } - return found - } - throw new Error("unkown initiator type") - } +//import { SimplePool, Sub, Event, UnsignedEvent, getEventHash, signEvent } from 'nostr-tools' +import { SimplePool, Sub, Event, UnsignedEvent, getEventHash, finishEvent, relayInit } from './tools/index.js' +import { encryptData, decryptData, getSharedSecret, decodePayload, encodePayload } from './nip44.js' +import { ERROR, getLogger } from '../helpers/logger.js' +import { encodeNprofile } from '../../custom-nip19.js' +const handledEvents: string[] = [] // TODO: - big memory leak here, add TTL +type AppInfo = { appId: string, publicKey: string, privateKey: string, name: string } +type ClientInfo = { clientId: string, publicKey: string, privateKey: string, name: string } +export type SendData = { type: "content", content: string, pub: string } | { type: "event", event: UnsignedEvent } +export type SendInitiator = { type: 'app', appId: string } | { type: 'client', clientId: string } +export type NostrSend = (initiator: SendInitiator, data: SendData, relays?: string[] | undefined) => void + +export type NostrSettings = { + apps: AppInfo[] + relays: string[] + clients: ClientInfo[] +} +export type NostrEvent = { + id: string + pub: string + content: string + appId: string + startAtNano: string + startAtMs: number +} + +type SettingsRequest = { + type: 'settings' + settings: NostrSettings +} + +type SendRequest = { + type: 'send' + initiator: SendInitiator + data: SendData + relays?: string[] +} +type ReadyResponse = { + type: 'ready' +} +type EventResponse = { + type: 'event' + event: NostrEvent +} + +export type ChildProcessRequest = SettingsRequest | SendRequest +export type ChildProcessResponse = ReadyResponse | EventResponse +const send = (message: ChildProcessResponse) => { + if (process.send) { + process.send(message, undefined, undefined, err => { + if (err) { + getLogger({ component: "nostrMiddleware" })(ERROR, "failed to send message to parent process", err, "message:", message) + process.exit(1) + } + }) + } +} +let subProcessHandler: Handler | undefined +process.on("message", (message: ChildProcessRequest) => { + switch (message.type) { + case 'settings': + initSubprocessHandler(message.settings) + break + case 'send': + sendToNostr(message.initiator, message.data, message.relays) + break + default: + getLogger({ component: "nostrMiddleware" })(ERROR, "unknown nostr request", message) + break + } +}) +const initSubprocessHandler = (settings: NostrSettings) => { + if (subProcessHandler) { + getLogger({ component: "nostrMiddleware" })(ERROR, "nostr settings ignored since handler already exists") + return + } + subProcessHandler = new Handler(settings, event => { + send({ + type: 'event', + event: event + }) + }) +} +const sendToNostr: NostrSend = (initiator, data, relays) => { + if (!subProcessHandler) { + getLogger({ component: "nostrMiddleware" })(ERROR, "nostr was not initialized") + return + } + subProcessHandler.Send(initiator, data, relays) +} +send({ type: 'ready' }) + +export default class Handler { + pool = new SimplePool() + settings: NostrSettings + subs: Sub[] = [] + apps: Record = {} + eventCallback: (event: NostrEvent) => void + log = getLogger({ component: "nostrMiddleware" }) + constructor(settings: NostrSettings, eventCallback: (event: NostrEvent) => void) { + this.settings = settings + this.log("connecting to relays:", settings.relays) + this.settings.apps.forEach(app => { + this.log("appId:", app.appId, "pubkey:", app.publicKey, "nprofile:", encodeNprofile({ pubkey: app.publicKey, relays: settings.relays })) + }) + this.eventCallback = eventCallback + this.settings.apps.forEach(app => { + this.apps[app.publicKey] = app + }) + this.Connect() + } + + async Connect() { + const log = getLogger({}) + log("conneting to relay...", this.settings.relays[0]) + const relay = relayInit(this.settings.relays[0]) // TODO: create multiple conns for multiple relays + try { + await relay.connect() + } catch (err) { + log("failed to connect to relay, will try again in 2 seconds") + setTimeout(() => { + this.Connect() + }, 2000) + return + } + log("connected, subbing...") + relay.on('disconnect', () => { + log("relay disconnected, will try to reconnect") + relay.close() + this.Connect() + }) + const sub = relay.sub([ + { + since: Math.ceil(Date.now() / 1000), + kinds: [21000], + '#p': Object.keys(this.apps), + } + ]) + sub.on('eose', () => { + log("up to date with nostr events") + }) + sub.on('event', async (e) => { + if (e.kind !== 21000 || !e.pubkey) { + return + } + const pubTags = e.tags.find(tags => tags && tags.length > 1 && tags[0] === 'p') + if (!pubTags) { + return + } + const app = this.apps[pubTags[1]] + if (app) { + await this.processEvent(e, app) + return + } + }) + } + + async processEvent(e: Event<21000>, app: AppInfo) { + const eventId = e.id + if (handledEvents.includes(eventId)) { + this.log("event already handled") + return + } + handledEvents.push(eventId) + const startAtMs = Date.now() + const startAtNano = process.hrtime.bigint().toString() + const decoded = decodePayload(e.content) + const content = await decryptData(decoded, getSharedSecret(app.privateKey, e.pubkey)) + this.eventCallback({ id: eventId, content, pub: e.pubkey, appId: app.appId, startAtNano, startAtMs }) + } + + async Send(initiator: SendInitiator, data: SendData, relays?: string[]) { + const keys = this.GetSendKeys(initiator) + let toSign: UnsignedEvent + if (data.type === 'content') { + const decoded = await encryptData(data.content, getSharedSecret(keys.privateKey, data.pub)) + const content = encodePayload(decoded) + toSign = { + content, + created_at: Math.floor(Date.now() / 1000), + kind: 21000, + pubkey: keys.publicKey, + tags: [['p', data.pub]], + } + } else { + toSign = data.event + } + + const signed = finishEvent(toSign, keys.privateKey) + let sent = false + const log = getLogger({ appName: keys.name }) + await Promise.all(this.pool.publish(relays || this.settings.relays, signed).map(async p => { + try { + await p + sent = true + } catch (e: any) { + console.log(e) + log(e) + } + })) + if (!sent) { + log("failed to send event") + } + } + + GetSendKeys(initiator: SendInitiator) { + if (initiator.type === 'app') { + const { appId } = initiator + const found = this.settings.apps.find((info: AppInfo) => info.appId === appId) + if (!found) { + throw new Error("unkown app") + } + return found + } else if (initiator.type === 'client') { + const { clientId } = initiator + const found = this.settings.clients.find((info: ClientInfo) => info.clientId === clientId) + if (!found) { + throw new Error("unkown client") + } + return found + } + throw new Error("unkown initiator type") + } } \ No newline at end of file diff --git a/src/services/serverMethods/index.ts b/src/services/serverMethods/index.ts index 7e8a1363..0f385ce1 100644 --- a/src/services/serverMethods/index.ts +++ b/src/services/serverMethods/index.ts @@ -214,6 +214,13 @@ export default (mainHandler: Main): Types.ServerMethods => { }) if (err != null) throw new Error(err.message) return mainHandler.applicationManager.LinkNpubThroughToken(ctx, req) - } + }, + EnrollAdminToken: async ({ ctx, req }) => { + const err = Types.EnrollAdminTokenRequestValidate(req, { + admin_token_CustomCheck: token => token !== '' + }) + if (err != null) throw new Error(err.message) + return mainHandler.adminManager.PromoteUserToAdmin(ctx.app_id, ctx.app_user_id, req.admin_token) + }, } } \ No newline at end of file diff --git a/src/services/storage/db.ts b/src/services/storage/db.ts index 657e4724..7993a3cb 100644 --- a/src/services/storage/db.ts +++ b/src/services/storage/db.ts @@ -9,7 +9,6 @@ import { EnvMustBeNonEmptyString } from "../helpers/envParser.js" import { UserTransactionPayment } from "./entity/UserTransactionPayment.js" import { UserBasicAuth } from "./entity/UserBasicAuth.js" import { UserEphemeralKey } from "./entity/UserEphemeralKey.js" -import { Product } from "./entity/Product.js" import { UserToUserPayment } from "./entity/UserToUserPayment.js" import { Application } from "./entity/Application.js" import { ApplicationUser } from "./entity/ApplicationUser.js" @@ -18,6 +17,9 @@ import { ChannelBalanceEvent } from "./entity/ChannelsBalanceEvent.js" import { getLogger } from "../helpers/logger.js" import { ChannelRouting } from "./entity/ChannelRouting.js" import { LspOrder } from "./entity/LspOrder.js" +import { Product } from "./entity/Product.js" +import { LndNodeInfo } from "./entity/LndNodeInfo.js" +import { TrackedProvider } from "./entity/TrackedProvider.js" export type DbSettings = { @@ -57,7 +59,7 @@ export default async (settings: DbSettings, migrations: Function[]): Promise<{ s database: settings.databaseFile, // logging: true, entities: [User, UserReceivingInvoice, UserReceivingAddress, AddressReceivingTransaction, UserInvoicePayment, UserTransactionPayment, - UserBasicAuth, UserEphemeralKey, Product, UserToUserPayment, Application, ApplicationUser, UserToUserPayment, LspOrder], + UserBasicAuth, UserEphemeralKey, Product, UserToUserPayment, Application, ApplicationUser, UserToUserPayment, LspOrder, LndNodeInfo, TrackedProvider], //synchronize: true, migrations }).initialize() diff --git a/src/services/storage/entity/LndNodeInfo.ts b/src/services/storage/entity/LndNodeInfo.ts new file mode 100644 index 00000000..f6c40603 --- /dev/null +++ b/src/services/storage/entity/LndNodeInfo.ts @@ -0,0 +1,24 @@ +import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, UpdateDateColumn } from "typeorm" +import { User } from "./User.js" + +@Entity() +export class LndNodeInfo { + + @PrimaryGeneratedColumn() + serial_id: number + + @Column() + pubkey: string + + @Column({ nullable: true }) + seed?: string + + @Column({ nullable: true }) + backup?: string + + @CreateDateColumn() + created_at: Date + + @UpdateDateColumn() + updated_at: Date +} diff --git a/src/services/storage/entity/TrackedProvider.ts b/src/services/storage/entity/TrackedProvider.ts new file mode 100644 index 00000000..5c07a64c --- /dev/null +++ b/src/services/storage/entity/TrackedProvider.ts @@ -0,0 +1,26 @@ +import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, UpdateDateColumn, Index } from "typeorm" + +@Entity() +@Index("tracked_provider_unique", ["provider_type", "provider_pubkey"], { unique: true }) +export class TrackedProvider { + @PrimaryGeneratedColumn() + serial_id: number + + @Column() + provider_type: 'lnd' | 'lnPub' + + @Column() + provider_pubkey: string + + @Column() + latest_balance: number + + @Column({ default: 0 }) + latest_distruption_at_unix: number + + @CreateDateColumn() + created_at: Date + + @UpdateDateColumn() + updated_at: Date +} \ No newline at end of file diff --git a/src/services/storage/entity/UserInvoicePayment.ts b/src/services/storage/entity/UserInvoicePayment.ts index 7ab53b4a..a29809ef 100644 --- a/src/services/storage/entity/UserInvoicePayment.ts +++ b/src/services/storage/entity/UserInvoicePayment.ts @@ -1,42 +1,47 @@ -import { Entity, PrimaryGeneratedColumn, Column, Index, Check, ManyToOne, JoinColumn, CreateDateColumn, UpdateDateColumn } from "typeorm" -import { User } from "./User.js" -import { Application } from "./Application.js" - -@Entity() -export class UserInvoicePayment { - - @PrimaryGeneratedColumn() - serial_id: number - - @ManyToOne(type => User, { eager: true }) - @JoinColumn() - user: User - - @Column() - @Index({ unique: true }) - invoice: string - - @Column() - paid_amount: number - - @Column() - routing_fees: number - - @Column() - service_fees: number - - @Column() - paid_at_unix: number - - @Column({ default: false }) - internal: boolean - - @ManyToOne(type => Application, { eager: true }) - linkedApplication: Application | null - - @CreateDateColumn() - created_at: Date - - @UpdateDateColumn() - updated_at: Date -} +import { Entity, PrimaryGeneratedColumn, Column, Index, Check, ManyToOne, JoinColumn, CreateDateColumn, UpdateDateColumn } from "typeorm" +import { User } from "./User.js" +import { Application } from "./Application.js" + +@Entity() +export class UserInvoicePayment { + + @PrimaryGeneratedColumn() + serial_id: number + + @ManyToOne(type => User, { eager: true }) + @JoinColumn() + user: User + + @Column() + @Index({ unique: true }) + invoice: string + + @Column() + paid_amount: number + + @Column() + routing_fees: number + + @Column() + service_fees: number + + @Column() + paid_at_unix: number + + @Column({ default: false }) + internal: boolean + + @ManyToOne(type => Application, { eager: true }) + linkedApplication: Application | null + + @Column({ + nullable: true, + }) + liquidityProvider?: string + + @CreateDateColumn() + created_at: Date + + @UpdateDateColumn() + updated_at: Date +} diff --git a/src/services/storage/entity/UserReceivingInvoice.ts b/src/services/storage/entity/UserReceivingInvoice.ts index fa7af39c..356f4886 100644 --- a/src/services/storage/entity/UserReceivingInvoice.ts +++ b/src/services/storage/entity/UserReceivingInvoice.ts @@ -1,66 +1,71 @@ -import { Entity, PrimaryGeneratedColumn, Column, Index, Check, ManyToOne, JoinColumn, CreateDateColumn, UpdateDateColumn } from "typeorm" -import { Product } from "./Product.js" -import { User } from "./User.js" -import { Application } from "./Application.js" -export type ZapInfo = { - pub: string - eventId: string - relays: string[] - description: string -} -@Entity() -export class UserReceivingInvoice { - - @PrimaryGeneratedColumn() - serial_id: number - - @ManyToOne(type => User, { eager: true }) - @JoinColumn() - user: User - - @Column() - @Index({ unique: true }) - invoice: string - - @Column() - expires_at_unix: number - - @Column({ default: 0 }) - paid_at_unix: number - - @Column({ default: false }) - internal: boolean - - @Column({ default: false }) - paidByLnd: boolean - - @Column({ default: "" }) - callbackUrl: string - - @Column({ default: 0 }) - paid_amount: number - - @Column({ default: 0 }) - service_fee: number - - @ManyToOne(type => Product, { eager: true }) - product: Product | null - - @ManyToOne(type => User, { eager: true }) - payer: User | null - - @ManyToOne(type => Application, { eager: true }) - linkedApplication: Application | null - - @Column({ - nullable: true, - type: 'simple-json' - }) - zap_info?: ZapInfo - - @CreateDateColumn() - created_at: Date - - @UpdateDateColumn() - updated_at: Date -} +import { Entity, PrimaryGeneratedColumn, Column, Index, Check, ManyToOne, JoinColumn, CreateDateColumn, UpdateDateColumn } from "typeorm" +import { Product } from "./Product.js" +import { User } from "./User.js" +import { Application } from "./Application.js" +export type ZapInfo = { + pub: string + eventId: string + relays: string[] + description: string +} +@Entity() +export class UserReceivingInvoice { + + @PrimaryGeneratedColumn() + serial_id: number + + @ManyToOne(type => User, { eager: true }) + @JoinColumn() + user: User + + @Column() + @Index({ unique: true }) + invoice: string + + @Column() + expires_at_unix: number + + @Column({ default: 0 }) + paid_at_unix: number + + @Column({ default: false }) + internal: boolean + + @Column({ default: false }) + paidByLnd: boolean + + @Column({ default: "" }) + callbackUrl: string + + @Column({ default: 0 }) + paid_amount: number + + @Column({ default: 0 }) + service_fee: number + + @ManyToOne(type => Product, { eager: true }) + product: Product | null + + @ManyToOne(type => User, { eager: true }) + payer: User | null + + @ManyToOne(type => Application, { eager: true }) + linkedApplication: Application | null + + @Column({ + nullable: true, + type: 'simple-json' + }) + zap_info?: ZapInfo + + @Column({ + nullable: true, + }) + liquidityProvider?: string + + @CreateDateColumn() + created_at: Date + + @UpdateDateColumn() + updated_at: Date +} diff --git a/src/services/storage/eventsLog.ts b/src/services/storage/eventsLog.ts index ca586993..9aee4fa8 100644 --- a/src/services/storage/eventsLog.ts +++ b/src/services/storage/eventsLog.ts @@ -1,125 +1,125 @@ -import fs from 'fs' -import { parse, stringify } from 'csv' -import { getLogger } from '../helpers/logger.js' -//const eventLogPath = "logs/eventLogV2.csv" -type LoggedEventType = 'new_invoice' | 'new_address' | 'address_paid' | 'invoice_paid' | 'invoice_payment' | 'address_payment' | 'u2u_receiver' | 'u2u_sender' | 'balance_increment' | 'balance_decrement' -export type LoggedEvent = { - timestampMs: number - userId: string - appUserId: string - appId: string - balance: number - type: LoggedEventType - data: string - amount: number -} -type TimeEntry = { - timestamp: number - amount: number - balance: number - userId: string -} -const columns = ["timestampMs", "userId", "appUserId", "appId", "balance", "type", "data", "amount"] -type StringerWrite = (chunk: any, cb: (error: Error | null | undefined) => void) => boolean -export default class EventsLogManager { - eventLogPath: string - log = getLogger({ component: "EventsLogManager" }) - stringerWrite: StringerWrite - constructor(eventLogPath: string) { - this.eventLogPath = eventLogPath - const exists = fs.existsSync(eventLogPath) - if (!exists) { - const stringer = stringify({ header: true, columns }) - stringer.pipe(fs.createWriteStream(eventLogPath, { flags: 'a' })) - this.stringerWrite = (chunk, cb) => stringer.write(chunk, cb) - } else { - const stringer = stringify({}) - stringer.pipe(fs.createWriteStream(eventLogPath, { flags: 'a' })) - this.stringerWrite = (chunk, cb) => stringer.write(chunk, cb) - } - } - - - - LogEvent = (e: Omit) => { - this.log(e.type, "->", e.userId, "->", e.appId, "->", e.appUserId, "->", e.balance, "->", e.data, "->", e.amount) - this.write([Date.now(), e.userId, e.appUserId, e.appId, e.balance, e.type, e.data, e.amount]) - } - - GetAllLogs = async (path?: string): Promise => { - const logs = await this.Read(path) - this.log("found", logs.length, "event logs") - return logs - } - - Read = async (path?: string): Promise => { - const filePath = path ? path : this.eventLogPath - const exists = fs.existsSync(filePath) - if (!exists) { - return [] - } - return new Promise((res, rej) => { - const result: LoggedEvent[] = [] - fs.createReadStream(filePath) - .pipe(parse({ delimiter: ",", from_line: 2 })) - .on('data', data => { result.push(this.parseEvent(data)) }) - .on('error', err => { rej(err) }) - .on('end', () => { res(result) }) - }) - } - - parseEvent = (args: string[]): LoggedEvent => { - const [timestampMs, userId, appUserId, appId, balance, type, data, amount] = args - return { timestampMs: +timestampMs, userId, appUserId, appId, balance: +balance, type: type as LoggedEventType, data, amount: +amount } - } - - write = async (args: (string | number)[]) => { - return new Promise((res, rej) => { - this.stringerWrite(args, err => { - if (err) { - rej(err) - } else { res() } - }) - }) - } - - ignoredKeys = ['fees', "bc1qkafgye62h2zhzlwtrga6jytz2p7af4lg8fwqt6", "6eb1d279f95377b8514aad3b79ff1cddbe9f5d3b95653b55719850df9df63821", "b11585413bfa7bf65a5f1263e3100e53b4c9afe6b5d8c94c6b85017dfcbf3d49"] - createTimeSeries = (events: LoggedEvent[]) => { - const dataAppIds: Record = {} - const order: { timestamp: number, data: string, type: 'inc' | 'dec' }[] = [] - const incrementEntries: Record = {} - const decrementEntries: Record = {} - events.forEach(e => { - if (this.ignoredKeys.includes(e.data)) { - return - } - if (e.type === 'balance_increment') { - if (incrementEntries[e.data]) { - throw new Error("increment duplicate! " + e.data) - } - incrementEntries[e.data] = { timestamp: e.timestampMs, balance: e.balance, amount: e.amount, userId: e.userId } - order.push({ timestamp: e.timestampMs, data: e.data, type: 'inc' }) - } else if (e.type === 'balance_decrement') { - if (decrementEntries[e.data]) { - throw new Error("decrement duplicate! " + e.data) - } - decrementEntries[e.data] = { timestamp: e.timestampMs, balance: e.balance, amount: e.amount, userId: e.userId } - order.push({ timestamp: e.timestampMs, data: e.data, type: 'dec' }) - } else if (e.appId) { - dataAppIds[e.data] = e.appId - } - }) - const full = order.map(o => { - const { type } = o - if (type === 'inc') { - const entry = incrementEntries[o.data] - return { timestamp: entry.timestamp, amount: entry.amount, balance: entry.balance, userId: entry.userId, appId: dataAppIds[o.data], internal: !!decrementEntries[o.data] } - } else { - const entry = decrementEntries[o.data] - return { timestamp: entry.timestamp, amount: -entry.amount, balance: entry.balance, userId: entry.userId, appId: dataAppIds[o.data], internal: !!incrementEntries[o.data] } - } - }) - full.sort((a, b) => a.timestamp - b.timestamp) - fs.writeFileSync("timeSeries.json", JSON.stringify(full, null, 2)) - } +import fs from 'fs' +import { parse, stringify } from 'csv' +import { getLogger } from '../helpers/logger.js' +//const eventLogPath = "logs/eventLogV3.csv" +type LoggedEventType = 'new_invoice' | 'new_address' | 'address_paid' | 'invoice_paid' | 'invoice_payment' | 'address_payment' | 'u2u_receiver' | 'u2u_sender' | 'balance_increment' | 'balance_decrement' +export type LoggedEvent = { + timestampMs: number + userId: string + appUserId: string + appId: string + balance: number + type: LoggedEventType + data: string + amount: number +} +type TimeEntry = { + timestamp: number + amount: number + balance: number + userId: string +} +const columns = ["timestampMs", "userId", "appUserId", "appId", "balance", "type", "data", "amount"] +type StringerWrite = (chunk: any, cb: (error: Error | null | undefined) => void) => boolean +export default class EventsLogManager { + eventLogPath: string + log = getLogger({ component: "EventsLogManager" }) + stringerWrite: StringerWrite + constructor(eventLogPath: string) { + this.eventLogPath = eventLogPath + const exists = fs.existsSync(eventLogPath) + if (!exists) { + const stringer = stringify({ header: true, columns }) + stringer.pipe(fs.createWriteStream(eventLogPath, { flags: 'a' })) + this.stringerWrite = (chunk, cb) => stringer.write(chunk, cb) + } else { + const stringer = stringify({}) + stringer.pipe(fs.createWriteStream(eventLogPath, { flags: 'a' })) + this.stringerWrite = (chunk, cb) => stringer.write(chunk, cb) + } + } + + + + LogEvent = (e: Omit) => { + //this.log(e.type, "->", e.userId, "->", e.appId, "->", e.appUserId, "->", e.balance, "->", e.data, "->", e.amount) + this.write([Date.now(), e.userId, e.appUserId, e.appId, e.balance, e.type, e.data, e.amount]) + } + + GetAllLogs = async (path?: string): Promise => { + const logs = await this.Read(path) + this.log("found", logs.length, "event logs") + return logs + } + + Read = async (path?: string): Promise => { + const filePath = path ? path : this.eventLogPath + const exists = fs.existsSync(filePath) + if (!exists) { + return [] + } + return new Promise((res, rej) => { + const result: LoggedEvent[] = [] + fs.createReadStream(filePath) + .pipe(parse({ delimiter: ",", from_line: 2 })) + .on('data', data => { result.push(this.parseEvent(data)) }) + .on('error', err => { rej(err) }) + .on('end', () => { res(result) }) + }) + } + + parseEvent = (args: string[]): LoggedEvent => { + const [timestampMs, userId, appUserId, appId, balance, type, data, amount] = args + return { timestampMs: +timestampMs, userId, appUserId, appId, balance: +balance, type: type as LoggedEventType, data, amount: +amount } + } + + write = async (args: (string | number)[]) => { + return new Promise((res, rej) => { + this.stringerWrite(args, err => { + if (err) { + rej(err) + } else { res() } + }) + }) + } + + ignoredKeys = ['fees', "bc1qkafgye62h2zhzlwtrga6jytz2p7af4lg8fwqt6", "6eb1d279f95377b8514aad3b79ff1cddbe9f5d3b95653b55719850df9df63821", "b11585413bfa7bf65a5f1263e3100e53b4c9afe6b5d8c94c6b85017dfcbf3d49"] + createTimeSeries = (events: LoggedEvent[]) => { + const dataAppIds: Record = {} + const order: { timestamp: number, data: string, type: 'inc' | 'dec' }[] = [] + const incrementEntries: Record = {} + const decrementEntries: Record = {} + events.forEach(e => { + if (this.ignoredKeys.includes(e.data)) { + return + } + if (e.type === 'balance_increment') { + if (incrementEntries[e.data]) { + throw new Error("increment duplicate! " + e.data) + } + incrementEntries[e.data] = { timestamp: e.timestampMs, balance: e.balance, amount: e.amount, userId: e.userId } + order.push({ timestamp: e.timestampMs, data: e.data, type: 'inc' }) + } else if (e.type === 'balance_decrement') { + if (decrementEntries[e.data]) { + throw new Error("decrement duplicate! " + e.data) + } + decrementEntries[e.data] = { timestamp: e.timestampMs, balance: e.balance, amount: e.amount, userId: e.userId } + order.push({ timestamp: e.timestampMs, data: e.data, type: 'dec' }) + } else if (e.appId) { + dataAppIds[e.data] = e.appId + } + }) + const full = order.map(o => { + const { type } = o + if (type === 'inc') { + const entry = incrementEntries[o.data] + return { timestamp: entry.timestamp, amount: entry.amount, balance: entry.balance, userId: entry.userId, appId: dataAppIds[o.data], internal: !!decrementEntries[o.data] } + } else { + const entry = decrementEntries[o.data] + return { timestamp: entry.timestamp, amount: -entry.amount, balance: entry.balance, userId: entry.userId, appId: dataAppIds[o.data], internal: !!incrementEntries[o.data] } + } + }) + full.sort((a, b) => a.timestamp - b.timestamp) + fs.writeFileSync("timeSeries.json", JSON.stringify(full, null, 2)) + } } \ No newline at end of file diff --git a/src/services/storage/index.ts b/src/services/storage/index.ts index 169691be..0988c265 100644 --- a/src/services/storage/index.ts +++ b/src/services/storage/index.ts @@ -1,4 +1,5 @@ import { DataSource, EntityManager } from "typeorm" +import fs from 'fs' import NewDB, { DbSettings, LoadDbSettingsFromEnv } from "./db.js" import ProductStorage from './productStorage.js' import ApplicationStorage from './applicationStorage.js' @@ -8,13 +9,14 @@ import MetricsStorage from "./metricsStorage.js"; import TransactionsQueue, { TX } from "./transactionsQueue.js"; import EventsLogManager from "./eventsLog.js"; import { LiquidityStorage } from "./liquidityStorage.js"; +import { StateBundler } from "./stateBundler.js"; export type StorageSettings = { dbSettings: DbSettings eventLogPath: string dataDir: string } export const LoadStorageSettingsFromEnv = (): StorageSettings => { - return { dbSettings: LoadDbSettingsFromEnv(), eventLogPath: "logs/eventLogV2.csv", dataDir: process.env.DATA_DIR || "" } + return { dbSettings: LoadDbSettingsFromEnv(), eventLogPath: "logs/eventLogV3.csv", dataDir: process.env.DATA_DIR || "" } } export default class { DB: DataSource | EntityManager @@ -27,6 +29,7 @@ export default class { metricsStorage: MetricsStorage liquidityStorage: LiquidityStorage eventsLog: EventsLogManager + stateBundler: StateBundler constructor(settings: StorageSettings) { this.settings = settings this.eventsLog = new EventsLogManager(settings.eventLogPath) @@ -41,6 +44,7 @@ export default class { this.paymentStorage = new PaymentStorage(this.DB, this.userStorage, this.txQueue) this.metricsStorage = new MetricsStorage(this.settings) this.liquidityStorage = new LiquidityStorage(this.DB, this.txQueue) + try { if (this.settings.dataDir) fs.mkdirSync(this.settings.dataDir) } catch (e) { } const executedMetricsMigrations = await this.metricsStorage.Connect(metricsMigrations) return { executedMigrations, executedMetricsMigrations }; } diff --git a/src/services/storage/liquidityStorage.ts b/src/services/storage/liquidityStorage.ts index 2ee2e92a..d93f77b3 100644 --- a/src/services/storage/liquidityStorage.ts +++ b/src/services/storage/liquidityStorage.ts @@ -1,6 +1,8 @@ import { DataSource, EntityManager, MoreThan } from "typeorm" import { LspOrder } from "./entity/LspOrder.js"; import TransactionsQueue, { TX } from "./transactionsQueue.js"; +import { LndNodeInfo } from "./entity/LndNodeInfo.js"; +import { TrackedProvider } from "./entity/TrackedProvider.js"; export class LiquidityStorage { DB: DataSource | EntityManager txQueue: TransactionsQueue @@ -17,4 +19,46 @@ export class LiquidityStorage { const entry = this.DB.getRepository(LspOrder).create(order) return this.txQueue.PushToQueue({ exec: async db => db.getRepository(LspOrder).save(entry), dbTx: false }) } + + async SaveNodeSeed(pubkey: string, seed: string) { + const existing = await this.DB.getRepository(LndNodeInfo).findOne({ where: { pubkey } }) + if (existing) { + throw new Error("A seed already exists for this pub key") + } + const entry = this.DB.getRepository(LndNodeInfo).create({ pubkey, seed }) + return this.txQueue.PushToQueue({ exec: async db => db.getRepository(LndNodeInfo).save(entry), dbTx: false }) + } + + async SaveNodeBackup(pubkey: string, backup: string) { + const existing = await this.DB.getRepository(LndNodeInfo).findOne({ where: { pubkey } }) + if (existing) { + await this.DB.getRepository(LndNodeInfo).update(existing.serial_id, { backup }) + return + } + const entry = this.DB.getRepository(LndNodeInfo).create({ pubkey, backup }) + await this.txQueue.PushToQueue({ exec: async db => db.getRepository(LndNodeInfo).save(entry), dbTx: false }) + } + + async GetTrackedProvider(providerType: 'lnd' | 'lnPub', pub: string) { + return this.DB.getRepository(TrackedProvider).findOne({ where: { provider_pubkey: pub, provider_type: providerType } }) + } + async CreateTrackedProvider(providerType: 'lnd' | 'lnPub', pub: string, latestBalance = 0) { + const entry = this.DB.getRepository(TrackedProvider).create({ provider_pubkey: pub, provider_type: providerType, latest_balance: latestBalance }) + return this.txQueue.PushToQueue({ exec: async db => db.getRepository(TrackedProvider).save(entry), dbTx: false }) + } + async UpdateTrackedProviderBalance(providerType: 'lnd' | 'lnPub', pub: string, latestBalance: number) { + console.log("updating tracked balance:", latestBalance) + return this.DB.getRepository(TrackedProvider).update({ provider_pubkey: pub, provider_type: providerType }, { latest_balance: latestBalance }) + } + async IncrementTrackedProviderBalance(providerType: 'lnd' | 'lnPub', pub: string, amount: number) { + if (amount < 0) { + return this.DB.getRepository(TrackedProvider).increment({ provider_pubkey: pub, provider_type: providerType }, "latest_balance", amount) + } else { + return this.DB.getRepository(TrackedProvider).decrement({ provider_pubkey: pub, provider_type: providerType }, "latest_balance", -amount) + } + + } + async UpdateTrackedProviderDisruption(providerType: 'lnd' | 'lnPub', pub: string, latestDisruptionAtUnix: number) { + return this.DB.getRepository(TrackedProvider).update({ provider_pubkey: pub, provider_type: providerType }, { latest_distruption_at_unix: latestDisruptionAtUnix }) + } } \ No newline at end of file diff --git a/src/services/storage/migrations/1719335699480-liquidity_provider.ts b/src/services/storage/migrations/1719335699480-liquidity_provider.ts new file mode 100644 index 00000000..f02a05f3 --- /dev/null +++ b/src/services/storage/migrations/1719335699480-liquidity_provider.ts @@ -0,0 +1,36 @@ +import { MigrationInterface, QueryRunner } from "typeorm"; + +export class LiquidityProvider1719335699480 implements MigrationInterface { + name = 'LiquidityProvider1719335699480' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query(`DROP INDEX "IDX_a131e6b58f084f1340538681b5"`); + await queryRunner.query(`CREATE TABLE "temporary_user_receiving_invoice" ("serial_id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "invoice" varchar NOT NULL, "expires_at_unix" integer NOT NULL, "paid_at_unix" integer NOT NULL DEFAULT (0), "internal" boolean NOT NULL DEFAULT (0), "paidByLnd" boolean NOT NULL DEFAULT (0), "callbackUrl" varchar NOT NULL DEFAULT (''), "paid_amount" integer NOT NULL DEFAULT (0), "service_fee" integer NOT NULL DEFAULT (0), "zap_info" text, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "updated_at" datetime NOT NULL DEFAULT (datetime('now')), "userSerialId" integer, "productProductId" varchar, "payerSerialId" integer, "linkedApplicationSerialId" integer, "liquidityProvider" varchar, CONSTRAINT "FK_714a8b7d4f89f8a802ca181b789" FOREIGN KEY ("linkedApplicationSerialId") REFERENCES "application" ("serial_id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_d4bb1e4c60e8a869f1f43ca2e31" FOREIGN KEY ("payerSerialId") REFERENCES "user" ("serial_id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_5263bde2a519db9ea608b702ec8" FOREIGN KEY ("productProductId") REFERENCES "product" ("product_id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_2c0dfb3483f3e5e7e3cdd5dc71f" FOREIGN KEY ("userSerialId") REFERENCES "user" ("serial_id") ON DELETE NO ACTION ON UPDATE NO ACTION)`); + await queryRunner.query(`INSERT INTO "temporary_user_receiving_invoice"("serial_id", "invoice", "expires_at_unix", "paid_at_unix", "internal", "paidByLnd", "callbackUrl", "paid_amount", "service_fee", "zap_info", "created_at", "updated_at", "userSerialId", "productProductId", "payerSerialId", "linkedApplicationSerialId") SELECT "serial_id", "invoice", "expires_at_unix", "paid_at_unix", "internal", "paidByLnd", "callbackUrl", "paid_amount", "service_fee", "zap_info", "created_at", "updated_at", "userSerialId", "productProductId", "payerSerialId", "linkedApplicationSerialId" FROM "user_receiving_invoice"`); + await queryRunner.query(`DROP TABLE "user_receiving_invoice"`); + await queryRunner.query(`ALTER TABLE "temporary_user_receiving_invoice" RENAME TO "user_receiving_invoice"`); + await queryRunner.query(`CREATE UNIQUE INDEX "IDX_a131e6b58f084f1340538681b5" ON "user_receiving_invoice" ("invoice") `); + await queryRunner.query(`DROP INDEX "IDX_a609a4d3d8d9b07b90692a3c45"`); + await queryRunner.query(`CREATE TABLE "temporary_user_invoice_payment" ("serial_id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "invoice" varchar NOT NULL, "paid_amount" integer NOT NULL, "routing_fees" integer NOT NULL, "service_fees" integer NOT NULL, "paid_at_unix" integer NOT NULL, "internal" boolean NOT NULL DEFAULT (0), "created_at" datetime NOT NULL DEFAULT (datetime('now')), "updated_at" datetime NOT NULL DEFAULT (datetime('now')), "userSerialId" integer, "linkedApplicationSerialId" integer, "liquidityProvider" varchar, CONSTRAINT "FK_6bcac90887eea1dc61d37db2994" FOREIGN KEY ("linkedApplicationSerialId") REFERENCES "application" ("serial_id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_ef2aa6761ab681bbbd5f94e0fcb" FOREIGN KEY ("userSerialId") REFERENCES "user" ("serial_id") ON DELETE NO ACTION ON UPDATE NO ACTION)`); + await queryRunner.query(`INSERT INTO "temporary_user_invoice_payment"("serial_id", "invoice", "paid_amount", "routing_fees", "service_fees", "paid_at_unix", "internal", "created_at", "updated_at", "userSerialId", "linkedApplicationSerialId") SELECT "serial_id", "invoice", "paid_amount", "routing_fees", "service_fees", "paid_at_unix", "internal", "created_at", "updated_at", "userSerialId", "linkedApplicationSerialId" FROM "user_invoice_payment"`); + await queryRunner.query(`DROP TABLE "user_invoice_payment"`); + await queryRunner.query(`ALTER TABLE "temporary_user_invoice_payment" RENAME TO "user_invoice_payment"`); + await queryRunner.query(`CREATE UNIQUE INDEX "IDX_a609a4d3d8d9b07b90692a3c45" ON "user_invoice_payment" ("invoice") `); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`DROP INDEX "IDX_a609a4d3d8d9b07b90692a3c45"`); + await queryRunner.query(`ALTER TABLE "user_invoice_payment" RENAME TO "temporary_user_invoice_payment"`); + await queryRunner.query(`CREATE TABLE "user_invoice_payment" ("serial_id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "invoice" varchar NOT NULL, "paid_amount" integer NOT NULL, "routing_fees" integer NOT NULL, "service_fees" integer NOT NULL, "paid_at_unix" integer NOT NULL, "internal" boolean NOT NULL DEFAULT (0), "created_at" datetime NOT NULL DEFAULT (datetime('now')), "updated_at" datetime NOT NULL DEFAULT (datetime('now')), "userSerialId" integer, "linkedApplicationSerialId" integer, CONSTRAINT "FK_6bcac90887eea1dc61d37db2994" FOREIGN KEY ("linkedApplicationSerialId") REFERENCES "application" ("serial_id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_ef2aa6761ab681bbbd5f94e0fcb" FOREIGN KEY ("userSerialId") REFERENCES "user" ("serial_id") ON DELETE NO ACTION ON UPDATE NO ACTION)`); + await queryRunner.query(`INSERT INTO "user_invoice_payment"("serial_id", "invoice", "paid_amount", "routing_fees", "service_fees", "paid_at_unix", "internal", "created_at", "updated_at", "userSerialId", "linkedApplicationSerialId") SELECT "serial_id", "invoice", "paid_amount", "routing_fees", "service_fees", "paid_at_unix", "internal", "created_at", "updated_at", "userSerialId", "linkedApplicationSerialId" FROM "temporary_user_invoice_payment"`); + await queryRunner.query(`DROP TABLE "temporary_user_invoice_payment"`); + await queryRunner.query(`CREATE UNIQUE INDEX "IDX_a609a4d3d8d9b07b90692a3c45" ON "user_invoice_payment" ("invoice") `); + await queryRunner.query(`DROP INDEX "IDX_a131e6b58f084f1340538681b5"`); + await queryRunner.query(`ALTER TABLE "user_receiving_invoice" RENAME TO "temporary_user_receiving_invoice"`); + await queryRunner.query(`CREATE TABLE "user_receiving_invoice" ("serial_id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "invoice" varchar NOT NULL, "expires_at_unix" integer NOT NULL, "paid_at_unix" integer NOT NULL DEFAULT (0), "internal" boolean NOT NULL DEFAULT (0), "paidByLnd" boolean NOT NULL DEFAULT (0), "callbackUrl" varchar NOT NULL DEFAULT (''), "paid_amount" integer NOT NULL DEFAULT (0), "service_fee" integer NOT NULL DEFAULT (0), "zap_info" text, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "updated_at" datetime NOT NULL DEFAULT (datetime('now')), "userSerialId" integer, "productProductId" varchar, "payerSerialId" integer, "linkedApplicationSerialId" integer, CONSTRAINT "FK_714a8b7d4f89f8a802ca181b789" FOREIGN KEY ("linkedApplicationSerialId") REFERENCES "application" ("serial_id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_d4bb1e4c60e8a869f1f43ca2e31" FOREIGN KEY ("payerSerialId") REFERENCES "user" ("serial_id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_5263bde2a519db9ea608b702ec8" FOREIGN KEY ("productProductId") REFERENCES "product" ("product_id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_2c0dfb3483f3e5e7e3cdd5dc71f" FOREIGN KEY ("userSerialId") REFERENCES "user" ("serial_id") ON DELETE NO ACTION ON UPDATE NO ACTION)`); + await queryRunner.query(`INSERT INTO "user_receiving_invoice"("serial_id", "invoice", "expires_at_unix", "paid_at_unix", "internal", "paidByLnd", "callbackUrl", "paid_amount", "service_fee", "zap_info", "created_at", "updated_at", "userSerialId", "productProductId", "payerSerialId", "linkedApplicationSerialId") SELECT "serial_id", "invoice", "expires_at_unix", "paid_at_unix", "internal", "paidByLnd", "callbackUrl", "paid_amount", "service_fee", "zap_info", "created_at", "updated_at", "userSerialId", "productProductId", "payerSerialId", "linkedApplicationSerialId" FROM "temporary_user_receiving_invoice"`); + await queryRunner.query(`DROP TABLE "temporary_user_receiving_invoice"`); + await queryRunner.query(`CREATE UNIQUE INDEX "IDX_a131e6b58f084f1340538681b5" ON "user_receiving_invoice" ("invoice") `); + } + +} diff --git a/src/services/storage/migrations/1720187506189-lnd_node_info.ts b/src/services/storage/migrations/1720187506189-lnd_node_info.ts new file mode 100644 index 00000000..39285f69 --- /dev/null +++ b/src/services/storage/migrations/1720187506189-lnd_node_info.ts @@ -0,0 +1,14 @@ +import { MigrationInterface, QueryRunner } from "typeorm"; + +export class LndNodeInfo1720187506189 implements MigrationInterface { + name = 'LndNodeInfo1720187506189' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query(`CREATE TABLE "lnd_node_info" ("serial_id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "pubkey" varchar NOT NULL, "seed" varchar, "backup" varchar, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "updated_at" datetime NOT NULL DEFAULT (datetime('now')))`); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`DROP TABLE "lnd_node_info"`); + } + +} diff --git a/src/services/storage/migrations/1720814323679-tracked_provider.ts b/src/services/storage/migrations/1720814323679-tracked_provider.ts new file mode 100644 index 00000000..1436a6e0 --- /dev/null +++ b/src/services/storage/migrations/1720814323679-tracked_provider.ts @@ -0,0 +1,16 @@ +import { MigrationInterface, QueryRunner } from "typeorm"; + +export class TrackedProvider1720814323679 implements MigrationInterface { + name = 'TrackedProvider1720814323679' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query(`CREATE TABLE "tracked_provider" ("serial_id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "provider_type" varchar NOT NULL, "provider_pubkey" varchar NOT NULL, "latest_balance" integer NOT NULL, "latest_distruption_at_unix" integer NOT NULL DEFAULT (0), "created_at" datetime NOT NULL DEFAULT (datetime('now')), "updated_at" datetime NOT NULL DEFAULT (datetime('now')))`); + await queryRunner.query(`CREATE UNIQUE INDEX "tracked_provider_unique" ON "tracked_provider" ("provider_type", "provider_pubkey") `); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`DROP INDEX "tracked_provider_unique"`); + await queryRunner.query(`DROP TABLE "tracked_provider"`); + } + +} diff --git a/src/services/storage/migrations/runner.ts b/src/services/storage/migrations/runner.ts index 479264e4..2f09dc5e 100644 --- a/src/services/storage/migrations/runner.ts +++ b/src/services/storage/migrations/runner.ts @@ -5,7 +5,10 @@ import { Initial1703170309875 } from './1703170309875-initial.js' import { LndMetrics1703170330183 } from './1703170330183-lnd_metrics.js' import { ChannelRouting1709316653538 } from './1709316653538-channel_routing.js' import { LspOrder1718387847693 } from './1718387847693-lsp_order.js' -const allMigrations = [Initial1703170309875, LspOrder1718387847693] +import { LiquidityProvider1719335699480 } from './1719335699480-liquidity_provider.js' +import { LndNodeInfo1720187506189 } from './1720187506189-lnd_node_info.js' +import { TrackedProvider1720814323679 } from './1720814323679-tracked_provider.js' +const allMigrations = [Initial1703170309875, LspOrder1718387847693, LiquidityProvider1719335699480, LndNodeInfo1720187506189, TrackedProvider1720814323679] const allMetricsMigrations = [LndMetrics1703170330183, ChannelRouting1709316653538] export const TypeOrmMigrationRunner = async (log: PubLogger, storageManager: Storage, settings: DbSettings, arg: string | undefined): Promise => { if (arg === 'fake_initial_migration') { diff --git a/src/services/storage/paymentStorage.ts b/src/services/storage/paymentStorage.ts index 23337255..9e4542c1 100644 --- a/src/services/storage/paymentStorage.ts +++ b/src/services/storage/paymentStorage.ts @@ -1,417 +1,419 @@ -import crypto from 'crypto'; -import { Between, DataSource, EntityManager, FindOperator, IsNull, LessThanOrEqual, MoreThan, MoreThanOrEqual } from "typeorm" -import { User } from './entity/User.js'; -import { UserTransactionPayment } from './entity/UserTransactionPayment.js'; -import { EphemeralKeyType, UserEphemeralKey } from './entity/UserEphemeralKey.js'; -import { UserReceivingInvoice, ZapInfo } from './entity/UserReceivingInvoice.js'; -import { UserReceivingAddress } from './entity/UserReceivingAddress.js'; -import { Product } from './entity/Product.js'; -import UserStorage from './userStorage.js'; -import { AddressReceivingTransaction } from './entity/AddressReceivingTransaction.js'; -import { UserInvoicePayment } from './entity/UserInvoicePayment.js'; -import { UserToUserPayment } from './entity/UserToUserPayment.js'; -import { Application } from './entity/Application.js'; -import TransactionsQueue from "./transactionsQueue.js"; -import { LoggedEvent } from './eventsLog.js'; -export type InboundOptionals = { product?: Product, callbackUrl?: string, expiry: number, expectedPayer?: User, linkedApplication?: Application, zapInfo?: ZapInfo } -export const defaultInvoiceExpiry = 60 * 60 -export default class { - DB: DataSource | EntityManager - userStorage: UserStorage - txQueue: TransactionsQueue - constructor(DB: DataSource | EntityManager, userStorage: UserStorage, txQueue: TransactionsQueue) { - this.DB = DB - this.userStorage = userStorage - this.txQueue = txQueue - } - - async AddAddressReceivingTransaction(address: UserReceivingAddress, txHash: string, outputIndex: number, amount: number, serviceFee: number, internal: boolean, height: number, dbTx: EntityManager | DataSource) { - const newAddressTransaction = dbTx.getRepository(AddressReceivingTransaction).create({ - user_address: address, - tx_hash: txHash, - output_index: outputIndex, - paid_amount: amount, - service_fee: serviceFee, - paid_at_unix: Math.floor(Date.now() / 1000), - internal, - broadcast_height: height, - confs: internal ? 10 : 0 - }) - return dbTx.getRepository(AddressReceivingTransaction).save(newAddressTransaction) - } - - GetUserReceivingTransactions(userId: string, fromIndex: number, take = 50, entityManager = this.DB): Promise { - return entityManager.getRepository(AddressReceivingTransaction).find({ - where: { - user_address: { user: { user_id: userId } }, - serial_id: MoreThanOrEqual(fromIndex), - paid_at_unix: MoreThan(0), - }, - order: { - paid_at_unix: 'DESC' - }, - take - }) - } - - async GetExistingUserAddress(userId: string, linkedApplication: Application, entityManager = this.DB) { - return entityManager.getRepository(UserReceivingAddress).findOne({ where: { user: { user_id: userId }, linkedApplication: { app_id: linkedApplication.app_id } } }) - } - - async AddUserAddress(user: User, address: string, opts: { callbackUrl?: string, linkedApplication?: Application } = {}): Promise { - const newUserAddress = this.DB.getRepository(UserReceivingAddress).create({ - address, - callbackUrl: opts.callbackUrl || "", - linkedApplication: opts.linkedApplication, - user - }) - return this.txQueue.PushToQueue({ exec: async db => db.getRepository(UserReceivingAddress).save(newUserAddress), dbTx: false, description: `add address for ${user.user_id} linked to ${opts.linkedApplication?.app_id}: ${address} ` }) - } - - async FlagInvoiceAsPaid(invoice: UserReceivingInvoice, amount: number, serviceFee: number, internal: boolean, dbTx: EntityManager | DataSource) { - const i: Partial = { paid_at_unix: Math.floor(Date.now() / 1000), paid_amount: amount, service_fee: serviceFee, internal } - if (!internal) { - i.paidByLnd = true - } - return dbTx.getRepository(UserReceivingInvoice).update(invoice.serial_id, i) - } - - GetUserInvoicesFlaggedAsPaid(userId: string, fromIndex: number, take = 50, entityManager = this.DB): Promise { - return entityManager.getRepository(UserReceivingInvoice).find({ - where: { - user: { - user_id: userId - }, - serial_id: MoreThanOrEqual(fromIndex), - paid_at_unix: MoreThan(0), - }, - order: { - paid_at_unix: 'DESC' - }, - take - }) - } - - async AddUserInvoice(user: User, invoice: string, options: InboundOptionals = { expiry: defaultInvoiceExpiry }): Promise { - const newUserInvoice = this.DB.getRepository(UserReceivingInvoice).create({ - invoice: invoice, - callbackUrl: options.callbackUrl, - user: user, - product: options.product, - expires_at_unix: Math.floor(Date.now() / 1000) + options.expiry, - payer: options.expectedPayer, - linkedApplication: options.linkedApplication, - zap_info: options.zapInfo - }) - return this.txQueue.PushToQueue({ exec: async db => db.getRepository(UserReceivingInvoice).save(newUserInvoice), dbTx: false, description: `add invoice for ${user.user_id} linked to ${options.linkedApplication?.app_id}: ${invoice} ` }) - } - - async GetAddressOwner(address: string, entityManager = this.DB): Promise { - return entityManager.getRepository(UserReceivingAddress).findOne({ - where: { - address - } - }) - } - - async GetAddressReceivingTransactionOwner(address: string, txHash: string, entityManager = this.DB): Promise { - return entityManager.getRepository(AddressReceivingTransaction).findOne({ - where: { - user_address: { address }, - tx_hash: txHash - } - }) - } - async GetUserTransactionPaymentOwner(address: string, txHash: string, entityManager = this.DB): Promise { - return entityManager.getRepository(UserTransactionPayment).findOne({ - where: { - address, - tx_hash: txHash - } - }) - } - - async GetInvoiceOwner(paymentRequest: string, entityManager = this.DB): Promise { - return entityManager.getRepository(UserReceivingInvoice).findOne({ - where: { - invoice: paymentRequest - } - }) - } - async GetPaymentOwner(paymentRequest: string, entityManager = this.DB): Promise { - return entityManager.getRepository(UserInvoicePayment).findOne({ - where: { - invoice: paymentRequest - } - }) - } - async GetUser2UserPayment(serialId: number, entityManager = this.DB): Promise { - return entityManager.getRepository(UserToUserPayment).findOne({ - where: { - serial_id: serialId - } - }) - } - - async AddPendingExternalPayment(userId: string, invoice: string, amount: number, linkedApplication: Application): Promise { - const newPayment = this.DB.getRepository(UserInvoicePayment).create({ - user: await this.userStorage.GetUser(userId), - paid_amount: amount, - invoice, - routing_fees: 0, - service_fees: 0, - paid_at_unix: 0, - internal: false, - linkedApplication - }) - return this.txQueue.PushToQueue({ exec: async db => db.getRepository(UserInvoicePayment).save(newPayment), dbTx: false, description: `add pending invoice payment for ${userId} linked to ${linkedApplication.app_id}: ${invoice}, amt: ${amount} ` }) - } - - async UpdateExternalPayment(invoicePaymentSerialId: number, routingFees: number, serviceFees: number, success: boolean) { - return this.DB.getRepository(UserInvoicePayment).update(invoicePaymentSerialId, { - routing_fees: routingFees, - service_fees: serviceFees, - paid_at_unix: success ? Math.floor(Date.now() / 1000) : -1 - }) - } - - async AddInternalPayment(userId: string, invoice: string, amount: number, serviceFees: number, linkedApplication: Application): Promise { - const newPayment = this.DB.getRepository(UserInvoicePayment).create({ - user: await this.userStorage.GetUser(userId), - paid_amount: amount, - invoice, - routing_fees: 0, - service_fees: serviceFees, - paid_at_unix: Math.floor(Date.now() / 1000), - internal: true, - linkedApplication - }) - return this.txQueue.PushToQueue({ exec: async db => db.getRepository(UserInvoicePayment).save(newPayment), dbTx: false, description: `add internal invoice payment for ${userId} linked to ${linkedApplication.app_id}: ${invoice}, amt: ${amount} ` }) - } - - GetUserInvoicePayments(userId: string, fromIndex: number, take = 50, entityManager = this.DB): Promise { - return entityManager.getRepository(UserInvoicePayment).find({ - where: { - user: { - user_id: userId - }, - serial_id: MoreThanOrEqual(fromIndex), - paid_at_unix: MoreThan(0), - }, - order: { - paid_at_unix: 'DESC' - }, - take - }) - } - - async AddUserTransactionPayment(userId: string, address: string, txHash: string, txOutput: number, amount: number, chainFees: number, serviceFees: number, internal: boolean, height: number, linkedApplication: Application): Promise { - const newTx = this.DB.getRepository(UserTransactionPayment).create({ - user: await this.userStorage.GetUser(userId), - address, - paid_amount: amount, - chain_fees: chainFees, - output_index: txOutput, - tx_hash: txHash, - service_fees: serviceFees, - paid_at_unix: Math.floor(Date.now() / 1000), - internal, - broadcast_height: height, - confs: internal ? 10 : 0, - linkedApplication - }) - return this.txQueue.PushToQueue({ exec: async db => db.getRepository(UserTransactionPayment).save(newTx), dbTx: false, description: `add tx payment for ${userId} linked to ${linkedApplication.app_id}: ${address}, amt: ${amount} ` }) - } - - GetUserTransactionPayments(userId: string, fromIndex: number, take = 50, entityManager = this.DB): Promise { - return entityManager.getRepository(UserTransactionPayment).find({ - where: { - user: { - user_id: userId - }, - serial_id: MoreThanOrEqual(fromIndex), - paid_at_unix: MoreThan(0), - }, - order: { - paid_at_unix: 'DESC' - }, - take - }) - } - - async GetPendingTransactions(entityManager = this.DB) { - const incoming = await entityManager.getRepository(AddressReceivingTransaction).find({ where: { confs: 0 } }) - const outgoing = await entityManager.getRepository(UserTransactionPayment).find({ where: { confs: 0 } }) - return { incoming, outgoing } - } - - async UpdateAddressReceivingTransaction(serialId: number, update: Partial, entityManager = this.DB) { - return entityManager.getRepository(AddressReceivingTransaction).update(serialId, update) - } - async UpdateUserTransactionPayment(serialId: number, update: Partial, entityManager = this.DB) { - await entityManager.getRepository(UserTransactionPayment).update(serialId, update) - } - - - async AddUserEphemeralKey(userId: string, keyType: EphemeralKeyType, linkedApplication: Application): Promise { - const found = await this.DB.getRepository(UserEphemeralKey).findOne({ where: { type: keyType, user: { user_id: userId }, linkedApplication: { app_id: linkedApplication.app_id } } }) - if (found) { - return found - } - const newKey = this.DB.getRepository(UserEphemeralKey).create({ - user: await this.userStorage.GetUser(userId), - key: crypto.randomBytes(31).toString('hex'), - type: keyType, - linkedApplication - }) - return this.txQueue.PushToQueue({ exec: async db => db.getRepository(UserEphemeralKey).save(newKey), dbTx: false }) - } - - async UseUserEphemeralKey(key: string, keyType: EphemeralKeyType, persist = false, entityManager = this.DB): Promise { - const found = await entityManager.getRepository(UserEphemeralKey).findOne({ - where: { - key: key, - type: keyType - } - }) - if (!found) { - throw new Error("the provided ephemeral key is invalid") - } - if (!persist) { - await entityManager.getRepository(UserEphemeralKey).delete(found.serial_id) - } - return found - } - - async AddPendingUserToUserPayment(fromUserId: string, toUserId: string, amount: number, fee: number, linkedApplication: Application, dbTx: DataSource | EntityManager) { - const entry = dbTx.getRepository(UserToUserPayment).create({ - from_user: await this.userStorage.GetUser(fromUserId, dbTx), - to_user: await this.userStorage.GetUser(toUserId, dbTx), - paid_at_unix: 0, - paid_amount: amount, - service_fees: fee, - linkedApplication - }) - return dbTx.getRepository(UserToUserPayment).save(entry) - } - async SetPendingUserToUserPaymentAsPaid(serialId: number, dbTx: DataSource | EntityManager) { - dbTx.getRepository(UserToUserPayment).update(serialId, { paid_at_unix: Math.floor(Date.now() / 1000) }) - } - - GetUserToUserReceivedPayments(userId: string, fromIndex: number, take = 50, entityManager = this.DB) { - return entityManager.getRepository(UserToUserPayment).find({ - where: { - to_user: { - user_id: userId - }, - serial_id: MoreThanOrEqual(fromIndex), - paid_at_unix: MoreThan(0), - }, - order: { - paid_at_unix: 'DESC' - }, - take - }) - } - - GetUserToUserSentPayments(userId: string, fromIndex: number, take = 50, entityManager = this.DB) { - return entityManager.getRepository(UserToUserPayment).find({ - where: { - from_user: { - user_id: userId - }, - serial_id: MoreThanOrEqual(fromIndex), - paid_at_unix: MoreThan(0), - }, - order: { - paid_at_unix: 'DESC' - }, - take - }) - } - - async GetTotalFeesPaidInApp(app: Application | null, entityManager = this.DB) { - if (!app) { - return 0 - } - const entries = await Promise.all([ - entityManager.getRepository(UserReceivingInvoice).sum("service_fee", { linkedApplication: { app_id: app.app_id } }), - entityManager.getRepository(AddressReceivingTransaction).sum("service_fee", { user_address: { linkedApplication: { app_id: app.app_id } } }), - entityManager.getRepository(UserInvoicePayment).sum("service_fees", { linkedApplication: { app_id: app.app_id } }), - entityManager.getRepository(UserTransactionPayment).sum("service_fees", { linkedApplication: { app_id: app.app_id } }), - entityManager.getRepository(UserToUserPayment).sum("service_fees", { linkedApplication: { app_id: app.app_id } }) - ]) - let total = 0 - entries.forEach(e => { - if (e) { - total += e - } - }) - return total - } - - async GetAppOperations(application: Application | null, { from, to }: { from?: number, to?: number }, entityManager = this.DB) { - const q = application ? { app_id: application.app_id } : IsNull() - let time: { created_at?: FindOperator } = {} - if (!!from && !!to) { - time.created_at = Between(new Date(from * 1000), new Date(to * 1000)) - } else if (!!from) { - time.created_at = MoreThanOrEqual(new Date(from * 1000)) - } else if (!!to) { - time.created_at = LessThanOrEqual(new Date(to * 1000)) - } - - const [receivingInvoices, receivingAddresses, outgoingInvoices, outgoingTransactions, userToUser] = await Promise.all([ - entityManager.getRepository(UserReceivingInvoice).find({ where: { linkedApplication: q, ...time } }), - entityManager.getRepository(UserReceivingAddress).find({ where: { linkedApplication: q, ...time } }), - entityManager.getRepository(UserInvoicePayment).find({ where: { linkedApplication: q, ...time } }), - entityManager.getRepository(UserTransactionPayment).find({ where: { linkedApplication: q, ...time } }), - entityManager.getRepository(UserToUserPayment).find({ where: { linkedApplication: q, ...time } }) - ]) - const receivingTransactions = await Promise.all(receivingAddresses.map(addr => entityManager.getRepository(AddressReceivingTransaction).find({ where: { user_address: { serial_id: addr.serial_id }, ...time } }))) - return { - receivingInvoices, receivingAddresses, receivingTransactions, - outgoingInvoices, outgoingTransactions, - userToUser - } - } - - async UserHasOutgoingOperation(userId: string, entityManager = this.DB) { - const [i, tx, u2u] = await Promise.all([ - entityManager.getRepository(UserInvoicePayment).findOne({ where: { user: { user_id: userId } } }), - entityManager.getRepository(UserTransactionPayment).findOne({ where: { user: { user_id: userId } } }), - entityManager.getRepository(UserToUserPayment).findOne({ where: { from_user: { user_id: userId } } }), - ]) - return !!i || !!tx || !!u2u - } - - async VerifyDbEvent(e: LoggedEvent) { - switch (e.type) { - case "new_invoice": - return this.DB.getRepository(UserReceivingInvoice).findOneOrFail({ where: { invoice: e.data, user: { user_id: e.userId } } }) - case 'new_address': - return this.DB.getRepository(UserReceivingAddress).findOneOrFail({ where: { address: e.data, user: { user_id: e.userId } } }) - case 'invoice_paid': - return this.DB.getRepository(UserReceivingInvoice).findOneOrFail({ where: { invoice: e.data, user: { user_id: e.userId }, paid_at_unix: MoreThan(0) } }) - case 'invoice_payment': - return this.DB.getRepository(UserInvoicePayment).findOneOrFail({ where: { invoice: e.data, user: { user_id: e.userId } } }) - case 'address_paid': - const [receivingAddress, receivedHash] = e.data.split(":") - return this.DB.getRepository(AddressReceivingTransaction).findOneOrFail({ where: { user_address: { address: receivingAddress }, tx_hash: receivedHash, confs: MoreThan(0) } }) - case 'address_payment': - const [sentAddress, sentHash] = e.data.split(":") - return this.DB.getRepository(UserTransactionPayment).findOneOrFail({ where: { address: sentAddress, tx_hash: sentHash, user: { user_id: e.userId } } }) - case 'u2u_receiver': - return this.DB.getRepository(UserToUserPayment).findOneOrFail({ where: { from_user: { user_id: e.data }, to_user: { user_id: e.userId } } }) - case 'u2u_sender': - return this.DB.getRepository(UserToUserPayment).findOneOrFail({ where: { to_user: { user_id: e.data }, from_user: { user_id: e.userId } } }) - default: - break; - } - } - - async GetTotalUsersBalance(entityManager = this.DB) { - const total = await entityManager.getRepository(User).sum("balance_sats") - return total || 0 - } +import crypto from 'crypto'; +import { Between, DataSource, EntityManager, FindOperator, IsNull, LessThanOrEqual, MoreThan, MoreThanOrEqual } from "typeorm" +import { User } from './entity/User.js'; +import { UserTransactionPayment } from './entity/UserTransactionPayment.js'; +import { EphemeralKeyType, UserEphemeralKey } from './entity/UserEphemeralKey.js'; +import { UserReceivingInvoice, ZapInfo } from './entity/UserReceivingInvoice.js'; +import { UserReceivingAddress } from './entity/UserReceivingAddress.js'; +import { Product } from './entity/Product.js'; +import UserStorage from './userStorage.js'; +import { AddressReceivingTransaction } from './entity/AddressReceivingTransaction.js'; +import { UserInvoicePayment } from './entity/UserInvoicePayment.js'; +import { UserToUserPayment } from './entity/UserToUserPayment.js'; +import { Application } from './entity/Application.js'; +import TransactionsQueue from "./transactionsQueue.js"; +import { LoggedEvent } from './eventsLog.js'; +export type InboundOptionals = { product?: Product, callbackUrl?: string, expiry: number, expectedPayer?: User, linkedApplication?: Application, zapInfo?: ZapInfo } +export const defaultInvoiceExpiry = 60 * 60 +export default class { + DB: DataSource | EntityManager + userStorage: UserStorage + txQueue: TransactionsQueue + constructor(DB: DataSource | EntityManager, userStorage: UserStorage, txQueue: TransactionsQueue) { + this.DB = DB + this.userStorage = userStorage + this.txQueue = txQueue + } + + async AddAddressReceivingTransaction(address: UserReceivingAddress, txHash: string, outputIndex: number, amount: number, serviceFee: number, internal: boolean, height: number, dbTx: EntityManager | DataSource) { + const newAddressTransaction = dbTx.getRepository(AddressReceivingTransaction).create({ + user_address: address, + tx_hash: txHash, + output_index: outputIndex, + paid_amount: amount, + service_fee: serviceFee, + paid_at_unix: Math.floor(Date.now() / 1000), + internal, + broadcast_height: height, + confs: internal ? 10 : 0 + }) + return dbTx.getRepository(AddressReceivingTransaction).save(newAddressTransaction) + } + + GetUserReceivingTransactions(userId: string, fromIndex: number, take = 50, entityManager = this.DB): Promise { + return entityManager.getRepository(AddressReceivingTransaction).find({ + where: { + user_address: { user: { user_id: userId } }, + serial_id: MoreThanOrEqual(fromIndex), + paid_at_unix: MoreThan(0), + }, + order: { + paid_at_unix: 'DESC' + }, + take + }) + } + + async GetExistingUserAddress(userId: string, linkedApplication: Application, entityManager = this.DB) { + return entityManager.getRepository(UserReceivingAddress).findOne({ where: { user: { user_id: userId }, linkedApplication: { app_id: linkedApplication.app_id } } }) + } + + async AddUserAddress(user: User, address: string, opts: { callbackUrl?: string, linkedApplication?: Application } = {}): Promise { + const newUserAddress = this.DB.getRepository(UserReceivingAddress).create({ + address, + callbackUrl: opts.callbackUrl || "", + linkedApplication: opts.linkedApplication, + user + }) + return this.txQueue.PushToQueue({ exec: async db => db.getRepository(UserReceivingAddress).save(newUserAddress), dbTx: false, description: `add address for ${user.user_id} linked to ${opts.linkedApplication?.app_id}: ${address} ` }) + } + + async FlagInvoiceAsPaid(invoice: UserReceivingInvoice, amount: number, serviceFee: number, internal: boolean, dbTx: EntityManager | DataSource) { + const i: Partial = { paid_at_unix: Math.floor(Date.now() / 1000), paid_amount: amount, service_fee: serviceFee, internal } + if (!internal) { + i.paidByLnd = true + } + return dbTx.getRepository(UserReceivingInvoice).update(invoice.serial_id, i) + } + + GetUserInvoicesFlaggedAsPaid(userId: string, fromIndex: number, take = 50, entityManager = this.DB): Promise { + return entityManager.getRepository(UserReceivingInvoice).find({ + where: { + user: { + user_id: userId + }, + serial_id: MoreThanOrEqual(fromIndex), + paid_at_unix: MoreThan(0), + }, + order: { + paid_at_unix: 'DESC' + }, + take + }) + } + + async AddUserInvoice(user: User, invoice: string, options: InboundOptionals = { expiry: defaultInvoiceExpiry }, providerDestination?: string): Promise { + const newUserInvoice = this.DB.getRepository(UserReceivingInvoice).create({ + invoice: invoice, + callbackUrl: options.callbackUrl, + user: user, + product: options.product, + expires_at_unix: Math.floor(Date.now() / 1000) + options.expiry, + payer: options.expectedPayer, + linkedApplication: options.linkedApplication, + zap_info: options.zapInfo, + liquidityProvider: providerDestination + }) + return this.txQueue.PushToQueue({ exec: async db => db.getRepository(UserReceivingInvoice).save(newUserInvoice), dbTx: false, description: `add invoice for ${user.user_id} linked to ${options.linkedApplication?.app_id}: ${invoice} ` }) + } + + async GetAddressOwner(address: string, entityManager = this.DB): Promise { + return entityManager.getRepository(UserReceivingAddress).findOne({ + where: { + address + } + }) + } + + async GetAddressReceivingTransactionOwner(address: string, txHash: string, entityManager = this.DB): Promise { + return entityManager.getRepository(AddressReceivingTransaction).findOne({ + where: { + user_address: { address }, + tx_hash: txHash + } + }) + } + async GetUserTransactionPaymentOwner(address: string, txHash: string, entityManager = this.DB): Promise { + return entityManager.getRepository(UserTransactionPayment).findOne({ + where: { + address, + tx_hash: txHash + } + }) + } + + async GetInvoiceOwner(paymentRequest: string, entityManager = this.DB): Promise { + return entityManager.getRepository(UserReceivingInvoice).findOne({ + where: { + invoice: paymentRequest + } + }) + } + async GetPaymentOwner(paymentRequest: string, entityManager = this.DB): Promise { + return entityManager.getRepository(UserInvoicePayment).findOne({ + where: { + invoice: paymentRequest + } + }) + } + async GetUser2UserPayment(serialId: number, entityManager = this.DB): Promise { + return entityManager.getRepository(UserToUserPayment).findOne({ + where: { + serial_id: serialId + } + }) + } + + async AddPendingExternalPayment(userId: string, invoice: string, amount: number, linkedApplication: Application): Promise { + const newPayment = this.DB.getRepository(UserInvoicePayment).create({ + user: await this.userStorage.GetUser(userId), + paid_amount: amount, + invoice, + routing_fees: 0, + service_fees: 0, + paid_at_unix: 0, + internal: false, + linkedApplication + }) + return this.txQueue.PushToQueue({ exec: async db => db.getRepository(UserInvoicePayment).save(newPayment), dbTx: false, description: `add pending invoice payment for ${userId} linked to ${linkedApplication.app_id}: ${invoice}, amt: ${amount} ` }) + } + + async UpdateExternalPayment(invoicePaymentSerialId: number, routingFees: number, serviceFees: number, success: boolean, providerDestination?: string) { + return this.DB.getRepository(UserInvoicePayment).update(invoicePaymentSerialId, { + routing_fees: routingFees, + service_fees: serviceFees, + paid_at_unix: success ? Math.floor(Date.now() / 1000) : -1, + liquidityProvider: providerDestination + }) + } + + async AddInternalPayment(userId: string, invoice: string, amount: number, serviceFees: number, linkedApplication: Application): Promise { + const newPayment = this.DB.getRepository(UserInvoicePayment).create({ + user: await this.userStorage.GetUser(userId), + paid_amount: amount, + invoice, + routing_fees: 0, + service_fees: serviceFees, + paid_at_unix: Math.floor(Date.now() / 1000), + internal: true, + linkedApplication + }) + return this.txQueue.PushToQueue({ exec: async db => db.getRepository(UserInvoicePayment).save(newPayment), dbTx: false, description: `add internal invoice payment for ${userId} linked to ${linkedApplication.app_id}: ${invoice}, amt: ${amount} ` }) + } + + GetUserInvoicePayments(userId: string, fromIndex: number, take = 50, entityManager = this.DB): Promise { + return entityManager.getRepository(UserInvoicePayment).find({ + where: { + user: { + user_id: userId + }, + serial_id: MoreThanOrEqual(fromIndex), + paid_at_unix: MoreThan(0), + }, + order: { + paid_at_unix: 'DESC' + }, + take + }) + } + + async AddUserTransactionPayment(userId: string, address: string, txHash: string, txOutput: number, amount: number, chainFees: number, serviceFees: number, internal: boolean, height: number, linkedApplication: Application): Promise { + const newTx = this.DB.getRepository(UserTransactionPayment).create({ + user: await this.userStorage.GetUser(userId), + address, + paid_amount: amount, + chain_fees: chainFees, + output_index: txOutput, + tx_hash: txHash, + service_fees: serviceFees, + paid_at_unix: Math.floor(Date.now() / 1000), + internal, + broadcast_height: height, + confs: internal ? 10 : 0, + linkedApplication + }) + return this.txQueue.PushToQueue({ exec: async db => db.getRepository(UserTransactionPayment).save(newTx), dbTx: false, description: `add tx payment for ${userId} linked to ${linkedApplication.app_id}: ${address}, amt: ${amount} ` }) + } + + GetUserTransactionPayments(userId: string, fromIndex: number, take = 50, entityManager = this.DB): Promise { + return entityManager.getRepository(UserTransactionPayment).find({ + where: { + user: { + user_id: userId + }, + serial_id: MoreThanOrEqual(fromIndex), + paid_at_unix: MoreThan(0), + }, + order: { + paid_at_unix: 'DESC' + }, + take + }) + } + + async GetPendingTransactions(entityManager = this.DB) { + const incoming = await entityManager.getRepository(AddressReceivingTransaction).find({ where: { confs: 0 } }) + const outgoing = await entityManager.getRepository(UserTransactionPayment).find({ where: { confs: 0 } }) + return { incoming, outgoing } + } + + async UpdateAddressReceivingTransaction(serialId: number, update: Partial, entityManager = this.DB) { + return entityManager.getRepository(AddressReceivingTransaction).update(serialId, update) + } + async UpdateUserTransactionPayment(serialId: number, update: Partial, entityManager = this.DB) { + await entityManager.getRepository(UserTransactionPayment).update(serialId, update) + } + + + async AddUserEphemeralKey(userId: string, keyType: EphemeralKeyType, linkedApplication: Application): Promise { + const found = await this.DB.getRepository(UserEphemeralKey).findOne({ where: { type: keyType, user: { user_id: userId }, linkedApplication: { app_id: linkedApplication.app_id } } }) + if (found) { + return found + } + const newKey = this.DB.getRepository(UserEphemeralKey).create({ + user: await this.userStorage.GetUser(userId), + key: crypto.randomBytes(31).toString('hex'), + type: keyType, + linkedApplication + }) + return this.txQueue.PushToQueue({ exec: async db => db.getRepository(UserEphemeralKey).save(newKey), dbTx: false }) + } + + async UseUserEphemeralKey(key: string, keyType: EphemeralKeyType, persist = false, entityManager = this.DB): Promise { + const found = await entityManager.getRepository(UserEphemeralKey).findOne({ + where: { + key: key, + type: keyType + } + }) + if (!found) { + throw new Error("the provided ephemeral key is invalid") + } + if (!persist) { + await entityManager.getRepository(UserEphemeralKey).delete(found.serial_id) + } + return found + } + + async AddPendingUserToUserPayment(fromUserId: string, toUserId: string, amount: number, fee: number, linkedApplication: Application, dbTx: DataSource | EntityManager) { + const entry = dbTx.getRepository(UserToUserPayment).create({ + from_user: await this.userStorage.GetUser(fromUserId, dbTx), + to_user: await this.userStorage.GetUser(toUserId, dbTx), + paid_at_unix: 0, + paid_amount: amount, + service_fees: fee, + linkedApplication + }) + return dbTx.getRepository(UserToUserPayment).save(entry) + } + async SetPendingUserToUserPaymentAsPaid(serialId: number, dbTx: DataSource | EntityManager) { + dbTx.getRepository(UserToUserPayment).update(serialId, { paid_at_unix: Math.floor(Date.now() / 1000) }) + } + + GetUserToUserReceivedPayments(userId: string, fromIndex: number, take = 50, entityManager = this.DB) { + return entityManager.getRepository(UserToUserPayment).find({ + where: { + to_user: { + user_id: userId + }, + serial_id: MoreThanOrEqual(fromIndex), + paid_at_unix: MoreThan(0), + }, + order: { + paid_at_unix: 'DESC' + }, + take + }) + } + + GetUserToUserSentPayments(userId: string, fromIndex: number, take = 50, entityManager = this.DB) { + return entityManager.getRepository(UserToUserPayment).find({ + where: { + from_user: { + user_id: userId + }, + serial_id: MoreThanOrEqual(fromIndex), + paid_at_unix: MoreThan(0), + }, + order: { + paid_at_unix: 'DESC' + }, + take + }) + } + + async GetTotalFeesPaidInApp(app: Application | null, entityManager = this.DB) { + if (!app) { + return 0 + } + const entries = await Promise.all([ + entityManager.getRepository(UserReceivingInvoice).sum("service_fee", { linkedApplication: { app_id: app.app_id } }), + entityManager.getRepository(AddressReceivingTransaction).sum("service_fee", { user_address: { linkedApplication: { app_id: app.app_id } } }), + entityManager.getRepository(UserInvoicePayment).sum("service_fees", { linkedApplication: { app_id: app.app_id } }), + entityManager.getRepository(UserTransactionPayment).sum("service_fees", { linkedApplication: { app_id: app.app_id } }), + entityManager.getRepository(UserToUserPayment).sum("service_fees", { linkedApplication: { app_id: app.app_id } }) + ]) + let total = 0 + entries.forEach(e => { + if (e) { + total += e + } + }) + return total + } + + async GetAppOperations(application: Application | null, { from, to }: { from?: number, to?: number }, entityManager = this.DB) { + const q = application ? { app_id: application.app_id } : IsNull() + let time: { created_at?: FindOperator } = {} + if (!!from && !!to) { + time.created_at = Between(new Date(from * 1000), new Date(to * 1000)) + } else if (!!from) { + time.created_at = MoreThanOrEqual(new Date(from * 1000)) + } else if (!!to) { + time.created_at = LessThanOrEqual(new Date(to * 1000)) + } + + const [receivingInvoices, receivingAddresses, outgoingInvoices, outgoingTransactions, userToUser] = await Promise.all([ + entityManager.getRepository(UserReceivingInvoice).find({ where: { linkedApplication: q, ...time } }), + entityManager.getRepository(UserReceivingAddress).find({ where: { linkedApplication: q, ...time } }), + entityManager.getRepository(UserInvoicePayment).find({ where: { linkedApplication: q, ...time } }), + entityManager.getRepository(UserTransactionPayment).find({ where: { linkedApplication: q, ...time } }), + entityManager.getRepository(UserToUserPayment).find({ where: { linkedApplication: q, ...time } }) + ]) + const receivingTransactions = await Promise.all(receivingAddresses.map(addr => entityManager.getRepository(AddressReceivingTransaction).find({ where: { user_address: { serial_id: addr.serial_id }, ...time } }))) + return { + receivingInvoices, receivingAddresses, receivingTransactions, + outgoingInvoices, outgoingTransactions, + userToUser + } + } + + async UserHasOutgoingOperation(userId: string, entityManager = this.DB) { + const [i, tx, u2u] = await Promise.all([ + entityManager.getRepository(UserInvoicePayment).findOne({ where: { user: { user_id: userId } } }), + entityManager.getRepository(UserTransactionPayment).findOne({ where: { user: { user_id: userId } } }), + entityManager.getRepository(UserToUserPayment).findOne({ where: { from_user: { user_id: userId } } }), + ]) + return !!i || !!tx || !!u2u + } + + async VerifyDbEvent(e: LoggedEvent) { + switch (e.type) { + case "new_invoice": + return this.DB.getRepository(UserReceivingInvoice).findOneOrFail({ where: { invoice: e.data, user: { user_id: e.userId } } }) + case 'new_address': + return this.DB.getRepository(UserReceivingAddress).findOneOrFail({ where: { address: e.data, user: { user_id: e.userId } } }) + case 'invoice_paid': + return this.DB.getRepository(UserReceivingInvoice).findOneOrFail({ where: { invoice: e.data, user: { user_id: e.userId }, paid_at_unix: MoreThan(0) } }) + case 'invoice_payment': + return this.DB.getRepository(UserInvoicePayment).findOneOrFail({ where: { invoice: e.data, user: { user_id: e.userId } } }) + case 'address_paid': + const [receivingAddress, receivedHash] = e.data.split(":") + return this.DB.getRepository(AddressReceivingTransaction).findOneOrFail({ where: { user_address: { address: receivingAddress }, tx_hash: receivedHash, confs: MoreThan(0) } }) + case 'address_payment': + const [sentAddress, sentHash] = e.data.split(":") + return this.DB.getRepository(UserTransactionPayment).findOneOrFail({ where: { address: sentAddress, tx_hash: sentHash, user: { user_id: e.userId } } }) + case 'u2u_receiver': + return this.DB.getRepository(UserToUserPayment).findOneOrFail({ where: { from_user: { user_id: e.data }, to_user: { user_id: e.userId } } }) + case 'u2u_sender': + return this.DB.getRepository(UserToUserPayment).findOneOrFail({ where: { to_user: { user_id: e.data }, from_user: { user_id: e.userId } } }) + default: + break; + } + } + + async GetTotalUsersBalance(entityManager = this.DB) { + const total = await entityManager.getRepository(User).sum("balance_sats") + return total || 0 + } } \ No newline at end of file diff --git a/src/services/storage/stateBundler.ts b/src/services/storage/stateBundler.ts new file mode 100644 index 00000000..dab2a215 --- /dev/null +++ b/src/services/storage/stateBundler.ts @@ -0,0 +1,142 @@ +import { getLogger } from "../helpers/logger.js" + +const transactionStatePointTypes = ['addedInvoice', 'invoiceWasPaid', 'paidAnInvoice', 'addedAddress', 'addressWasPaid', 'paidAnAddress', 'user2user'] as const +const balanceStatePointTypes = ['providerBalance', 'providerMaxWithdrawable', 'walletBalance', 'channelBalance', 'usersBalance', 'feesPaidForLiquidity', 'totalLndBalance', 'accumulatedHtlcFees', 'deltaUsers', 'deltaExternal'] as const +const maxStatePointTypes = ['maxProviderRespTime'] as const +export type TransactionStatePointType = typeof transactionStatePointTypes[number] +export type BalanceStatePointType = typeof balanceStatePointTypes[number] +export type MaxStatePointType = typeof maxStatePointTypes[number] +/*export type TransactionStatePoint = { + type: typeof TransactionStatePointTypes[number] + with: 'lnd' | 'internal' | 'provider' + by: 'user' | 'system' + amount: number + success: boolean + networkFee?: number + serviceFee?: number + liquidtyFee?: number +}*/ + +type StateBundle = Record +export type TxPointSettings = { + used: 'lnd' | 'internal' | 'provider' | 'unknown' + from: 'user' | 'system' + meta?: string[] + timeDiscount?: true +} +export class StateBundler { + sinceStart: StateBundle = {} + lastReport: StateBundle = {} + sinceLatestReport: StateBundle = {} + reportPeriod = 1000 * 60 * 60 * 12 //12h + satsPer1SecondDiscount = 1 + totalSatsForDiscount = 0 + latestReport = Date.now() + reportLog = getLogger({ component: 'stateBundlerReport' }) + constructor() { + process.on('exit', () => { + this.Report() + }); + + // catch ctrl+c event and exit normally + process.on('SIGINT', () => { + console.log('Ctrl-C...'); + process.exit(2); + }); + + //catch uncaught exceptions, trace, then exit normally + process.on('uncaughtException', (e) => { + console.log('Uncaught Exception...'); + console.log(e.stack); + process.exit(99); + }); + } + + increment = (key: string, value: number) => { + this.sinceStart[key] = (this.sinceStart[key] || 0) + value + this.sinceLatestReport[key] = (this.sinceLatestReport[key] || 0) + value + this.triggerReportCheck() + } + set = (key: string, value: number) => { + this.sinceStart[key] = value + this.sinceLatestReport[key] = value + this.triggerReportCheck() + } + max = (key: string, value: number) => { + this.sinceStart[key] = Math.max(this.sinceStart[key] || 0, value) + this.sinceLatestReport[key] = Math.max(this.sinceLatestReport[key] || 0, value) + this.triggerReportCheck() + } + + AddTxPoint = (actionName: TransactionStatePointType, v: number, settings: TxPointSettings) => { + const { used, from, timeDiscount } = settings + const meta = settings.meta || [] + const key = [actionName, from, used, ...meta].join('_') + if (timeDiscount) { + this.totalSatsForDiscount += v + } + this.increment(key, v) + //this.smallLogEvent(actionName, from) + } + + AddTxPointFailed = (actionName: TransactionStatePointType, v: number, settings: TxPointSettings) => { + const { used, from } = settings + const meta = settings.meta || [] + const key = [actionName, from, used, ...meta, 'failed'].join('_') + this.increment(key, v) + } + + AddBalancePoint = (actionName: BalanceStatePointType, v: number, meta = []) => { + const key = [actionName, ...meta].join('_') + this.set(key, v) + } + + AddMaxPoint = (actionName: MaxStatePointType, v: number, meta = []) => { + const key = [actionName, ...meta].join('_') + this.max(key, v) + } + + triggerReportCheck = () => { + const discountSeconds = Math.floor(this.totalSatsForDiscount / this.satsPer1SecondDiscount) + const totalElapsed = Date.now() - this.latestReport + const elapsedWithDiscount = totalElapsed + discountSeconds * 1000 + if (elapsedWithDiscount > this.reportPeriod) { + this.Report() + } + } + + smallLogEvent(event: TransactionStatePointType, from: 'user' | 'system') { + const char = from === 'user' ? 'U' : 'S' + switch (event) { + case 'addedAddress': + case 'addedInvoice': + process.stdout.write(`${char}+,`) + return + case 'addressWasPaid': + case 'invoiceWasPaid': + process.stdout.write(`${char}>,`) + return + case 'paidAnAddress': + case 'paidAnInvoice': + process.stdout.write(`${char}<,`) + return + case 'user2user': + process.stdout.write(`UU`) + } + } + + Report = () => { + this.totalSatsForDiscount = 0 + this.latestReport = Date.now() + this.reportLog("+++++ since last report:") + Object.entries(this.sinceLatestReport).forEach(([key, value]) => { + this.reportLog(key, value) + }) + this.reportLog("+++++ since start:") + Object.entries(this.sinceStart).forEach(([key, value]) => { + this.reportLog(key, value) + }) + this.lastReport = { ...this.sinceLatestReport } + this.sinceLatestReport = {} + } +} \ No newline at end of file diff --git a/src/services/storage/transactionsQueue.ts b/src/services/storage/transactionsQueue.ts index 3dc36425..8c808e7f 100644 --- a/src/services/storage/transactionsQueue.ts +++ b/src/services/storage/transactionsQueue.ts @@ -20,21 +20,17 @@ export default class { PushToQueue(op: TxOperation) { if (!this.pendingTx) { - this.log("queue empty, starting transaction", this.transactionsQueue.length) return this.execQueueItem(op) } - this.log("queue not empty, possibly stuck") return new Promise((res, rej) => { this.transactionsQueue.push({ op, res, rej }) }) } async execNextInQueue() { - this.log("executing next in queue") this.pendingTx = false const next = this.transactionsQueue.pop() if (!next) { - this.log("queue is clear") return } try { @@ -51,7 +47,6 @@ export default class { throw new Error("cannot start DB transaction") } this.pendingTx = true - this.log("starting", op.dbTx ? "db transaction" : "operation", op.description || "") if (op.dbTx) { return this.doTransaction(op.exec) } diff --git a/src/services/wizard/index.ts b/src/services/wizard/index.ts new file mode 100644 index 00000000..00558384 --- /dev/null +++ b/src/services/wizard/index.ts @@ -0,0 +1,171 @@ +import fs from 'fs' +import path from 'path'; +import { config as loadEnvFile } from 'dotenv' +import { getLogger } from "../helpers/logger.js" +import NewWizardServer from "../../../proto/wizard_service/autogenerated/ts/express_server.js" +import * as WizardTypes from "../../../proto/wizard_service/autogenerated/ts/types.js" +import { MainSettings } from "../main/settings.js" +import Storage from '../storage/index.js' +import { Unlocker } from "../main/unlocker.js" +import { AdminManager } from '../main/adminManager.js'; +export type WizardSettings = { + sourceName: string + relayUrl: string + automateLiquidity: boolean + pushBackupsToNostr: boolean +} +const defaultProviderPub = "" +export class Wizard { + log = getLogger({ component: "wizard" }) + settings: MainSettings + adminManager: AdminManager + storage: Storage + configQueue: { res: (reload: boolean) => void }[] = [] + pendingConfig: WizardSettings | null = null + awaitingNprofile: { res: (nprofile: string) => void }[] = [] + nprofile = "" + relays: string[] = [] + constructor(mainSettings: MainSettings, storage: Storage, adminManager: AdminManager) { + this.settings = mainSettings + this.adminManager = adminManager + this.storage = storage + this.log('Starting wizard...') + const wizardServer = NewWizardServer({ + WizardState: async () => { return this.WizardState() }, + WizardConfig: async ({ req }) => { return this.wizardConfig(req) }, + GetAdminConnectInfo: async () => { return this.GetAdminConnectInfo() }, + GetServiceState: async () => { return this.GetServiceState() } + }, { GuestAuthGuard: async () => "", metricsCallback: () => { }, staticFiles: 'static' }) + wizardServer.Listen(mainSettings.servicePort + 1) + } + + GetServiceState = async (): Promise => { + const apps = await this.storage.applicationStorage.GetApplications() + const appNamesList = apps.map(app => app.name).join(', ') + return { + admin_npub: this.adminManager.GetAdminNpub(), + http_url: this.settings.serviceUrl, + lnd_state: WizardTypes.LndState.OFFLINE, + nprofile: this.nprofile, + provider_name: appNamesList, + relay_connected: false, + relays: this.relays, + watchdog_ok: false + } + } + WizardState = async (): Promise => { + return { + config_sent: this.pendingConfig !== null, + admin_linked: this.adminManager.GetAdminNpub() !== "", + } + } + IsInitialized = () => { + return !!this.adminManager.GetAdminNpub() + } + + GetAdminConnectInfo = async (): Promise => { + const nprofile = await this.getNprofile() + const enrolledAdmin = this.adminManager.GetAdminNpub() + if (enrolledAdmin !== "") { + return { + nprofile, connect_info: { + type: WizardTypes.AdminConnectInfoResponse_connect_info_type.ENROLLED_NPUB, + enrolled_npub: enrolledAdmin + } + } + } + const adminEnroll = this.adminManager.ReadAdminEnrollToken() + if (adminEnroll !== "") { + return { + nprofile, connect_info: { + type: WizardTypes.AdminConnectInfoResponse_connect_info_type.ADMIN_TOKEN, + admin_token: adminEnroll + } + } + } + throw new Error("something went wrong initializing admin creds") + } + + getNprofile = async (): Promise => { + if (this.nprofile !== "") { + return this.nprofile + } + console.log("waiting for nprofile") + return new Promise((res) => { + this.awaitingNprofile.push({ res }) + }) + } + + AddConnectInfo = (nprofile: string, relays: string[]) => { + this.nprofile = nprofile + this.awaitingNprofile.forEach(q => q.res(nprofile)) + this.awaitingNprofile = [] + } + + Configure = async (): Promise => { + if (this.IsInitialized() || this.pendingConfig !== null) { + return false + } + return new Promise((res) => { + this.configQueue.push({ res }) + }) + } + + wizardConfig = async (req: WizardTypes.ConfigRequest): Promise => { + const err = WizardTypes.ConfigRequestValidate(req, { + source_name_CustomCheck: source => source !== '', + relay_url_CustomCheck: relay => relay !== '', + }) + if (err != null) { throw new Error(err.message) } + if (this.IsInitialized() || this.pendingConfig !== null) { + throw new Error("already initialized") + } + const pendingConfig = { sourceName: req.source_name, relayUrl: req.relay_url, automateLiquidity: req.automate_liquidity, pushBackupsToNostr: req.push_backups_to_nostr } + this.updateEnvFile(pendingConfig) + this.configQueue.forEach(q => q.res(true)) + this.configQueue = [] + return + } + + updateEnvFile = (pendingConfig: WizardSettings) => { + let envFileContent: string[] = [] + try { + envFileContent = fs.readFileSync('.env', 'utf-8').split('\n') + } catch (err: any) { + if (err.code !== 'ENOENT') { + throw err + } + } + + const toMerge: string[] = [] + const sourceNameIndex = envFileContent.findIndex(line => line.startsWith('DEFAULT_APP_NAME')) + if (sourceNameIndex === -1) { + toMerge.push(`DEFAULT_APP_NAME=${pendingConfig.sourceName}`) + } else { + envFileContent[sourceNameIndex] = `DEFAULT_APP_NAME=${pendingConfig.sourceName}` + } + const relayUrlIndex = envFileContent.findIndex(line => line.startsWith('RELAY_URL')) + if (relayUrlIndex === -1) { + toMerge.push(`RELAY_URL=${pendingConfig.relayUrl}`) + } else { + envFileContent[relayUrlIndex] = `RELAY_URL=${pendingConfig.relayUrl}` + } + + const automateLiquidityIndex = envFileContent.findIndex(line => line.startsWith('LIQUIDITY_PROVIDER_PUB')) + if (automateLiquidityIndex === -1) { + toMerge.push(`LIQUIDITY_PROVIDER_PUB=${pendingConfig.automateLiquidity ? defaultProviderPub : ""}`) + } else { + envFileContent[automateLiquidityIndex] = `LIQUIDITY_PROVIDER_PUB=` + } + + const pushBackupsToNostrIndex = envFileContent.findIndex(line => line.startsWith('PUSH_BACKUPS_TO_NOSTR')) + if (pushBackupsToNostrIndex === -1) { + toMerge.push(`PUSH_BACKUPS_TO_NOSTR=${pendingConfig.pushBackupsToNostr ? 'true' : 'false'}`) + } else { + envFileContent[pushBackupsToNostrIndex] = `PUSH_BACKUPS_TO_NOSTR=${pendingConfig.pushBackupsToNostr ? 'true' : 'false'}` + } + const merged = [...envFileContent, ...toMerge].join('\n') + fs.writeFileSync('.env', merged) + loadEnvFile() + } +} \ No newline at end of file diff --git a/src/tests/externalPayment.spec.ts b/src/tests/externalPayment.spec.ts index 45642767..f5524ed1 100644 --- a/src/tests/externalPayment.spec.ts +++ b/src/tests/externalPayment.spec.ts @@ -13,7 +13,7 @@ export default async (T: TestBase) => { const testSuccessfulExternalPayment = async (T: TestBase) => { T.d("starting testSuccessfulExternalPayment") const application = await T.main.storage.applicationStorage.GetApplication(T.app.appId) - const invoice = await T.externalAccessToOtherLnd.NewInvoice(500, "test", defaultInvoiceExpiry) + const invoice = await T.externalAccessToOtherLnd.NewInvoice(500, "test", defaultInvoiceExpiry, { from: 'system', useProvider: false }) expect(invoice.payRequest).to.startWith("lnbcrt5u") T.d("generated 500 sats invoice for external node") @@ -32,7 +32,7 @@ const testSuccessfulExternalPayment = async (T: TestBase) => { const testFailedExternalPayment = async (T: TestBase) => { T.d("starting testFailedExternalPayment") const application = await T.main.storage.applicationStorage.GetApplication(T.app.appId) - const invoice = await T.externalAccessToOtherLnd.NewInvoice(1500, "test", defaultInvoiceExpiry) + const invoice = await T.externalAccessToOtherLnd.NewInvoice(1500, "test", defaultInvoiceExpiry, { from: 'system', useProvider: false }) expect(invoice.payRequest).to.startWith("lnbcrt15u") T.d("generated 1500 sats invoice for external node") diff --git a/src/tests/liquidityProvider.spec.ts b/src/tests/liquidityProvider.spec.ts index fd44fdd7..30b9f37d 100644 --- a/src/tests/liquidityProvider.spec.ts +++ b/src/tests/liquidityProvider.spec.ts @@ -23,16 +23,13 @@ const testInboundPaymentFromProvider = async (T: TestBase, bootstrapped: Main, b T.d("starting testInboundPaymentFromProvider") const invoiceRes = await bootstrapped.appUserManager.NewInvoice({ app_id: bUser.appId, user_id: bUser.userId, app_user_id: bUser.appUserIdentifier }, { amountSats: 2000, memo: "liquidityTest" }) - await T.externalAccessToOtherLnd.PayInvoice(invoiceRes.invoice, 0, 100) + await T.externalAccessToOtherLnd.PayInvoice(invoiceRes.invoice, 0, 100, 2000, { from: 'system', useProvider: false }) await new Promise((resolve) => setTimeout(resolve, 200)) const userBalance = await bootstrapped.appUserManager.GetUserInfo({ app_id: bUser.appId, user_id: bUser.userId, app_user_id: bUser.appUserIdentifier }) T.expect(userBalance.balance).to.equal(2000) T.d("user balance is 2000") - const providerBalance = await bootstrapped.liquidProvider.CheckUserState() - if (!providerBalance) { - throw new Error("provider balance not found") - } - T.expect(providerBalance.balance).to.equal(2000) + const providerBalance = await bootstrapped.liquidityProvider.GetLatestBalance() + T.expect(providerBalance).to.equal(2000) T.d("provider balance is 2000") T.d("testInboundPaymentFromProvider done") } @@ -40,17 +37,14 @@ const testInboundPaymentFromProvider = async (T: TestBase, bootstrapped: Main, b const testOutboundPaymentFromProvider = async (T: TestBase, bootstrapped: Main, bootstrappedUser: TestUserData) => { T.d("starting testOutboundPaymentFromProvider") - const invoice = await T.externalAccessToOtherLnd.NewInvoice(1000, "", 60 * 60) + const invoice = await T.externalAccessToOtherLnd.NewInvoice(1000, "", 60 * 60, { from: 'system', useProvider: false }) const ctx = { app_id: bootstrappedUser.appId, user_id: bootstrappedUser.userId, app_user_id: bootstrappedUser.appUserIdentifier } const res = await bootstrapped.appUserManager.PayInvoice(ctx, { invoice: invoice.payRequest, amount: 0 }) const userBalance = await bootstrapped.appUserManager.GetUserInfo(ctx) T.expect(userBalance.balance).to.equal(986) // 2000 - (1000 + 6(x2) + 2) - const providerBalance = await bootstrapped.liquidProvider.CheckUserState() - if (!providerBalance) { - throw new Error("provider balance not found") - } - T.expect(providerBalance.balance).to.equal(992) // 2000 - (1000 + 6 +2) + const providerBalance = await bootstrapped.liquidityProvider.GetLatestBalance() + T.expect(providerBalance).to.equal(992) // 2000 - (1000 + 6 +2) T.d("testOutboundPaymentFromProvider done") } \ No newline at end of file diff --git a/src/tests/networkSetup.ts b/src/tests/networkSetup.ts index 2b83c711..487450a1 100644 --- a/src/tests/networkSetup.ts +++ b/src/tests/networkSetup.ts @@ -1,15 +1,17 @@ import { LoadTestSettingsFromEnv } from "../services/main/settings.js" import { BitcoinCoreWrapper } from "./bitcoinCore.js" import LND from '../services/lnd/lnd.js' -import { LiquidityProvider } from "../services/lnd/liquidityProvider.js" +import { LiquidityProvider } from "../services/main/liquidityProvider.js" +import { Utils } from "../services/helpers/utilsWrapper.js" export const setupNetwork = async () => { const settings = LoadTestSettingsFromEnv() const core = new BitcoinCoreWrapper(settings) await core.InitAddress() await core.Mine(1) - const alice = new LND(settings.lndSettings, { liquidProvider: new LiquidityProvider("", () => { }) }, () => { }, () => { }, () => { }, () => { }) - const bob = new LND({ ...settings.lndSettings, mainNode: settings.lndSettings.otherNode }, { liquidProvider: new LiquidityProvider("", () => { }) }, () => { }, () => { }, () => { }, () => { }) + const setupUtils = new Utils(settings) + const alice = new LND(settings.lndSettings, new LiquidityProvider("", setupUtils, async () => { }, async () => { }), setupUtils, async () => { }, async () => { }, () => { }, () => { }) + const bob = new LND({ ...settings.lndSettings, mainNode: settings.lndSettings.otherNode }, new LiquidityProvider("", setupUtils, async () => { }, async () => { }), setupUtils, async () => { }, async () => { }, () => { }, () => { }) await tryUntil(async i => { const peers = await alice.ListPeers() if (peers.peers.length > 0) { diff --git a/src/tests/setupBootstrapped.ts b/src/tests/setupBootstrapped.ts index a25c2367..0b5b1d24 100644 --- a/src/tests/setupBootstrapped.ts +++ b/src/tests/setupBootstrapped.ts @@ -24,9 +24,9 @@ export const initBootstrappedInstance = async (T: TestBase) => { } const j = JSON.parse(data.content) as { requestId: string } console.log("sending new operation to provider") - bootstrapped.liquidProvider.onEvent(j, T.app.publicKey) + bootstrapped.liquidityProvider.onEvent(j, T.app.publicKey) }) - bootstrapped.liquidProvider.attachNostrSend(async (_, data, r) => { + bootstrapped.liquidityProvider.attachNostrSend(async (_, data, r) => { const res = await handleSend(T, data) if (data.type === 'event') { throw new Error("unsupported event type") @@ -34,12 +34,13 @@ export const initBootstrappedInstance = async (T: TestBase) => { if (!res) { return } - bootstrapped.liquidProvider.onEvent(res, data.pub) + bootstrapped.liquidityProvider.onEvent(res, data.pub) }) - bootstrapped.liquidProvider.setNostrInfo({ clientId: liquidityProviderInfo.clientId, myPub: liquidityProviderInfo.publicKey }) + bootstrapped.liquidityProvider.setNostrInfo({ clientId: liquidityProviderInfo.clientId, myPub: liquidityProviderInfo.publicKey }) await new Promise(res => { - const interval = setInterval(() => { - if (bootstrapped.liquidProvider.CanProviderHandle({ action: 'receive', amount: 2000 })) { + const interval = setInterval(async () => { + const canHandle = await bootstrapped.liquidityProvider.CanProviderHandle({ action: 'receive', amount: 2000 }) + if (canHandle) { clearInterval(interval) res() } else { diff --git a/src/tests/spamExternalPayments.spec.ts b/src/tests/spamExternalPayments.spec.ts index 6e2390ac..f1dd114b 100644 --- a/src/tests/spamExternalPayments.spec.ts +++ b/src/tests/spamExternalPayments.spec.ts @@ -14,7 +14,7 @@ export default async (T: TestBase) => { const testSpamExternalPayment = async (T: TestBase) => { T.d("starting testSpamExternalPayment") const application = await T.main.storage.applicationStorage.GetApplication(T.app.appId) - const invoices = await Promise.all(new Array(10).fill(0).map(() => T.externalAccessToOtherLnd.NewInvoice(500, "test", defaultInvoiceExpiry))) + const invoices = await Promise.all(new Array(10).fill(0).map(() => T.externalAccessToOtherLnd.NewInvoice(500, "test", defaultInvoiceExpiry, { from: 'system', useProvider: false }))) T.d("generated 10 500 sats invoices for external node") const res = await Promise.all(invoices.map(async (invoice, i) => { try { diff --git a/src/tests/spamMixedPayments.spec.ts b/src/tests/spamMixedPayments.spec.ts index db361e6c..f775f161 100644 --- a/src/tests/spamMixedPayments.spec.ts +++ b/src/tests/spamMixedPayments.spec.ts @@ -15,7 +15,7 @@ export default async (T: TestBase) => { const testSpamExternalPayment = async (T: TestBase) => { T.d("starting testSpamExternalPayment") const application = await T.main.storage.applicationStorage.GetApplication(T.app.appId) - const invoicesForExternal = await Promise.all(new Array(5).fill(0).map(() => T.externalAccessToOtherLnd.NewInvoice(500, "test", defaultInvoiceExpiry))) + const invoicesForExternal = await Promise.all(new Array(5).fill(0).map(() => T.externalAccessToOtherLnd.NewInvoice(500, "test", defaultInvoiceExpiry, { from: 'system', useProvider: false }))) const invoicesForUser2 = await Promise.all(new Array(5).fill(0).map(() => T.main.paymentManager.NewInvoice(T.user2.userId, { amountSats: 500, memo: "test" }, { linkedApplication: application, expiry: defaultInvoiceExpiry }))) const invoices = invoicesForExternal.map(i => i.payRequest).concat(invoicesForUser2.map(i => i.invoice)) T.d("generated 10 500 sats mixed invoices between external node and user 2") diff --git a/src/tests/testBase.ts b/src/tests/testBase.ts index e2ee7902..dcad8364 100644 --- a/src/tests/testBase.ts +++ b/src/tests/testBase.ts @@ -10,7 +10,9 @@ import { defaultInvoiceExpiry } from '../services/storage/paymentStorage.js' import SanityChecker from '../services/main/sanityChecker.js' import LND from '../services/lnd/lnd.js' import { getLogger, resetDisabledLoggers } from '../services/helpers/logger.js' -import { LiquidityProvider } from '../services/lnd/liquidityProvider.js' +import { LiquidityProvider } from '../services/main/liquidityProvider.js' +import { Utils } from '../services/helpers/utilsWrapper.js' +import { AdminManager } from '../services/main/adminManager.js' chai.use(chaiString) export const expect = chai.expect export type Describe = (message: string, failure?: boolean) => void @@ -29,6 +31,7 @@ export type TestBase = { externalAccessToMainLnd: LND externalAccessToOtherLnd: LND externalAccessToThirdLnd: LND + adminManager: AdminManager d: Describe } @@ -45,16 +48,16 @@ export const SetupTest = async (d: Describe): Promise => { const user1 = { userId: u1.info.userId, appUserIdentifier: u1.identifier, appId: app.appId } const user2 = { userId: u2.info.userId, appUserIdentifier: u2.identifier, appId: app.appId } - - const externalAccessToMainLnd = new LND(settings.lndSettings, { liquidProvider: new LiquidityProvider("", () => { }) }, console.log, console.log, () => { }, () => { }) + const extermnalUtils = new Utils(settings) + const externalAccessToMainLnd = new LND(settings.lndSettings, new LiquidityProvider("", extermnalUtils, async () => { }, async () => { }), extermnalUtils, async () => { }, async () => { }, () => { }, () => { }) await externalAccessToMainLnd.Warmup() const otherLndSetting = { ...settings.lndSettings, mainNode: settings.lndSettings.otherNode } - const externalAccessToOtherLnd = new LND(otherLndSetting, { liquidProvider: new LiquidityProvider("", () => { }) }, console.log, console.log, () => { }, () => { }) + const externalAccessToOtherLnd = new LND(otherLndSetting, new LiquidityProvider("", extermnalUtils, async () => { }, async () => { }), extermnalUtils, async () => { }, async () => { }, () => { }, () => { }) await externalAccessToOtherLnd.Warmup() const thirdLndSetting = { ...settings.lndSettings, mainNode: settings.lndSettings.thirdNode } - const externalAccessToThirdLnd = new LND(thirdLndSetting, { liquidProvider: new LiquidityProvider("", () => { }) }, console.log, console.log, () => { }, () => { }) + const externalAccessToThirdLnd = new LND(thirdLndSetting, new LiquidityProvider("", extermnalUtils, async () => { }, async () => { }), extermnalUtils, async () => { }, async () => { }, () => { }, () => { }) await externalAccessToThirdLnd.Warmup() @@ -62,7 +65,8 @@ export const SetupTest = async (d: Describe): Promise => { expect, main, app, user1, user2, externalAccessToMainLnd, externalAccessToOtherLnd, externalAccessToThirdLnd, - d + d, + adminManager: initialized.adminManager } } @@ -71,6 +75,7 @@ export const teardown = async (T: TestBase) => { T.externalAccessToMainLnd.Stop() T.externalAccessToOtherLnd.Stop() T.externalAccessToThirdLnd.Stop() + T.adminManager.Stop() resetDisabledLoggers() console.log("teardown") } @@ -78,7 +83,7 @@ export const teardown = async (T: TestBase) => { export const safelySetUserBalance = async (T: TestBase, user: TestUserData, amount: number) => { const app = await T.main.storage.applicationStorage.GetApplication(user.appId) const invoice = await T.main.paymentManager.NewInvoice(user.userId, { amountSats: amount, memo: "test" }, { linkedApplication: app, expiry: defaultInvoiceExpiry }) - await T.externalAccessToOtherLnd.PayInvoice(invoice.invoice, 0, 100) + await T.externalAccessToOtherLnd.PayInvoice(invoice.invoice, 0, 100, amount, { from: 'system', useProvider: false }) const u = await T.main.storage.userStorage.GetUser(user.userId) expect(u.balance_sats).to.be.equal(amount) T.d(`user ${user.appUserIdentifier} balance is now ${amount}`) diff --git a/src/tests/userPayment.spec.ts b/src/tests/userPayment.spec.ts index 7e807097..39709382 100644 --- a/src/tests/userPayment.spec.ts +++ b/src/tests/userPayment.spec.ts @@ -12,7 +12,7 @@ export default async (T: TestBase) => { const testSuccessfulUserPaymentToExternalNode = async (T: TestBase) => { T.d("starting testSuccessfulUserPaymentToExternalNode") - const invoice = await T.externalAccessToOtherLnd.NewInvoice(500, "test", defaultInvoiceExpiry) + const invoice = await T.externalAccessToOtherLnd.NewInvoice(500, "test", defaultInvoiceExpiry, { from: 'system', useProvider: false }) const payment = await T.main.appUserManager.PayInvoice({ app_id: T.user1.appId, user_id: T.user1.userId, app_user_id: T.user1.appUserIdentifier }, { invoice: invoice.payRequest, amount: 0 }) T.d("paid 500 sats invoice from user1 to external node") } \ No newline at end of file diff --git a/static/backup.html b/static/backup.html index 8b7b4bd0..ac27dee4 100644 --- a/static/backup.html +++ b/static/backup.html @@ -1,102 +1,142 @@ - - - - - - - - - - Lightning.Pub - - - - -
- Lightning Pub logo - Lightning Pub logo -
-
-
- -

Choose a Recovery Method

-

- New Node! 🎉 It's important - to backup your keys. -

-
+ + + + + + + + + + Lightning.Pub + + + -
+ +
+ Lightning Pub logo + Lightning Pub logo +
-
-
-
- In addition to your seed phrase, you also need channel details to recover funds should your node experience a hardware failure. -
-
-
- It's important always to have the latest version of this file. Fortunately, it's small enough to automatically store on the Nostr relay. -
-
-
- If you did not choose the developers relay, be sure your relay has - adequate storage policies to hold NIP78 events. -
-
-
- -
- -
-
-
-
- -
- -
-
- -
-
+
+
+ +

Choose a Recovery Method

+

+ New Node! 🎉 It's important + to backup your keys. +

+
-
-
+
+ If you did not choose the developers relay, be sure your relay has + adequate storage policies to hold NIP78 events. +
+
+
+ +
+ +
+
+
+
+ +
+ +
+
+
+

+
+ + +
- - - +
+ +
+ Need Help? +
+ + + + + + \ No newline at end of file diff --git a/static/connect.html b/static/connect.html index 64a792ed..2bd2381e 100644 --- a/static/connect.html +++ b/static/connect.html @@ -1,80 +1,116 @@ - - - - - - - - - - Lightning.Pub - - - - -
- Lightning Pub logo - Lightning Pub logo -
-
-
- -

Connect

-

- You can now manage your node remotely -

-
+ + + + + + + + + + Lightning.Pub + + + -
+ +
+ Lightning Pub logo + Lightning Pub logo +
-
-
For dashboard access, use ShockWallet and tap the logo 3 times.
-
Scan the QR or Copy-Paste the string to establish the connection.
-
-
-
-
Code contains a one-time pairing secret
-
Click to reveal
-
-
-
-
npub123abcdefghhhhhhhhhhhhhhh
-
relay.lightning.pub
-
+
+
+ +

Connect

+

+ You can now manage your node remotely +

+
+ +
+ +
+
For dashboard access, use ShockWallet and tap the logo 3 times.
+
Scan the QR or Copy-Paste the string to establish the connection. +
+
+
+
+
Code contains a one-time pairing secret
+
Click to reveal
+
+
+
+
-
-
- -
- -
- Need Help? -
+
+
+

+
+ +
+ Need Help? +
- + - - - - + + + + + \ No newline at end of file diff --git a/static/index.html b/static/index.html index 0270e2c4..58a7351e 100644 --- a/static/index.html +++ b/static/index.html @@ -1,89 +1,112 @@ - - - - - - - - - Lightning.Pub - - - -
- Lightning Pub logo - Lightning Pub logo -
-
-
-

Setup your Pub

-

-

-
+ + + + + + + + + Lightning.Pub + + -
+ +
+ Lightning Pub logo + Lightning Pub logo +
-
-
- Give this node a name that wallet users will see: - -
+
+
+

Setup your Pub

+

+

+
-
- If you want to use a specific Nostr relay, enter it now: - -
+
-
- -
- -
- - -
-
- -
-
- - + +
+ If you want to use a specific Nostr relay, enter it now: + +
+ +
+ +
+ +
+ +
+

+
+ + + + + +
+ +
+ Need Help? +
+ + + + \ No newline at end of file diff --git a/static/liquidity.html b/static/liquidity.html index f281bc9b..3f406e75 100644 --- a/static/liquidity.html +++ b/static/liquidity.html @@ -1,93 +1,108 @@ - - - - - - - - - - Lightning.Pub - - - - -
- Lightning Pub logo - Lightning Pub logo -
-
-
- -

Manage Node Liquidity

-

- How do you want to manage Lightning channels? -

-
+ + + + + + + + + + Lightning.Pub + + + -
+ +
+ Lightning Pub logo + Lightning Pub logo +
-
-
- -
- -
-
- -
- -
- -
-
+
+
+ +

Manage Node Liquidity

+

+ How do you want to manage Lightning channels? +

+
-
-
+
+ +
+ +
+
+

+
+ + +
- - - +
+ +
+ Need Help? +
+ + + + + \ No newline at end of file diff --git a/static/seed.html b/static/seed.html index dc859d92..646961eb 100644 --- a/static/seed.html +++ b/static/seed.html @@ -1,180 +1,74 @@ - - - - - - - - - - Lightning.Pub - - - - -
- Lightning Pub logo - Lightning Pub logo -
-
-
- -

Seed Phrase

-

- Store your seed phrase somewhere safe, you will need it if something ever goes wrong with your node hard drive. -

-
+ + + + + + + + + + Lightning.Pub + + + -
+ +
+ Lightning Pub logo + Lightning Pub logo +
-
-
-
- 1 - albert -
-
- 1 - albert -
-
- 1 - albert -
-
- 1 - albert -
-
- 1 - albert -
-
- 1 - albert -
-
- 1 - albert -
-
- 1 - albert -
-
- 1 - albert -
-
- 1 - albert -
-
- 1 - albert -
-
- 1 - albert -
-
- 1 - albert -
-
- 1 - albert -
-
- 1 - albert -
-
- 1 - albert -
-
- 1 - albert -
-
- 1 - albert -
-
- 1 - albert -
-
- 1 - albert -
-
- 1 - albert -
-
- 1 - albert -
-
- 1 - albert -
-
- 1 - albert -
-
+
+
+ +

Seed Phrase

+

+ Store your seed phrase somewhere safe, you will need it if something ever goes wrong with your node hard drive. +

+
- +
-
-
- -
- -
-
- -
-
+
+
+
-
-
+ +
+ - - - +
+ +
+ Need Help? +
+ + + + + \ No newline at end of file diff --git a/static/status.html b/static/status.html new file mode 100644 index 00000000..e878bb0b --- /dev/null +++ b/static/status.html @@ -0,0 +1,174 @@ + + + + + + + + + + + + + Lightning.Pub + + + + + +
+ Lightning Pub logo + Lightning Pub logo +
+ +
+
+

Node Status

+

+
+ +
+ +
+

+
+
+
Public Node Name:
+
+ +
Nodey McNodeFace
+
+ +
+
+
+
+
Nostr Relay:
+
+ +
wss://relay.lightning.pub
+
+ +
+
+
+
+
Administrator:
+
+ Loading... +
+
+
+
+
+ Reset +
+ +
+
+
+
+
+ +
+
+
+
Continue
+
+
+
+
+
+
Relay Status:
+
+ Loading... +
+
+
+
Lightning Status:
+
+ Loading... +
+
+
+
+ Watchdog Status: +
+ +
+
+
+ Loading... +
+
+
+ + +
+
+ + + + + + + + \ No newline at end of file diff --git a/static/stauts.html b/static/stauts.html deleted file mode 100644 index 0e93a8fb..00000000 --- a/static/stauts.html +++ /dev/null @@ -1,148 +0,0 @@ - - - - - - - - - - - - Lightning.Pub - - - - -
- Lightning Pub logo - Lightning Pub logo -
- -
-
-

Node Status

-

-
- -
- -
-
-
-
Public Node Name:
-
- -
Nodey McNodeFace
-
- -
-
-
-
-
Nostr Relay:
-
- -
wss://relay.lightning.pub
-
- -
-
-
-
-
Administrator:
-
- npub12334556677889990 -
-
-
-
-
Reset -
- -
-
-
-
-
- -
-
-
-
Continue
-
-
-
-
-
-
Relay Status:
-
- Connected -
-
-
-
Lightning Status:
-
- Syncing -
-
-
-
- Watchdog Status: -
- -
-
-
- No Alarms -
-
-
- - -
-
- - - - - -