Merge branch 'master' into fix/bootstrap
This commit is contained in:
commit
fb7e679325
117 changed files with 51904 additions and 50029 deletions
4
.dockerignore
Normal file
4
.dockerignore
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
.git
|
||||||
|
.github
|
||||||
|
build
|
||||||
|
node_modules
|
||||||
6
.github/FUNDING.yml
vendored
6
.github/FUNDING.yml
vendored
|
|
@ -1,3 +1,3 @@
|
||||||
# These are supported funding model platforms
|
# These are supported funding model platforms
|
||||||
|
|
||||||
github: [shocknet,]
|
github: [shocknet,]
|
||||||
|
|
|
||||||
126
.github/workflows/push.yml
vendored
126
.github/workflows/push.yml
vendored
|
|
@ -1,63 +1,63 @@
|
||||||
name: Create and publish a Docker image
|
name: Create and publish a Docker image
|
||||||
|
|
||||||
on:
|
on:
|
||||||
release:
|
release:
|
||||||
types: [created, published, prereleased]
|
types: [created, published, prereleased]
|
||||||
workflow_dispatch: # This allows manual triggering of the workflow
|
workflow_dispatch: # This allows manual triggering of the workflow
|
||||||
|
|
||||||
env:
|
env:
|
||||||
REGISTRY: ghcr.io
|
REGISTRY: ghcr.io
|
||||||
IMAGE_NAME: ${{ github.repository }}
|
IMAGE_NAME: ${{ github.repository }}
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build-and-push-image:
|
build-and-push-image:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
packages: write
|
packages: write
|
||||||
id-token: write
|
id-token: write
|
||||||
security-events: write
|
security-events: write
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Log in to the Container registry
|
- name: Log in to the Container registry
|
||||||
uses: docker/login-action@v2
|
uses: docker/login-action@v2
|
||||||
with:
|
with:
|
||||||
registry: ${{ env.REGISTRY }}
|
registry: ${{ env.REGISTRY }}
|
||||||
username: ${{ github.actor }}
|
username: ${{ github.actor }}
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Extract metadata (tags, labels) for Docker
|
- name: Extract metadata (tags, labels) for Docker
|
||||||
id: meta
|
id: meta
|
||||||
uses: docker/metadata-action@v4
|
uses: docker/metadata-action@v4
|
||||||
with:
|
with:
|
||||||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
||||||
|
|
||||||
- name: Build and push Docker image
|
- name: Build and push Docker image
|
||||||
id: build-and-push
|
id: build-and-push
|
||||||
uses: docker/build-push-action@v4
|
uses: docker/build-push-action@v4
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
file: ./Dockerfile
|
file: ./Dockerfile
|
||||||
push: true
|
push: true
|
||||||
tags: ghcr.io/${{ github.repository_owner }}/lightning-pub:latest
|
tags: ghcr.io/${{ github.repository_owner }}/lightning-pub:latest
|
||||||
labels: ${{ steps.meta.outputs.labels }}
|
labels: ${{ steps.meta.outputs.labels }}
|
||||||
|
|
||||||
- name: Capture image digest
|
- name: Capture image digest
|
||||||
id: capture-digest
|
id: capture-digest
|
||||||
run: |
|
run: |
|
||||||
DIGEST=$(docker inspect --format='{{index .RepoDigests 0}}' ghcr.io/${{ github.repository_owner }}/lightning-pub:latest | cut -d'@' -f2)
|
DIGEST=$(docker inspect --format='{{index .RepoDigests 0}}' ghcr.io/${{ github.repository_owner }}/lightning-pub:latest | cut -d'@' -f2)
|
||||||
echo "Raw Digest is $DIGEST"
|
echo "Raw Digest is $DIGEST"
|
||||||
echo "::set-output name=digest::$DIGEST"
|
echo "::set-output name=digest::$DIGEST"
|
||||||
|
|
||||||
- name: Debug Print Digest
|
- name: Debug Print Digest
|
||||||
run: echo "Digest is ${{ steps.capture-digest.outputs.digest }}"
|
run: echo "Digest is ${{ steps.capture-digest.outputs.digest }}"
|
||||||
|
|
||||||
- name: Attest build provenance
|
- name: Attest build provenance
|
||||||
uses: actions/attest-build-provenance@v1
|
uses: actions/attest-build-provenance@v1
|
||||||
with:
|
with:
|
||||||
subject-digest: ${{ steps.capture-digest.outputs.digest }}
|
subject-digest: ${{ steps.capture-digest.outputs.digest }}
|
||||||
subject-name: ghcr.io/${{ github.repository_owner }}/lightning-pub:latest
|
subject-name: ghcr.io/${{ github.repository_owner }}/lightning-pub:latest
|
||||||
github-token: ${{ secrets.PAT_TOKEN }}
|
github-token: ${{ secrets.PAT_TOKEN }}
|
||||||
|
|
|
||||||
110
.github/workflows/test.yaml
vendored
110
.github/workflows/test.yaml
vendored
|
|
@ -1,55 +1,55 @@
|
||||||
name: Docker Compose Actions Workflow
|
name: Docker Compose Actions Workflow
|
||||||
on: push
|
on: push
|
||||||
jobs:
|
jobs:
|
||||||
test:
|
test:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- name: unzip the file
|
- name: unzip the file
|
||||||
run: unzip src/tests/regtestNetwork.zip
|
run: unzip src/tests/regtestNetwork.zip
|
||||||
- name: list files
|
- name: list files
|
||||||
run: ls -la
|
run: ls -la
|
||||||
- name: Build the stack
|
- name: Build the stack
|
||||||
run: docker-compose --project-directory ./ -f src/tests/docker-compose.yml up -d
|
run: docker-compose --project-directory ./ -f src/tests/docker-compose.yml up -d
|
||||||
- name: Copy alice cert file
|
- name: Copy alice cert file
|
||||||
run: docker cp polar-n2-alice:/home/lnd/.lnd/tls.cert alice-tls.cert
|
run: docker cp polar-n2-alice:/home/lnd/.lnd/tls.cert alice-tls.cert
|
||||||
- name: Copy bob cert file
|
- name: Copy bob cert file
|
||||||
run: docker cp polar-n2-bob:/home/lnd/.lnd/tls.cert bob-tls.cert
|
run: docker cp polar-n2-bob:/home/lnd/.lnd/tls.cert bob-tls.cert
|
||||||
- name: Copy carol cert file
|
- name: Copy carol cert file
|
||||||
run: docker cp polar-n2-carol:/home/lnd/.lnd/tls.cert carol-tls.cert
|
run: docker cp polar-n2-carol:/home/lnd/.lnd/tls.cert carol-tls.cert
|
||||||
- name: Copy dave cert file
|
- name: Copy dave cert file
|
||||||
run: docker cp polar-n2-dave:/home/lnd/.lnd/tls.cert dave-tls.cert
|
run: docker cp polar-n2-dave:/home/lnd/.lnd/tls.cert dave-tls.cert
|
||||||
- name: Copy alice macaroon file
|
- name: Copy alice macaroon file
|
||||||
run: docker cp polar-n2-alice:/home/lnd/.lnd/data/chain/bitcoin/regtest/admin.macaroon alice-admin.macaroon
|
run: docker cp polar-n2-alice:/home/lnd/.lnd/data/chain/bitcoin/regtest/admin.macaroon alice-admin.macaroon
|
||||||
- name: Copy bob macaroon file
|
- name: Copy bob macaroon file
|
||||||
run: docker cp polar-n2-bob:/home/lnd/.lnd/data/chain/bitcoin/regtest/admin.macaroon bob-admin.macaroon
|
run: docker cp polar-n2-bob:/home/lnd/.lnd/data/chain/bitcoin/regtest/admin.macaroon bob-admin.macaroon
|
||||||
- name: Copy carol macaroon file
|
- name: Copy carol macaroon file
|
||||||
run: docker cp polar-n2-carol:/home/lnd/.lnd/data/chain/bitcoin/regtest/admin.macaroon carol-admin.macaroon
|
run: docker cp polar-n2-carol:/home/lnd/.lnd/data/chain/bitcoin/regtest/admin.macaroon carol-admin.macaroon
|
||||||
- name: Copy dave macaroon file
|
- name: Copy dave macaroon file
|
||||||
run: docker cp polar-n2-dave:/home/lnd/.lnd/data/chain/bitcoin/regtest/admin.macaroon dave-admin.macaroon
|
run: docker cp polar-n2-dave:/home/lnd/.lnd/data/chain/bitcoin/regtest/admin.macaroon dave-admin.macaroon
|
||||||
- name: copy env file
|
- name: copy env file
|
||||||
run: cp src/tests/.env.test .env
|
run: cp src/tests/.env.test .env
|
||||||
- name: List files
|
- name: List files
|
||||||
run: ls -la
|
run: ls -la
|
||||||
- name: Cache node modules
|
- name: Cache node modules
|
||||||
id: cache-npm
|
id: cache-npm
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v3
|
||||||
env:
|
env:
|
||||||
cache-name: cache-node-modules
|
cache-name: cache-node-modules
|
||||||
with:
|
with:
|
||||||
# npm cache files are stored in `~/.npm` on Linux/macOS
|
# npm cache files are stored in `~/.npm` on Linux/macOS
|
||||||
path: ~/.npm
|
path: ~/.npm
|
||||||
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
|
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
|
||||||
restore-keys: |
|
restore-keys: |
|
||||||
${{ runner.os }}-build-${{ env.cache-name }}-
|
${{ runner.os }}-build-${{ env.cache-name }}-
|
||||||
${{ runner.os }}-build-
|
${{ runner.os }}-build-
|
||||||
${{ runner.os }}-
|
${{ runner.os }}-
|
||||||
|
|
||||||
- if: ${{ steps.cache-npm.outputs.cache-hit != 'true' }}
|
- if: ${{ steps.cache-npm.outputs.cache-hit != 'true' }}
|
||||||
name: List the state of node modules
|
name: List the state of node modules
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
run: npm list
|
run: npm list
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: npm install
|
run: npm install
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
run: npm test
|
run: npm test
|
||||||
|
|
|
||||||
24
.gitignore
vendored
24
.gitignore
vendored
|
|
@ -1,13 +1,13 @@
|
||||||
.idea/
|
.idea/
|
||||||
.vscode/
|
.vscode/
|
||||||
node_modules/
|
node_modules/
|
||||||
build/
|
build/
|
||||||
tmp/
|
tmp/
|
||||||
temp/
|
temp/
|
||||||
.env
|
.env
|
||||||
build/
|
build/
|
||||||
db.sqlite
|
db.sqlite
|
||||||
metrics.sqlite
|
metrics.sqlite
|
||||||
.key/
|
.key/
|
||||||
logs
|
logs
|
||||||
.jwt_secret
|
.jwt_secret
|
||||||
22
Dockerfile
22
Dockerfile
|
|
@ -1,11 +1,11 @@
|
||||||
FROM node:18
|
FROM node:18
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
COPY package*.json /app
|
COPY package*.json /app
|
||||||
|
|
||||||
RUN npm i
|
RUN npm i
|
||||||
|
|
||||||
COPY . /app
|
COPY . /app
|
||||||
|
|
||||||
CMD [ "npm", "start" ]
|
CMD [ "npm", "start" ]
|
||||||
|
|
|
||||||
226
README.md
226
README.md
|
|
@ -1,113 +1,113 @@
|
||||||

|

|
||||||
|
|
||||||

|

|
||||||
[](http://makeapullrequest.com)
|
[](http://makeapullrequest.com)
|
||||||
[](https://t.me/ShockBTC)
|
[](https://t.me/ShockBTC)
|
||||||

|

|
||||||
|
|
||||||
|
|
||||||
### Don't just run a Lightning Node, run a Lightning Pub.
|
### Don't just run a Lightning Node, run a Lightning Pub.
|
||||||
|
|
||||||
"Pub" is a [Nostr](https://nostr.info)-native account system designed to make running Lightning infrastructure for your friends/family/customers easier than previously thought possible.
|
"Pub" is a [Nostr](https://nostr.info)-native account system designed to make running Lightning infrastructure for your friends/family/customers easier than previously thought possible.
|
||||||
|
|
||||||
It may come as a surprise that the biggest hurdle to more Uncle Jim nodes hasn't been with Bitcoin/Lightning node management itself, as we've seen liquidity easily automated even in unreliable environments like mobile nodes.
|
It may come as a surprise that the biggest hurdle to more Uncle Jim nodes hasn't been with Bitcoin/Lightning node management itself, as we've seen liquidity easily automated even in unreliable environments like mobile nodes.
|
||||||
|
|
||||||
It's the legacy baggage of traditional Client-Server web infrastructure, things like IP4, Reverse Proxies, DNS, Firewalls and SSL certificates, all of which require a personal configuration that is a hurdle for most.
|
It's the legacy baggage of traditional Client-Server web infrastructure, things like IP4, Reverse Proxies, DNS, Firewalls and SSL certificates, all of which require a personal configuration that is a hurdle for most.
|
||||||
|
|
||||||
Tor as a workaround has proven too slow and unreliable, and a dead-end for clearnet-web usecases. Bxlt12, being a re-implementation of Tor, appears destined for the same fate.
|
Tor as a workaround has proven too slow and unreliable, and a dead-end for clearnet-web usecases. Bxlt12, being a re-implementation of Tor, appears destined for the same fate.
|
||||||
|
|
||||||
Pub solves these challenges with a P2P-like design that is also web-friendly, by implementing a full RPC that is Nostr-native. Being Nostr-native eliminates the complexity of configuring your node like a server by using commodity Nostr relays. These relays, unlike LNURL proxies, are trustless by nature of Nostr's own encryption spec (NIP44).
|
Pub solves these challenges with a P2P-like design that is also web-friendly, by implementing a full RPC that is Nostr-native. Being Nostr-native eliminates the complexity of configuring your node like a server by using commodity Nostr relays. These relays, unlike LNURL proxies, are trustless by nature of Nostr's own encryption spec (NIP44).
|
||||||
|
|
||||||
Additionally, support for optional services are integrated into Pub for operators seeking backward compatibility with legacy LNURLs and Lightning Addresses.
|
Additionally, support for optional services are integrated into Pub for operators seeking backward compatibility with legacy LNURLs and Lightning Addresses.
|
||||||
|
|
||||||
By solving the networking and programability hurdles, Pub provides Lightning with a 3rd Layer that enables node-runners and Uncle Jims to more easily bring their personal network into Bitcoin's permissionless economy. In doing so, Pub runners can keep the Lightning Network decentralized, with custodial scaling that is free of fiat rails, large banks, and other forms of high-time-preference shitcoinery.
|
By solving the networking and programability hurdles, Pub provides Lightning with a 3rd Layer that enables node-runners and Uncle Jims to more easily bring their personal network into Bitcoin's permissionless economy. In doing so, Pub runners can keep the Lightning Network decentralized, with custodial scaling that is free of fiat rails, large banks, and other forms of high-time-preference shitcoinery.
|
||||||
|
|
||||||
#### Features:
|
#### Features:
|
||||||
|
|
||||||
- Wrapper for [`LND`](https://github.com/lightningnetwork/lnd/releases) that can serve accounts over LNURL and NOSTR
|
- Wrapper for [`LND`](https://github.com/lightningnetwork/lnd/releases) that can serve accounts over LNURL and NOSTR
|
||||||
- A growing number of [methods](https://github.com/shocknet/Lightning.Pub/blob/master/proto/autogenerated/client.md)
|
- A growing number of [methods](https://github.com/shocknet/Lightning.Pub/blob/master/proto/autogenerated/client.md)
|
||||||
- Accounting SubLayers for Application Pools and Users
|
- Accounting SubLayers for Application Pools and Users
|
||||||
- A fee regime allows applications owners to monetize users, or node operators to host distinctly monetized applications.
|
- A fee regime allows applications owners to monetize users, or node operators to host distinctly monetized applications.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
- Connecting via ShockWallet is as easy as pasting an nprofile
|
- Connecting via ShockWallet is as easy as pasting an nprofile
|
||||||
- Or use a link to share your nprofile with friends and family
|
- Or use a link to share your nprofile with friends and family
|
||||||
|
|
||||||
<img src="https://cdn.shockwallet.app/add_src_sm.png" height="20%" alt="Connect Wallet"> <img src="https://cdn.shockwallet.app/src_invite_sm.png" height="20%" alt="Invite Guests">
|
<img src="https://cdn.shockwallet.app/add_src_sm.png" height="20%" alt="Connect Wallet"> <img src="https://cdn.shockwallet.app/src_invite_sm.png" height="20%" alt="Invite Guests">
|
||||||
|
|
||||||
|
|
||||||
#### Planned
|
#### Planned
|
||||||
- [ ] A management dashboard is actively being integrated into [ShockWallet](https://github.com/shocknet/wallet2)
|
- [ ] A management dashboard is actively being integrated into [ShockWallet](https://github.com/shocknet/wallet2)
|
||||||
- [ ] Nostr native "offers" (successor to LNURL-Pay, Lightning Address, Bxlt12)
|
- [ ] Nostr native "offers" (successor to LNURL-Pay, Lightning Address, Bxlt12)
|
||||||
- [ ] Automated Channels
|
- [ ] Automated Channels
|
||||||
- [ ] Bootstrap Peering (Passive "LSP")
|
- [ ] Bootstrap Peering (Passive "LSP")
|
||||||
- [ ] Event Notifications
|
- [ ] Event Notifications
|
||||||
- [ ] Swap integration
|
- [ ] Swap integration
|
||||||
- [ ] High-Availabilty / Clustering
|
- [ ] High-Availabilty / Clustering
|
||||||
|
|
||||||
Dashboard Wireframe:
|
Dashboard Wireframe:
|
||||||
|
|
||||||
<img src="https://shockwallet.b-cdn.net/pub_home_ss.png" alt="Pub Dashboard" width="240">
|
<img src="https://shockwallet.b-cdn.net/pub_home_ss.png" alt="Pub Dashboard" width="240">
|
||||||
|
|
||||||
> [!IMPORTANT]
|
> [!IMPORTANT]
|
||||||
> ShockWallet and Lightning.Pub are free software. If you would like to see continued development, please show your [**support**](https://github.com/sponsors/shocknet) 😊<br>
|
> ShockWallet and Lightning.Pub are free software. If you would like to see continued development, please show your [**support**](https://github.com/sponsors/shocknet) 😊<br>
|
||||||
|
|
||||||
<img src="https://www.gnu.org/graphics/agplv3-with-text-162x68.png" alt="License">
|
<img src="https://www.gnu.org/graphics/agplv3-with-text-162x68.png" alt="License">
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
> [!WARNING]
|
> [!WARNING]
|
||||||
> While this software has been used in a high-profile production environment for over a year, it should still be considered bleeding edge. Special care has been taken to mitigate the risk of drainage attacks, which is a common risk to all Lightning API's. An integrated Watchdog service will terminate spends if it detects a discrepency between LND and the database, for this reason **IT IS NOT RECOMMENDED TO USE PUB ALONGSIDE OTHER ACCOUNT SYSTEMS**. While we give the utmost care and attention to security, **the internet is an adversarial environment and SECURITY/RELIABILITY ARE NOT GUARANTEED- USE AT YOUR OWN RISK**.
|
> While this software has been used in a high-profile production environment for over a year, it should still be considered bleeding edge. Special care has been taken to mitigate the risk of drainage attacks, which is a common risk to all Lightning API's. An integrated Watchdog service will terminate spends if it detects a discrepency between LND and the database, for this reason **IT IS NOT RECOMMENDED TO USE PUB ALONGSIDE OTHER ACCOUNT SYSTEMS**. While we give the utmost care and attention to security, **the internet is an adversarial environment and SECURITY/RELIABILITY ARE NOT GUARANTEED- USE AT YOUR OWN RISK**.
|
||||||
|
|
||||||
## Umbrel Installation
|
## Umbrel Installation
|
||||||
|
|
||||||
Coming Soon
|
Coming Soon
|
||||||
|
|
||||||
## Desktop Installation
|
## Desktop Installation
|
||||||
|
|
||||||
Coming Soon
|
Coming Soon
|
||||||
|
|
||||||
## Docker
|
## Docker
|
||||||
|
|
||||||
`docker pull ghcr.io/shocknet/lightning-pub:latest`
|
`docker pull ghcr.io/shocknet/lightning-pub:latest`
|
||||||
|
|
||||||
## Manual CLI Installation
|
## Manual CLI Installation
|
||||||
|
|
||||||
#### Notes:
|
#### Notes:
|
||||||
* Use of a reverse proxy is only required if you wish to serve LNURLs
|
* Use of a reverse proxy is only required if you wish to serve LNURLs
|
||||||
* The service defaults to port `1776`
|
* The service defaults to port `1776`
|
||||||
* Requires [Node.js](https://nodejs.org) >=18.x
|
* Requires [Node.js](https://nodejs.org) >=18.x
|
||||||
* Commands for your specific OS may differ slightly, Ubuntu/Debian used for example
|
* Commands for your specific OS may differ slightly, Ubuntu/Debian used for example
|
||||||
|
|
||||||
#### Steps:
|
#### Steps:
|
||||||
1) Run [LND](https://github.com/lightningnetwork/lnd/releases) if you aren't already
|
1) Run [LND](https://github.com/lightningnetwork/lnd/releases) if you aren't already
|
||||||
|
|
||||||
*Example mainnet startup*:
|
*Example mainnet startup*:
|
||||||
|
|
||||||
```
|
```
|
||||||
./lnd --bitcoin.active --bitcoin.mainnet --bitcoin.node=neutrino --neutrino.addpeer=neutrino.shock.network --feeurl=https://nodes.lightning.computer/fees/v1/btc-fee-estimates.json
|
./lnd --bitcoin.active --bitcoin.mainnet --bitcoin.node=neutrino --neutrino.addpeer=neutrino.shock.network --feeurl=https://nodes.lightning.computer/fees/v1/btc-fee-estimates.json
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
2) Download and Install Lightning.Pub
|
2) Download and Install Lightning.Pub
|
||||||
|
|
||||||
|
|
||||||
* `git clone https://github.com/shocknet/Lightning.Pub`
|
* `git clone https://github.com/shocknet/Lightning.Pub`
|
||||||
|
|
||||||
* `cd Lightning.Pub && npm i`
|
* `cd Lightning.Pub && npm i`
|
||||||
|
|
||||||
|
|
||||||
3) Configure values to env file as desired
|
3) Configure values to env file as desired
|
||||||
* `cp env.example .env && nano .env`
|
* `cp env.example .env && nano .env`
|
||||||
|
|
||||||
5) `npm start`
|
5) `npm start`
|
||||||
|
|
||||||
- A default "wallet" application pool will be automatically created, if you wish to create other app pools:
|
- A default "wallet" application pool will be automatically created, if you wish to create other app pools:
|
||||||
|
|
||||||
* `curl -XPOST -H 'Authorization: Bearer defined_in_ADMIN_TOKEN_env' -H "Content-type: application/json" -d '{"name":"ExampleApplicationPoolName"}' 'http://localhost:8080/api/admin/app/add'`
|
* `curl -XPOST -H 'Authorization: Bearer defined_in_ADMIN_TOKEN_env' -H "Content-type: application/json" -d '{"name":"ExampleApplicationPoolName"}' 'http://localhost:8080/api/admin/app/add'`
|
||||||
|
|
||||||
5) Connect with [wallet2](https://github.com/shocknet/wallet2) using the wallet nprofile that gets logged at startup.
|
5) Connect with [wallet2](https://github.com/shocknet/wallet2) using the wallet nprofile that gets logged at startup.
|
||||||
> [!NOTE]
|
> [!NOTE]
|
||||||
> Connecting with wallet will create an account on the node, it will not show or have access to the full LND balance
|
> Connecting with wallet will create an account on the node, it will not show or have access to the full LND balance
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
22
Umbrel/docker-compose.yml
Normal file
22
Umbrel/docker-compose.yml
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
version: "3.7"
|
||||||
|
services:
|
||||||
|
app_proxy:
|
||||||
|
environment:
|
||||||
|
APP_HOST: lightning-pub
|
||||||
|
APP_PORT: 1776
|
||||||
|
|
||||||
|
server:
|
||||||
|
image: ghcr.io/shocknet/lightning.pub:umbrel-works
|
||||||
|
volumes:
|
||||||
|
- "${APP_DATA_DIR}/data:/data"
|
||||||
|
- "${APP_LIGHTNING_NODE_DATA_DIR}:/lnd:ro"
|
||||||
|
environment:
|
||||||
|
LN_BACKEND_TYPE: "LND"
|
||||||
|
LND_ADDRESS: $APP_LIGHTNING_NODE_IP:$APP_LIGHTNING_NODE_GRPC_PORT
|
||||||
|
LND_CERT_PATH: "/lnd/tls.cert"
|
||||||
|
LND_MACAROON_PATH: "/lnd/data/chain/bitcoin/${APP_BITCOIN_NETWORK}/admin.macaroon"
|
||||||
|
DATABASE_FILE: "/data/db.sqlite"
|
||||||
|
METRICS_DATABASE_FILE: "/data/metrics.sqlite"
|
||||||
|
PORT: 1776
|
||||||
|
restart: on-failure
|
||||||
|
stop_grace_period: 1m
|
||||||
36
Umbrel/umbrel-app.yml
Normal file
36
Umbrel/umbrel-app.yml
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
manifestVersion: 1
|
||||||
|
id: lightning-pub
|
||||||
|
category: finance
|
||||||
|
name: Lightning.Pub
|
||||||
|
version: "1.0.0"
|
||||||
|
tagline: lightning, nostr, accounts, lnurl, web
|
||||||
|
description: >-
|
||||||
|
"Pub" is a Nostr-native account system designed
|
||||||
|
to make running Lightning infrastructure for your friends/family/customers
|
||||||
|
easier than previously thought possible.
|
||||||
|
|
||||||
|
Being Nostr-native eliminates the complexity of configuring your node like a server by using commodity Nostr relays.
|
||||||
|
These relays, unlike LNURL proxies, are trustless by nature of Nostr's own encryption spec (NIP44).
|
||||||
|
|
||||||
|
Support for optional services are integrated into Pub for operators seeking backward compatibility with legacy LNURLs and Lightning Addresses.
|
||||||
|
|
||||||
|
By solving the networking and programability hurdles, Pub provides Lightning with a 3rd Layer that enables node-runners and
|
||||||
|
Uncle Jims to more easily bring their personal network into Bitcoin's permissionless economy. In doing so, Pub runners
|
||||||
|
can keep the Lightning Network decentralized, with custodial scaling that is free of fiat rails, large banks,
|
||||||
|
and other forms of high-time-preference shitcoinery.
|
||||||
|
developer: shocknet
|
||||||
|
website: https://shock.network
|
||||||
|
dependencies:
|
||||||
|
- lightning
|
||||||
|
repo: https://github.com/shocknet/Lightning.Pub
|
||||||
|
support: https://github.com/shocknet/Lightning.Pub/discussions
|
||||||
|
port: 1776
|
||||||
|
gallery:
|
||||||
|
- 1.jpg
|
||||||
|
- 2.jpg
|
||||||
|
- 3.jpg
|
||||||
|
path: ""
|
||||||
|
defaultUsername: ""
|
||||||
|
defaultPassword: ""
|
||||||
|
submitter: shocknet
|
||||||
|
submission: https://github.com/getumbrel/umbrel/pull/334
|
||||||
376
deploy.sh
Executable file
376
deploy.sh
Executable file
|
|
@ -0,0 +1,376 @@
|
||||||
|
#!/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)"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
install_rsync_mac() {
|
||||||
|
check_homebrew
|
||||||
|
log "${PRIMARY_COLOR}Installing${RESET_COLOR} rsync using Homebrew..."
|
||||||
|
brew install rsync
|
||||||
|
}
|
||||||
|
|
||||||
|
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 <<EOF > "$plist_path"
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>Label</key>
|
||||||
|
<string>${label}</string>
|
||||||
|
<key>ProgramArguments</key>
|
||||||
|
<array>
|
||||||
|
${program_args}
|
||||||
|
</array>
|
||||||
|
<key>WorkingDirectory</key>
|
||||||
|
<string>${working_dir}</string>
|
||||||
|
<key>RunAtLoad</key>
|
||||||
|
<true/>
|
||||||
|
<key>KeepAlive</key>
|
||||||
|
<true/>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
|
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" "<string>${USER_HOME}/lnd/lnd</string>" ""
|
||||||
|
create_plist "${LAUNCH_AGENTS_DIR}/local.lightning_pub.plist" "local.lightning_pub" "<string>/bin/bash</string><string>-c</string><string>source ${NVM_DIR}/nvm.sh && npm start</string>" "${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
|
||||||
|
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
|
||||||
|
|
||||||
|
# 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
|
||||||
|
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 <<EOF > ~/.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 "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
|
||||||
|
mkdir -p lightning_pub_temp
|
||||||
|
tar -xvzf lightning_pub.tar.gz -C lightning_pub_temp --strip-components=1 > /dev/null 2>&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 &
|
||||||
|
npm_pid=$!
|
||||||
|
wait $npm_pid
|
||||||
|
|
||||||
|
log "${SECONDARY_COLOR}Lightning.Pub${RESET_COLOR} installation completed."
|
||||||
|
}
|
||||||
|
|
||||||
|
create_start_script() {
|
||||||
|
cat <<EOF > 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 <<EOF
|
||||||
|
[Unit]
|
||||||
|
Description=LND Service
|
||||||
|
After=network.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
ExecStart=${USER_HOME}/lnd/lnd
|
||||||
|
User=$(whoami)
|
||||||
|
Restart=always
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
EOF"
|
||||||
|
|
||||||
|
sudo bash -c "cat > /etc/systemd/system/lightning_pub.service <<EOF
|
||||||
|
[Unit]
|
||||||
|
Description=Lightning.Pub Service
|
||||||
|
After=network.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
ExecStart=/bin/bash -c 'source ${NVM_DIR}/nvm.sh && npm start'
|
||||||
|
WorkingDirectory=${USER_HOME}/lightning_pub
|
||||||
|
User=$(whoami)
|
||||||
|
Restart=always
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
EOF"
|
||||||
|
|
||||||
|
sudo systemctl daemon-reload
|
||||||
|
sudo systemctl enable lnd
|
||||||
|
sudo systemctl enable lightning_pub
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
# 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
|
||||||
|
fi
|
||||||
12
genkey.js
12
genkey.js
|
|
@ -1,6 +1,6 @@
|
||||||
import { generatePrivateKey, getPublicKey } from 'nostr-tools'
|
import { generatePrivateKey, getPublicKey } from 'nostr-tools'
|
||||||
const p = generatePrivateKey()
|
const p = generatePrivateKey()
|
||||||
console.log({
|
console.log({
|
||||||
privateKey: p,
|
privateKey: p,
|
||||||
publicKey: getPublicKey(Buffer.from(p, 'hex'))
|
publicKey: getPublicKey(Buffer.from(p, 'hex'))
|
||||||
})
|
})
|
||||||
|
|
|
||||||
162
package.json
162
package.json
|
|
@ -1,81 +1,81 @@
|
||||||
{
|
{
|
||||||
"name": "lightning.pub",
|
"name": "lightning.pub",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"description": "",
|
"description": "",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"clean": "rimraf build",
|
"clean": "rimraf build",
|
||||||
"test": "npm run clean && tsc && node build/src/tests/testRunner.js",
|
"test": "npm run clean && tsc && node build/src/tests/testRunner.js",
|
||||||
"start": "npm run clean && tsc && node build/src/index.js",
|
"start": "npm run clean && tsc && node build/src/index.js",
|
||||||
"start:ci": "git reset --hard && git pull && npm run start",
|
"start:ci": "git reset --hard && git pull && npm run start",
|
||||||
"build_autogenerated": "cd proto && rimraf autogenerated && protoc -I ./service --pub_out=. service/*",
|
"build_autogenerated": "cd proto && rimraf autogenerated && protoc -I ./service --pub_out=. service/*",
|
||||||
"build_lnd_client_1": "cd proto && protoc -I ./others --plugin=.\\node_modules\\.bin\\protoc-gen-ts_proto.cmd --ts_proto_out=./lnd --ts_proto_opt=esModuleInterop=true others/* ",
|
"build_lnd_client_1": "cd proto && protoc -I ./others --plugin=.\\node_modules\\.bin\\protoc-gen-ts_proto.cmd --ts_proto_out=./lnd --ts_proto_opt=esModuleInterop=true others/* ",
|
||||||
"build_lnd_client": "cd proto && rimraf lnd/* && npx protoc --ts_out ./lnd --ts_opt long_type_string --proto_path others others/* ",
|
"build_lnd_client": "cd proto && rimraf lnd/* && npx protoc --ts_out ./lnd --ts_opt long_type_string --proto_path others others/* ",
|
||||||
"typeorm": "typeorm-ts-node-commonjs"
|
"typeorm": "typeorm-ts-node-commonjs"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "git+https://github.com/shocknet/Lightning.Pub.git"
|
"url": "git+https://github.com/shocknet/Lightning.Pub.git"
|
||||||
},
|
},
|
||||||
"author": "",
|
"author": "",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"bugs": {
|
"bugs": {
|
||||||
"url": "https://github.com/shocknet/Lightning.Pub/issues"
|
"url": "https://github.com/shocknet/Lightning.Pub/issues"
|
||||||
},
|
},
|
||||||
"homepage": "https://github.com/shocknet/Lightning.Pub#readme",
|
"homepage": "https://github.com/shocknet/Lightning.Pub#readme",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@grpc/grpc-js": "^1.6.7",
|
"@grpc/grpc-js": "^1.6.7",
|
||||||
"@protobuf-ts/grpc-transport": "^2.5.0",
|
"@protobuf-ts/grpc-transport": "^2.5.0",
|
||||||
"@protobuf-ts/plugin": "^2.5.0",
|
"@protobuf-ts/plugin": "^2.5.0",
|
||||||
"@protobuf-ts/runtime": "^2.5.0",
|
"@protobuf-ts/runtime": "^2.5.0",
|
||||||
"@stablelib/xchacha20": "^1.0.1",
|
"@stablelib/xchacha20": "^1.0.1",
|
||||||
"@types/express": "^4.17.13",
|
"@types/express": "^4.17.13",
|
||||||
"@types/node": "^17.0.31",
|
"@types/node": "^17.0.31",
|
||||||
"@types/secp256k1": "^4.0.3",
|
"@types/secp256k1": "^4.0.3",
|
||||||
"axios": "^0.28.0",
|
"axios": "^0.28.0",
|
||||||
"bech32": "^2.0.0",
|
"bech32": "^2.0.0",
|
||||||
"bitcoin-core": "^4.2.0",
|
"bitcoin-core": "^4.2.0",
|
||||||
"chai": "^4.3.7",
|
"chai": "^4.3.7",
|
||||||
"chai-string": "^1.5.0",
|
"chai-string": "^1.5.0",
|
||||||
"copyfiles": "^2.4.1",
|
"copyfiles": "^2.4.1",
|
||||||
"cors": "^2.8.5",
|
"cors": "^2.8.5",
|
||||||
"csv": "^6.3.8",
|
"csv": "^6.3.8",
|
||||||
"dotenv": "^16.0.0",
|
"dotenv": "^16.0.0",
|
||||||
"eccrypto": "^1.1.6",
|
"eccrypto": "^1.1.6",
|
||||||
"express": "^4.19.2",
|
"express": "^4.19.2",
|
||||||
"globby": "^13.1.2",
|
"globby": "^13.1.2",
|
||||||
"grpc-tools": "^1.11.2",
|
"grpc-tools": "^1.11.2",
|
||||||
"jsonwebtoken": "^9.0.0",
|
"jsonwebtoken": "^9.0.0",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"nostr-tools": "^1.9.0",
|
"nostr-tools": "^1.9.0",
|
||||||
"pg": "^8.4.0",
|
"pg": "^8.4.0",
|
||||||
"reflect-metadata": "^0.1.13",
|
"reflect-metadata": "^0.1.13",
|
||||||
"rimraf": "^3.0.2",
|
"rimraf": "^3.0.2",
|
||||||
"rxjs": "^7.5.5",
|
"rxjs": "^7.5.5",
|
||||||
"secp256k1": "^4.0.3",
|
"secp256k1": "^4.0.3",
|
||||||
"sqlite3": "^5.1.5",
|
"sqlite3": "^5.1.5",
|
||||||
"ts-node": "^10.7.0",
|
"ts-node": "^10.7.0",
|
||||||
"ts-proto": "^1.131.2",
|
"ts-proto": "^1.131.2",
|
||||||
"typeorm": "0.3.15",
|
"typeorm": "0.3.15",
|
||||||
"typescript": "^4.6.4",
|
"typescript": "^4.6.4",
|
||||||
"uuid": "^8.3.2",
|
"uuid": "^8.3.2",
|
||||||
"websocket": "^1.0.34",
|
"websocket": "^1.0.34",
|
||||||
"websocket-polyfill": "^0.0.3"
|
"websocket-polyfill": "^0.0.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/chai": "^4.3.4",
|
"@types/chai": "^4.3.4",
|
||||||
"@types/chai-string": "^1.4.5",
|
"@types/chai-string": "^1.4.5",
|
||||||
"@types/cors": "^2.8.12",
|
"@types/cors": "^2.8.12",
|
||||||
"@types/eccrypto": "^1.1.3",
|
"@types/eccrypto": "^1.1.3",
|
||||||
"@types/jsonwebtoken": "^8.5.9",
|
"@types/jsonwebtoken": "^8.5.9",
|
||||||
"@types/lodash": "^4.14.182",
|
"@types/lodash": "^4.14.182",
|
||||||
"@types/node": "^16.11.10",
|
"@types/node": "^16.11.10",
|
||||||
"@types/node-fetch": "^2.6.3",
|
"@types/node-fetch": "^2.6.3",
|
||||||
"@types/uuid": "^8.3.4",
|
"@types/uuid": "^8.3.4",
|
||||||
"@types/websocket": "^1.0.6",
|
"@types/websocket": "^1.0.6",
|
||||||
"nodemon": "^2.0.20",
|
"nodemon": "^2.0.20",
|
||||||
"ts-node": "10.7.0",
|
"ts-node": "10.7.0",
|
||||||
"typescript": "4.5.2"
|
"typescript": "4.5.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,2 +1,2 @@
|
||||||
create lnd classes: `npx protoc -I ./others --ts_out=./lnd others/*`
|
create lnd classes: `npx protoc -I ./others --ts_out=./lnd others/*`
|
||||||
create server classes: `npx protoc -I ./service --pub_out=. service/*`
|
create server classes: `npx protoc -I ./service --pub_out=. service/*`
|
||||||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -1,282 +1,282 @@
|
||||||
// This file was autogenerated from a .proto file, DO NOT EDIT!
|
// This file was autogenerated from a .proto file, DO NOT EDIT!
|
||||||
import { NostrRequest } from './nostr_transport.js'
|
import { NostrRequest } from './nostr_transport.js'
|
||||||
import * as Types from './types.js'
|
import * as Types from './types.js'
|
||||||
export type ResultError = { status: 'ERROR', reason: string }
|
export type ResultError = { status: 'ERROR', reason: string }
|
||||||
|
|
||||||
export type NostrClientParams = {
|
export type NostrClientParams = {
|
||||||
pubDestination: string
|
pubDestination: string
|
||||||
retrieveNostrUserAuth: () => Promise<string | null>
|
retrieveNostrUserAuth: () => Promise<string | null>
|
||||||
checkResult?: true
|
checkResult?: true
|
||||||
}
|
}
|
||||||
export default (params: NostrClientParams, send: (to:string, message: NostrRequest) => Promise<any>, subscribe: (to:string, message: NostrRequest, cb:(res:any)=> void) => void) => ({
|
export default (params: NostrClientParams, send: (to:string, message: NostrRequest) => Promise<any>, subscribe: (to:string, message: NostrRequest, cb:(res:any)=> void) => void) => ({
|
||||||
LinkNPubThroughToken: async (request: Types.LinkNPubThroughTokenRequest): Promise<ResultError | ({ status: 'OK' })> => {
|
LinkNPubThroughToken: async (request: Types.LinkNPubThroughTokenRequest): Promise<ResultError | ({ status: 'OK' })> => {
|
||||||
const auth = await params.retrieveNostrUserAuth()
|
const auth = await params.retrieveNostrUserAuth()
|
||||||
if (auth === null) throw new Error('retrieveNostrUserAuth() returned null')
|
if (auth === null) throw new Error('retrieveNostrUserAuth() returned null')
|
||||||
const nostrRequest: NostrRequest = {}
|
const nostrRequest: NostrRequest = {}
|
||||||
nostrRequest.body = request
|
nostrRequest.body = request
|
||||||
const data = await send(params.pubDestination, {rpcName:'LinkNPubThroughToken',authIdentifier:auth, ...nostrRequest })
|
const data = await send(params.pubDestination, {rpcName:'LinkNPubThroughToken',authIdentifier:auth, ...nostrRequest })
|
||||||
if (data.status === 'ERROR' && typeof data.reason === 'string') return data
|
if (data.status === 'ERROR' && typeof data.reason === 'string') return data
|
||||||
if (data.status === 'OK') {
|
if (data.status === 'OK') {
|
||||||
return data
|
return data
|
||||||
}
|
}
|
||||||
return { status: 'ERROR', reason: 'invalid response' }
|
return { status: 'ERROR', reason: 'invalid response' }
|
||||||
},
|
},
|
||||||
UserHealth: async (): Promise<ResultError | ({ status: 'OK' })> => {
|
UserHealth: async (): Promise<ResultError | ({ status: 'OK' })> => {
|
||||||
const auth = await params.retrieveNostrUserAuth()
|
const auth = await params.retrieveNostrUserAuth()
|
||||||
if (auth === null) throw new Error('retrieveNostrUserAuth() returned null')
|
if (auth === null) throw new Error('retrieveNostrUserAuth() returned null')
|
||||||
const nostrRequest: NostrRequest = {}
|
const nostrRequest: NostrRequest = {}
|
||||||
const data = await send(params.pubDestination, {rpcName:'UserHealth',authIdentifier:auth, ...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 === 'ERROR' && typeof data.reason === 'string') return data
|
||||||
if (data.status === 'OK') {
|
if (data.status === 'OK') {
|
||||||
return data
|
return data
|
||||||
}
|
}
|
||||||
return { status: 'ERROR', reason: 'invalid response' }
|
return { status: 'ERROR', reason: 'invalid response' }
|
||||||
},
|
},
|
||||||
GetUserInfo: async (): Promise<ResultError | ({ status: 'OK' }& Types.UserInfo)> => {
|
GetUserInfo: async (): Promise<ResultError | ({ status: 'OK' }& Types.UserInfo)> => {
|
||||||
const auth = await params.retrieveNostrUserAuth()
|
const auth = await params.retrieveNostrUserAuth()
|
||||||
if (auth === null) throw new Error('retrieveNostrUserAuth() returned null')
|
if (auth === null) throw new Error('retrieveNostrUserAuth() returned null')
|
||||||
const nostrRequest: NostrRequest = {}
|
const nostrRequest: NostrRequest = {}
|
||||||
const data = await send(params.pubDestination, {rpcName:'GetUserInfo',authIdentifier:auth, ...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 === 'ERROR' && typeof data.reason === 'string') return data
|
||||||
if (data.status === 'OK') {
|
if (data.status === 'OK') {
|
||||||
const result = data
|
const result = data
|
||||||
if(!params.checkResult) return { status: 'OK', ...result }
|
if(!params.checkResult) return { status: 'OK', ...result }
|
||||||
const error = Types.UserInfoValidate(result)
|
const error = Types.UserInfoValidate(result)
|
||||||
if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message }
|
if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message }
|
||||||
}
|
}
|
||||||
return { status: 'ERROR', reason: 'invalid response' }
|
return { status: 'ERROR', reason: 'invalid response' }
|
||||||
},
|
},
|
||||||
AddProduct: async (request: Types.AddProductRequest): Promise<ResultError | ({ status: 'OK' }& Types.Product)> => {
|
AddProduct: async (request: Types.AddProductRequest): Promise<ResultError | ({ status: 'OK' }& Types.Product)> => {
|
||||||
const auth = await params.retrieveNostrUserAuth()
|
const auth = await params.retrieveNostrUserAuth()
|
||||||
if (auth === null) throw new Error('retrieveNostrUserAuth() returned null')
|
if (auth === null) throw new Error('retrieveNostrUserAuth() returned null')
|
||||||
const nostrRequest: NostrRequest = {}
|
const nostrRequest: NostrRequest = {}
|
||||||
nostrRequest.body = request
|
nostrRequest.body = request
|
||||||
const data = await send(params.pubDestination, {rpcName:'AddProduct',authIdentifier:auth, ...nostrRequest })
|
const data = await send(params.pubDestination, {rpcName:'AddProduct',authIdentifier:auth, ...nostrRequest })
|
||||||
if (data.status === 'ERROR' && typeof data.reason === 'string') return data
|
if (data.status === 'ERROR' && typeof data.reason === 'string') return data
|
||||||
if (data.status === 'OK') {
|
if (data.status === 'OK') {
|
||||||
const result = data
|
const result = data
|
||||||
if(!params.checkResult) return { status: 'OK', ...result }
|
if(!params.checkResult) return { status: 'OK', ...result }
|
||||||
const error = Types.ProductValidate(result)
|
const error = Types.ProductValidate(result)
|
||||||
if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message }
|
if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message }
|
||||||
}
|
}
|
||||||
return { status: 'ERROR', reason: 'invalid response' }
|
return { status: 'ERROR', reason: 'invalid response' }
|
||||||
},
|
},
|
||||||
NewProductInvoice: async (query: Types.NewProductInvoice_Query): Promise<ResultError | ({ status: 'OK' }& Types.NewInvoiceResponse)> => {
|
NewProductInvoice: async (query: Types.NewProductInvoice_Query): Promise<ResultError | ({ status: 'OK' }& Types.NewInvoiceResponse)> => {
|
||||||
const auth = await params.retrieveNostrUserAuth()
|
const auth = await params.retrieveNostrUserAuth()
|
||||||
if (auth === null) throw new Error('retrieveNostrUserAuth() returned null')
|
if (auth === null) throw new Error('retrieveNostrUserAuth() returned null')
|
||||||
const nostrRequest: NostrRequest = {}
|
const nostrRequest: NostrRequest = {}
|
||||||
nostrRequest.query = query
|
nostrRequest.query = query
|
||||||
const data = await send(params.pubDestination, {rpcName:'NewProductInvoice',authIdentifier:auth, ...nostrRequest })
|
const data = await send(params.pubDestination, {rpcName:'NewProductInvoice',authIdentifier:auth, ...nostrRequest })
|
||||||
if (data.status === 'ERROR' && typeof data.reason === 'string') return data
|
if (data.status === 'ERROR' && typeof data.reason === 'string') return data
|
||||||
if (data.status === 'OK') {
|
if (data.status === 'OK') {
|
||||||
const result = data
|
const result = data
|
||||||
if(!params.checkResult) return { status: 'OK', ...result }
|
if(!params.checkResult) return { status: 'OK', ...result }
|
||||||
const error = Types.NewInvoiceResponseValidate(result)
|
const error = Types.NewInvoiceResponseValidate(result)
|
||||||
if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message }
|
if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message }
|
||||||
}
|
}
|
||||||
return { status: 'ERROR', reason: 'invalid response' }
|
return { status: 'ERROR', reason: 'invalid response' }
|
||||||
},
|
},
|
||||||
GetUserOperations: async (request: Types.GetUserOperationsRequest): Promise<ResultError | ({ status: 'OK' }& Types.GetUserOperationsResponse)> => {
|
GetUserOperations: async (request: Types.GetUserOperationsRequest): Promise<ResultError | ({ status: 'OK' }& Types.GetUserOperationsResponse)> => {
|
||||||
const auth = await params.retrieveNostrUserAuth()
|
const auth = await params.retrieveNostrUserAuth()
|
||||||
if (auth === null) throw new Error('retrieveNostrUserAuth() returned null')
|
if (auth === null) throw new Error('retrieveNostrUserAuth() returned null')
|
||||||
const nostrRequest: NostrRequest = {}
|
const nostrRequest: NostrRequest = {}
|
||||||
nostrRequest.body = request
|
nostrRequest.body = request
|
||||||
const data = await send(params.pubDestination, {rpcName:'GetUserOperations',authIdentifier:auth, ...nostrRequest })
|
const data = await send(params.pubDestination, {rpcName:'GetUserOperations',authIdentifier:auth, ...nostrRequest })
|
||||||
if (data.status === 'ERROR' && typeof data.reason === 'string') return data
|
if (data.status === 'ERROR' && typeof data.reason === 'string') return data
|
||||||
if (data.status === 'OK') {
|
if (data.status === 'OK') {
|
||||||
const result = data
|
const result = data
|
||||||
if(!params.checkResult) return { status: 'OK', ...result }
|
if(!params.checkResult) return { status: 'OK', ...result }
|
||||||
const error = Types.GetUserOperationsResponseValidate(result)
|
const error = Types.GetUserOperationsResponseValidate(result)
|
||||||
if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message }
|
if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message }
|
||||||
}
|
}
|
||||||
return { status: 'ERROR', reason: 'invalid response' }
|
return { status: 'ERROR', reason: 'invalid response' }
|
||||||
},
|
},
|
||||||
NewAddress: async (request: Types.NewAddressRequest): Promise<ResultError | ({ status: 'OK' }& Types.NewAddressResponse)> => {
|
NewAddress: async (request: Types.NewAddressRequest): Promise<ResultError | ({ status: 'OK' }& Types.NewAddressResponse)> => {
|
||||||
const auth = await params.retrieveNostrUserAuth()
|
const auth = await params.retrieveNostrUserAuth()
|
||||||
if (auth === null) throw new Error('retrieveNostrUserAuth() returned null')
|
if (auth === null) throw new Error('retrieveNostrUserAuth() returned null')
|
||||||
const nostrRequest: NostrRequest = {}
|
const nostrRequest: NostrRequest = {}
|
||||||
nostrRequest.body = request
|
nostrRequest.body = request
|
||||||
const data = await send(params.pubDestination, {rpcName:'NewAddress',authIdentifier:auth, ...nostrRequest })
|
const data = await send(params.pubDestination, {rpcName:'NewAddress',authIdentifier:auth, ...nostrRequest })
|
||||||
if (data.status === 'ERROR' && typeof data.reason === 'string') return data
|
if (data.status === 'ERROR' && typeof data.reason === 'string') return data
|
||||||
if (data.status === 'OK') {
|
if (data.status === 'OK') {
|
||||||
const result = data
|
const result = data
|
||||||
if(!params.checkResult) return { status: 'OK', ...result }
|
if(!params.checkResult) return { status: 'OK', ...result }
|
||||||
const error = Types.NewAddressResponseValidate(result)
|
const error = Types.NewAddressResponseValidate(result)
|
||||||
if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message }
|
if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message }
|
||||||
}
|
}
|
||||||
return { status: 'ERROR', reason: 'invalid response' }
|
return { status: 'ERROR', reason: 'invalid response' }
|
||||||
},
|
},
|
||||||
PayAddress: async (request: Types.PayAddressRequest): Promise<ResultError | ({ status: 'OK' }& Types.PayAddressResponse)> => {
|
PayAddress: async (request: Types.PayAddressRequest): Promise<ResultError | ({ status: 'OK' }& Types.PayAddressResponse)> => {
|
||||||
const auth = await params.retrieveNostrUserAuth()
|
const auth = await params.retrieveNostrUserAuth()
|
||||||
if (auth === null) throw new Error('retrieveNostrUserAuth() returned null')
|
if (auth === null) throw new Error('retrieveNostrUserAuth() returned null')
|
||||||
const nostrRequest: NostrRequest = {}
|
const nostrRequest: NostrRequest = {}
|
||||||
nostrRequest.body = request
|
nostrRequest.body = request
|
||||||
const data = await send(params.pubDestination, {rpcName:'PayAddress',authIdentifier:auth, ...nostrRequest })
|
const data = await send(params.pubDestination, {rpcName:'PayAddress',authIdentifier:auth, ...nostrRequest })
|
||||||
if (data.status === 'ERROR' && typeof data.reason === 'string') return data
|
if (data.status === 'ERROR' && typeof data.reason === 'string') return data
|
||||||
if (data.status === 'OK') {
|
if (data.status === 'OK') {
|
||||||
const result = data
|
const result = data
|
||||||
if(!params.checkResult) return { status: 'OK', ...result }
|
if(!params.checkResult) return { status: 'OK', ...result }
|
||||||
const error = Types.PayAddressResponseValidate(result)
|
const error = Types.PayAddressResponseValidate(result)
|
||||||
if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message }
|
if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message }
|
||||||
}
|
}
|
||||||
return { status: 'ERROR', reason: 'invalid response' }
|
return { status: 'ERROR', reason: 'invalid response' }
|
||||||
},
|
},
|
||||||
NewInvoice: async (request: Types.NewInvoiceRequest): Promise<ResultError | ({ status: 'OK' }& Types.NewInvoiceResponse)> => {
|
NewInvoice: async (request: Types.NewInvoiceRequest): Promise<ResultError | ({ status: 'OK' }& Types.NewInvoiceResponse)> => {
|
||||||
const auth = await params.retrieveNostrUserAuth()
|
const auth = await params.retrieveNostrUserAuth()
|
||||||
if (auth === null) throw new Error('retrieveNostrUserAuth() returned null')
|
if (auth === null) throw new Error('retrieveNostrUserAuth() returned null')
|
||||||
const nostrRequest: NostrRequest = {}
|
const nostrRequest: NostrRequest = {}
|
||||||
nostrRequest.body = request
|
nostrRequest.body = request
|
||||||
const data = await send(params.pubDestination, {rpcName:'NewInvoice',authIdentifier:auth, ...nostrRequest })
|
const data = await send(params.pubDestination, {rpcName:'NewInvoice',authIdentifier:auth, ...nostrRequest })
|
||||||
if (data.status === 'ERROR' && typeof data.reason === 'string') return data
|
if (data.status === 'ERROR' && typeof data.reason === 'string') return data
|
||||||
if (data.status === 'OK') {
|
if (data.status === 'OK') {
|
||||||
const result = data
|
const result = data
|
||||||
if(!params.checkResult) return { status: 'OK', ...result }
|
if(!params.checkResult) return { status: 'OK', ...result }
|
||||||
const error = Types.NewInvoiceResponseValidate(result)
|
const error = Types.NewInvoiceResponseValidate(result)
|
||||||
if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message }
|
if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message }
|
||||||
}
|
}
|
||||||
return { status: 'ERROR', reason: 'invalid response' }
|
return { status: 'ERROR', reason: 'invalid response' }
|
||||||
},
|
},
|
||||||
DecodeInvoice: async (request: Types.DecodeInvoiceRequest): Promise<ResultError | ({ status: 'OK' }& Types.DecodeInvoiceResponse)> => {
|
DecodeInvoice: async (request: Types.DecodeInvoiceRequest): Promise<ResultError | ({ status: 'OK' }& Types.DecodeInvoiceResponse)> => {
|
||||||
const auth = await params.retrieveNostrUserAuth()
|
const auth = await params.retrieveNostrUserAuth()
|
||||||
if (auth === null) throw new Error('retrieveNostrUserAuth() returned null')
|
if (auth === null) throw new Error('retrieveNostrUserAuth() returned null')
|
||||||
const nostrRequest: NostrRequest = {}
|
const nostrRequest: NostrRequest = {}
|
||||||
nostrRequest.body = request
|
nostrRequest.body = request
|
||||||
const data = await send(params.pubDestination, {rpcName:'DecodeInvoice',authIdentifier:auth, ...nostrRequest })
|
const data = await send(params.pubDestination, {rpcName:'DecodeInvoice',authIdentifier:auth, ...nostrRequest })
|
||||||
if (data.status === 'ERROR' && typeof data.reason === 'string') return data
|
if (data.status === 'ERROR' && typeof data.reason === 'string') return data
|
||||||
if (data.status === 'OK') {
|
if (data.status === 'OK') {
|
||||||
const result = data
|
const result = data
|
||||||
if(!params.checkResult) return { status: 'OK', ...result }
|
if(!params.checkResult) return { status: 'OK', ...result }
|
||||||
const error = Types.DecodeInvoiceResponseValidate(result)
|
const error = Types.DecodeInvoiceResponseValidate(result)
|
||||||
if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message }
|
if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message }
|
||||||
}
|
}
|
||||||
return { status: 'ERROR', reason: 'invalid response' }
|
return { status: 'ERROR', reason: 'invalid response' }
|
||||||
},
|
},
|
||||||
PayInvoice: async (request: Types.PayInvoiceRequest): Promise<ResultError | ({ status: 'OK' }& Types.PayInvoiceResponse)> => {
|
PayInvoice: async (request: Types.PayInvoiceRequest): Promise<ResultError | ({ status: 'OK' }& Types.PayInvoiceResponse)> => {
|
||||||
const auth = await params.retrieveNostrUserAuth()
|
const auth = await params.retrieveNostrUserAuth()
|
||||||
if (auth === null) throw new Error('retrieveNostrUserAuth() returned null')
|
if (auth === null) throw new Error('retrieveNostrUserAuth() returned null')
|
||||||
const nostrRequest: NostrRequest = {}
|
const nostrRequest: NostrRequest = {}
|
||||||
nostrRequest.body = request
|
nostrRequest.body = request
|
||||||
const data = await send(params.pubDestination, {rpcName:'PayInvoice',authIdentifier:auth, ...nostrRequest })
|
const data = await send(params.pubDestination, {rpcName:'PayInvoice',authIdentifier:auth, ...nostrRequest })
|
||||||
if (data.status === 'ERROR' && typeof data.reason === 'string') return data
|
if (data.status === 'ERROR' && typeof data.reason === 'string') return data
|
||||||
if (data.status === 'OK') {
|
if (data.status === 'OK') {
|
||||||
const result = data
|
const result = data
|
||||||
if(!params.checkResult) return { status: 'OK', ...result }
|
if(!params.checkResult) return { status: 'OK', ...result }
|
||||||
const error = Types.PayInvoiceResponseValidate(result)
|
const error = Types.PayInvoiceResponseValidate(result)
|
||||||
if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message }
|
if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message }
|
||||||
}
|
}
|
||||||
return { status: 'ERROR', reason: 'invalid response' }
|
return { status: 'ERROR', reason: 'invalid response' }
|
||||||
},
|
},
|
||||||
OpenChannel: async (request: Types.OpenChannelRequest): Promise<ResultError | ({ status: 'OK' }& Types.OpenChannelResponse)> => {
|
OpenChannel: async (request: Types.OpenChannelRequest): Promise<ResultError | ({ status: 'OK' }& Types.OpenChannelResponse)> => {
|
||||||
const auth = await params.retrieveNostrUserAuth()
|
const auth = await params.retrieveNostrUserAuth()
|
||||||
if (auth === null) throw new Error('retrieveNostrUserAuth() returned null')
|
if (auth === null) throw new Error('retrieveNostrUserAuth() returned null')
|
||||||
const nostrRequest: NostrRequest = {}
|
const nostrRequest: NostrRequest = {}
|
||||||
nostrRequest.body = request
|
nostrRequest.body = request
|
||||||
const data = await send(params.pubDestination, {rpcName:'OpenChannel',authIdentifier:auth, ...nostrRequest })
|
const data = await send(params.pubDestination, {rpcName:'OpenChannel',authIdentifier:auth, ...nostrRequest })
|
||||||
if (data.status === 'ERROR' && typeof data.reason === 'string') return data
|
if (data.status === 'ERROR' && typeof data.reason === 'string') return data
|
||||||
if (data.status === 'OK') {
|
if (data.status === 'OK') {
|
||||||
const result = data
|
const result = data
|
||||||
if(!params.checkResult) return { status: 'OK', ...result }
|
if(!params.checkResult) return { status: 'OK', ...result }
|
||||||
const error = Types.OpenChannelResponseValidate(result)
|
const error = Types.OpenChannelResponseValidate(result)
|
||||||
if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message }
|
if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message }
|
||||||
}
|
}
|
||||||
return { status: 'ERROR', reason: 'invalid response' }
|
return { status: 'ERROR', reason: 'invalid response' }
|
||||||
},
|
},
|
||||||
GetLnurlWithdrawLink: async (): Promise<ResultError | ({ status: 'OK' }& Types.LnurlLinkResponse)> => {
|
GetLnurlWithdrawLink: async (): Promise<ResultError | ({ status: 'OK' }& Types.LnurlLinkResponse)> => {
|
||||||
const auth = await params.retrieveNostrUserAuth()
|
const auth = await params.retrieveNostrUserAuth()
|
||||||
if (auth === null) throw new Error('retrieveNostrUserAuth() returned null')
|
if (auth === null) throw new Error('retrieveNostrUserAuth() returned null')
|
||||||
const nostrRequest: NostrRequest = {}
|
const nostrRequest: NostrRequest = {}
|
||||||
const data = await send(params.pubDestination, {rpcName:'GetLnurlWithdrawLink',authIdentifier:auth, ...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 === 'ERROR' && typeof data.reason === 'string') return data
|
||||||
if (data.status === 'OK') {
|
if (data.status === 'OK') {
|
||||||
const result = data
|
const result = data
|
||||||
if(!params.checkResult) return { status: 'OK', ...result }
|
if(!params.checkResult) return { status: 'OK', ...result }
|
||||||
const error = Types.LnurlLinkResponseValidate(result)
|
const error = Types.LnurlLinkResponseValidate(result)
|
||||||
if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message }
|
if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message }
|
||||||
}
|
}
|
||||||
return { status: 'ERROR', reason: 'invalid response' }
|
return { status: 'ERROR', reason: 'invalid response' }
|
||||||
},
|
},
|
||||||
GetLnurlPayLink: async (): Promise<ResultError | ({ status: 'OK' }& Types.LnurlLinkResponse)> => {
|
GetLnurlPayLink: async (): Promise<ResultError | ({ status: 'OK' }& Types.LnurlLinkResponse)> => {
|
||||||
const auth = await params.retrieveNostrUserAuth()
|
const auth = await params.retrieveNostrUserAuth()
|
||||||
if (auth === null) throw new Error('retrieveNostrUserAuth() returned null')
|
if (auth === null) throw new Error('retrieveNostrUserAuth() returned null')
|
||||||
const nostrRequest: NostrRequest = {}
|
const nostrRequest: NostrRequest = {}
|
||||||
const data = await send(params.pubDestination, {rpcName:'GetLnurlPayLink',authIdentifier:auth, ...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 === 'ERROR' && typeof data.reason === 'string') return data
|
||||||
if (data.status === 'OK') {
|
if (data.status === 'OK') {
|
||||||
const result = data
|
const result = data
|
||||||
if(!params.checkResult) return { status: 'OK', ...result }
|
if(!params.checkResult) return { status: 'OK', ...result }
|
||||||
const error = Types.LnurlLinkResponseValidate(result)
|
const error = Types.LnurlLinkResponseValidate(result)
|
||||||
if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message }
|
if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message }
|
||||||
}
|
}
|
||||||
return { status: 'ERROR', reason: 'invalid response' }
|
return { status: 'ERROR', reason: 'invalid response' }
|
||||||
},
|
},
|
||||||
GetLNURLChannelLink: async (): Promise<ResultError | ({ status: 'OK' }& Types.LnurlLinkResponse)> => {
|
GetLNURLChannelLink: async (): Promise<ResultError | ({ status: 'OK' }& Types.LnurlLinkResponse)> => {
|
||||||
const auth = await params.retrieveNostrUserAuth()
|
const auth = await params.retrieveNostrUserAuth()
|
||||||
if (auth === null) throw new Error('retrieveNostrUserAuth() returned null')
|
if (auth === null) throw new Error('retrieveNostrUserAuth() returned null')
|
||||||
const nostrRequest: NostrRequest = {}
|
const nostrRequest: NostrRequest = {}
|
||||||
const data = await send(params.pubDestination, {rpcName:'GetLNURLChannelLink',authIdentifier:auth, ...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 === 'ERROR' && typeof data.reason === 'string') return data
|
||||||
if (data.status === 'OK') {
|
if (data.status === 'OK') {
|
||||||
const result = data
|
const result = data
|
||||||
if(!params.checkResult) return { status: 'OK', ...result }
|
if(!params.checkResult) return { status: 'OK', ...result }
|
||||||
const error = Types.LnurlLinkResponseValidate(result)
|
const error = Types.LnurlLinkResponseValidate(result)
|
||||||
if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message }
|
if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message }
|
||||||
}
|
}
|
||||||
return { status: 'ERROR', reason: 'invalid response' }
|
return { status: 'ERROR', reason: 'invalid response' }
|
||||||
},
|
},
|
||||||
GetLiveUserOperations: async (cb: (res:ResultError | ({ status: 'OK' }& Types.LiveUserOperation)) => void): Promise<void> => {
|
GetLiveUserOperations: async (cb: (res:ResultError | ({ status: 'OK' }& Types.LiveUserOperation)) => void): Promise<void> => {
|
||||||
const auth = await params.retrieveNostrUserAuth()
|
const auth = await params.retrieveNostrUserAuth()
|
||||||
if (auth === null) throw new Error('retrieveNostrUserAuth() returned null')
|
if (auth === null) throw new Error('retrieveNostrUserAuth() returned null')
|
||||||
const nostrRequest: NostrRequest = {}
|
const nostrRequest: NostrRequest = {}
|
||||||
subscribe(params.pubDestination, {rpcName:'GetLiveUserOperations',authIdentifier:auth, ...nostrRequest }, (data) => {
|
subscribe(params.pubDestination, {rpcName:'GetLiveUserOperations',authIdentifier:auth, ...nostrRequest }, (data) => {
|
||||||
if (data.status === 'ERROR' && typeof data.reason === 'string') return cb(data)
|
if (data.status === 'ERROR' && typeof data.reason === 'string') return cb(data)
|
||||||
if (data.status === 'OK') {
|
if (data.status === 'OK') {
|
||||||
const result = data
|
const result = data
|
||||||
if(!params.checkResult) return cb({ status: 'OK', ...result })
|
if(!params.checkResult) return cb({ status: 'OK', ...result })
|
||||||
const error = Types.LiveUserOperationValidate(result)
|
const error = Types.LiveUserOperationValidate(result)
|
||||||
if (error === null) { return cb({ status: 'OK', ...result }) } else return cb({ status: 'ERROR', reason: error.message })
|
if (error === null) { return cb({ status: 'OK', ...result }) } else return cb({ status: 'ERROR', reason: error.message })
|
||||||
}
|
}
|
||||||
return cb({ status: 'ERROR', reason: 'invalid response' })
|
return cb({ status: 'ERROR', reason: 'invalid response' })
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
GetMigrationUpdate: async (cb: (res:ResultError | ({ status: 'OK' }& Types.MigrationUpdate)) => void): Promise<void> => {
|
GetMigrationUpdate: async (cb: (res:ResultError | ({ status: 'OK' }& Types.MigrationUpdate)) => void): Promise<void> => {
|
||||||
const auth = await params.retrieveNostrUserAuth()
|
const auth = await params.retrieveNostrUserAuth()
|
||||||
if (auth === null) throw new Error('retrieveNostrUserAuth() returned null')
|
if (auth === null) throw new Error('retrieveNostrUserAuth() returned null')
|
||||||
const nostrRequest: NostrRequest = {}
|
const nostrRequest: NostrRequest = {}
|
||||||
subscribe(params.pubDestination, {rpcName:'GetMigrationUpdate',authIdentifier:auth, ...nostrRequest }, (data) => {
|
subscribe(params.pubDestination, {rpcName:'GetMigrationUpdate',authIdentifier:auth, ...nostrRequest }, (data) => {
|
||||||
if (data.status === 'ERROR' && typeof data.reason === 'string') return cb(data)
|
if (data.status === 'ERROR' && typeof data.reason === 'string') return cb(data)
|
||||||
if (data.status === 'OK') {
|
if (data.status === 'OK') {
|
||||||
const result = data
|
const result = data
|
||||||
if(!params.checkResult) return cb({ status: 'OK', ...result })
|
if(!params.checkResult) return cb({ status: 'OK', ...result })
|
||||||
const error = Types.MigrationUpdateValidate(result)
|
const error = Types.MigrationUpdateValidate(result)
|
||||||
if (error === null) { return cb({ status: 'OK', ...result }) } else return cb({ status: 'ERROR', reason: error.message })
|
if (error === null) { return cb({ status: 'OK', ...result }) } else return cb({ status: 'ERROR', reason: error.message })
|
||||||
}
|
}
|
||||||
return cb({ status: 'ERROR', reason: 'invalid response' })
|
return cb({ status: 'ERROR', reason: 'invalid response' })
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
GetHttpCreds: async (cb: (res:ResultError | ({ status: 'OK' }& Types.HttpCreds)) => void): Promise<void> => {
|
GetHttpCreds: async (cb: (res:ResultError | ({ status: 'OK' }& Types.HttpCreds)) => void): Promise<void> => {
|
||||||
const auth = await params.retrieveNostrUserAuth()
|
const auth = await params.retrieveNostrUserAuth()
|
||||||
if (auth === null) throw new Error('retrieveNostrUserAuth() returned null')
|
if (auth === null) throw new Error('retrieveNostrUserAuth() returned null')
|
||||||
const nostrRequest: NostrRequest = {}
|
const nostrRequest: NostrRequest = {}
|
||||||
subscribe(params.pubDestination, {rpcName:'GetHttpCreds',authIdentifier:auth, ...nostrRequest }, (data) => {
|
subscribe(params.pubDestination, {rpcName:'GetHttpCreds',authIdentifier:auth, ...nostrRequest }, (data) => {
|
||||||
if (data.status === 'ERROR' && typeof data.reason === 'string') return cb(data)
|
if (data.status === 'ERROR' && typeof data.reason === 'string') return cb(data)
|
||||||
if (data.status === 'OK') {
|
if (data.status === 'OK') {
|
||||||
const result = data
|
const result = data
|
||||||
if(!params.checkResult) return cb({ status: 'OK', ...result })
|
if(!params.checkResult) return cb({ status: 'OK', ...result })
|
||||||
const error = Types.HttpCredsValidate(result)
|
const error = Types.HttpCredsValidate(result)
|
||||||
if (error === null) { return cb({ status: 'OK', ...result }) } else return cb({ status: 'ERROR', reason: error.message })
|
if (error === null) { return cb({ status: 'OK', ...result }) } else return cb({ status: 'ERROR', reason: error.message })
|
||||||
}
|
}
|
||||||
return cb({ status: 'ERROR', reason: 'invalid response' })
|
return cb({ status: 'ERROR', reason: 'invalid response' })
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
BatchUser: async (requests:Types.UserMethodInputs[]): Promise<ResultError | ({ status: 'OK', responses:(Types.UserMethodOutputs)[] })> => {
|
BatchUser: async (requests:Types.UserMethodInputs[]): Promise<ResultError | ({ status: 'OK', responses:(Types.UserMethodOutputs)[] })> => {
|
||||||
const auth = await params.retrieveNostrUserAuth()
|
const auth = await params.retrieveNostrUserAuth()
|
||||||
if (auth === null) throw new Error('retrieveNostrUserAuth() returned null')
|
if (auth === null) throw new Error('retrieveNostrUserAuth() returned null')
|
||||||
const nostrRequest: NostrRequest = {body:{requests}}
|
const nostrRequest: NostrRequest = {body:{requests}}
|
||||||
const data = await send(params.pubDestination, {rpcName:'BatchUser',authIdentifier:auth, ...nostrRequest })
|
const data = await send(params.pubDestination, {rpcName:'BatchUser',authIdentifier:auth, ...nostrRequest })
|
||||||
if (data.status === 'ERROR' && typeof data.reason === 'string') return data
|
if (data.status === 'ERROR' && typeof data.reason === 'string') return data
|
||||||
if (data.status === 'OK') {
|
if (data.status === 'OK') {
|
||||||
return data
|
return data
|
||||||
}
|
}
|
||||||
return { status: 'ERROR', reason: 'invalid response' }
|
return { status: 'ERROR', reason: 'invalid response' }
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -1,499 +1,499 @@
|
||||||
// This file was autogenerated from a .proto file, DO NOT EDIT!
|
// This file was autogenerated from a .proto file, DO NOT EDIT!
|
||||||
|
|
||||||
import * as Types from './types.js'
|
import * as Types from './types.js'
|
||||||
export type Logger = { log: (v: any) => void, error: (v: any) => void }
|
export type Logger = { log: (v: any) => void, error: (v: any) => void }
|
||||||
type NostrResponse = (message: object) => void
|
type NostrResponse = (message: object) => void
|
||||||
export type NostrRequest = {
|
export type NostrRequest = {
|
||||||
rpcName?: string
|
rpcName?: string
|
||||||
params?: Record<string, string>
|
params?: Record<string, string>
|
||||||
query?: Record<string, string>
|
query?: Record<string, string>
|
||||||
body?: any
|
body?: any
|
||||||
authIdentifier?: string
|
authIdentifier?: string
|
||||||
requestId?: string
|
requestId?: string
|
||||||
appId?: string
|
appId?: string
|
||||||
}
|
}
|
||||||
export type NostrOptions = {
|
export type NostrOptions = {
|
||||||
logger?: Logger
|
logger?: Logger
|
||||||
throwErrors?: true
|
throwErrors?: true
|
||||||
metricsCallback: (metrics: Types.RequestMetric[]) => void
|
metricsCallback: (metrics: Types.RequestMetric[]) => void
|
||||||
NostrUserAuthGuard: (appId?: string, identifier?: string) => Promise<Types.UserContext>
|
NostrUserAuthGuard: (appId?: string, identifier?: string) => Promise<Types.UserContext>
|
||||||
}
|
}
|
||||||
const logErrorAndReturnResponse = (error: Error, response: string, res: NostrResponse, logger: Logger, metric: Types.RequestMetric, 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 })
|
logger.error(error.message || error); metricsCallback([{ ...metric, error: response }]); res({ status: 'ERROR', reason: response })
|
||||||
}
|
}
|
||||||
export default (methods: Types.ServerMethods, opts: NostrOptions) => {
|
export default (methods: Types.ServerMethods, opts: NostrOptions) => {
|
||||||
const logger = opts.logger || { log: console.log, error: console.error }
|
const logger = opts.logger || { log: console.log, error: console.error }
|
||||||
return async (req: NostrRequest, res: NostrResponse, startString: string, startMs: number) => {
|
return async (req: NostrRequest, res: NostrResponse, startString: string, startMs: number) => {
|
||||||
const startTime = BigInt(startString)
|
const startTime = BigInt(startString)
|
||||||
const info: Types.RequestInfo = { rpcName: req.rpcName || 'unkown', batch: false, nostr: true, batchSize: 0 }
|
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 }
|
const stats: Types.RequestStats = { startMs, start: startTime, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n }
|
||||||
let authCtx: Types.AuthContext = {}
|
let authCtx: Types.AuthContext = {}
|
||||||
switch (req.rpcName) {
|
switch (req.rpcName) {
|
||||||
case 'LinkNPubThroughToken':
|
case 'LinkNPubThroughToken':
|
||||||
try {
|
try {
|
||||||
if (!methods.LinkNPubThroughToken) throw new Error('method: LinkNPubThroughToken is not implemented')
|
if (!methods.LinkNPubThroughToken) throw new Error('method: LinkNPubThroughToken is not implemented')
|
||||||
const authContext = await opts.NostrUserAuthGuard(req.appId, req.authIdentifier)
|
const authContext = await opts.NostrUserAuthGuard(req.appId, req.authIdentifier)
|
||||||
stats.guard = process.hrtime.bigint()
|
stats.guard = process.hrtime.bigint()
|
||||||
authCtx = authContext
|
authCtx = authContext
|
||||||
const request = req.body
|
const request = req.body
|
||||||
const error = Types.LinkNPubThroughTokenRequestValidate(request)
|
const error = Types.LinkNPubThroughTokenRequestValidate(request)
|
||||||
stats.validate = process.hrtime.bigint()
|
stats.validate = process.hrtime.bigint()
|
||||||
if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback)
|
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 })
|
await methods.LinkNPubThroughToken({ rpcName: 'LinkNPubThroughToken', ctx: authContext, req: request })
|
||||||
stats.handle = process.hrtime.bigint()
|
stats.handle = process.hrtime.bigint()
|
||||||
res({ status: 'OK' })
|
res({ status: 'OK' })
|
||||||
opts.metricsCallback([{ ...info, ...stats, ...authContext }])
|
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 }
|
} 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
|
break
|
||||||
case 'UserHealth':
|
case 'UserHealth':
|
||||||
try {
|
try {
|
||||||
if (!methods.UserHealth) throw new Error('method: UserHealth is not implemented')
|
if (!methods.UserHealth) throw new Error('method: UserHealth is not implemented')
|
||||||
const authContext = await opts.NostrUserAuthGuard(req.appId, req.authIdentifier)
|
const authContext = await opts.NostrUserAuthGuard(req.appId, req.authIdentifier)
|
||||||
stats.guard = process.hrtime.bigint()
|
stats.guard = process.hrtime.bigint()
|
||||||
authCtx = authContext
|
authCtx = authContext
|
||||||
stats.validate = stats.guard
|
stats.validate = stats.guard
|
||||||
await methods.UserHealth({ rpcName: 'UserHealth', ctx: authContext })
|
await methods.UserHealth({ rpcName: 'UserHealth', ctx: authContext })
|
||||||
stats.handle = process.hrtime.bigint()
|
stats.handle = process.hrtime.bigint()
|
||||||
res({ status: 'OK' })
|
res({ status: 'OK' })
|
||||||
opts.metricsCallback([{ ...info, ...stats, ...authContext }])
|
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 }
|
} 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
|
break
|
||||||
case 'GetUserInfo':
|
case 'GetUserInfo':
|
||||||
try {
|
try {
|
||||||
if (!methods.GetUserInfo) throw new Error('method: GetUserInfo is not implemented')
|
if (!methods.GetUserInfo) throw new Error('method: GetUserInfo is not implemented')
|
||||||
const authContext = await opts.NostrUserAuthGuard(req.appId, req.authIdentifier)
|
const authContext = await opts.NostrUserAuthGuard(req.appId, req.authIdentifier)
|
||||||
stats.guard = process.hrtime.bigint()
|
stats.guard = process.hrtime.bigint()
|
||||||
authCtx = authContext
|
authCtx = authContext
|
||||||
stats.validate = stats.guard
|
stats.validate = stats.guard
|
||||||
const response = await methods.GetUserInfo({ rpcName: 'GetUserInfo', ctx: authContext })
|
const response = await methods.GetUserInfo({ rpcName: 'GetUserInfo', ctx: authContext })
|
||||||
stats.handle = process.hrtime.bigint()
|
stats.handle = process.hrtime.bigint()
|
||||||
res({ status: 'OK', ...response })
|
res({ status: 'OK', ...response })
|
||||||
opts.metricsCallback([{ ...info, ...stats, ...authContext }])
|
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 }
|
} 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
|
break
|
||||||
case 'AddProduct':
|
case 'AddProduct':
|
||||||
try {
|
try {
|
||||||
if (!methods.AddProduct) throw new Error('method: AddProduct is not implemented')
|
if (!methods.AddProduct) throw new Error('method: AddProduct is not implemented')
|
||||||
const authContext = await opts.NostrUserAuthGuard(req.appId, req.authIdentifier)
|
const authContext = await opts.NostrUserAuthGuard(req.appId, req.authIdentifier)
|
||||||
stats.guard = process.hrtime.bigint()
|
stats.guard = process.hrtime.bigint()
|
||||||
authCtx = authContext
|
authCtx = authContext
|
||||||
const request = req.body
|
const request = req.body
|
||||||
const error = Types.AddProductRequestValidate(request)
|
const error = Types.AddProductRequestValidate(request)
|
||||||
stats.validate = process.hrtime.bigint()
|
stats.validate = process.hrtime.bigint()
|
||||||
if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback)
|
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 })
|
const response = await methods.AddProduct({ rpcName: 'AddProduct', ctx: authContext, req: request })
|
||||||
stats.handle = process.hrtime.bigint()
|
stats.handle = process.hrtime.bigint()
|
||||||
res({ status: 'OK', ...response })
|
res({ status: 'OK', ...response })
|
||||||
opts.metricsCallback([{ ...info, ...stats, ...authContext }])
|
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 }
|
} 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
|
break
|
||||||
case 'NewProductInvoice':
|
case 'NewProductInvoice':
|
||||||
try {
|
try {
|
||||||
if (!methods.NewProductInvoice) throw new Error('method: NewProductInvoice is not implemented')
|
if (!methods.NewProductInvoice) throw new Error('method: NewProductInvoice is not implemented')
|
||||||
const authContext = await opts.NostrUserAuthGuard(req.appId, req.authIdentifier)
|
const authContext = await opts.NostrUserAuthGuard(req.appId, req.authIdentifier)
|
||||||
stats.guard = process.hrtime.bigint()
|
stats.guard = process.hrtime.bigint()
|
||||||
authCtx = authContext
|
authCtx = authContext
|
||||||
stats.validate = stats.guard
|
stats.validate = stats.guard
|
||||||
const response = await methods.NewProductInvoice({ rpcName: 'NewProductInvoice', ctx: authContext, query: req.query || {} })
|
const response = await methods.NewProductInvoice({ rpcName: 'NewProductInvoice', ctx: authContext, query: req.query || {} })
|
||||||
stats.handle = process.hrtime.bigint()
|
stats.handle = process.hrtime.bigint()
|
||||||
res({ status: 'OK', ...response })
|
res({ status: 'OK', ...response })
|
||||||
opts.metricsCallback([{ ...info, ...stats, ...authContext }])
|
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 }
|
} 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
|
break
|
||||||
case 'GetUserOperations':
|
case 'GetUserOperations':
|
||||||
try {
|
try {
|
||||||
if (!methods.GetUserOperations) throw new Error('method: GetUserOperations is not implemented')
|
if (!methods.GetUserOperations) throw new Error('method: GetUserOperations is not implemented')
|
||||||
const authContext = await opts.NostrUserAuthGuard(req.appId, req.authIdentifier)
|
const authContext = await opts.NostrUserAuthGuard(req.appId, req.authIdentifier)
|
||||||
stats.guard = process.hrtime.bigint()
|
stats.guard = process.hrtime.bigint()
|
||||||
authCtx = authContext
|
authCtx = authContext
|
||||||
const request = req.body
|
const request = req.body
|
||||||
const error = Types.GetUserOperationsRequestValidate(request)
|
const error = Types.GetUserOperationsRequestValidate(request)
|
||||||
stats.validate = process.hrtime.bigint()
|
stats.validate = process.hrtime.bigint()
|
||||||
if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback)
|
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 })
|
const response = await methods.GetUserOperations({ rpcName: 'GetUserOperations', ctx: authContext, req: request })
|
||||||
stats.handle = process.hrtime.bigint()
|
stats.handle = process.hrtime.bigint()
|
||||||
res({ status: 'OK', ...response })
|
res({ status: 'OK', ...response })
|
||||||
opts.metricsCallback([{ ...info, ...stats, ...authContext }])
|
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 }
|
} 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
|
break
|
||||||
case 'NewAddress':
|
case 'NewAddress':
|
||||||
try {
|
try {
|
||||||
if (!methods.NewAddress) throw new Error('method: NewAddress is not implemented')
|
if (!methods.NewAddress) throw new Error('method: NewAddress is not implemented')
|
||||||
const authContext = await opts.NostrUserAuthGuard(req.appId, req.authIdentifier)
|
const authContext = await opts.NostrUserAuthGuard(req.appId, req.authIdentifier)
|
||||||
stats.guard = process.hrtime.bigint()
|
stats.guard = process.hrtime.bigint()
|
||||||
authCtx = authContext
|
authCtx = authContext
|
||||||
const request = req.body
|
const request = req.body
|
||||||
const error = Types.NewAddressRequestValidate(request)
|
const error = Types.NewAddressRequestValidate(request)
|
||||||
stats.validate = process.hrtime.bigint()
|
stats.validate = process.hrtime.bigint()
|
||||||
if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback)
|
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 })
|
const response = await methods.NewAddress({ rpcName: 'NewAddress', ctx: authContext, req: request })
|
||||||
stats.handle = process.hrtime.bigint()
|
stats.handle = process.hrtime.bigint()
|
||||||
res({ status: 'OK', ...response })
|
res({ status: 'OK', ...response })
|
||||||
opts.metricsCallback([{ ...info, ...stats, ...authContext }])
|
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 }
|
} 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
|
break
|
||||||
case 'PayAddress':
|
case 'PayAddress':
|
||||||
try {
|
try {
|
||||||
if (!methods.PayAddress) throw new Error('method: PayAddress is not implemented')
|
if (!methods.PayAddress) throw new Error('method: PayAddress is not implemented')
|
||||||
const authContext = await opts.NostrUserAuthGuard(req.appId, req.authIdentifier)
|
const authContext = await opts.NostrUserAuthGuard(req.appId, req.authIdentifier)
|
||||||
stats.guard = process.hrtime.bigint()
|
stats.guard = process.hrtime.bigint()
|
||||||
authCtx = authContext
|
authCtx = authContext
|
||||||
const request = req.body
|
const request = req.body
|
||||||
const error = Types.PayAddressRequestValidate(request)
|
const error = Types.PayAddressRequestValidate(request)
|
||||||
stats.validate = process.hrtime.bigint()
|
stats.validate = process.hrtime.bigint()
|
||||||
if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback)
|
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 })
|
const response = await methods.PayAddress({ rpcName: 'PayAddress', ctx: authContext, req: request })
|
||||||
stats.handle = process.hrtime.bigint()
|
stats.handle = process.hrtime.bigint()
|
||||||
res({ status: 'OK', ...response })
|
res({ status: 'OK', ...response })
|
||||||
opts.metricsCallback([{ ...info, ...stats, ...authContext }])
|
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 }
|
} 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
|
break
|
||||||
case 'NewInvoice':
|
case 'NewInvoice':
|
||||||
try {
|
try {
|
||||||
if (!methods.NewInvoice) throw new Error('method: NewInvoice is not implemented')
|
if (!methods.NewInvoice) throw new Error('method: NewInvoice is not implemented')
|
||||||
const authContext = await opts.NostrUserAuthGuard(req.appId, req.authIdentifier)
|
const authContext = await opts.NostrUserAuthGuard(req.appId, req.authIdentifier)
|
||||||
stats.guard = process.hrtime.bigint()
|
stats.guard = process.hrtime.bigint()
|
||||||
authCtx = authContext
|
authCtx = authContext
|
||||||
const request = req.body
|
const request = req.body
|
||||||
const error = Types.NewInvoiceRequestValidate(request)
|
const error = Types.NewInvoiceRequestValidate(request)
|
||||||
stats.validate = process.hrtime.bigint()
|
stats.validate = process.hrtime.bigint()
|
||||||
if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback)
|
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 })
|
const response = await methods.NewInvoice({ rpcName: 'NewInvoice', ctx: authContext, req: request })
|
||||||
stats.handle = process.hrtime.bigint()
|
stats.handle = process.hrtime.bigint()
|
||||||
res({ status: 'OK', ...response })
|
res({ status: 'OK', ...response })
|
||||||
opts.metricsCallback([{ ...info, ...stats, ...authContext }])
|
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 }
|
} 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
|
break
|
||||||
case 'DecodeInvoice':
|
case 'DecodeInvoice':
|
||||||
try {
|
try {
|
||||||
if (!methods.DecodeInvoice) throw new Error('method: DecodeInvoice is not implemented')
|
if (!methods.DecodeInvoice) throw new Error('method: DecodeInvoice is not implemented')
|
||||||
const authContext = await opts.NostrUserAuthGuard(req.appId, req.authIdentifier)
|
const authContext = await opts.NostrUserAuthGuard(req.appId, req.authIdentifier)
|
||||||
stats.guard = process.hrtime.bigint()
|
stats.guard = process.hrtime.bigint()
|
||||||
authCtx = authContext
|
authCtx = authContext
|
||||||
const request = req.body
|
const request = req.body
|
||||||
const error = Types.DecodeInvoiceRequestValidate(request)
|
const error = Types.DecodeInvoiceRequestValidate(request)
|
||||||
stats.validate = process.hrtime.bigint()
|
stats.validate = process.hrtime.bigint()
|
||||||
if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback)
|
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 })
|
const response = await methods.DecodeInvoice({ rpcName: 'DecodeInvoice', ctx: authContext, req: request })
|
||||||
stats.handle = process.hrtime.bigint()
|
stats.handle = process.hrtime.bigint()
|
||||||
res({ status: 'OK', ...response })
|
res({ status: 'OK', ...response })
|
||||||
opts.metricsCallback([{ ...info, ...stats, ...authContext }])
|
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 }
|
} 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
|
break
|
||||||
case 'PayInvoice':
|
case 'PayInvoice':
|
||||||
try {
|
try {
|
||||||
if (!methods.PayInvoice) throw new Error('method: PayInvoice is not implemented')
|
if (!methods.PayInvoice) throw new Error('method: PayInvoice is not implemented')
|
||||||
const authContext = await opts.NostrUserAuthGuard(req.appId, req.authIdentifier)
|
const authContext = await opts.NostrUserAuthGuard(req.appId, req.authIdentifier)
|
||||||
stats.guard = process.hrtime.bigint()
|
stats.guard = process.hrtime.bigint()
|
||||||
authCtx = authContext
|
authCtx = authContext
|
||||||
const request = req.body
|
const request = req.body
|
||||||
const error = Types.PayInvoiceRequestValidate(request)
|
const error = Types.PayInvoiceRequestValidate(request)
|
||||||
stats.validate = process.hrtime.bigint()
|
stats.validate = process.hrtime.bigint()
|
||||||
if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback)
|
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 })
|
const response = await methods.PayInvoice({ rpcName: 'PayInvoice', ctx: authContext, req: request })
|
||||||
stats.handle = process.hrtime.bigint()
|
stats.handle = process.hrtime.bigint()
|
||||||
res({ status: 'OK', ...response })
|
res({ status: 'OK', ...response })
|
||||||
opts.metricsCallback([{ ...info, ...stats, ...authContext }])
|
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 }
|
} 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
|
break
|
||||||
case 'OpenChannel':
|
case 'OpenChannel':
|
||||||
try {
|
try {
|
||||||
if (!methods.OpenChannel) throw new Error('method: OpenChannel is not implemented')
|
if (!methods.OpenChannel) throw new Error('method: OpenChannel is not implemented')
|
||||||
const authContext = await opts.NostrUserAuthGuard(req.appId, req.authIdentifier)
|
const authContext = await opts.NostrUserAuthGuard(req.appId, req.authIdentifier)
|
||||||
stats.guard = process.hrtime.bigint()
|
stats.guard = process.hrtime.bigint()
|
||||||
authCtx = authContext
|
authCtx = authContext
|
||||||
const request = req.body
|
const request = req.body
|
||||||
const error = Types.OpenChannelRequestValidate(request)
|
const error = Types.OpenChannelRequestValidate(request)
|
||||||
stats.validate = process.hrtime.bigint()
|
stats.validate = process.hrtime.bigint()
|
||||||
if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback)
|
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 })
|
const response = await methods.OpenChannel({ rpcName: 'OpenChannel', ctx: authContext, req: request })
|
||||||
stats.handle = process.hrtime.bigint()
|
stats.handle = process.hrtime.bigint()
|
||||||
res({ status: 'OK', ...response })
|
res({ status: 'OK', ...response })
|
||||||
opts.metricsCallback([{ ...info, ...stats, ...authContext }])
|
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 }
|
} 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
|
break
|
||||||
case 'GetLnurlWithdrawLink':
|
case 'GetLnurlWithdrawLink':
|
||||||
try {
|
try {
|
||||||
if (!methods.GetLnurlWithdrawLink) throw new Error('method: GetLnurlWithdrawLink is not implemented')
|
if (!methods.GetLnurlWithdrawLink) throw new Error('method: GetLnurlWithdrawLink is not implemented')
|
||||||
const authContext = await opts.NostrUserAuthGuard(req.appId, req.authIdentifier)
|
const authContext = await opts.NostrUserAuthGuard(req.appId, req.authIdentifier)
|
||||||
stats.guard = process.hrtime.bigint()
|
stats.guard = process.hrtime.bigint()
|
||||||
authCtx = authContext
|
authCtx = authContext
|
||||||
stats.validate = stats.guard
|
stats.validate = stats.guard
|
||||||
const response = await methods.GetLnurlWithdrawLink({ rpcName: 'GetLnurlWithdrawLink', ctx: authContext })
|
const response = await methods.GetLnurlWithdrawLink({ rpcName: 'GetLnurlWithdrawLink', ctx: authContext })
|
||||||
stats.handle = process.hrtime.bigint()
|
stats.handle = process.hrtime.bigint()
|
||||||
res({ status: 'OK', ...response })
|
res({ status: 'OK', ...response })
|
||||||
opts.metricsCallback([{ ...info, ...stats, ...authContext }])
|
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 }
|
} 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
|
break
|
||||||
case 'GetLnurlPayLink':
|
case 'GetLnurlPayLink':
|
||||||
try {
|
try {
|
||||||
if (!methods.GetLnurlPayLink) throw new Error('method: GetLnurlPayLink is not implemented')
|
if (!methods.GetLnurlPayLink) throw new Error('method: GetLnurlPayLink is not implemented')
|
||||||
const authContext = await opts.NostrUserAuthGuard(req.appId, req.authIdentifier)
|
const authContext = await opts.NostrUserAuthGuard(req.appId, req.authIdentifier)
|
||||||
stats.guard = process.hrtime.bigint()
|
stats.guard = process.hrtime.bigint()
|
||||||
authCtx = authContext
|
authCtx = authContext
|
||||||
stats.validate = stats.guard
|
stats.validate = stats.guard
|
||||||
const response = await methods.GetLnurlPayLink({ rpcName: 'GetLnurlPayLink', ctx: authContext })
|
const response = await methods.GetLnurlPayLink({ rpcName: 'GetLnurlPayLink', ctx: authContext })
|
||||||
stats.handle = process.hrtime.bigint()
|
stats.handle = process.hrtime.bigint()
|
||||||
res({ status: 'OK', ...response })
|
res({ status: 'OK', ...response })
|
||||||
opts.metricsCallback([{ ...info, ...stats, ...authContext }])
|
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 }
|
} 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
|
break
|
||||||
case 'GetLNURLChannelLink':
|
case 'GetLNURLChannelLink':
|
||||||
try {
|
try {
|
||||||
if (!methods.GetLNURLChannelLink) throw new Error('method: GetLNURLChannelLink is not implemented')
|
if (!methods.GetLNURLChannelLink) throw new Error('method: GetLNURLChannelLink is not implemented')
|
||||||
const authContext = await opts.NostrUserAuthGuard(req.appId, req.authIdentifier)
|
const authContext = await opts.NostrUserAuthGuard(req.appId, req.authIdentifier)
|
||||||
stats.guard = process.hrtime.bigint()
|
stats.guard = process.hrtime.bigint()
|
||||||
authCtx = authContext
|
authCtx = authContext
|
||||||
stats.validate = stats.guard
|
stats.validate = stats.guard
|
||||||
const response = await methods.GetLNURLChannelLink({ rpcName: 'GetLNURLChannelLink', ctx: authContext })
|
const response = await methods.GetLNURLChannelLink({ rpcName: 'GetLNURLChannelLink', ctx: authContext })
|
||||||
stats.handle = process.hrtime.bigint()
|
stats.handle = process.hrtime.bigint()
|
||||||
res({ status: 'OK', ...response })
|
res({ status: 'OK', ...response })
|
||||||
opts.metricsCallback([{ ...info, ...stats, ...authContext }])
|
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 }
|
} 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
|
break
|
||||||
case 'GetLiveUserOperations':
|
case 'GetLiveUserOperations':
|
||||||
try {
|
try {
|
||||||
if (!methods.GetLiveUserOperations) throw new Error('method: GetLiveUserOperations is not implemented')
|
if (!methods.GetLiveUserOperations) throw new Error('method: GetLiveUserOperations is not implemented')
|
||||||
const authContext = await opts.NostrUserAuthGuard(req.appId, req.authIdentifier)
|
const authContext = await opts.NostrUserAuthGuard(req.appId, req.authIdentifier)
|
||||||
stats.guard = process.hrtime.bigint()
|
stats.guard = process.hrtime.bigint()
|
||||||
authCtx = authContext
|
authCtx = authContext
|
||||||
stats.validate = stats.guard
|
stats.validate = stats.guard
|
||||||
methods.GetLiveUserOperations({
|
methods.GetLiveUserOperations({
|
||||||
rpcName: 'GetLiveUserOperations', ctx: authContext, cb: (response, err) => {
|
rpcName: 'GetLiveUserOperations', ctx: authContext, cb: (response, err) => {
|
||||||
stats.handle = process.hrtime.bigint()
|
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 }]) }
|
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 }
|
} 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
|
break
|
||||||
case 'GetMigrationUpdate':
|
case 'GetMigrationUpdate':
|
||||||
try {
|
try {
|
||||||
if (!methods.GetMigrationUpdate) throw new Error('method: GetMigrationUpdate is not implemented')
|
if (!methods.GetMigrationUpdate) throw new Error('method: GetMigrationUpdate is not implemented')
|
||||||
const authContext = await opts.NostrUserAuthGuard(req.appId, req.authIdentifier)
|
const authContext = await opts.NostrUserAuthGuard(req.appId, req.authIdentifier)
|
||||||
stats.guard = process.hrtime.bigint()
|
stats.guard = process.hrtime.bigint()
|
||||||
authCtx = authContext
|
authCtx = authContext
|
||||||
stats.validate = stats.guard
|
stats.validate = stats.guard
|
||||||
methods.GetMigrationUpdate({
|
methods.GetMigrationUpdate({
|
||||||
rpcName: 'GetMigrationUpdate', ctx: authContext, cb: (response, err) => {
|
rpcName: 'GetMigrationUpdate', ctx: authContext, cb: (response, err) => {
|
||||||
stats.handle = process.hrtime.bigint()
|
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 }]) }
|
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 }
|
} 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
|
break
|
||||||
case 'GetHttpCreds':
|
case 'GetHttpCreds':
|
||||||
try {
|
try {
|
||||||
if (!methods.GetHttpCreds) throw new Error('method: GetHttpCreds is not implemented')
|
if (!methods.GetHttpCreds) throw new Error('method: GetHttpCreds is not implemented')
|
||||||
const authContext = await opts.NostrUserAuthGuard(req.appId, req.authIdentifier)
|
const authContext = await opts.NostrUserAuthGuard(req.appId, req.authIdentifier)
|
||||||
stats.guard = process.hrtime.bigint()
|
stats.guard = process.hrtime.bigint()
|
||||||
authCtx = authContext
|
authCtx = authContext
|
||||||
stats.validate = stats.guard
|
stats.validate = stats.guard
|
||||||
methods.GetHttpCreds({
|
methods.GetHttpCreds({
|
||||||
rpcName: 'GetHttpCreds', ctx: authContext, cb: (response, err) => {
|
rpcName: 'GetHttpCreds', ctx: authContext, cb: (response, err) => {
|
||||||
stats.handle = process.hrtime.bigint()
|
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 }]) }
|
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 }
|
} 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
|
break
|
||||||
case 'BatchUser':
|
case 'BatchUser':
|
||||||
try {
|
try {
|
||||||
info.batch = true
|
info.batch = true
|
||||||
const requests = req.body.requests as Types.UserMethodInputs[]
|
const requests = req.body.requests as Types.UserMethodInputs[]
|
||||||
if (!Array.isArray(requests)) throw new Error('invalid body, is not an array')
|
if (!Array.isArray(requests)) throw new Error('invalid body, is not an array')
|
||||||
info.batchSize = requests.length
|
info.batchSize = requests.length
|
||||||
if (requests.length > 10) throw new Error('too many requests in the batch')
|
if (requests.length > 10) throw new Error('too many requests in the batch')
|
||||||
const ctx = await opts.NostrUserAuthGuard(req.appId, req.authIdentifier)
|
const ctx = await opts.NostrUserAuthGuard(req.appId, req.authIdentifier)
|
||||||
stats.guard = process.hrtime.bigint()
|
stats.guard = process.hrtime.bigint()
|
||||||
authCtx = ctx
|
authCtx = ctx
|
||||||
stats.validate = stats.guard
|
stats.validate = stats.guard
|
||||||
const responses = []
|
const responses = []
|
||||||
const callsMetrics: Types.RequestMetric[] = []
|
const callsMetrics: Types.RequestMetric[] = []
|
||||||
for (let i = 0; i < requests.length; i++) {
|
for (let i = 0; i < requests.length; i++) {
|
||||||
const operation = requests[i]
|
const operation = requests[i]
|
||||||
const opInfo: Types.RequestInfo = { rpcName: operation.rpcName, batch: true, nostr: true, batchSize: 0 }
|
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 }
|
const opStats: Types.RequestStats = { startMs, start: startTime, parse: stats.parse, guard: stats.guard, validate: 0n, handle: 0n }
|
||||||
try {
|
try {
|
||||||
switch (operation.rpcName) {
|
switch (operation.rpcName) {
|
||||||
case 'LinkNPubThroughToken':
|
case 'LinkNPubThroughToken':
|
||||||
if (!methods.LinkNPubThroughToken) {
|
if (!methods.LinkNPubThroughToken) {
|
||||||
throw new Error('method not defined: LinkNPubThroughToken')
|
throw new Error('method not defined: LinkNPubThroughToken')
|
||||||
} else {
|
} else {
|
||||||
const error = Types.LinkNPubThroughTokenRequestValidate(operation.req)
|
const error = Types.LinkNPubThroughTokenRequestValidate(operation.req)
|
||||||
opStats.validate = process.hrtime.bigint()
|
opStats.validate = process.hrtime.bigint()
|
||||||
if (error !== null) throw error
|
if (error !== null) throw error
|
||||||
await methods.LinkNPubThroughToken({ ...operation, ctx }); responses.push({ status: 'OK' })
|
await methods.LinkNPubThroughToken({ ...operation, ctx }); responses.push({ status: 'OK' })
|
||||||
opStats.handle = process.hrtime.bigint()
|
opStats.handle = process.hrtime.bigint()
|
||||||
callsMetrics.push({ ...opInfo, ...opStats, ...ctx })
|
callsMetrics.push({ ...opInfo, ...opStats, ...ctx })
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
case 'UserHealth':
|
case 'UserHealth':
|
||||||
if (!methods.UserHealth) {
|
if (!methods.UserHealth) {
|
||||||
throw new Error('method not defined: UserHealth')
|
throw new Error('method not defined: UserHealth')
|
||||||
} else {
|
} else {
|
||||||
opStats.validate = opStats.guard
|
opStats.validate = opStats.guard
|
||||||
await methods.UserHealth({ ...operation, ctx }); responses.push({ status: 'OK' })
|
await methods.UserHealth({ ...operation, ctx }); responses.push({ status: 'OK' })
|
||||||
opStats.handle = process.hrtime.bigint()
|
opStats.handle = process.hrtime.bigint()
|
||||||
callsMetrics.push({ ...opInfo, ...opStats, ...ctx })
|
callsMetrics.push({ ...opInfo, ...opStats, ...ctx })
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
case 'GetUserInfo':
|
case 'GetUserInfo':
|
||||||
if (!methods.GetUserInfo) {
|
if (!methods.GetUserInfo) {
|
||||||
throw new Error('method not defined: GetUserInfo')
|
throw new Error('method not defined: GetUserInfo')
|
||||||
} else {
|
} else {
|
||||||
opStats.validate = opStats.guard
|
opStats.validate = opStats.guard
|
||||||
const res = await methods.GetUserInfo({ ...operation, ctx }); responses.push({ status: 'OK', ...res })
|
const res = await methods.GetUserInfo({ ...operation, ctx }); responses.push({ status: 'OK', ...res })
|
||||||
opStats.handle = process.hrtime.bigint()
|
opStats.handle = process.hrtime.bigint()
|
||||||
callsMetrics.push({ ...opInfo, ...opStats, ...ctx })
|
callsMetrics.push({ ...opInfo, ...opStats, ...ctx })
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
case 'AddProduct':
|
case 'AddProduct':
|
||||||
if (!methods.AddProduct) {
|
if (!methods.AddProduct) {
|
||||||
throw new Error('method not defined: AddProduct')
|
throw new Error('method not defined: AddProduct')
|
||||||
} else {
|
} else {
|
||||||
const error = Types.AddProductRequestValidate(operation.req)
|
const error = Types.AddProductRequestValidate(operation.req)
|
||||||
opStats.validate = process.hrtime.bigint()
|
opStats.validate = process.hrtime.bigint()
|
||||||
if (error !== null) throw error
|
if (error !== null) throw error
|
||||||
const res = await methods.AddProduct({ ...operation, ctx }); responses.push({ status: 'OK', ...res })
|
const res = await methods.AddProduct({ ...operation, ctx }); responses.push({ status: 'OK', ...res })
|
||||||
opStats.handle = process.hrtime.bigint()
|
opStats.handle = process.hrtime.bigint()
|
||||||
callsMetrics.push({ ...opInfo, ...opStats, ...ctx })
|
callsMetrics.push({ ...opInfo, ...opStats, ...ctx })
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
case 'NewProductInvoice':
|
case 'NewProductInvoice':
|
||||||
if (!methods.NewProductInvoice) {
|
if (!methods.NewProductInvoice) {
|
||||||
throw new Error('method not defined: NewProductInvoice')
|
throw new Error('method not defined: NewProductInvoice')
|
||||||
} else {
|
} else {
|
||||||
opStats.validate = opStats.guard
|
opStats.validate = opStats.guard
|
||||||
const res = await methods.NewProductInvoice({ ...operation, ctx }); responses.push({ status: 'OK', ...res })
|
const res = await methods.NewProductInvoice({ ...operation, ctx }); responses.push({ status: 'OK', ...res })
|
||||||
opStats.handle = process.hrtime.bigint()
|
opStats.handle = process.hrtime.bigint()
|
||||||
callsMetrics.push({ ...opInfo, ...opStats, ...ctx })
|
callsMetrics.push({ ...opInfo, ...opStats, ...ctx })
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
case 'GetUserOperations':
|
case 'GetUserOperations':
|
||||||
if (!methods.GetUserOperations) {
|
if (!methods.GetUserOperations) {
|
||||||
throw new Error('method not defined: GetUserOperations')
|
throw new Error('method not defined: GetUserOperations')
|
||||||
} else {
|
} else {
|
||||||
const error = Types.GetUserOperationsRequestValidate(operation.req)
|
const error = Types.GetUserOperationsRequestValidate(operation.req)
|
||||||
opStats.validate = process.hrtime.bigint()
|
opStats.validate = process.hrtime.bigint()
|
||||||
if (error !== null) throw error
|
if (error !== null) throw error
|
||||||
const res = await methods.GetUserOperations({ ...operation, ctx }); responses.push({ status: 'OK', ...res })
|
const res = await methods.GetUserOperations({ ...operation, ctx }); responses.push({ status: 'OK', ...res })
|
||||||
opStats.handle = process.hrtime.bigint()
|
opStats.handle = process.hrtime.bigint()
|
||||||
callsMetrics.push({ ...opInfo, ...opStats, ...ctx })
|
callsMetrics.push({ ...opInfo, ...opStats, ...ctx })
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
case 'NewAddress':
|
case 'NewAddress':
|
||||||
if (!methods.NewAddress) {
|
if (!methods.NewAddress) {
|
||||||
throw new Error('method not defined: NewAddress')
|
throw new Error('method not defined: NewAddress')
|
||||||
} else {
|
} else {
|
||||||
const error = Types.NewAddressRequestValidate(operation.req)
|
const error = Types.NewAddressRequestValidate(operation.req)
|
||||||
opStats.validate = process.hrtime.bigint()
|
opStats.validate = process.hrtime.bigint()
|
||||||
if (error !== null) throw error
|
if (error !== null) throw error
|
||||||
const res = await methods.NewAddress({ ...operation, ctx }); responses.push({ status: 'OK', ...res })
|
const res = await methods.NewAddress({ ...operation, ctx }); responses.push({ status: 'OK', ...res })
|
||||||
opStats.handle = process.hrtime.bigint()
|
opStats.handle = process.hrtime.bigint()
|
||||||
callsMetrics.push({ ...opInfo, ...opStats, ...ctx })
|
callsMetrics.push({ ...opInfo, ...opStats, ...ctx })
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
case 'PayAddress':
|
case 'PayAddress':
|
||||||
if (!methods.PayAddress) {
|
if (!methods.PayAddress) {
|
||||||
throw new Error('method not defined: PayAddress')
|
throw new Error('method not defined: PayAddress')
|
||||||
} else {
|
} else {
|
||||||
const error = Types.PayAddressRequestValidate(operation.req)
|
const error = Types.PayAddressRequestValidate(operation.req)
|
||||||
opStats.validate = process.hrtime.bigint()
|
opStats.validate = process.hrtime.bigint()
|
||||||
if (error !== null) throw error
|
if (error !== null) throw error
|
||||||
const res = await methods.PayAddress({ ...operation, ctx }); responses.push({ status: 'OK', ...res })
|
const res = await methods.PayAddress({ ...operation, ctx }); responses.push({ status: 'OK', ...res })
|
||||||
opStats.handle = process.hrtime.bigint()
|
opStats.handle = process.hrtime.bigint()
|
||||||
callsMetrics.push({ ...opInfo, ...opStats, ...ctx })
|
callsMetrics.push({ ...opInfo, ...opStats, ...ctx })
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
case 'NewInvoice':
|
case 'NewInvoice':
|
||||||
if (!methods.NewInvoice) {
|
if (!methods.NewInvoice) {
|
||||||
throw new Error('method not defined: NewInvoice')
|
throw new Error('method not defined: NewInvoice')
|
||||||
} else {
|
} else {
|
||||||
const error = Types.NewInvoiceRequestValidate(operation.req)
|
const error = Types.NewInvoiceRequestValidate(operation.req)
|
||||||
opStats.validate = process.hrtime.bigint()
|
opStats.validate = process.hrtime.bigint()
|
||||||
if (error !== null) throw error
|
if (error !== null) throw error
|
||||||
const res = await methods.NewInvoice({ ...operation, ctx }); responses.push({ status: 'OK', ...res })
|
const res = await methods.NewInvoice({ ...operation, ctx }); responses.push({ status: 'OK', ...res })
|
||||||
opStats.handle = process.hrtime.bigint()
|
opStats.handle = process.hrtime.bigint()
|
||||||
callsMetrics.push({ ...opInfo, ...opStats, ...ctx })
|
callsMetrics.push({ ...opInfo, ...opStats, ...ctx })
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
case 'DecodeInvoice':
|
case 'DecodeInvoice':
|
||||||
if (!methods.DecodeInvoice) {
|
if (!methods.DecodeInvoice) {
|
||||||
throw new Error('method not defined: DecodeInvoice')
|
throw new Error('method not defined: DecodeInvoice')
|
||||||
} else {
|
} else {
|
||||||
const error = Types.DecodeInvoiceRequestValidate(operation.req)
|
const error = Types.DecodeInvoiceRequestValidate(operation.req)
|
||||||
opStats.validate = process.hrtime.bigint()
|
opStats.validate = process.hrtime.bigint()
|
||||||
if (error !== null) throw error
|
if (error !== null) throw error
|
||||||
const res = await methods.DecodeInvoice({ ...operation, ctx }); responses.push({ status: 'OK', ...res })
|
const res = await methods.DecodeInvoice({ ...operation, ctx }); responses.push({ status: 'OK', ...res })
|
||||||
opStats.handle = process.hrtime.bigint()
|
opStats.handle = process.hrtime.bigint()
|
||||||
callsMetrics.push({ ...opInfo, ...opStats, ...ctx })
|
callsMetrics.push({ ...opInfo, ...opStats, ...ctx })
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
case 'PayInvoice':
|
case 'PayInvoice':
|
||||||
if (!methods.PayInvoice) {
|
if (!methods.PayInvoice) {
|
||||||
throw new Error('method not defined: PayInvoice')
|
throw new Error('method not defined: PayInvoice')
|
||||||
} else {
|
} else {
|
||||||
const error = Types.PayInvoiceRequestValidate(operation.req)
|
const error = Types.PayInvoiceRequestValidate(operation.req)
|
||||||
opStats.validate = process.hrtime.bigint()
|
opStats.validate = process.hrtime.bigint()
|
||||||
if (error !== null) throw error
|
if (error !== null) throw error
|
||||||
const res = await methods.PayInvoice({ ...operation, ctx }); responses.push({ status: 'OK', ...res })
|
const res = await methods.PayInvoice({ ...operation, ctx }); responses.push({ status: 'OK', ...res })
|
||||||
opStats.handle = process.hrtime.bigint()
|
opStats.handle = process.hrtime.bigint()
|
||||||
callsMetrics.push({ ...opInfo, ...opStats, ...ctx })
|
callsMetrics.push({ ...opInfo, ...opStats, ...ctx })
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
case 'OpenChannel':
|
case 'OpenChannel':
|
||||||
if (!methods.OpenChannel) {
|
if (!methods.OpenChannel) {
|
||||||
throw new Error('method not defined: OpenChannel')
|
throw new Error('method not defined: OpenChannel')
|
||||||
} else {
|
} else {
|
||||||
const error = Types.OpenChannelRequestValidate(operation.req)
|
const error = Types.OpenChannelRequestValidate(operation.req)
|
||||||
opStats.validate = process.hrtime.bigint()
|
opStats.validate = process.hrtime.bigint()
|
||||||
if (error !== null) throw error
|
if (error !== null) throw error
|
||||||
const res = await methods.OpenChannel({ ...operation, ctx }); responses.push({ status: 'OK', ...res })
|
const res = await methods.OpenChannel({ ...operation, ctx }); responses.push({ status: 'OK', ...res })
|
||||||
opStats.handle = process.hrtime.bigint()
|
opStats.handle = process.hrtime.bigint()
|
||||||
callsMetrics.push({ ...opInfo, ...opStats, ...ctx })
|
callsMetrics.push({ ...opInfo, ...opStats, ...ctx })
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
case 'GetLnurlWithdrawLink':
|
case 'GetLnurlWithdrawLink':
|
||||||
if (!methods.GetLnurlWithdrawLink) {
|
if (!methods.GetLnurlWithdrawLink) {
|
||||||
throw new Error('method not defined: GetLnurlWithdrawLink')
|
throw new Error('method not defined: GetLnurlWithdrawLink')
|
||||||
} else {
|
} else {
|
||||||
opStats.validate = opStats.guard
|
opStats.validate = opStats.guard
|
||||||
const res = await methods.GetLnurlWithdrawLink({ ...operation, ctx }); responses.push({ status: 'OK', ...res })
|
const res = await methods.GetLnurlWithdrawLink({ ...operation, ctx }); responses.push({ status: 'OK', ...res })
|
||||||
opStats.handle = process.hrtime.bigint()
|
opStats.handle = process.hrtime.bigint()
|
||||||
callsMetrics.push({ ...opInfo, ...opStats, ...ctx })
|
callsMetrics.push({ ...opInfo, ...opStats, ...ctx })
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
case 'GetLnurlPayLink':
|
case 'GetLnurlPayLink':
|
||||||
if (!methods.GetLnurlPayLink) {
|
if (!methods.GetLnurlPayLink) {
|
||||||
throw new Error('method not defined: GetLnurlPayLink')
|
throw new Error('method not defined: GetLnurlPayLink')
|
||||||
} else {
|
} else {
|
||||||
opStats.validate = opStats.guard
|
opStats.validate = opStats.guard
|
||||||
const res = await methods.GetLnurlPayLink({ ...operation, ctx }); responses.push({ status: 'OK', ...res })
|
const res = await methods.GetLnurlPayLink({ ...operation, ctx }); responses.push({ status: 'OK', ...res })
|
||||||
opStats.handle = process.hrtime.bigint()
|
opStats.handle = process.hrtime.bigint()
|
||||||
callsMetrics.push({ ...opInfo, ...opStats, ...ctx })
|
callsMetrics.push({ ...opInfo, ...opStats, ...ctx })
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
case 'GetLNURLChannelLink':
|
case 'GetLNURLChannelLink':
|
||||||
if (!methods.GetLNURLChannelLink) {
|
if (!methods.GetLNURLChannelLink) {
|
||||||
throw new Error('method not defined: GetLNURLChannelLink')
|
throw new Error('method not defined: GetLNURLChannelLink')
|
||||||
} else {
|
} else {
|
||||||
opStats.validate = opStats.guard
|
opStats.validate = opStats.guard
|
||||||
const res = await methods.GetLNURLChannelLink({ ...operation, ctx }); responses.push({ status: 'OK', ...res })
|
const res = await methods.GetLNURLChannelLink({ ...operation, ctx }); responses.push({ status: 'OK', ...res })
|
||||||
opStats.handle = process.hrtime.bigint()
|
opStats.handle = process.hrtime.bigint()
|
||||||
callsMetrics.push({ ...opInfo, ...opStats, ...ctx })
|
callsMetrics.push({ ...opInfo, ...opStats, ...ctx })
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
default:
|
default:
|
||||||
throw new Error('unkown rpcName')
|
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 }) }
|
} 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()
|
stats.handle = process.hrtime.bigint()
|
||||||
res({ status: 'OK', responses })
|
res({ status: 'OK', responses })
|
||||||
opts.metricsCallback([{ ...info, ...stats, ...ctx }, ...callsMetrics])
|
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 }
|
} 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
|
break
|
||||||
default: logger.error('unknown rpc call name from nostr event:' + req.rpcName)
|
default: logger.error('unknown rpc call name from nostr event:' + req.rpcName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,128 +1,128 @@
|
||||||
// @generated by protobuf-ts 2.8.1
|
// @generated by protobuf-ts 2.8.1
|
||||||
// @generated from protobuf file "chainnotifier.proto" (package "chainrpc", syntax proto3)
|
// @generated from protobuf file "chainnotifier.proto" (package "chainrpc", syntax proto3)
|
||||||
// tslint:disable
|
// tslint:disable
|
||||||
import type { RpcTransport } from "@protobuf-ts/runtime-rpc";
|
import type { RpcTransport } from "@protobuf-ts/runtime-rpc";
|
||||||
import type { ServiceInfo } from "@protobuf-ts/runtime-rpc";
|
import type { ServiceInfo } from "@protobuf-ts/runtime-rpc";
|
||||||
import { ChainNotifier } from "./chainnotifier.js";
|
import { ChainNotifier } from "./chainnotifier.js";
|
||||||
import type { BlockEpoch } from "./chainnotifier.js";
|
import type { BlockEpoch } from "./chainnotifier.js";
|
||||||
import type { SpendEvent } from "./chainnotifier.js";
|
import type { SpendEvent } from "./chainnotifier.js";
|
||||||
import type { SpendRequest } from "./chainnotifier.js";
|
import type { SpendRequest } from "./chainnotifier.js";
|
||||||
import { stackIntercept } from "@protobuf-ts/runtime-rpc";
|
import { stackIntercept } from "@protobuf-ts/runtime-rpc";
|
||||||
import type { ConfEvent } from "./chainnotifier.js";
|
import type { ConfEvent } from "./chainnotifier.js";
|
||||||
import type { ConfRequest } from "./chainnotifier.js";
|
import type { ConfRequest } from "./chainnotifier.js";
|
||||||
import type { ServerStreamingCall } from "@protobuf-ts/runtime-rpc";
|
import type { ServerStreamingCall } from "@protobuf-ts/runtime-rpc";
|
||||||
import type { RpcOptions } from "@protobuf-ts/runtime-rpc";
|
import type { RpcOptions } from "@protobuf-ts/runtime-rpc";
|
||||||
/**
|
/**
|
||||||
* ChainNotifier is a service that can be used to get information about the
|
* ChainNotifier is a service that can be used to get information about the
|
||||||
* chain backend by registering notifiers for chain events.
|
* chain backend by registering notifiers for chain events.
|
||||||
*
|
*
|
||||||
* @generated from protobuf service chainrpc.ChainNotifier
|
* @generated from protobuf service chainrpc.ChainNotifier
|
||||||
*/
|
*/
|
||||||
export interface IChainNotifierClient {
|
export interface IChainNotifierClient {
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* RegisterConfirmationsNtfn is a synchronous response-streaming RPC that
|
* RegisterConfirmationsNtfn is a synchronous response-streaming RPC that
|
||||||
* registers an intent for a client to be notified once a confirmation request
|
* registers an intent for a client to be notified once a confirmation request
|
||||||
* has reached its required number of confirmations on-chain.
|
* has reached its required number of confirmations on-chain.
|
||||||
*
|
*
|
||||||
* A confirmation request must have a valid output script. It is also possible
|
* A confirmation request must have a valid output script. It is also possible
|
||||||
* to give a transaction ID. If the transaction ID is not set, a notification
|
* to give a transaction ID. If the transaction ID is not set, a notification
|
||||||
* is sent once the output script confirms. If the transaction ID is also set,
|
* is sent once the output script confirms. If the transaction ID is also set,
|
||||||
* a notification is sent once the output script confirms in the given
|
* a notification is sent once the output script confirms in the given
|
||||||
* transaction.
|
* transaction.
|
||||||
*
|
*
|
||||||
* @generated from protobuf rpc: RegisterConfirmationsNtfn(chainrpc.ConfRequest) returns (stream chainrpc.ConfEvent);
|
* @generated from protobuf rpc: RegisterConfirmationsNtfn(chainrpc.ConfRequest) returns (stream chainrpc.ConfEvent);
|
||||||
*/
|
*/
|
||||||
registerConfirmationsNtfn(input: ConfRequest, options?: RpcOptions): ServerStreamingCall<ConfRequest, ConfEvent>;
|
registerConfirmationsNtfn(input: ConfRequest, options?: RpcOptions): ServerStreamingCall<ConfRequest, ConfEvent>;
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* RegisterSpendNtfn is a synchronous response-streaming RPC that registers an
|
* RegisterSpendNtfn is a synchronous response-streaming RPC that registers an
|
||||||
* intent for a client to be notification once a spend request has been spent
|
* intent for a client to be notification once a spend request has been spent
|
||||||
* by a transaction that has confirmed on-chain.
|
* by a transaction that has confirmed on-chain.
|
||||||
*
|
*
|
||||||
* A client can specify whether the spend request should be for a particular
|
* A client can specify whether the spend request should be for a particular
|
||||||
* outpoint or for an output script by specifying a zero outpoint.
|
* outpoint or for an output script by specifying a zero outpoint.
|
||||||
*
|
*
|
||||||
* @generated from protobuf rpc: RegisterSpendNtfn(chainrpc.SpendRequest) returns (stream chainrpc.SpendEvent);
|
* @generated from protobuf rpc: RegisterSpendNtfn(chainrpc.SpendRequest) returns (stream chainrpc.SpendEvent);
|
||||||
*/
|
*/
|
||||||
registerSpendNtfn(input: SpendRequest, options?: RpcOptions): ServerStreamingCall<SpendRequest, SpendEvent>;
|
registerSpendNtfn(input: SpendRequest, options?: RpcOptions): ServerStreamingCall<SpendRequest, SpendEvent>;
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* RegisterBlockEpochNtfn is a synchronous response-streaming RPC that
|
* RegisterBlockEpochNtfn is a synchronous response-streaming RPC that
|
||||||
* registers an intent for a client to be notified of blocks in the chain. The
|
* registers an intent for a client to be notified of blocks in the chain. The
|
||||||
* stream will return a hash and height tuple of a block for each new/stale
|
* stream will return a hash and height tuple of a block for each new/stale
|
||||||
* block in the chain. It is the client's responsibility to determine whether
|
* block in the chain. It is the client's responsibility to determine whether
|
||||||
* the tuple returned is for a new or stale block in the chain.
|
* the tuple returned is for a new or stale block in the chain.
|
||||||
*
|
*
|
||||||
* A client can also request a historical backlog of blocks from a particular
|
* A client can also request a historical backlog of blocks from a particular
|
||||||
* point. This allows clients to be idempotent by ensuring that they do not
|
* point. This allows clients to be idempotent by ensuring that they do not
|
||||||
* missing processing a single block within the chain.
|
* missing processing a single block within the chain.
|
||||||
*
|
*
|
||||||
* @generated from protobuf rpc: RegisterBlockEpochNtfn(chainrpc.BlockEpoch) returns (stream chainrpc.BlockEpoch);
|
* @generated from protobuf rpc: RegisterBlockEpochNtfn(chainrpc.BlockEpoch) returns (stream chainrpc.BlockEpoch);
|
||||||
*/
|
*/
|
||||||
registerBlockEpochNtfn(input: BlockEpoch, options?: RpcOptions): ServerStreamingCall<BlockEpoch, BlockEpoch>;
|
registerBlockEpochNtfn(input: BlockEpoch, options?: RpcOptions): ServerStreamingCall<BlockEpoch, BlockEpoch>;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* ChainNotifier is a service that can be used to get information about the
|
* ChainNotifier is a service that can be used to get information about the
|
||||||
* chain backend by registering notifiers for chain events.
|
* chain backend by registering notifiers for chain events.
|
||||||
*
|
*
|
||||||
* @generated from protobuf service chainrpc.ChainNotifier
|
* @generated from protobuf service chainrpc.ChainNotifier
|
||||||
*/
|
*/
|
||||||
export class ChainNotifierClient implements IChainNotifierClient, ServiceInfo {
|
export class ChainNotifierClient implements IChainNotifierClient, ServiceInfo {
|
||||||
typeName = ChainNotifier.typeName;
|
typeName = ChainNotifier.typeName;
|
||||||
methods = ChainNotifier.methods;
|
methods = ChainNotifier.methods;
|
||||||
options = ChainNotifier.options;
|
options = ChainNotifier.options;
|
||||||
constructor(private readonly _transport: RpcTransport) {
|
constructor(private readonly _transport: RpcTransport) {
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* RegisterConfirmationsNtfn is a synchronous response-streaming RPC that
|
* RegisterConfirmationsNtfn is a synchronous response-streaming RPC that
|
||||||
* registers an intent for a client to be notified once a confirmation request
|
* registers an intent for a client to be notified once a confirmation request
|
||||||
* has reached its required number of confirmations on-chain.
|
* has reached its required number of confirmations on-chain.
|
||||||
*
|
*
|
||||||
* A confirmation request must have a valid output script. It is also possible
|
* A confirmation request must have a valid output script. It is also possible
|
||||||
* to give a transaction ID. If the transaction ID is not set, a notification
|
* to give a transaction ID. If the transaction ID is not set, a notification
|
||||||
* is sent once the output script confirms. If the transaction ID is also set,
|
* is sent once the output script confirms. If the transaction ID is also set,
|
||||||
* a notification is sent once the output script confirms in the given
|
* a notification is sent once the output script confirms in the given
|
||||||
* transaction.
|
* transaction.
|
||||||
*
|
*
|
||||||
* @generated from protobuf rpc: RegisterConfirmationsNtfn(chainrpc.ConfRequest) returns (stream chainrpc.ConfEvent);
|
* @generated from protobuf rpc: RegisterConfirmationsNtfn(chainrpc.ConfRequest) returns (stream chainrpc.ConfEvent);
|
||||||
*/
|
*/
|
||||||
registerConfirmationsNtfn(input: ConfRequest, options?: RpcOptions): ServerStreamingCall<ConfRequest, ConfEvent> {
|
registerConfirmationsNtfn(input: ConfRequest, options?: RpcOptions): ServerStreamingCall<ConfRequest, ConfEvent> {
|
||||||
const method = this.methods[0], opt = this._transport.mergeOptions(options);
|
const method = this.methods[0], opt = this._transport.mergeOptions(options);
|
||||||
return stackIntercept<ConfRequest, ConfEvent>("serverStreaming", this._transport, method, opt, input);
|
return stackIntercept<ConfRequest, ConfEvent>("serverStreaming", this._transport, method, opt, input);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* RegisterSpendNtfn is a synchronous response-streaming RPC that registers an
|
* RegisterSpendNtfn is a synchronous response-streaming RPC that registers an
|
||||||
* intent for a client to be notification once a spend request has been spent
|
* intent for a client to be notification once a spend request has been spent
|
||||||
* by a transaction that has confirmed on-chain.
|
* by a transaction that has confirmed on-chain.
|
||||||
*
|
*
|
||||||
* A client can specify whether the spend request should be for a particular
|
* A client can specify whether the spend request should be for a particular
|
||||||
* outpoint or for an output script by specifying a zero outpoint.
|
* outpoint or for an output script by specifying a zero outpoint.
|
||||||
*
|
*
|
||||||
* @generated from protobuf rpc: RegisterSpendNtfn(chainrpc.SpendRequest) returns (stream chainrpc.SpendEvent);
|
* @generated from protobuf rpc: RegisterSpendNtfn(chainrpc.SpendRequest) returns (stream chainrpc.SpendEvent);
|
||||||
*/
|
*/
|
||||||
registerSpendNtfn(input: SpendRequest, options?: RpcOptions): ServerStreamingCall<SpendRequest, SpendEvent> {
|
registerSpendNtfn(input: SpendRequest, options?: RpcOptions): ServerStreamingCall<SpendRequest, SpendEvent> {
|
||||||
const method = this.methods[1], opt = this._transport.mergeOptions(options);
|
const method = this.methods[1], opt = this._transport.mergeOptions(options);
|
||||||
return stackIntercept<SpendRequest, SpendEvent>("serverStreaming", this._transport, method, opt, input);
|
return stackIntercept<SpendRequest, SpendEvent>("serverStreaming", this._transport, method, opt, input);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* RegisterBlockEpochNtfn is a synchronous response-streaming RPC that
|
* RegisterBlockEpochNtfn is a synchronous response-streaming RPC that
|
||||||
* registers an intent for a client to be notified of blocks in the chain. The
|
* registers an intent for a client to be notified of blocks in the chain. The
|
||||||
* stream will return a hash and height tuple of a block for each new/stale
|
* stream will return a hash and height tuple of a block for each new/stale
|
||||||
* block in the chain. It is the client's responsibility to determine whether
|
* block in the chain. It is the client's responsibility to determine whether
|
||||||
* the tuple returned is for a new or stale block in the chain.
|
* the tuple returned is for a new or stale block in the chain.
|
||||||
*
|
*
|
||||||
* A client can also request a historical backlog of blocks from a particular
|
* A client can also request a historical backlog of blocks from a particular
|
||||||
* point. This allows clients to be idempotent by ensuring that they do not
|
* point. This allows clients to be idempotent by ensuring that they do not
|
||||||
* missing processing a single block within the chain.
|
* missing processing a single block within the chain.
|
||||||
*
|
*
|
||||||
* @generated from protobuf rpc: RegisterBlockEpochNtfn(chainrpc.BlockEpoch) returns (stream chainrpc.BlockEpoch);
|
* @generated from protobuf rpc: RegisterBlockEpochNtfn(chainrpc.BlockEpoch) returns (stream chainrpc.BlockEpoch);
|
||||||
*/
|
*/
|
||||||
registerBlockEpochNtfn(input: BlockEpoch, options?: RpcOptions): ServerStreamingCall<BlockEpoch, BlockEpoch> {
|
registerBlockEpochNtfn(input: BlockEpoch, options?: RpcOptions): ServerStreamingCall<BlockEpoch, BlockEpoch> {
|
||||||
const method = this.methods[2], opt = this._transport.mergeOptions(options);
|
const method = this.methods[2], opt = this._transport.mergeOptions(options);
|
||||||
return stackIntercept<BlockEpoch, BlockEpoch>("serverStreaming", this._transport, method, opt, input);
|
return stackIntercept<BlockEpoch, BlockEpoch>("serverStreaming", this._transport, method, opt, input);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,139 +1,139 @@
|
||||||
// @generated by protobuf-ts 2.8.1
|
// @generated by protobuf-ts 2.8.1
|
||||||
// @generated from protobuf file "invoices.proto" (package "invoicesrpc", syntax proto3)
|
// @generated from protobuf file "invoices.proto" (package "invoicesrpc", syntax proto3)
|
||||||
// tslint:disable
|
// tslint:disable
|
||||||
import type { RpcTransport } from "@protobuf-ts/runtime-rpc";
|
import type { RpcTransport } from "@protobuf-ts/runtime-rpc";
|
||||||
import type { ServiceInfo } from "@protobuf-ts/runtime-rpc";
|
import type { ServiceInfo } from "@protobuf-ts/runtime-rpc";
|
||||||
import { Invoices } from "./invoices.js";
|
import { Invoices } from "./invoices.js";
|
||||||
import type { LookupInvoiceMsg } from "./invoices.js";
|
import type { LookupInvoiceMsg } from "./invoices.js";
|
||||||
import type { SettleInvoiceResp } from "./invoices.js";
|
import type { SettleInvoiceResp } from "./invoices.js";
|
||||||
import type { SettleInvoiceMsg } from "./invoices.js";
|
import type { SettleInvoiceMsg } from "./invoices.js";
|
||||||
import type { AddHoldInvoiceResp } from "./invoices.js";
|
import type { AddHoldInvoiceResp } from "./invoices.js";
|
||||||
import type { AddHoldInvoiceRequest } from "./invoices.js";
|
import type { AddHoldInvoiceRequest } from "./invoices.js";
|
||||||
import type { CancelInvoiceResp } from "./invoices.js";
|
import type { CancelInvoiceResp } from "./invoices.js";
|
||||||
import type { CancelInvoiceMsg } from "./invoices.js";
|
import type { CancelInvoiceMsg } from "./invoices.js";
|
||||||
import type { UnaryCall } from "@protobuf-ts/runtime-rpc";
|
import type { UnaryCall } from "@protobuf-ts/runtime-rpc";
|
||||||
import { stackIntercept } from "@protobuf-ts/runtime-rpc";
|
import { stackIntercept } from "@protobuf-ts/runtime-rpc";
|
||||||
import type { Invoice } from "./lightning.js";
|
import type { Invoice } from "./lightning.js";
|
||||||
import type { SubscribeSingleInvoiceRequest } from "./invoices.js";
|
import type { SubscribeSingleInvoiceRequest } from "./invoices.js";
|
||||||
import type { ServerStreamingCall } from "@protobuf-ts/runtime-rpc";
|
import type { ServerStreamingCall } from "@protobuf-ts/runtime-rpc";
|
||||||
import type { RpcOptions } from "@protobuf-ts/runtime-rpc";
|
import type { RpcOptions } from "@protobuf-ts/runtime-rpc";
|
||||||
/**
|
/**
|
||||||
* Invoices is a service that can be used to create, accept, settle and cancel
|
* Invoices is a service that can be used to create, accept, settle and cancel
|
||||||
* invoices.
|
* invoices.
|
||||||
*
|
*
|
||||||
* @generated from protobuf service invoicesrpc.Invoices
|
* @generated from protobuf service invoicesrpc.Invoices
|
||||||
*/
|
*/
|
||||||
export interface IInvoicesClient {
|
export interface IInvoicesClient {
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* SubscribeSingleInvoice returns a uni-directional stream (server -> client)
|
* SubscribeSingleInvoice returns a uni-directional stream (server -> client)
|
||||||
* to notify the client of state transitions of the specified invoice.
|
* to notify the client of state transitions of the specified invoice.
|
||||||
* Initially the current invoice state is always sent out.
|
* Initially the current invoice state is always sent out.
|
||||||
*
|
*
|
||||||
* @generated from protobuf rpc: SubscribeSingleInvoice(invoicesrpc.SubscribeSingleInvoiceRequest) returns (stream lnrpc.Invoice);
|
* @generated from protobuf rpc: SubscribeSingleInvoice(invoicesrpc.SubscribeSingleInvoiceRequest) returns (stream lnrpc.Invoice);
|
||||||
*/
|
*/
|
||||||
subscribeSingleInvoice(input: SubscribeSingleInvoiceRequest, options?: RpcOptions): ServerStreamingCall<SubscribeSingleInvoiceRequest, Invoice>;
|
subscribeSingleInvoice(input: SubscribeSingleInvoiceRequest, options?: RpcOptions): ServerStreamingCall<SubscribeSingleInvoiceRequest, Invoice>;
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* CancelInvoice cancels a currently open invoice. If the invoice is already
|
* CancelInvoice cancels a currently open invoice. If the invoice is already
|
||||||
* canceled, this call will succeed. If the invoice is already settled, it will
|
* canceled, this call will succeed. If the invoice is already settled, it will
|
||||||
* fail.
|
* fail.
|
||||||
*
|
*
|
||||||
* @generated from protobuf rpc: CancelInvoice(invoicesrpc.CancelInvoiceMsg) returns (invoicesrpc.CancelInvoiceResp);
|
* @generated from protobuf rpc: CancelInvoice(invoicesrpc.CancelInvoiceMsg) returns (invoicesrpc.CancelInvoiceResp);
|
||||||
*/
|
*/
|
||||||
cancelInvoice(input: CancelInvoiceMsg, options?: RpcOptions): UnaryCall<CancelInvoiceMsg, CancelInvoiceResp>;
|
cancelInvoice(input: CancelInvoiceMsg, options?: RpcOptions): UnaryCall<CancelInvoiceMsg, CancelInvoiceResp>;
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* AddHoldInvoice creates a hold invoice. It ties the invoice to the hash
|
* AddHoldInvoice creates a hold invoice. It ties the invoice to the hash
|
||||||
* supplied in the request.
|
* supplied in the request.
|
||||||
*
|
*
|
||||||
* @generated from protobuf rpc: AddHoldInvoice(invoicesrpc.AddHoldInvoiceRequest) returns (invoicesrpc.AddHoldInvoiceResp);
|
* @generated from protobuf rpc: AddHoldInvoice(invoicesrpc.AddHoldInvoiceRequest) returns (invoicesrpc.AddHoldInvoiceResp);
|
||||||
*/
|
*/
|
||||||
addHoldInvoice(input: AddHoldInvoiceRequest, options?: RpcOptions): UnaryCall<AddHoldInvoiceRequest, AddHoldInvoiceResp>;
|
addHoldInvoice(input: AddHoldInvoiceRequest, options?: RpcOptions): UnaryCall<AddHoldInvoiceRequest, AddHoldInvoiceResp>;
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* SettleInvoice settles an accepted invoice. If the invoice is already
|
* SettleInvoice settles an accepted invoice. If the invoice is already
|
||||||
* settled, this call will succeed.
|
* settled, this call will succeed.
|
||||||
*
|
*
|
||||||
* @generated from protobuf rpc: SettleInvoice(invoicesrpc.SettleInvoiceMsg) returns (invoicesrpc.SettleInvoiceResp);
|
* @generated from protobuf rpc: SettleInvoice(invoicesrpc.SettleInvoiceMsg) returns (invoicesrpc.SettleInvoiceResp);
|
||||||
*/
|
*/
|
||||||
settleInvoice(input: SettleInvoiceMsg, options?: RpcOptions): UnaryCall<SettleInvoiceMsg, SettleInvoiceResp>;
|
settleInvoice(input: SettleInvoiceMsg, options?: RpcOptions): UnaryCall<SettleInvoiceMsg, SettleInvoiceResp>;
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* LookupInvoiceV2 attempts to look up at invoice. An invoice can be refrenced
|
* LookupInvoiceV2 attempts to look up at invoice. An invoice can be refrenced
|
||||||
* using either its payment hash, payment address, or set ID.
|
* using either its payment hash, payment address, or set ID.
|
||||||
*
|
*
|
||||||
* @generated from protobuf rpc: LookupInvoiceV2(invoicesrpc.LookupInvoiceMsg) returns (lnrpc.Invoice);
|
* @generated from protobuf rpc: LookupInvoiceV2(invoicesrpc.LookupInvoiceMsg) returns (lnrpc.Invoice);
|
||||||
*/
|
*/
|
||||||
lookupInvoiceV2(input: LookupInvoiceMsg, options?: RpcOptions): UnaryCall<LookupInvoiceMsg, Invoice>;
|
lookupInvoiceV2(input: LookupInvoiceMsg, options?: RpcOptions): UnaryCall<LookupInvoiceMsg, Invoice>;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Invoices is a service that can be used to create, accept, settle and cancel
|
* Invoices is a service that can be used to create, accept, settle and cancel
|
||||||
* invoices.
|
* invoices.
|
||||||
*
|
*
|
||||||
* @generated from protobuf service invoicesrpc.Invoices
|
* @generated from protobuf service invoicesrpc.Invoices
|
||||||
*/
|
*/
|
||||||
export class InvoicesClient implements IInvoicesClient, ServiceInfo {
|
export class InvoicesClient implements IInvoicesClient, ServiceInfo {
|
||||||
typeName = Invoices.typeName;
|
typeName = Invoices.typeName;
|
||||||
methods = Invoices.methods;
|
methods = Invoices.methods;
|
||||||
options = Invoices.options;
|
options = Invoices.options;
|
||||||
constructor(private readonly _transport: RpcTransport) {
|
constructor(private readonly _transport: RpcTransport) {
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* SubscribeSingleInvoice returns a uni-directional stream (server -> client)
|
* SubscribeSingleInvoice returns a uni-directional stream (server -> client)
|
||||||
* to notify the client of state transitions of the specified invoice.
|
* to notify the client of state transitions of the specified invoice.
|
||||||
* Initially the current invoice state is always sent out.
|
* Initially the current invoice state is always sent out.
|
||||||
*
|
*
|
||||||
* @generated from protobuf rpc: SubscribeSingleInvoice(invoicesrpc.SubscribeSingleInvoiceRequest) returns (stream lnrpc.Invoice);
|
* @generated from protobuf rpc: SubscribeSingleInvoice(invoicesrpc.SubscribeSingleInvoiceRequest) returns (stream lnrpc.Invoice);
|
||||||
*/
|
*/
|
||||||
subscribeSingleInvoice(input: SubscribeSingleInvoiceRequest, options?: RpcOptions): ServerStreamingCall<SubscribeSingleInvoiceRequest, Invoice> {
|
subscribeSingleInvoice(input: SubscribeSingleInvoiceRequest, options?: RpcOptions): ServerStreamingCall<SubscribeSingleInvoiceRequest, Invoice> {
|
||||||
const method = this.methods[0], opt = this._transport.mergeOptions(options);
|
const method = this.methods[0], opt = this._transport.mergeOptions(options);
|
||||||
return stackIntercept<SubscribeSingleInvoiceRequest, Invoice>("serverStreaming", this._transport, method, opt, input);
|
return stackIntercept<SubscribeSingleInvoiceRequest, Invoice>("serverStreaming", this._transport, method, opt, input);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* CancelInvoice cancels a currently open invoice. If the invoice is already
|
* CancelInvoice cancels a currently open invoice. If the invoice is already
|
||||||
* canceled, this call will succeed. If the invoice is already settled, it will
|
* canceled, this call will succeed. If the invoice is already settled, it will
|
||||||
* fail.
|
* fail.
|
||||||
*
|
*
|
||||||
* @generated from protobuf rpc: CancelInvoice(invoicesrpc.CancelInvoiceMsg) returns (invoicesrpc.CancelInvoiceResp);
|
* @generated from protobuf rpc: CancelInvoice(invoicesrpc.CancelInvoiceMsg) returns (invoicesrpc.CancelInvoiceResp);
|
||||||
*/
|
*/
|
||||||
cancelInvoice(input: CancelInvoiceMsg, options?: RpcOptions): UnaryCall<CancelInvoiceMsg, CancelInvoiceResp> {
|
cancelInvoice(input: CancelInvoiceMsg, options?: RpcOptions): UnaryCall<CancelInvoiceMsg, CancelInvoiceResp> {
|
||||||
const method = this.methods[1], opt = this._transport.mergeOptions(options);
|
const method = this.methods[1], opt = this._transport.mergeOptions(options);
|
||||||
return stackIntercept<CancelInvoiceMsg, CancelInvoiceResp>("unary", this._transport, method, opt, input);
|
return stackIntercept<CancelInvoiceMsg, CancelInvoiceResp>("unary", this._transport, method, opt, input);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* AddHoldInvoice creates a hold invoice. It ties the invoice to the hash
|
* AddHoldInvoice creates a hold invoice. It ties the invoice to the hash
|
||||||
* supplied in the request.
|
* supplied in the request.
|
||||||
*
|
*
|
||||||
* @generated from protobuf rpc: AddHoldInvoice(invoicesrpc.AddHoldInvoiceRequest) returns (invoicesrpc.AddHoldInvoiceResp);
|
* @generated from protobuf rpc: AddHoldInvoice(invoicesrpc.AddHoldInvoiceRequest) returns (invoicesrpc.AddHoldInvoiceResp);
|
||||||
*/
|
*/
|
||||||
addHoldInvoice(input: AddHoldInvoiceRequest, options?: RpcOptions): UnaryCall<AddHoldInvoiceRequest, AddHoldInvoiceResp> {
|
addHoldInvoice(input: AddHoldInvoiceRequest, options?: RpcOptions): UnaryCall<AddHoldInvoiceRequest, AddHoldInvoiceResp> {
|
||||||
const method = this.methods[2], opt = this._transport.mergeOptions(options);
|
const method = this.methods[2], opt = this._transport.mergeOptions(options);
|
||||||
return stackIntercept<AddHoldInvoiceRequest, AddHoldInvoiceResp>("unary", this._transport, method, opt, input);
|
return stackIntercept<AddHoldInvoiceRequest, AddHoldInvoiceResp>("unary", this._transport, method, opt, input);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* SettleInvoice settles an accepted invoice. If the invoice is already
|
* SettleInvoice settles an accepted invoice. If the invoice is already
|
||||||
* settled, this call will succeed.
|
* settled, this call will succeed.
|
||||||
*
|
*
|
||||||
* @generated from protobuf rpc: SettleInvoice(invoicesrpc.SettleInvoiceMsg) returns (invoicesrpc.SettleInvoiceResp);
|
* @generated from protobuf rpc: SettleInvoice(invoicesrpc.SettleInvoiceMsg) returns (invoicesrpc.SettleInvoiceResp);
|
||||||
*/
|
*/
|
||||||
settleInvoice(input: SettleInvoiceMsg, options?: RpcOptions): UnaryCall<SettleInvoiceMsg, SettleInvoiceResp> {
|
settleInvoice(input: SettleInvoiceMsg, options?: RpcOptions): UnaryCall<SettleInvoiceMsg, SettleInvoiceResp> {
|
||||||
const method = this.methods[3], opt = this._transport.mergeOptions(options);
|
const method = this.methods[3], opt = this._transport.mergeOptions(options);
|
||||||
return stackIntercept<SettleInvoiceMsg, SettleInvoiceResp>("unary", this._transport, method, opt, input);
|
return stackIntercept<SettleInvoiceMsg, SettleInvoiceResp>("unary", this._transport, method, opt, input);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* LookupInvoiceV2 attempts to look up at invoice. An invoice can be refrenced
|
* LookupInvoiceV2 attempts to look up at invoice. An invoice can be refrenced
|
||||||
* using either its payment hash, payment address, or set ID.
|
* using either its payment hash, payment address, or set ID.
|
||||||
*
|
*
|
||||||
* @generated from protobuf rpc: LookupInvoiceV2(invoicesrpc.LookupInvoiceMsg) returns (lnrpc.Invoice);
|
* @generated from protobuf rpc: LookupInvoiceV2(invoicesrpc.LookupInvoiceMsg) returns (lnrpc.Invoice);
|
||||||
*/
|
*/
|
||||||
lookupInvoiceV2(input: LookupInvoiceMsg, options?: RpcOptions): UnaryCall<LookupInvoiceMsg, Invoice> {
|
lookupInvoiceV2(input: LookupInvoiceMsg, options?: RpcOptions): UnaryCall<LookupInvoiceMsg, Invoice> {
|
||||||
const method = this.methods[4], opt = this._transport.mergeOptions(options);
|
const method = this.methods[4], opt = this._transport.mergeOptions(options);
|
||||||
return stackIntercept<LookupInvoiceMsg, Invoice>("unary", this._transport, method, opt, input);
|
return stackIntercept<LookupInvoiceMsg, Invoice>("unary", this._transport, method, opt, input);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
41990
proto/lnd/lightning.ts
41990
proto/lnd/lightning.ts
File diff suppressed because it is too large
Load diff
|
|
@ -1,446 +1,446 @@
|
||||||
// @generated by protobuf-ts 2.8.1
|
// @generated by protobuf-ts 2.8.1
|
||||||
// @generated from protobuf file "router.proto" (package "routerrpc", syntax proto3)
|
// @generated from protobuf file "router.proto" (package "routerrpc", syntax proto3)
|
||||||
// tslint:disable
|
// tslint:disable
|
||||||
import type { RpcTransport } from "@protobuf-ts/runtime-rpc";
|
import type { RpcTransport } from "@protobuf-ts/runtime-rpc";
|
||||||
import type { ServiceInfo } from "@protobuf-ts/runtime-rpc";
|
import type { ServiceInfo } from "@protobuf-ts/runtime-rpc";
|
||||||
import { Router } from "./router.js";
|
import { Router } from "./router.js";
|
||||||
import type { UpdateChanStatusResponse } from "./router.js";
|
import type { UpdateChanStatusResponse } from "./router.js";
|
||||||
import type { UpdateChanStatusRequest } from "./router.js";
|
import type { UpdateChanStatusRequest } from "./router.js";
|
||||||
import type { ForwardHtlcInterceptRequest } from "./router.js";
|
import type { ForwardHtlcInterceptRequest } from "./router.js";
|
||||||
import type { ForwardHtlcInterceptResponse } from "./router.js";
|
import type { ForwardHtlcInterceptResponse } from "./router.js";
|
||||||
import type { DuplexStreamingCall } from "@protobuf-ts/runtime-rpc";
|
import type { DuplexStreamingCall } from "@protobuf-ts/runtime-rpc";
|
||||||
import type { PaymentStatus } from "./router.js";
|
import type { PaymentStatus } from "./router.js";
|
||||||
import type { HtlcEvent } from "./router.js";
|
import type { HtlcEvent } from "./router.js";
|
||||||
import type { SubscribeHtlcEventsRequest } from "./router.js";
|
import type { SubscribeHtlcEventsRequest } from "./router.js";
|
||||||
import type { BuildRouteResponse } from "./router.js";
|
import type { BuildRouteResponse } from "./router.js";
|
||||||
import type { BuildRouteRequest } from "./router.js";
|
import type { BuildRouteRequest } from "./router.js";
|
||||||
import type { QueryProbabilityResponse } from "./router.js";
|
import type { QueryProbabilityResponse } from "./router.js";
|
||||||
import type { QueryProbabilityRequest } from "./router.js";
|
import type { QueryProbabilityRequest } from "./router.js";
|
||||||
import type { SetMissionControlConfigResponse } from "./router.js";
|
import type { SetMissionControlConfigResponse } from "./router.js";
|
||||||
import type { SetMissionControlConfigRequest } from "./router.js";
|
import type { SetMissionControlConfigRequest } from "./router.js";
|
||||||
import type { GetMissionControlConfigResponse } from "./router.js";
|
import type { GetMissionControlConfigResponse } from "./router.js";
|
||||||
import type { GetMissionControlConfigRequest } from "./router.js";
|
import type { GetMissionControlConfigRequest } from "./router.js";
|
||||||
import type { XImportMissionControlResponse } from "./router.js";
|
import type { XImportMissionControlResponse } from "./router.js";
|
||||||
import type { XImportMissionControlRequest } from "./router.js";
|
import type { XImportMissionControlRequest } from "./router.js";
|
||||||
import type { QueryMissionControlResponse } from "./router.js";
|
import type { QueryMissionControlResponse } from "./router.js";
|
||||||
import type { QueryMissionControlRequest } from "./router.js";
|
import type { QueryMissionControlRequest } from "./router.js";
|
||||||
import type { ResetMissionControlResponse } from "./router.js";
|
import type { ResetMissionControlResponse } from "./router.js";
|
||||||
import type { ResetMissionControlRequest } from "./router.js";
|
import type { ResetMissionControlRequest } from "./router.js";
|
||||||
import type { HTLCAttempt } from "./lightning.js";
|
import type { HTLCAttempt } from "./lightning.js";
|
||||||
import type { SendToRouteResponse } from "./router.js";
|
import type { SendToRouteResponse } from "./router.js";
|
||||||
import type { SendToRouteRequest } from "./router.js";
|
import type { SendToRouteRequest } from "./router.js";
|
||||||
import type { RouteFeeResponse } from "./router.js";
|
import type { RouteFeeResponse } from "./router.js";
|
||||||
import type { RouteFeeRequest } from "./router.js";
|
import type { RouteFeeRequest } from "./router.js";
|
||||||
import type { UnaryCall } from "@protobuf-ts/runtime-rpc";
|
import type { UnaryCall } from "@protobuf-ts/runtime-rpc";
|
||||||
import type { TrackPaymentsRequest } from "./router.js";
|
import type { TrackPaymentsRequest } from "./router.js";
|
||||||
import type { TrackPaymentRequest } from "./router.js";
|
import type { TrackPaymentRequest } from "./router.js";
|
||||||
import { stackIntercept } from "@protobuf-ts/runtime-rpc";
|
import { stackIntercept } from "@protobuf-ts/runtime-rpc";
|
||||||
import type { Payment } from "./lightning.js";
|
import type { Payment } from "./lightning.js";
|
||||||
import type { SendPaymentRequest } from "./router.js";
|
import type { SendPaymentRequest } from "./router.js";
|
||||||
import type { ServerStreamingCall } from "@protobuf-ts/runtime-rpc";
|
import type { ServerStreamingCall } from "@protobuf-ts/runtime-rpc";
|
||||||
import type { RpcOptions } from "@protobuf-ts/runtime-rpc";
|
import type { RpcOptions } from "@protobuf-ts/runtime-rpc";
|
||||||
/**
|
/**
|
||||||
* Router is a service that offers advanced interaction with the router
|
* Router is a service that offers advanced interaction with the router
|
||||||
* subsystem of the daemon.
|
* subsystem of the daemon.
|
||||||
*
|
*
|
||||||
* @generated from protobuf service routerrpc.Router
|
* @generated from protobuf service routerrpc.Router
|
||||||
*/
|
*/
|
||||||
export interface IRouterClient {
|
export interface IRouterClient {
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* SendPaymentV2 attempts to route a payment described by the passed
|
* SendPaymentV2 attempts to route a payment described by the passed
|
||||||
* PaymentRequest to the final destination. The call returns a stream of
|
* PaymentRequest to the final destination. The call returns a stream of
|
||||||
* payment updates.
|
* payment updates.
|
||||||
*
|
*
|
||||||
* @generated from protobuf rpc: SendPaymentV2(routerrpc.SendPaymentRequest) returns (stream lnrpc.Payment);
|
* @generated from protobuf rpc: SendPaymentV2(routerrpc.SendPaymentRequest) returns (stream lnrpc.Payment);
|
||||||
*/
|
*/
|
||||||
sendPaymentV2(input: SendPaymentRequest, options?: RpcOptions): ServerStreamingCall<SendPaymentRequest, Payment>;
|
sendPaymentV2(input: SendPaymentRequest, options?: RpcOptions): ServerStreamingCall<SendPaymentRequest, Payment>;
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* TrackPaymentV2 returns an update stream for the payment identified by the
|
* TrackPaymentV2 returns an update stream for the payment identified by the
|
||||||
* payment hash.
|
* payment hash.
|
||||||
*
|
*
|
||||||
* @generated from protobuf rpc: TrackPaymentV2(routerrpc.TrackPaymentRequest) returns (stream lnrpc.Payment);
|
* @generated from protobuf rpc: TrackPaymentV2(routerrpc.TrackPaymentRequest) returns (stream lnrpc.Payment);
|
||||||
*/
|
*/
|
||||||
trackPaymentV2(input: TrackPaymentRequest, options?: RpcOptions): ServerStreamingCall<TrackPaymentRequest, Payment>;
|
trackPaymentV2(input: TrackPaymentRequest, options?: RpcOptions): ServerStreamingCall<TrackPaymentRequest, Payment>;
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* TrackPayments returns an update stream for every payment that is not in a
|
* TrackPayments returns an update stream for every payment that is not in a
|
||||||
* terminal state. Note that if payments are in-flight while starting a new
|
* terminal state. Note that if payments are in-flight while starting a new
|
||||||
* subscription, the start of the payment stream could produce out-of-order
|
* subscription, the start of the payment stream could produce out-of-order
|
||||||
* and/or duplicate events. In order to get updates for every in-flight
|
* and/or duplicate events. In order to get updates for every in-flight
|
||||||
* payment attempt make sure to subscribe to this method before initiating any
|
* payment attempt make sure to subscribe to this method before initiating any
|
||||||
* payments.
|
* payments.
|
||||||
*
|
*
|
||||||
* @generated from protobuf rpc: TrackPayments(routerrpc.TrackPaymentsRequest) returns (stream lnrpc.Payment);
|
* @generated from protobuf rpc: TrackPayments(routerrpc.TrackPaymentsRequest) returns (stream lnrpc.Payment);
|
||||||
*/
|
*/
|
||||||
trackPayments(input: TrackPaymentsRequest, options?: RpcOptions): ServerStreamingCall<TrackPaymentsRequest, Payment>;
|
trackPayments(input: TrackPaymentsRequest, options?: RpcOptions): ServerStreamingCall<TrackPaymentsRequest, Payment>;
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* EstimateRouteFee allows callers to obtain a lower bound w.r.t how much it
|
* EstimateRouteFee allows callers to obtain a lower bound w.r.t how much it
|
||||||
* may cost to send an HTLC to the target end destination.
|
* may cost to send an HTLC to the target end destination.
|
||||||
*
|
*
|
||||||
* @generated from protobuf rpc: EstimateRouteFee(routerrpc.RouteFeeRequest) returns (routerrpc.RouteFeeResponse);
|
* @generated from protobuf rpc: EstimateRouteFee(routerrpc.RouteFeeRequest) returns (routerrpc.RouteFeeResponse);
|
||||||
*/
|
*/
|
||||||
estimateRouteFee(input: RouteFeeRequest, options?: RpcOptions): UnaryCall<RouteFeeRequest, RouteFeeResponse>;
|
estimateRouteFee(input: RouteFeeRequest, options?: RpcOptions): UnaryCall<RouteFeeRequest, RouteFeeResponse>;
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* Deprecated, use SendToRouteV2. SendToRoute attempts to make a payment via
|
* Deprecated, use SendToRouteV2. SendToRoute attempts to make a payment via
|
||||||
* the specified route. This method differs from SendPayment in that it
|
* the specified route. This method differs from SendPayment in that it
|
||||||
* allows users to specify a full route manually. This can be used for
|
* allows users to specify a full route manually. This can be used for
|
||||||
* things like rebalancing, and atomic swaps. It differs from the newer
|
* things like rebalancing, and atomic swaps. It differs from the newer
|
||||||
* SendToRouteV2 in that it doesn't return the full HTLC information.
|
* SendToRouteV2 in that it doesn't return the full HTLC information.
|
||||||
*
|
*
|
||||||
* @deprecated
|
* @deprecated
|
||||||
* @generated from protobuf rpc: SendToRoute(routerrpc.SendToRouteRequest) returns (routerrpc.SendToRouteResponse);
|
* @generated from protobuf rpc: SendToRoute(routerrpc.SendToRouteRequest) returns (routerrpc.SendToRouteResponse);
|
||||||
*/
|
*/
|
||||||
sendToRoute(input: SendToRouteRequest, options?: RpcOptions): UnaryCall<SendToRouteRequest, SendToRouteResponse>;
|
sendToRoute(input: SendToRouteRequest, options?: RpcOptions): UnaryCall<SendToRouteRequest, SendToRouteResponse>;
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* SendToRouteV2 attempts to make a payment via the specified route. This
|
* SendToRouteV2 attempts to make a payment via the specified route. This
|
||||||
* method differs from SendPayment in that it allows users to specify a full
|
* method differs from SendPayment in that it allows users to specify a full
|
||||||
* route manually. This can be used for things like rebalancing, and atomic
|
* route manually. This can be used for things like rebalancing, and atomic
|
||||||
* swaps.
|
* swaps.
|
||||||
*
|
*
|
||||||
* @generated from protobuf rpc: SendToRouteV2(routerrpc.SendToRouteRequest) returns (lnrpc.HTLCAttempt);
|
* @generated from protobuf rpc: SendToRouteV2(routerrpc.SendToRouteRequest) returns (lnrpc.HTLCAttempt);
|
||||||
*/
|
*/
|
||||||
sendToRouteV2(input: SendToRouteRequest, options?: RpcOptions): UnaryCall<SendToRouteRequest, HTLCAttempt>;
|
sendToRouteV2(input: SendToRouteRequest, options?: RpcOptions): UnaryCall<SendToRouteRequest, HTLCAttempt>;
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* ResetMissionControl clears all mission control state and starts with a clean
|
* ResetMissionControl clears all mission control state and starts with a clean
|
||||||
* slate.
|
* slate.
|
||||||
*
|
*
|
||||||
* @generated from protobuf rpc: ResetMissionControl(routerrpc.ResetMissionControlRequest) returns (routerrpc.ResetMissionControlResponse);
|
* @generated from protobuf rpc: ResetMissionControl(routerrpc.ResetMissionControlRequest) returns (routerrpc.ResetMissionControlResponse);
|
||||||
*/
|
*/
|
||||||
resetMissionControl(input: ResetMissionControlRequest, options?: RpcOptions): UnaryCall<ResetMissionControlRequest, ResetMissionControlResponse>;
|
resetMissionControl(input: ResetMissionControlRequest, options?: RpcOptions): UnaryCall<ResetMissionControlRequest, ResetMissionControlResponse>;
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* QueryMissionControl exposes the internal mission control state to callers.
|
* QueryMissionControl exposes the internal mission control state to callers.
|
||||||
* It is a development feature.
|
* It is a development feature.
|
||||||
*
|
*
|
||||||
* @generated from protobuf rpc: QueryMissionControl(routerrpc.QueryMissionControlRequest) returns (routerrpc.QueryMissionControlResponse);
|
* @generated from protobuf rpc: QueryMissionControl(routerrpc.QueryMissionControlRequest) returns (routerrpc.QueryMissionControlResponse);
|
||||||
*/
|
*/
|
||||||
queryMissionControl(input: QueryMissionControlRequest, options?: RpcOptions): UnaryCall<QueryMissionControlRequest, QueryMissionControlResponse>;
|
queryMissionControl(input: QueryMissionControlRequest, options?: RpcOptions): UnaryCall<QueryMissionControlRequest, QueryMissionControlResponse>;
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* XImportMissionControl is an experimental API that imports the state provided
|
* XImportMissionControl is an experimental API that imports the state provided
|
||||||
* to the internal mission control's state, using all results which are more
|
* to the internal mission control's state, using all results which are more
|
||||||
* recent than our existing values. These values will only be imported
|
* recent than our existing values. These values will only be imported
|
||||||
* in-memory, and will not be persisted across restarts.
|
* in-memory, and will not be persisted across restarts.
|
||||||
*
|
*
|
||||||
* @generated from protobuf rpc: XImportMissionControl(routerrpc.XImportMissionControlRequest) returns (routerrpc.XImportMissionControlResponse);
|
* @generated from protobuf rpc: XImportMissionControl(routerrpc.XImportMissionControlRequest) returns (routerrpc.XImportMissionControlResponse);
|
||||||
*/
|
*/
|
||||||
xImportMissionControl(input: XImportMissionControlRequest, options?: RpcOptions): UnaryCall<XImportMissionControlRequest, XImportMissionControlResponse>;
|
xImportMissionControl(input: XImportMissionControlRequest, options?: RpcOptions): UnaryCall<XImportMissionControlRequest, XImportMissionControlResponse>;
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* GetMissionControlConfig returns mission control's current config.
|
* GetMissionControlConfig returns mission control's current config.
|
||||||
*
|
*
|
||||||
* @generated from protobuf rpc: GetMissionControlConfig(routerrpc.GetMissionControlConfigRequest) returns (routerrpc.GetMissionControlConfigResponse);
|
* @generated from protobuf rpc: GetMissionControlConfig(routerrpc.GetMissionControlConfigRequest) returns (routerrpc.GetMissionControlConfigResponse);
|
||||||
*/
|
*/
|
||||||
getMissionControlConfig(input: GetMissionControlConfigRequest, options?: RpcOptions): UnaryCall<GetMissionControlConfigRequest, GetMissionControlConfigResponse>;
|
getMissionControlConfig(input: GetMissionControlConfigRequest, options?: RpcOptions): UnaryCall<GetMissionControlConfigRequest, GetMissionControlConfigResponse>;
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* SetMissionControlConfig will set mission control's config, if the config
|
* SetMissionControlConfig will set mission control's config, if the config
|
||||||
* provided is valid.
|
* provided is valid.
|
||||||
*
|
*
|
||||||
* @generated from protobuf rpc: SetMissionControlConfig(routerrpc.SetMissionControlConfigRequest) returns (routerrpc.SetMissionControlConfigResponse);
|
* @generated from protobuf rpc: SetMissionControlConfig(routerrpc.SetMissionControlConfigRequest) returns (routerrpc.SetMissionControlConfigResponse);
|
||||||
*/
|
*/
|
||||||
setMissionControlConfig(input: SetMissionControlConfigRequest, options?: RpcOptions): UnaryCall<SetMissionControlConfigRequest, SetMissionControlConfigResponse>;
|
setMissionControlConfig(input: SetMissionControlConfigRequest, options?: RpcOptions): UnaryCall<SetMissionControlConfigRequest, SetMissionControlConfigResponse>;
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* QueryProbability returns the current success probability estimate for a
|
* QueryProbability returns the current success probability estimate for a
|
||||||
* given node pair and amount.
|
* given node pair and amount.
|
||||||
*
|
*
|
||||||
* @generated from protobuf rpc: QueryProbability(routerrpc.QueryProbabilityRequest) returns (routerrpc.QueryProbabilityResponse);
|
* @generated from protobuf rpc: QueryProbability(routerrpc.QueryProbabilityRequest) returns (routerrpc.QueryProbabilityResponse);
|
||||||
*/
|
*/
|
||||||
queryProbability(input: QueryProbabilityRequest, options?: RpcOptions): UnaryCall<QueryProbabilityRequest, QueryProbabilityResponse>;
|
queryProbability(input: QueryProbabilityRequest, options?: RpcOptions): UnaryCall<QueryProbabilityRequest, QueryProbabilityResponse>;
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* BuildRoute builds a fully specified route based on a list of hop public
|
* BuildRoute builds a fully specified route based on a list of hop public
|
||||||
* keys. It retrieves the relevant channel policies from the graph in order to
|
* keys. It retrieves the relevant channel policies from the graph in order to
|
||||||
* calculate the correct fees and time locks.
|
* calculate the correct fees and time locks.
|
||||||
*
|
*
|
||||||
* @generated from protobuf rpc: BuildRoute(routerrpc.BuildRouteRequest) returns (routerrpc.BuildRouteResponse);
|
* @generated from protobuf rpc: BuildRoute(routerrpc.BuildRouteRequest) returns (routerrpc.BuildRouteResponse);
|
||||||
*/
|
*/
|
||||||
buildRoute(input: BuildRouteRequest, options?: RpcOptions): UnaryCall<BuildRouteRequest, BuildRouteResponse>;
|
buildRoute(input: BuildRouteRequest, options?: RpcOptions): UnaryCall<BuildRouteRequest, BuildRouteResponse>;
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* SubscribeHtlcEvents creates a uni-directional stream from the server to
|
* SubscribeHtlcEvents creates a uni-directional stream from the server to
|
||||||
* the client which delivers a stream of htlc events.
|
* the client which delivers a stream of htlc events.
|
||||||
*
|
*
|
||||||
* @generated from protobuf rpc: SubscribeHtlcEvents(routerrpc.SubscribeHtlcEventsRequest) returns (stream routerrpc.HtlcEvent);
|
* @generated from protobuf rpc: SubscribeHtlcEvents(routerrpc.SubscribeHtlcEventsRequest) returns (stream routerrpc.HtlcEvent);
|
||||||
*/
|
*/
|
||||||
subscribeHtlcEvents(input: SubscribeHtlcEventsRequest, options?: RpcOptions): ServerStreamingCall<SubscribeHtlcEventsRequest, HtlcEvent>;
|
subscribeHtlcEvents(input: SubscribeHtlcEventsRequest, options?: RpcOptions): ServerStreamingCall<SubscribeHtlcEventsRequest, HtlcEvent>;
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* Deprecated, use SendPaymentV2. SendPayment attempts to route a payment
|
* Deprecated, use SendPaymentV2. SendPayment attempts to route a payment
|
||||||
* described by the passed PaymentRequest to the final destination. The call
|
* described by the passed PaymentRequest to the final destination. The call
|
||||||
* returns a stream of payment status updates.
|
* returns a stream of payment status updates.
|
||||||
*
|
*
|
||||||
* @deprecated
|
* @deprecated
|
||||||
* @generated from protobuf rpc: SendPayment(routerrpc.SendPaymentRequest) returns (stream routerrpc.PaymentStatus);
|
* @generated from protobuf rpc: SendPayment(routerrpc.SendPaymentRequest) returns (stream routerrpc.PaymentStatus);
|
||||||
*/
|
*/
|
||||||
sendPayment(input: SendPaymentRequest, options?: RpcOptions): ServerStreamingCall<SendPaymentRequest, PaymentStatus>;
|
sendPayment(input: SendPaymentRequest, options?: RpcOptions): ServerStreamingCall<SendPaymentRequest, PaymentStatus>;
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* Deprecated, use TrackPaymentV2. TrackPayment returns an update stream for
|
* Deprecated, use TrackPaymentV2. TrackPayment returns an update stream for
|
||||||
* the payment identified by the payment hash.
|
* the payment identified by the payment hash.
|
||||||
*
|
*
|
||||||
* @deprecated
|
* @deprecated
|
||||||
* @generated from protobuf rpc: TrackPayment(routerrpc.TrackPaymentRequest) returns (stream routerrpc.PaymentStatus);
|
* @generated from protobuf rpc: TrackPayment(routerrpc.TrackPaymentRequest) returns (stream routerrpc.PaymentStatus);
|
||||||
*/
|
*/
|
||||||
trackPayment(input: TrackPaymentRequest, options?: RpcOptions): ServerStreamingCall<TrackPaymentRequest, PaymentStatus>;
|
trackPayment(input: TrackPaymentRequest, options?: RpcOptions): ServerStreamingCall<TrackPaymentRequest, PaymentStatus>;
|
||||||
/**
|
/**
|
||||||
* *
|
* *
|
||||||
* HtlcInterceptor dispatches a bi-directional streaming RPC in which
|
* HtlcInterceptor dispatches a bi-directional streaming RPC in which
|
||||||
* Forwarded HTLC requests are sent to the client and the client responds with
|
* Forwarded HTLC requests are sent to the client and the client responds with
|
||||||
* a boolean that tells LND if this htlc should be intercepted.
|
* a boolean that tells LND if this htlc should be intercepted.
|
||||||
* In case of interception, the htlc can be either settled, cancelled or
|
* In case of interception, the htlc can be either settled, cancelled or
|
||||||
* resumed later by using the ResolveHoldForward endpoint.
|
* resumed later by using the ResolveHoldForward endpoint.
|
||||||
*
|
*
|
||||||
* @generated from protobuf rpc: HtlcInterceptor(stream routerrpc.ForwardHtlcInterceptResponse) returns (stream routerrpc.ForwardHtlcInterceptRequest);
|
* @generated from protobuf rpc: HtlcInterceptor(stream routerrpc.ForwardHtlcInterceptResponse) returns (stream routerrpc.ForwardHtlcInterceptRequest);
|
||||||
*/
|
*/
|
||||||
htlcInterceptor(options?: RpcOptions): DuplexStreamingCall<ForwardHtlcInterceptResponse, ForwardHtlcInterceptRequest>;
|
htlcInterceptor(options?: RpcOptions): DuplexStreamingCall<ForwardHtlcInterceptResponse, ForwardHtlcInterceptRequest>;
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* UpdateChanStatus attempts to manually set the state of a channel
|
* UpdateChanStatus attempts to manually set the state of a channel
|
||||||
* (enabled, disabled, or auto). A manual "disable" request will cause the
|
* (enabled, disabled, or auto). A manual "disable" request will cause the
|
||||||
* channel to stay disabled until a subsequent manual request of either
|
* channel to stay disabled until a subsequent manual request of either
|
||||||
* "enable" or "auto".
|
* "enable" or "auto".
|
||||||
*
|
*
|
||||||
* @generated from protobuf rpc: UpdateChanStatus(routerrpc.UpdateChanStatusRequest) returns (routerrpc.UpdateChanStatusResponse);
|
* @generated from protobuf rpc: UpdateChanStatus(routerrpc.UpdateChanStatusRequest) returns (routerrpc.UpdateChanStatusResponse);
|
||||||
*/
|
*/
|
||||||
updateChanStatus(input: UpdateChanStatusRequest, options?: RpcOptions): UnaryCall<UpdateChanStatusRequest, UpdateChanStatusResponse>;
|
updateChanStatus(input: UpdateChanStatusRequest, options?: RpcOptions): UnaryCall<UpdateChanStatusRequest, UpdateChanStatusResponse>;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Router is a service that offers advanced interaction with the router
|
* Router is a service that offers advanced interaction with the router
|
||||||
* subsystem of the daemon.
|
* subsystem of the daemon.
|
||||||
*
|
*
|
||||||
* @generated from protobuf service routerrpc.Router
|
* @generated from protobuf service routerrpc.Router
|
||||||
*/
|
*/
|
||||||
export class RouterClient implements IRouterClient, ServiceInfo {
|
export class RouterClient implements IRouterClient, ServiceInfo {
|
||||||
typeName = Router.typeName;
|
typeName = Router.typeName;
|
||||||
methods = Router.methods;
|
methods = Router.methods;
|
||||||
options = Router.options;
|
options = Router.options;
|
||||||
constructor(private readonly _transport: RpcTransport) {
|
constructor(private readonly _transport: RpcTransport) {
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* SendPaymentV2 attempts to route a payment described by the passed
|
* SendPaymentV2 attempts to route a payment described by the passed
|
||||||
* PaymentRequest to the final destination. The call returns a stream of
|
* PaymentRequest to the final destination. The call returns a stream of
|
||||||
* payment updates.
|
* payment updates.
|
||||||
*
|
*
|
||||||
* @generated from protobuf rpc: SendPaymentV2(routerrpc.SendPaymentRequest) returns (stream lnrpc.Payment);
|
* @generated from protobuf rpc: SendPaymentV2(routerrpc.SendPaymentRequest) returns (stream lnrpc.Payment);
|
||||||
*/
|
*/
|
||||||
sendPaymentV2(input: SendPaymentRequest, options?: RpcOptions): ServerStreamingCall<SendPaymentRequest, Payment> {
|
sendPaymentV2(input: SendPaymentRequest, options?: RpcOptions): ServerStreamingCall<SendPaymentRequest, Payment> {
|
||||||
const method = this.methods[0], opt = this._transport.mergeOptions(options);
|
const method = this.methods[0], opt = this._transport.mergeOptions(options);
|
||||||
return stackIntercept<SendPaymentRequest, Payment>("serverStreaming", this._transport, method, opt, input);
|
return stackIntercept<SendPaymentRequest, Payment>("serverStreaming", this._transport, method, opt, input);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* TrackPaymentV2 returns an update stream for the payment identified by the
|
* TrackPaymentV2 returns an update stream for the payment identified by the
|
||||||
* payment hash.
|
* payment hash.
|
||||||
*
|
*
|
||||||
* @generated from protobuf rpc: TrackPaymentV2(routerrpc.TrackPaymentRequest) returns (stream lnrpc.Payment);
|
* @generated from protobuf rpc: TrackPaymentV2(routerrpc.TrackPaymentRequest) returns (stream lnrpc.Payment);
|
||||||
*/
|
*/
|
||||||
trackPaymentV2(input: TrackPaymentRequest, options?: RpcOptions): ServerStreamingCall<TrackPaymentRequest, Payment> {
|
trackPaymentV2(input: TrackPaymentRequest, options?: RpcOptions): ServerStreamingCall<TrackPaymentRequest, Payment> {
|
||||||
const method = this.methods[1], opt = this._transport.mergeOptions(options);
|
const method = this.methods[1], opt = this._transport.mergeOptions(options);
|
||||||
return stackIntercept<TrackPaymentRequest, Payment>("serverStreaming", this._transport, method, opt, input);
|
return stackIntercept<TrackPaymentRequest, Payment>("serverStreaming", this._transport, method, opt, input);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* TrackPayments returns an update stream for every payment that is not in a
|
* TrackPayments returns an update stream for every payment that is not in a
|
||||||
* terminal state. Note that if payments are in-flight while starting a new
|
* terminal state. Note that if payments are in-flight while starting a new
|
||||||
* subscription, the start of the payment stream could produce out-of-order
|
* subscription, the start of the payment stream could produce out-of-order
|
||||||
* and/or duplicate events. In order to get updates for every in-flight
|
* and/or duplicate events. In order to get updates for every in-flight
|
||||||
* payment attempt make sure to subscribe to this method before initiating any
|
* payment attempt make sure to subscribe to this method before initiating any
|
||||||
* payments.
|
* payments.
|
||||||
*
|
*
|
||||||
* @generated from protobuf rpc: TrackPayments(routerrpc.TrackPaymentsRequest) returns (stream lnrpc.Payment);
|
* @generated from protobuf rpc: TrackPayments(routerrpc.TrackPaymentsRequest) returns (stream lnrpc.Payment);
|
||||||
*/
|
*/
|
||||||
trackPayments(input: TrackPaymentsRequest, options?: RpcOptions): ServerStreamingCall<TrackPaymentsRequest, Payment> {
|
trackPayments(input: TrackPaymentsRequest, options?: RpcOptions): ServerStreamingCall<TrackPaymentsRequest, Payment> {
|
||||||
const method = this.methods[2], opt = this._transport.mergeOptions(options);
|
const method = this.methods[2], opt = this._transport.mergeOptions(options);
|
||||||
return stackIntercept<TrackPaymentsRequest, Payment>("serverStreaming", this._transport, method, opt, input);
|
return stackIntercept<TrackPaymentsRequest, Payment>("serverStreaming", this._transport, method, opt, input);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* EstimateRouteFee allows callers to obtain a lower bound w.r.t how much it
|
* EstimateRouteFee allows callers to obtain a lower bound w.r.t how much it
|
||||||
* may cost to send an HTLC to the target end destination.
|
* may cost to send an HTLC to the target end destination.
|
||||||
*
|
*
|
||||||
* @generated from protobuf rpc: EstimateRouteFee(routerrpc.RouteFeeRequest) returns (routerrpc.RouteFeeResponse);
|
* @generated from protobuf rpc: EstimateRouteFee(routerrpc.RouteFeeRequest) returns (routerrpc.RouteFeeResponse);
|
||||||
*/
|
*/
|
||||||
estimateRouteFee(input: RouteFeeRequest, options?: RpcOptions): UnaryCall<RouteFeeRequest, RouteFeeResponse> {
|
estimateRouteFee(input: RouteFeeRequest, options?: RpcOptions): UnaryCall<RouteFeeRequest, RouteFeeResponse> {
|
||||||
const method = this.methods[3], opt = this._transport.mergeOptions(options);
|
const method = this.methods[3], opt = this._transport.mergeOptions(options);
|
||||||
return stackIntercept<RouteFeeRequest, RouteFeeResponse>("unary", this._transport, method, opt, input);
|
return stackIntercept<RouteFeeRequest, RouteFeeResponse>("unary", this._transport, method, opt, input);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* Deprecated, use SendToRouteV2. SendToRoute attempts to make a payment via
|
* Deprecated, use SendToRouteV2. SendToRoute attempts to make a payment via
|
||||||
* the specified route. This method differs from SendPayment in that it
|
* the specified route. This method differs from SendPayment in that it
|
||||||
* allows users to specify a full route manually. This can be used for
|
* allows users to specify a full route manually. This can be used for
|
||||||
* things like rebalancing, and atomic swaps. It differs from the newer
|
* things like rebalancing, and atomic swaps. It differs from the newer
|
||||||
* SendToRouteV2 in that it doesn't return the full HTLC information.
|
* SendToRouteV2 in that it doesn't return the full HTLC information.
|
||||||
*
|
*
|
||||||
* @deprecated
|
* @deprecated
|
||||||
* @generated from protobuf rpc: SendToRoute(routerrpc.SendToRouteRequest) returns (routerrpc.SendToRouteResponse);
|
* @generated from protobuf rpc: SendToRoute(routerrpc.SendToRouteRequest) returns (routerrpc.SendToRouteResponse);
|
||||||
*/
|
*/
|
||||||
sendToRoute(input: SendToRouteRequest, options?: RpcOptions): UnaryCall<SendToRouteRequest, SendToRouteResponse> {
|
sendToRoute(input: SendToRouteRequest, options?: RpcOptions): UnaryCall<SendToRouteRequest, SendToRouteResponse> {
|
||||||
const method = this.methods[4], opt = this._transport.mergeOptions(options);
|
const method = this.methods[4], opt = this._transport.mergeOptions(options);
|
||||||
return stackIntercept<SendToRouteRequest, SendToRouteResponse>("unary", this._transport, method, opt, input);
|
return stackIntercept<SendToRouteRequest, SendToRouteResponse>("unary", this._transport, method, opt, input);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* SendToRouteV2 attempts to make a payment via the specified route. This
|
* SendToRouteV2 attempts to make a payment via the specified route. This
|
||||||
* method differs from SendPayment in that it allows users to specify a full
|
* method differs from SendPayment in that it allows users to specify a full
|
||||||
* route manually. This can be used for things like rebalancing, and atomic
|
* route manually. This can be used for things like rebalancing, and atomic
|
||||||
* swaps.
|
* swaps.
|
||||||
*
|
*
|
||||||
* @generated from protobuf rpc: SendToRouteV2(routerrpc.SendToRouteRequest) returns (lnrpc.HTLCAttempt);
|
* @generated from protobuf rpc: SendToRouteV2(routerrpc.SendToRouteRequest) returns (lnrpc.HTLCAttempt);
|
||||||
*/
|
*/
|
||||||
sendToRouteV2(input: SendToRouteRequest, options?: RpcOptions): UnaryCall<SendToRouteRequest, HTLCAttempt> {
|
sendToRouteV2(input: SendToRouteRequest, options?: RpcOptions): UnaryCall<SendToRouteRequest, HTLCAttempt> {
|
||||||
const method = this.methods[5], opt = this._transport.mergeOptions(options);
|
const method = this.methods[5], opt = this._transport.mergeOptions(options);
|
||||||
return stackIntercept<SendToRouteRequest, HTLCAttempt>("unary", this._transport, method, opt, input);
|
return stackIntercept<SendToRouteRequest, HTLCAttempt>("unary", this._transport, method, opt, input);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* ResetMissionControl clears all mission control state and starts with a clean
|
* ResetMissionControl clears all mission control state and starts with a clean
|
||||||
* slate.
|
* slate.
|
||||||
*
|
*
|
||||||
* @generated from protobuf rpc: ResetMissionControl(routerrpc.ResetMissionControlRequest) returns (routerrpc.ResetMissionControlResponse);
|
* @generated from protobuf rpc: ResetMissionControl(routerrpc.ResetMissionControlRequest) returns (routerrpc.ResetMissionControlResponse);
|
||||||
*/
|
*/
|
||||||
resetMissionControl(input: ResetMissionControlRequest, options?: RpcOptions): UnaryCall<ResetMissionControlRequest, ResetMissionControlResponse> {
|
resetMissionControl(input: ResetMissionControlRequest, options?: RpcOptions): UnaryCall<ResetMissionControlRequest, ResetMissionControlResponse> {
|
||||||
const method = this.methods[6], opt = this._transport.mergeOptions(options);
|
const method = this.methods[6], opt = this._transport.mergeOptions(options);
|
||||||
return stackIntercept<ResetMissionControlRequest, ResetMissionControlResponse>("unary", this._transport, method, opt, input);
|
return stackIntercept<ResetMissionControlRequest, ResetMissionControlResponse>("unary", this._transport, method, opt, input);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* QueryMissionControl exposes the internal mission control state to callers.
|
* QueryMissionControl exposes the internal mission control state to callers.
|
||||||
* It is a development feature.
|
* It is a development feature.
|
||||||
*
|
*
|
||||||
* @generated from protobuf rpc: QueryMissionControl(routerrpc.QueryMissionControlRequest) returns (routerrpc.QueryMissionControlResponse);
|
* @generated from protobuf rpc: QueryMissionControl(routerrpc.QueryMissionControlRequest) returns (routerrpc.QueryMissionControlResponse);
|
||||||
*/
|
*/
|
||||||
queryMissionControl(input: QueryMissionControlRequest, options?: RpcOptions): UnaryCall<QueryMissionControlRequest, QueryMissionControlResponse> {
|
queryMissionControl(input: QueryMissionControlRequest, options?: RpcOptions): UnaryCall<QueryMissionControlRequest, QueryMissionControlResponse> {
|
||||||
const method = this.methods[7], opt = this._transport.mergeOptions(options);
|
const method = this.methods[7], opt = this._transport.mergeOptions(options);
|
||||||
return stackIntercept<QueryMissionControlRequest, QueryMissionControlResponse>("unary", this._transport, method, opt, input);
|
return stackIntercept<QueryMissionControlRequest, QueryMissionControlResponse>("unary", this._transport, method, opt, input);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* XImportMissionControl is an experimental API that imports the state provided
|
* XImportMissionControl is an experimental API that imports the state provided
|
||||||
* to the internal mission control's state, using all results which are more
|
* to the internal mission control's state, using all results which are more
|
||||||
* recent than our existing values. These values will only be imported
|
* recent than our existing values. These values will only be imported
|
||||||
* in-memory, and will not be persisted across restarts.
|
* in-memory, and will not be persisted across restarts.
|
||||||
*
|
*
|
||||||
* @generated from protobuf rpc: XImportMissionControl(routerrpc.XImportMissionControlRequest) returns (routerrpc.XImportMissionControlResponse);
|
* @generated from protobuf rpc: XImportMissionControl(routerrpc.XImportMissionControlRequest) returns (routerrpc.XImportMissionControlResponse);
|
||||||
*/
|
*/
|
||||||
xImportMissionControl(input: XImportMissionControlRequest, options?: RpcOptions): UnaryCall<XImportMissionControlRequest, XImportMissionControlResponse> {
|
xImportMissionControl(input: XImportMissionControlRequest, options?: RpcOptions): UnaryCall<XImportMissionControlRequest, XImportMissionControlResponse> {
|
||||||
const method = this.methods[8], opt = this._transport.mergeOptions(options);
|
const method = this.methods[8], opt = this._transport.mergeOptions(options);
|
||||||
return stackIntercept<XImportMissionControlRequest, XImportMissionControlResponse>("unary", this._transport, method, opt, input);
|
return stackIntercept<XImportMissionControlRequest, XImportMissionControlResponse>("unary", this._transport, method, opt, input);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* GetMissionControlConfig returns mission control's current config.
|
* GetMissionControlConfig returns mission control's current config.
|
||||||
*
|
*
|
||||||
* @generated from protobuf rpc: GetMissionControlConfig(routerrpc.GetMissionControlConfigRequest) returns (routerrpc.GetMissionControlConfigResponse);
|
* @generated from protobuf rpc: GetMissionControlConfig(routerrpc.GetMissionControlConfigRequest) returns (routerrpc.GetMissionControlConfigResponse);
|
||||||
*/
|
*/
|
||||||
getMissionControlConfig(input: GetMissionControlConfigRequest, options?: RpcOptions): UnaryCall<GetMissionControlConfigRequest, GetMissionControlConfigResponse> {
|
getMissionControlConfig(input: GetMissionControlConfigRequest, options?: RpcOptions): UnaryCall<GetMissionControlConfigRequest, GetMissionControlConfigResponse> {
|
||||||
const method = this.methods[9], opt = this._transport.mergeOptions(options);
|
const method = this.methods[9], opt = this._transport.mergeOptions(options);
|
||||||
return stackIntercept<GetMissionControlConfigRequest, GetMissionControlConfigResponse>("unary", this._transport, method, opt, input);
|
return stackIntercept<GetMissionControlConfigRequest, GetMissionControlConfigResponse>("unary", this._transport, method, opt, input);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* SetMissionControlConfig will set mission control's config, if the config
|
* SetMissionControlConfig will set mission control's config, if the config
|
||||||
* provided is valid.
|
* provided is valid.
|
||||||
*
|
*
|
||||||
* @generated from protobuf rpc: SetMissionControlConfig(routerrpc.SetMissionControlConfigRequest) returns (routerrpc.SetMissionControlConfigResponse);
|
* @generated from protobuf rpc: SetMissionControlConfig(routerrpc.SetMissionControlConfigRequest) returns (routerrpc.SetMissionControlConfigResponse);
|
||||||
*/
|
*/
|
||||||
setMissionControlConfig(input: SetMissionControlConfigRequest, options?: RpcOptions): UnaryCall<SetMissionControlConfigRequest, SetMissionControlConfigResponse> {
|
setMissionControlConfig(input: SetMissionControlConfigRequest, options?: RpcOptions): UnaryCall<SetMissionControlConfigRequest, SetMissionControlConfigResponse> {
|
||||||
const method = this.methods[10], opt = this._transport.mergeOptions(options);
|
const method = this.methods[10], opt = this._transport.mergeOptions(options);
|
||||||
return stackIntercept<SetMissionControlConfigRequest, SetMissionControlConfigResponse>("unary", this._transport, method, opt, input);
|
return stackIntercept<SetMissionControlConfigRequest, SetMissionControlConfigResponse>("unary", this._transport, method, opt, input);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* QueryProbability returns the current success probability estimate for a
|
* QueryProbability returns the current success probability estimate for a
|
||||||
* given node pair and amount.
|
* given node pair and amount.
|
||||||
*
|
*
|
||||||
* @generated from protobuf rpc: QueryProbability(routerrpc.QueryProbabilityRequest) returns (routerrpc.QueryProbabilityResponse);
|
* @generated from protobuf rpc: QueryProbability(routerrpc.QueryProbabilityRequest) returns (routerrpc.QueryProbabilityResponse);
|
||||||
*/
|
*/
|
||||||
queryProbability(input: QueryProbabilityRequest, options?: RpcOptions): UnaryCall<QueryProbabilityRequest, QueryProbabilityResponse> {
|
queryProbability(input: QueryProbabilityRequest, options?: RpcOptions): UnaryCall<QueryProbabilityRequest, QueryProbabilityResponse> {
|
||||||
const method = this.methods[11], opt = this._transport.mergeOptions(options);
|
const method = this.methods[11], opt = this._transport.mergeOptions(options);
|
||||||
return stackIntercept<QueryProbabilityRequest, QueryProbabilityResponse>("unary", this._transport, method, opt, input);
|
return stackIntercept<QueryProbabilityRequest, QueryProbabilityResponse>("unary", this._transport, method, opt, input);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* BuildRoute builds a fully specified route based on a list of hop public
|
* BuildRoute builds a fully specified route based on a list of hop public
|
||||||
* keys. It retrieves the relevant channel policies from the graph in order to
|
* keys. It retrieves the relevant channel policies from the graph in order to
|
||||||
* calculate the correct fees and time locks.
|
* calculate the correct fees and time locks.
|
||||||
*
|
*
|
||||||
* @generated from protobuf rpc: BuildRoute(routerrpc.BuildRouteRequest) returns (routerrpc.BuildRouteResponse);
|
* @generated from protobuf rpc: BuildRoute(routerrpc.BuildRouteRequest) returns (routerrpc.BuildRouteResponse);
|
||||||
*/
|
*/
|
||||||
buildRoute(input: BuildRouteRequest, options?: RpcOptions): UnaryCall<BuildRouteRequest, BuildRouteResponse> {
|
buildRoute(input: BuildRouteRequest, options?: RpcOptions): UnaryCall<BuildRouteRequest, BuildRouteResponse> {
|
||||||
const method = this.methods[12], opt = this._transport.mergeOptions(options);
|
const method = this.methods[12], opt = this._transport.mergeOptions(options);
|
||||||
return stackIntercept<BuildRouteRequest, BuildRouteResponse>("unary", this._transport, method, opt, input);
|
return stackIntercept<BuildRouteRequest, BuildRouteResponse>("unary", this._transport, method, opt, input);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* SubscribeHtlcEvents creates a uni-directional stream from the server to
|
* SubscribeHtlcEvents creates a uni-directional stream from the server to
|
||||||
* the client which delivers a stream of htlc events.
|
* the client which delivers a stream of htlc events.
|
||||||
*
|
*
|
||||||
* @generated from protobuf rpc: SubscribeHtlcEvents(routerrpc.SubscribeHtlcEventsRequest) returns (stream routerrpc.HtlcEvent);
|
* @generated from protobuf rpc: SubscribeHtlcEvents(routerrpc.SubscribeHtlcEventsRequest) returns (stream routerrpc.HtlcEvent);
|
||||||
*/
|
*/
|
||||||
subscribeHtlcEvents(input: SubscribeHtlcEventsRequest, options?: RpcOptions): ServerStreamingCall<SubscribeHtlcEventsRequest, HtlcEvent> {
|
subscribeHtlcEvents(input: SubscribeHtlcEventsRequest, options?: RpcOptions): ServerStreamingCall<SubscribeHtlcEventsRequest, HtlcEvent> {
|
||||||
const method = this.methods[13], opt = this._transport.mergeOptions(options);
|
const method = this.methods[13], opt = this._transport.mergeOptions(options);
|
||||||
return stackIntercept<SubscribeHtlcEventsRequest, HtlcEvent>("serverStreaming", this._transport, method, opt, input);
|
return stackIntercept<SubscribeHtlcEventsRequest, HtlcEvent>("serverStreaming", this._transport, method, opt, input);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* Deprecated, use SendPaymentV2. SendPayment attempts to route a payment
|
* Deprecated, use SendPaymentV2. SendPayment attempts to route a payment
|
||||||
* described by the passed PaymentRequest to the final destination. The call
|
* described by the passed PaymentRequest to the final destination. The call
|
||||||
* returns a stream of payment status updates.
|
* returns a stream of payment status updates.
|
||||||
*
|
*
|
||||||
* @deprecated
|
* @deprecated
|
||||||
* @generated from protobuf rpc: SendPayment(routerrpc.SendPaymentRequest) returns (stream routerrpc.PaymentStatus);
|
* @generated from protobuf rpc: SendPayment(routerrpc.SendPaymentRequest) returns (stream routerrpc.PaymentStatus);
|
||||||
*/
|
*/
|
||||||
sendPayment(input: SendPaymentRequest, options?: RpcOptions): ServerStreamingCall<SendPaymentRequest, PaymentStatus> {
|
sendPayment(input: SendPaymentRequest, options?: RpcOptions): ServerStreamingCall<SendPaymentRequest, PaymentStatus> {
|
||||||
const method = this.methods[14], opt = this._transport.mergeOptions(options);
|
const method = this.methods[14], opt = this._transport.mergeOptions(options);
|
||||||
return stackIntercept<SendPaymentRequest, PaymentStatus>("serverStreaming", this._transport, method, opt, input);
|
return stackIntercept<SendPaymentRequest, PaymentStatus>("serverStreaming", this._transport, method, opt, input);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* Deprecated, use TrackPaymentV2. TrackPayment returns an update stream for
|
* Deprecated, use TrackPaymentV2. TrackPayment returns an update stream for
|
||||||
* the payment identified by the payment hash.
|
* the payment identified by the payment hash.
|
||||||
*
|
*
|
||||||
* @deprecated
|
* @deprecated
|
||||||
* @generated from protobuf rpc: TrackPayment(routerrpc.TrackPaymentRequest) returns (stream routerrpc.PaymentStatus);
|
* @generated from protobuf rpc: TrackPayment(routerrpc.TrackPaymentRequest) returns (stream routerrpc.PaymentStatus);
|
||||||
*/
|
*/
|
||||||
trackPayment(input: TrackPaymentRequest, options?: RpcOptions): ServerStreamingCall<TrackPaymentRequest, PaymentStatus> {
|
trackPayment(input: TrackPaymentRequest, options?: RpcOptions): ServerStreamingCall<TrackPaymentRequest, PaymentStatus> {
|
||||||
const method = this.methods[15], opt = this._transport.mergeOptions(options);
|
const method = this.methods[15], opt = this._transport.mergeOptions(options);
|
||||||
return stackIntercept<TrackPaymentRequest, PaymentStatus>("serverStreaming", this._transport, method, opt, input);
|
return stackIntercept<TrackPaymentRequest, PaymentStatus>("serverStreaming", this._transport, method, opt, input);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* *
|
* *
|
||||||
* HtlcInterceptor dispatches a bi-directional streaming RPC in which
|
* HtlcInterceptor dispatches a bi-directional streaming RPC in which
|
||||||
* Forwarded HTLC requests are sent to the client and the client responds with
|
* Forwarded HTLC requests are sent to the client and the client responds with
|
||||||
* a boolean that tells LND if this htlc should be intercepted.
|
* a boolean that tells LND if this htlc should be intercepted.
|
||||||
* In case of interception, the htlc can be either settled, cancelled or
|
* In case of interception, the htlc can be either settled, cancelled or
|
||||||
* resumed later by using the ResolveHoldForward endpoint.
|
* resumed later by using the ResolveHoldForward endpoint.
|
||||||
*
|
*
|
||||||
* @generated from protobuf rpc: HtlcInterceptor(stream routerrpc.ForwardHtlcInterceptResponse) returns (stream routerrpc.ForwardHtlcInterceptRequest);
|
* @generated from protobuf rpc: HtlcInterceptor(stream routerrpc.ForwardHtlcInterceptResponse) returns (stream routerrpc.ForwardHtlcInterceptRequest);
|
||||||
*/
|
*/
|
||||||
htlcInterceptor(options?: RpcOptions): DuplexStreamingCall<ForwardHtlcInterceptResponse, ForwardHtlcInterceptRequest> {
|
htlcInterceptor(options?: RpcOptions): DuplexStreamingCall<ForwardHtlcInterceptResponse, ForwardHtlcInterceptRequest> {
|
||||||
const method = this.methods[16], opt = this._transport.mergeOptions(options);
|
const method = this.methods[16], opt = this._transport.mergeOptions(options);
|
||||||
return stackIntercept<ForwardHtlcInterceptResponse, ForwardHtlcInterceptRequest>("duplex", this._transport, method, opt);
|
return stackIntercept<ForwardHtlcInterceptResponse, ForwardHtlcInterceptRequest>("duplex", this._transport, method, opt);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* UpdateChanStatus attempts to manually set the state of a channel
|
* UpdateChanStatus attempts to manually set the state of a channel
|
||||||
* (enabled, disabled, or auto). A manual "disable" request will cause the
|
* (enabled, disabled, or auto). A manual "disable" request will cause the
|
||||||
* channel to stay disabled until a subsequent manual request of either
|
* channel to stay disabled until a subsequent manual request of either
|
||||||
* "enable" or "auto".
|
* "enable" or "auto".
|
||||||
*
|
*
|
||||||
* @generated from protobuf rpc: UpdateChanStatus(routerrpc.UpdateChanStatusRequest) returns (routerrpc.UpdateChanStatusResponse);
|
* @generated from protobuf rpc: UpdateChanStatus(routerrpc.UpdateChanStatusRequest) returns (routerrpc.UpdateChanStatusResponse);
|
||||||
*/
|
*/
|
||||||
updateChanStatus(input: UpdateChanStatusRequest, options?: RpcOptions): UnaryCall<UpdateChanStatusRequest, UpdateChanStatusResponse> {
|
updateChanStatus(input: UpdateChanStatusRequest, options?: RpcOptions): UnaryCall<UpdateChanStatusRequest, UpdateChanStatusResponse> {
|
||||||
const method = this.methods[17], opt = this._transport.mergeOptions(options);
|
const method = this.methods[17], opt = this._transport.mergeOptions(options);
|
||||||
return stackIntercept<UpdateChanStatusRequest, UpdateChanStatusResponse>("unary", this._transport, method, opt, input);
|
return stackIntercept<UpdateChanStatusRequest, UpdateChanStatusResponse>("unary", this._transport, method, opt, input);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
7088
proto/lnd/router.ts
7088
proto/lnd/router.ts
File diff suppressed because it is too large
Load diff
|
|
@ -1,200 +1,200 @@
|
||||||
syntax = "proto3";
|
syntax = "proto3";
|
||||||
|
|
||||||
package chainrpc;
|
package chainrpc;
|
||||||
|
|
||||||
option go_package = "github.com/lightningnetwork/lnd/lnrpc/chainrpc";
|
option go_package = "github.com/lightningnetwork/lnd/lnrpc/chainrpc";
|
||||||
|
|
||||||
// ChainNotifier is a service that can be used to get information about the
|
// ChainNotifier is a service that can be used to get information about the
|
||||||
// chain backend by registering notifiers for chain events.
|
// chain backend by registering notifiers for chain events.
|
||||||
service ChainNotifier {
|
service ChainNotifier {
|
||||||
/*
|
/*
|
||||||
RegisterConfirmationsNtfn is a synchronous response-streaming RPC that
|
RegisterConfirmationsNtfn is a synchronous response-streaming RPC that
|
||||||
registers an intent for a client to be notified once a confirmation request
|
registers an intent for a client to be notified once a confirmation request
|
||||||
has reached its required number of confirmations on-chain.
|
has reached its required number of confirmations on-chain.
|
||||||
|
|
||||||
A confirmation request must have a valid output script. It is also possible
|
A confirmation request must have a valid output script. It is also possible
|
||||||
to give a transaction ID. If the transaction ID is not set, a notification
|
to give a transaction ID. If the transaction ID is not set, a notification
|
||||||
is sent once the output script confirms. If the transaction ID is also set,
|
is sent once the output script confirms. If the transaction ID is also set,
|
||||||
a notification is sent once the output script confirms in the given
|
a notification is sent once the output script confirms in the given
|
||||||
transaction.
|
transaction.
|
||||||
*/
|
*/
|
||||||
rpc RegisterConfirmationsNtfn (ConfRequest) returns (stream ConfEvent);
|
rpc RegisterConfirmationsNtfn (ConfRequest) returns (stream ConfEvent);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
RegisterSpendNtfn is a synchronous response-streaming RPC that registers an
|
RegisterSpendNtfn is a synchronous response-streaming RPC that registers an
|
||||||
intent for a client to be notification once a spend request has been spent
|
intent for a client to be notification once a spend request has been spent
|
||||||
by a transaction that has confirmed on-chain.
|
by a transaction that has confirmed on-chain.
|
||||||
|
|
||||||
A client can specify whether the spend request should be for a particular
|
A client can specify whether the spend request should be for a particular
|
||||||
outpoint or for an output script by specifying a zero outpoint.
|
outpoint or for an output script by specifying a zero outpoint.
|
||||||
*/
|
*/
|
||||||
rpc RegisterSpendNtfn (SpendRequest) returns (stream SpendEvent);
|
rpc RegisterSpendNtfn (SpendRequest) returns (stream SpendEvent);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
RegisterBlockEpochNtfn is a synchronous response-streaming RPC that
|
RegisterBlockEpochNtfn is a synchronous response-streaming RPC that
|
||||||
registers an intent for a client to be notified of blocks in the chain. The
|
registers an intent for a client to be notified of blocks in the chain. The
|
||||||
stream will return a hash and height tuple of a block for each new/stale
|
stream will return a hash and height tuple of a block for each new/stale
|
||||||
block in the chain. It is the client's responsibility to determine whether
|
block in the chain. It is the client's responsibility to determine whether
|
||||||
the tuple returned is for a new or stale block in the chain.
|
the tuple returned is for a new or stale block in the chain.
|
||||||
|
|
||||||
A client can also request a historical backlog of blocks from a particular
|
A client can also request a historical backlog of blocks from a particular
|
||||||
point. This allows clients to be idempotent by ensuring that they do not
|
point. This allows clients to be idempotent by ensuring that they do not
|
||||||
missing processing a single block within the chain.
|
missing processing a single block within the chain.
|
||||||
*/
|
*/
|
||||||
rpc RegisterBlockEpochNtfn (BlockEpoch) returns (stream BlockEpoch);
|
rpc RegisterBlockEpochNtfn (BlockEpoch) returns (stream BlockEpoch);
|
||||||
}
|
}
|
||||||
|
|
||||||
message ConfRequest {
|
message ConfRequest {
|
||||||
/*
|
/*
|
||||||
The transaction hash for which we should request a confirmation notification
|
The transaction hash for which we should request a confirmation notification
|
||||||
for. If set to a hash of all zeros, then the confirmation notification will
|
for. If set to a hash of all zeros, then the confirmation notification will
|
||||||
be requested for the script instead.
|
be requested for the script instead.
|
||||||
*/
|
*/
|
||||||
bytes txid = 1;
|
bytes txid = 1;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
An output script within a transaction with the hash above which will be used
|
An output script within a transaction with the hash above which will be used
|
||||||
by light clients to match block filters. If the transaction hash is set to a
|
by light clients to match block filters. If the transaction hash is set to a
|
||||||
hash of all zeros, then a confirmation notification will be requested for
|
hash of all zeros, then a confirmation notification will be requested for
|
||||||
this script instead.
|
this script instead.
|
||||||
*/
|
*/
|
||||||
bytes script = 2;
|
bytes script = 2;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
The number of desired confirmations the transaction/output script should
|
The number of desired confirmations the transaction/output script should
|
||||||
reach before dispatching a confirmation notification.
|
reach before dispatching a confirmation notification.
|
||||||
*/
|
*/
|
||||||
uint32 num_confs = 3;
|
uint32 num_confs = 3;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
The earliest height in the chain for which the transaction/output script
|
The earliest height in the chain for which the transaction/output script
|
||||||
could have been included in a block. This should in most cases be set to the
|
could have been included in a block. This should in most cases be set to the
|
||||||
broadcast height of the transaction/output script.
|
broadcast height of the transaction/output script.
|
||||||
*/
|
*/
|
||||||
uint32 height_hint = 4;
|
uint32 height_hint = 4;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
If true, then the block that mines the specified txid/script will be
|
If true, then the block that mines the specified txid/script will be
|
||||||
included in eventual the notification event.
|
included in eventual the notification event.
|
||||||
*/
|
*/
|
||||||
bool include_block = 5;
|
bool include_block = 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
message ConfDetails {
|
message ConfDetails {
|
||||||
// The raw bytes of the confirmed transaction.
|
// The raw bytes of the confirmed transaction.
|
||||||
bytes raw_tx = 1;
|
bytes raw_tx = 1;
|
||||||
|
|
||||||
// The hash of the block in which the confirmed transaction was included in.
|
// The hash of the block in which the confirmed transaction was included in.
|
||||||
bytes block_hash = 2;
|
bytes block_hash = 2;
|
||||||
|
|
||||||
// The height of the block in which the confirmed transaction was included
|
// The height of the block in which the confirmed transaction was included
|
||||||
// in.
|
// in.
|
||||||
uint32 block_height = 3;
|
uint32 block_height = 3;
|
||||||
|
|
||||||
// The index of the confirmed transaction within the block.
|
// The index of the confirmed transaction within the block.
|
||||||
uint32 tx_index = 4;
|
uint32 tx_index = 4;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
The raw bytes of the block that mined the transaction. Only included if
|
The raw bytes of the block that mined the transaction. Only included if
|
||||||
include_block was set in the request.
|
include_block was set in the request.
|
||||||
*/
|
*/
|
||||||
bytes raw_block = 5;
|
bytes raw_block = 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
message Reorg {
|
message Reorg {
|
||||||
// TODO(wilmer): need to know how the client will use this first.
|
// TODO(wilmer): need to know how the client will use this first.
|
||||||
}
|
}
|
||||||
|
|
||||||
message ConfEvent {
|
message ConfEvent {
|
||||||
oneof event {
|
oneof event {
|
||||||
/*
|
/*
|
||||||
An event that includes the confirmation details of the request
|
An event that includes the confirmation details of the request
|
||||||
(txid/ouput script).
|
(txid/ouput script).
|
||||||
*/
|
*/
|
||||||
ConfDetails conf = 1;
|
ConfDetails conf = 1;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
An event send when the transaction of the request is reorged out of the
|
An event send when the transaction of the request is reorged out of the
|
||||||
chain.
|
chain.
|
||||||
*/
|
*/
|
||||||
Reorg reorg = 2;
|
Reorg reorg = 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
message Outpoint {
|
message Outpoint {
|
||||||
// The hash of the transaction.
|
// The hash of the transaction.
|
||||||
bytes hash = 1;
|
bytes hash = 1;
|
||||||
|
|
||||||
// The index of the output within the transaction.
|
// The index of the output within the transaction.
|
||||||
uint32 index = 2;
|
uint32 index = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
message SpendRequest {
|
message SpendRequest {
|
||||||
/*
|
/*
|
||||||
The outpoint for which we should request a spend notification for. If set to
|
The outpoint for which we should request a spend notification for. If set to
|
||||||
a zero outpoint, then the spend notification will be requested for the
|
a zero outpoint, then the spend notification will be requested for the
|
||||||
script instead. A zero or nil outpoint is not supported for Taproot spends
|
script instead. A zero or nil outpoint is not supported for Taproot spends
|
||||||
because the output script cannot reliably be computed from the witness alone
|
because the output script cannot reliably be computed from the witness alone
|
||||||
and the spent output script is not always available in the rescan context.
|
and the spent output script is not always available in the rescan context.
|
||||||
So an outpoint must _always_ be specified when registering a spend
|
So an outpoint must _always_ be specified when registering a spend
|
||||||
notification for a Taproot output.
|
notification for a Taproot output.
|
||||||
*/
|
*/
|
||||||
Outpoint outpoint = 1;
|
Outpoint outpoint = 1;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
The output script for the outpoint above. This will be used by light clients
|
The output script for the outpoint above. This will be used by light clients
|
||||||
to match block filters. If the outpoint is set to a zero outpoint, then a
|
to match block filters. If the outpoint is set to a zero outpoint, then a
|
||||||
spend notification will be requested for this script instead.
|
spend notification will be requested for this script instead.
|
||||||
*/
|
*/
|
||||||
bytes script = 2;
|
bytes script = 2;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
The earliest height in the chain for which the outpoint/output script could
|
The earliest height in the chain for which the outpoint/output script could
|
||||||
have been spent. This should in most cases be set to the broadcast height of
|
have been spent. This should in most cases be set to the broadcast height of
|
||||||
the outpoint/output script.
|
the outpoint/output script.
|
||||||
*/
|
*/
|
||||||
uint32 height_hint = 3;
|
uint32 height_hint = 3;
|
||||||
|
|
||||||
// TODO(wilmer): extend to support num confs on spending tx.
|
// TODO(wilmer): extend to support num confs on spending tx.
|
||||||
}
|
}
|
||||||
|
|
||||||
message SpendDetails {
|
message SpendDetails {
|
||||||
// The outpoint was that spent.
|
// The outpoint was that spent.
|
||||||
Outpoint spending_outpoint = 1;
|
Outpoint spending_outpoint = 1;
|
||||||
|
|
||||||
// The raw bytes of the spending transaction.
|
// The raw bytes of the spending transaction.
|
||||||
bytes raw_spending_tx = 2;
|
bytes raw_spending_tx = 2;
|
||||||
|
|
||||||
// The hash of the spending transaction.
|
// The hash of the spending transaction.
|
||||||
bytes spending_tx_hash = 3;
|
bytes spending_tx_hash = 3;
|
||||||
|
|
||||||
// The input of the spending transaction that fulfilled the spend request.
|
// The input of the spending transaction that fulfilled the spend request.
|
||||||
uint32 spending_input_index = 4;
|
uint32 spending_input_index = 4;
|
||||||
|
|
||||||
// The height at which the spending transaction was included in a block.
|
// The height at which the spending transaction was included in a block.
|
||||||
uint32 spending_height = 5;
|
uint32 spending_height = 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
message SpendEvent {
|
message SpendEvent {
|
||||||
oneof event {
|
oneof event {
|
||||||
/*
|
/*
|
||||||
An event that includes the details of the spending transaction of the
|
An event that includes the details of the spending transaction of the
|
||||||
request (outpoint/output script).
|
request (outpoint/output script).
|
||||||
*/
|
*/
|
||||||
SpendDetails spend = 1;
|
SpendDetails spend = 1;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
An event sent when the spending transaction of the request was
|
An event sent when the spending transaction of the request was
|
||||||
reorged out of the chain.
|
reorged out of the chain.
|
||||||
*/
|
*/
|
||||||
Reorg reorg = 2;
|
Reorg reorg = 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
message BlockEpoch {
|
message BlockEpoch {
|
||||||
// The hash of the block.
|
// The hash of the block.
|
||||||
bytes hash = 1;
|
bytes hash = 1;
|
||||||
|
|
||||||
// The height of the block.
|
// The height of the block.
|
||||||
uint32 height = 2;
|
uint32 height = 2;
|
||||||
}
|
}
|
||||||
|
|
@ -1,175 +1,175 @@
|
||||||
syntax = "proto3";
|
syntax = "proto3";
|
||||||
|
|
||||||
import "lightning.proto";
|
import "lightning.proto";
|
||||||
|
|
||||||
package invoicesrpc;
|
package invoicesrpc;
|
||||||
|
|
||||||
option go_package = "github.com/lightningnetwork/lnd/lnrpc/invoicesrpc";
|
option go_package = "github.com/lightningnetwork/lnd/lnrpc/invoicesrpc";
|
||||||
|
|
||||||
// Invoices is a service that can be used to create, accept, settle and cancel
|
// Invoices is a service that can be used to create, accept, settle and cancel
|
||||||
// invoices.
|
// invoices.
|
||||||
service Invoices {
|
service Invoices {
|
||||||
/*
|
/*
|
||||||
SubscribeSingleInvoice returns a uni-directional stream (server -> client)
|
SubscribeSingleInvoice returns a uni-directional stream (server -> client)
|
||||||
to notify the client of state transitions of the specified invoice.
|
to notify the client of state transitions of the specified invoice.
|
||||||
Initially the current invoice state is always sent out.
|
Initially the current invoice state is always sent out.
|
||||||
*/
|
*/
|
||||||
rpc SubscribeSingleInvoice (SubscribeSingleInvoiceRequest)
|
rpc SubscribeSingleInvoice (SubscribeSingleInvoiceRequest)
|
||||||
returns (stream lnrpc.Invoice);
|
returns (stream lnrpc.Invoice);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
CancelInvoice cancels a currently open invoice. If the invoice is already
|
CancelInvoice cancels a currently open invoice. If the invoice is already
|
||||||
canceled, this call will succeed. If the invoice is already settled, it will
|
canceled, this call will succeed. If the invoice is already settled, it will
|
||||||
fail.
|
fail.
|
||||||
*/
|
*/
|
||||||
rpc CancelInvoice (CancelInvoiceMsg) returns (CancelInvoiceResp);
|
rpc CancelInvoice (CancelInvoiceMsg) returns (CancelInvoiceResp);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
AddHoldInvoice creates a hold invoice. It ties the invoice to the hash
|
AddHoldInvoice creates a hold invoice. It ties the invoice to the hash
|
||||||
supplied in the request.
|
supplied in the request.
|
||||||
*/
|
*/
|
||||||
rpc AddHoldInvoice (AddHoldInvoiceRequest) returns (AddHoldInvoiceResp);
|
rpc AddHoldInvoice (AddHoldInvoiceRequest) returns (AddHoldInvoiceResp);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
SettleInvoice settles an accepted invoice. If the invoice is already
|
SettleInvoice settles an accepted invoice. If the invoice is already
|
||||||
settled, this call will succeed.
|
settled, this call will succeed.
|
||||||
*/
|
*/
|
||||||
rpc SettleInvoice (SettleInvoiceMsg) returns (SettleInvoiceResp);
|
rpc SettleInvoice (SettleInvoiceMsg) returns (SettleInvoiceResp);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
LookupInvoiceV2 attempts to look up at invoice. An invoice can be refrenced
|
LookupInvoiceV2 attempts to look up at invoice. An invoice can be refrenced
|
||||||
using either its payment hash, payment address, or set ID.
|
using either its payment hash, payment address, or set ID.
|
||||||
*/
|
*/
|
||||||
rpc LookupInvoiceV2 (LookupInvoiceMsg) returns (lnrpc.Invoice);
|
rpc LookupInvoiceV2 (LookupInvoiceMsg) returns (lnrpc.Invoice);
|
||||||
}
|
}
|
||||||
|
|
||||||
message CancelInvoiceMsg {
|
message CancelInvoiceMsg {
|
||||||
// Hash corresponding to the (hold) invoice to cancel. When using
|
// Hash corresponding to the (hold) invoice to cancel. When using
|
||||||
// REST, this field must be encoded as base64.
|
// REST, this field must be encoded as base64.
|
||||||
bytes payment_hash = 1;
|
bytes payment_hash = 1;
|
||||||
}
|
}
|
||||||
message CancelInvoiceResp {
|
message CancelInvoiceResp {
|
||||||
}
|
}
|
||||||
|
|
||||||
message AddHoldInvoiceRequest {
|
message AddHoldInvoiceRequest {
|
||||||
/*
|
/*
|
||||||
An optional memo to attach along with the invoice. Used for record keeping
|
An optional memo to attach along with the invoice. Used for record keeping
|
||||||
purposes for the invoice's creator, and will also be set in the description
|
purposes for the invoice's creator, and will also be set in the description
|
||||||
field of the encoded payment request if the description_hash field is not
|
field of the encoded payment request if the description_hash field is not
|
||||||
being used.
|
being used.
|
||||||
*/
|
*/
|
||||||
string memo = 1;
|
string memo = 1;
|
||||||
|
|
||||||
// The hash of the preimage
|
// The hash of the preimage
|
||||||
bytes hash = 2;
|
bytes hash = 2;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
The value of this invoice in satoshis
|
The value of this invoice in satoshis
|
||||||
|
|
||||||
The fields value and value_msat are mutually exclusive.
|
The fields value and value_msat are mutually exclusive.
|
||||||
*/
|
*/
|
||||||
int64 value = 3;
|
int64 value = 3;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
The value of this invoice in millisatoshis
|
The value of this invoice in millisatoshis
|
||||||
|
|
||||||
The fields value and value_msat are mutually exclusive.
|
The fields value and value_msat are mutually exclusive.
|
||||||
*/
|
*/
|
||||||
int64 value_msat = 10;
|
int64 value_msat = 10;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Hash (SHA-256) of a description of the payment. Used if the description of
|
Hash (SHA-256) of a description of the payment. Used if the description of
|
||||||
payment (memo) is too long to naturally fit within the description field
|
payment (memo) is too long to naturally fit within the description field
|
||||||
of an encoded payment request.
|
of an encoded payment request.
|
||||||
*/
|
*/
|
||||||
bytes description_hash = 4;
|
bytes description_hash = 4;
|
||||||
|
|
||||||
// Payment request expiry time in seconds. Default is 3600 (1 hour).
|
// Payment request expiry time in seconds. Default is 3600 (1 hour).
|
||||||
int64 expiry = 5;
|
int64 expiry = 5;
|
||||||
|
|
||||||
// Fallback on-chain address.
|
// Fallback on-chain address.
|
||||||
string fallback_addr = 6;
|
string fallback_addr = 6;
|
||||||
|
|
||||||
// Delta to use for the time-lock of the CLTV extended to the final hop.
|
// Delta to use for the time-lock of the CLTV extended to the final hop.
|
||||||
uint64 cltv_expiry = 7;
|
uint64 cltv_expiry = 7;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Route hints that can each be individually used to assist in reaching the
|
Route hints that can each be individually used to assist in reaching the
|
||||||
invoice's destination.
|
invoice's destination.
|
||||||
*/
|
*/
|
||||||
repeated lnrpc.RouteHint route_hints = 8;
|
repeated lnrpc.RouteHint route_hints = 8;
|
||||||
|
|
||||||
// Whether this invoice should include routing hints for private channels.
|
// Whether this invoice should include routing hints for private channels.
|
||||||
bool private = 9;
|
bool private = 9;
|
||||||
}
|
}
|
||||||
|
|
||||||
message AddHoldInvoiceResp {
|
message AddHoldInvoiceResp {
|
||||||
/*
|
/*
|
||||||
A bare-bones invoice for a payment within the Lightning Network. With the
|
A bare-bones invoice for a payment within the Lightning Network. With the
|
||||||
details of the invoice, the sender has all the data necessary to send a
|
details of the invoice, the sender has all the data necessary to send a
|
||||||
payment to the recipient.
|
payment to the recipient.
|
||||||
*/
|
*/
|
||||||
string payment_request = 1;
|
string payment_request = 1;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
The "add" index of this invoice. Each newly created invoice will increment
|
The "add" index of this invoice. Each newly created invoice will increment
|
||||||
this index making it monotonically increasing. Callers to the
|
this index making it monotonically increasing. Callers to the
|
||||||
SubscribeInvoices call can use this to instantly get notified of all added
|
SubscribeInvoices call can use this to instantly get notified of all added
|
||||||
invoices with an add_index greater than this one.
|
invoices with an add_index greater than this one.
|
||||||
*/
|
*/
|
||||||
uint64 add_index = 2;
|
uint64 add_index = 2;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
The payment address of the generated invoice. This value should be used
|
The payment address of the generated invoice. This value should be used
|
||||||
in all payments for this invoice as we require it for end to end
|
in all payments for this invoice as we require it for end to end
|
||||||
security.
|
security.
|
||||||
*/
|
*/
|
||||||
bytes payment_addr = 3;
|
bytes payment_addr = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
message SettleInvoiceMsg {
|
message SettleInvoiceMsg {
|
||||||
// Externally discovered pre-image that should be used to settle the hold
|
// Externally discovered pre-image that should be used to settle the hold
|
||||||
// invoice.
|
// invoice.
|
||||||
bytes preimage = 1;
|
bytes preimage = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
message SettleInvoiceResp {
|
message SettleInvoiceResp {
|
||||||
}
|
}
|
||||||
|
|
||||||
message SubscribeSingleInvoiceRequest {
|
message SubscribeSingleInvoiceRequest {
|
||||||
reserved 1;
|
reserved 1;
|
||||||
|
|
||||||
// Hash corresponding to the (hold) invoice to subscribe to. When using
|
// Hash corresponding to the (hold) invoice to subscribe to. When using
|
||||||
// REST, this field must be encoded as base64url.
|
// REST, this field must be encoded as base64url.
|
||||||
bytes r_hash = 2;
|
bytes r_hash = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum LookupModifier {
|
enum LookupModifier {
|
||||||
// The default look up modifier, no look up behavior is changed.
|
// The default look up modifier, no look up behavior is changed.
|
||||||
DEFAULT = 0;
|
DEFAULT = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Indicates that when a look up is done based on a set_id, then only that set
|
Indicates that when a look up is done based on a set_id, then only that set
|
||||||
of HTLCs related to that set ID should be returned.
|
of HTLCs related to that set ID should be returned.
|
||||||
*/
|
*/
|
||||||
HTLC_SET_ONLY = 1;
|
HTLC_SET_ONLY = 1;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Indicates that when a look up is done using a payment_addr, then no HTLCs
|
Indicates that when a look up is done using a payment_addr, then no HTLCs
|
||||||
related to the payment_addr should be returned. This is useful when one
|
related to the payment_addr should be returned. This is useful when one
|
||||||
wants to be able to obtain the set of associated setIDs with a given
|
wants to be able to obtain the set of associated setIDs with a given
|
||||||
invoice, then look up the sub-invoices "projected" by that set ID.
|
invoice, then look up the sub-invoices "projected" by that set ID.
|
||||||
*/
|
*/
|
||||||
HTLC_SET_BLANK = 2;
|
HTLC_SET_BLANK = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
message LookupInvoiceMsg {
|
message LookupInvoiceMsg {
|
||||||
oneof invoice_ref {
|
oneof invoice_ref {
|
||||||
// When using REST, this field must be encoded as base64.
|
// When using REST, this field must be encoded as base64.
|
||||||
bytes payment_hash = 1;
|
bytes payment_hash = 1;
|
||||||
bytes payment_addr = 2;
|
bytes payment_addr = 2;
|
||||||
bytes set_id = 3;
|
bytes set_id = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
LookupModifier lookup_modifier = 4;
|
LookupModifier lookup_modifier = 4;
|
||||||
}
|
}
|
||||||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -1,386 +1,386 @@
|
||||||
syntax = "proto3";
|
syntax = "proto3";
|
||||||
|
|
||||||
package methods;
|
package methods;
|
||||||
|
|
||||||
import "google/protobuf/descriptor.proto";
|
import "google/protobuf/descriptor.proto";
|
||||||
import "structs.proto";
|
import "structs.proto";
|
||||||
|
|
||||||
option go_package = "github.com/shocknet/lightning.pub";
|
option go_package = "github.com/shocknet/lightning.pub";
|
||||||
option (file_options) = {
|
option (file_options) = {
|
||||||
supported_http_methods:["post", "get"];
|
supported_http_methods:["post", "get"];
|
||||||
supported_auths:[
|
supported_auths:[
|
||||||
{
|
{
|
||||||
id: "guest"
|
id: "guest"
|
||||||
name: "Guest"
|
name: "Guest"
|
||||||
context:[]
|
context:[]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "user"
|
id: "user"
|
||||||
name: "User",
|
name: "User",
|
||||||
context:[{
|
context:[{
|
||||||
key:"user_id",
|
key:"user_id",
|
||||||
value:"string"
|
value:"string"
|
||||||
},{
|
},{
|
||||||
key:"app_id",
|
key:"app_id",
|
||||||
value:"string"
|
value:"string"
|
||||||
},{
|
},{
|
||||||
key:"app_user_id",
|
key:"app_user_id",
|
||||||
value:"string"
|
value:"string"
|
||||||
}]
|
}]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "admin",
|
id: "admin",
|
||||||
name: "Admin",
|
name: "Admin",
|
||||||
//encrypted:true,
|
//encrypted:true,
|
||||||
context:{
|
context:{
|
||||||
key:"admin_id",
|
key:"admin_id",
|
||||||
value:"string"
|
value:"string"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "metrics",
|
id: "metrics",
|
||||||
name: "Metrics",
|
name: "Metrics",
|
||||||
//encrypted:true,
|
//encrypted:true,
|
||||||
context:{
|
context:{
|
||||||
key:"operator_id",
|
key:"operator_id",
|
||||||
value:"string"
|
value:"string"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id:"app",
|
id:"app",
|
||||||
name:"App",
|
name:"App",
|
||||||
context:{
|
context:{
|
||||||
key:"app_id",
|
key:"app_id",
|
||||||
value: "string"
|
value: "string"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
message MethodQueryOptions {
|
message MethodQueryOptions {
|
||||||
repeated string items = 1;
|
repeated string items = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
extend google.protobuf.MethodOptions { // TODO: move this stuff to dep repo?
|
extend google.protobuf.MethodOptions { // TODO: move this stuff to dep repo?
|
||||||
string auth_type = 50003;
|
string auth_type = 50003;
|
||||||
string http_method = 50004;
|
string http_method = 50004;
|
||||||
string http_route = 50005;
|
string http_route = 50005;
|
||||||
MethodQueryOptions query = 50006;
|
MethodQueryOptions query = 50006;
|
||||||
bool nostr = 50007;
|
bool nostr = 50007;
|
||||||
bool batch = 50008;
|
bool batch = 50008;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
message ProtoFileOptions {
|
message ProtoFileOptions {
|
||||||
message SupportedAuth {
|
message SupportedAuth {
|
||||||
string id = 1;
|
string id = 1;
|
||||||
string name = 2;
|
string name = 2;
|
||||||
bool encrypted = 3;
|
bool encrypted = 3;
|
||||||
map<string,string> context = 4;
|
map<string,string> context = 4;
|
||||||
}
|
}
|
||||||
repeated SupportedAuth supported_auths = 1;
|
repeated SupportedAuth supported_auths = 1;
|
||||||
repeated string supported_http_methods = 2;
|
repeated string supported_http_methods = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
extend google.protobuf.FileOptions {
|
extend google.protobuf.FileOptions {
|
||||||
ProtoFileOptions file_options = 50004;
|
ProtoFileOptions file_options = 50004;
|
||||||
}
|
}
|
||||||
|
|
||||||
service LightningPub {
|
service LightningPub {
|
||||||
// <Admin>
|
// <Admin>
|
||||||
rpc LndGetInfo(structs.LndGetInfoRequest) returns (structs.LndGetInfoResponse){
|
rpc LndGetInfo(structs.LndGetInfoRequest) returns (structs.LndGetInfoResponse){
|
||||||
option (auth_type) = "Admin";
|
option (auth_type) = "Admin";
|
||||||
option (http_method) = "post";
|
option (http_method) = "post";
|
||||||
option (http_route) = "/api/admin/lnd/getinfo";
|
option (http_route) = "/api/admin/lnd/getinfo";
|
||||||
};
|
};
|
||||||
|
|
||||||
rpc AddApp(structs.AddAppRequest) returns (structs.AuthApp) {
|
rpc AddApp(structs.AddAppRequest) returns (structs.AuthApp) {
|
||||||
option (auth_type) = "Admin";
|
option (auth_type) = "Admin";
|
||||||
option (http_method) = "post";
|
option (http_method) = "post";
|
||||||
option (http_route) = "/api/admin/app/add";
|
option (http_route) = "/api/admin/app/add";
|
||||||
};
|
};
|
||||||
|
|
||||||
rpc AuthApp(structs.AuthAppRequest) returns (structs.AuthApp) {
|
rpc AuthApp(structs.AuthAppRequest) returns (structs.AuthApp) {
|
||||||
option (auth_type) = "Admin";
|
option (auth_type) = "Admin";
|
||||||
option (http_method) = "post";
|
option (http_method) = "post";
|
||||||
option (http_route) = "/api/admin/app/auth";
|
option (http_route) = "/api/admin/app/auth";
|
||||||
}
|
}
|
||||||
|
|
||||||
rpc BanUser(structs.BanUserRequest) returns (structs.BanUserResponse) {
|
rpc BanUser(structs.BanUserRequest) returns (structs.BanUserResponse) {
|
||||||
option (auth_type) = "Admin";
|
option (auth_type) = "Admin";
|
||||||
option (http_method) = "post";
|
option (http_method) = "post";
|
||||||
option (http_route) = "/api/admin/user/ban";
|
option (http_route) = "/api/admin/user/ban";
|
||||||
}
|
}
|
||||||
|
|
||||||
rpc GetUsageMetrics(structs.Empty) returns (structs.UsageMetrics) {
|
rpc GetUsageMetrics(structs.Empty) returns (structs.UsageMetrics) {
|
||||||
option (auth_type) = "Metrics";
|
option (auth_type) = "Metrics";
|
||||||
option (http_method) = "post";
|
option (http_method) = "post";
|
||||||
option (http_route) = "/api/reports/usage";
|
option (http_route) = "/api/reports/usage";
|
||||||
}
|
}
|
||||||
|
|
||||||
rpc GetAppsMetrics(structs.AppsMetricsRequest) returns (structs.AppsMetrics) {
|
rpc GetAppsMetrics(structs.AppsMetricsRequest) returns (structs.AppsMetrics) {
|
||||||
option (auth_type) = "Metrics";
|
option (auth_type) = "Metrics";
|
||||||
option (http_method) = "post";
|
option (http_method) = "post";
|
||||||
option (http_route) = "/api/reports/apps";
|
option (http_route) = "/api/reports/apps";
|
||||||
}
|
}
|
||||||
|
|
||||||
rpc GetLndMetrics(structs.LndMetricsRequest) returns (structs.LndMetrics) {
|
rpc GetLndMetrics(structs.LndMetricsRequest) returns (structs.LndMetrics) {
|
||||||
option (auth_type) = "Metrics";
|
option (auth_type) = "Metrics";
|
||||||
option (http_method) = "post";
|
option (http_method) = "post";
|
||||||
option (http_route) = "/api/reports/lnd";
|
option (http_route) = "/api/reports/lnd";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// </Admin>
|
// </Admin>
|
||||||
|
|
||||||
// <Guest>
|
// <Guest>
|
||||||
rpc Health(structs.Empty) returns (structs.Empty){
|
rpc Health(structs.Empty) returns (structs.Empty){
|
||||||
option (auth_type) = "Guest";
|
option (auth_type) = "Guest";
|
||||||
option (http_method) = "get";
|
option (http_method) = "get";
|
||||||
option (http_route) = "/api/health";
|
option (http_route) = "/api/health";
|
||||||
};
|
};
|
||||||
rpc EncryptionExchange(structs.EncryptionExchangeRequest) returns (structs.Empty){
|
rpc EncryptionExchange(structs.EncryptionExchangeRequest) returns (structs.Empty){
|
||||||
option (auth_type) = "Guest";
|
option (auth_type) = "Guest";
|
||||||
option (http_method) = "post";
|
option (http_method) = "post";
|
||||||
option (http_route) = "/api/encryption/exchange";
|
option (http_route) = "/api/encryption/exchange";
|
||||||
};
|
};
|
||||||
|
|
||||||
rpc SetMockInvoiceAsPaid(structs.SetMockInvoiceAsPaidRequest) returns (structs.Empty) {
|
rpc SetMockInvoiceAsPaid(structs.SetMockInvoiceAsPaidRequest) returns (structs.Empty) {
|
||||||
option (auth_type) = "Guest";
|
option (auth_type) = "Guest";
|
||||||
option (http_method) = "post";
|
option (http_method) = "post";
|
||||||
option (http_route) = "/api/lnd/mock/invoice/paid";
|
option (http_route) = "/api/lnd/mock/invoice/paid";
|
||||||
}
|
}
|
||||||
rpc GetLnurlWithdrawInfo(structs.Empty) returns (structs.LnurlWithdrawInfoResponse){
|
rpc GetLnurlWithdrawInfo(structs.Empty) returns (structs.LnurlWithdrawInfoResponse){
|
||||||
option (auth_type) = "Guest";
|
option (auth_type) = "Guest";
|
||||||
option (http_method) = "get";
|
option (http_method) = "get";
|
||||||
option (http_route) = "/api/guest/lnurl_withdraw/info";
|
option (http_route) = "/api/guest/lnurl_withdraw/info";
|
||||||
option (query) = {items: ["k1"]};
|
option (query) = {items: ["k1"]};
|
||||||
}
|
}
|
||||||
rpc HandleLnurlWithdraw(structs.Empty) returns (structs.Empty){
|
rpc HandleLnurlWithdraw(structs.Empty) returns (structs.Empty){
|
||||||
option (auth_type) = "Guest";
|
option (auth_type) = "Guest";
|
||||||
option (http_method) = "get";
|
option (http_method) = "get";
|
||||||
option (http_route) = "/api/guest/lnurl_withdraw/handle";
|
option (http_route) = "/api/guest/lnurl_withdraw/handle";
|
||||||
option (query) = {items: ["k1", "pr"]};
|
option (query) = {items: ["k1", "pr"]};
|
||||||
}
|
}
|
||||||
rpc GetLnurlPayInfo(structs.Empty)returns (structs.LnurlPayInfoResponse) {
|
rpc GetLnurlPayInfo(structs.Empty)returns (structs.LnurlPayInfoResponse) {
|
||||||
option (auth_type) = "Guest";
|
option (auth_type) = "Guest";
|
||||||
option (http_method) = "get";
|
option (http_method) = "get";
|
||||||
option (http_route) = "/api/guest/lnurl_pay/info";
|
option (http_route) = "/api/guest/lnurl_pay/info";
|
||||||
option (query) = {items: ["k1"]};
|
option (query) = {items: ["k1"]};
|
||||||
}
|
}
|
||||||
rpc HandleLnurlPay(structs.Empty)returns (structs.HandleLnurlPayResponse) {
|
rpc HandleLnurlPay(structs.Empty)returns (structs.HandleLnurlPayResponse) {
|
||||||
option (auth_type) = "Guest";
|
option (auth_type) = "Guest";
|
||||||
option (http_method) = "get";
|
option (http_method) = "get";
|
||||||
option (http_route) = "/api/guest/lnurl_pay/handle";
|
option (http_route) = "/api/guest/lnurl_pay/handle";
|
||||||
option (query) = {items: ["k1", "amount", "nostr", "lnurl"]};
|
option (query) = {items: ["k1", "amount", "nostr", "lnurl"]};
|
||||||
}
|
}
|
||||||
rpc HandleLnurlAddress(structs.Empty)returns (structs.LnurlPayInfoResponse) {
|
rpc HandleLnurlAddress(structs.Empty)returns (structs.LnurlPayInfoResponse) {
|
||||||
option (auth_type) = "Guest";
|
option (auth_type) = "Guest";
|
||||||
option (http_method) = "get";
|
option (http_method) = "get";
|
||||||
option (http_route) = "/.well-known/lnurlp/:address_name";
|
option (http_route) = "/.well-known/lnurlp/:address_name";
|
||||||
}
|
}
|
||||||
|
|
||||||
rpc LinkNPubThroughToken(structs.LinkNPubThroughTokenRequest) returns (structs.Empty) {
|
rpc LinkNPubThroughToken(structs.LinkNPubThroughTokenRequest) returns (structs.Empty) {
|
||||||
option (auth_type) = "User";
|
option (auth_type) = "User";
|
||||||
option(http_method) = "post";
|
option(http_method) = "post";
|
||||||
option (http_route) = "/api/guest/npub/link";
|
option (http_route) = "/api/guest/npub/link";
|
||||||
option (nostr) = true;
|
option (nostr) = true;
|
||||||
}
|
}
|
||||||
//</Guest>
|
//</Guest>
|
||||||
|
|
||||||
// <App>
|
// <App>
|
||||||
rpc GetApp(structs.Empty) returns (structs.Application) {
|
rpc GetApp(structs.Empty) returns (structs.Application) {
|
||||||
option (auth_type) = "App";
|
option (auth_type) = "App";
|
||||||
option (http_method) = "post";
|
option (http_method) = "post";
|
||||||
option (http_route) = "/api/app/get";
|
option (http_route) = "/api/app/get";
|
||||||
}
|
}
|
||||||
|
|
||||||
rpc AddAppUser(structs.AddAppUserRequest)returns (structs.AppUser) {
|
rpc AddAppUser(structs.AddAppUserRequest)returns (structs.AppUser) {
|
||||||
option (auth_type) = "App";
|
option (auth_type) = "App";
|
||||||
option (http_method) = "post";
|
option (http_method) = "post";
|
||||||
option (http_route) = "/api/app/user/add";
|
option (http_route) = "/api/app/user/add";
|
||||||
};
|
};
|
||||||
|
|
||||||
rpc AddAppInvoice(structs.AddAppInvoiceRequest) returns (structs.NewInvoiceResponse) {
|
rpc AddAppInvoice(structs.AddAppInvoiceRequest) returns (structs.NewInvoiceResponse) {
|
||||||
option (auth_type) = "App";
|
option (auth_type) = "App";
|
||||||
option (http_method) = "post";
|
option (http_method) = "post";
|
||||||
option (http_route) = "/api/app/add/invoice";
|
option (http_route) = "/api/app/add/invoice";
|
||||||
}
|
}
|
||||||
|
|
||||||
rpc AddAppUserInvoice(structs.AddAppUserInvoiceRequest) returns (structs.NewInvoiceResponse) {
|
rpc AddAppUserInvoice(structs.AddAppUserInvoiceRequest) returns (structs.NewInvoiceResponse) {
|
||||||
option (auth_type) = "App";
|
option (auth_type) = "App";
|
||||||
option (http_method) = "post";
|
option (http_method) = "post";
|
||||||
option (http_route) = "/api/app/user/add/invoice";
|
option (http_route) = "/api/app/user/add/invoice";
|
||||||
}
|
}
|
||||||
|
|
||||||
rpc GetAppUser(structs.GetAppUserRequest) returns (structs.AppUser) {
|
rpc GetAppUser(structs.GetAppUserRequest) returns (structs.AppUser) {
|
||||||
option (auth_type) = "App";
|
option (auth_type) = "App";
|
||||||
option (http_method) = "post";
|
option (http_method) = "post";
|
||||||
option (http_route) = "/api/app/user/get";
|
option (http_route) = "/api/app/user/get";
|
||||||
}
|
}
|
||||||
|
|
||||||
rpc PayAppUserInvoice(structs.PayAppUserInvoiceRequest) returns (structs.PayInvoiceResponse) {
|
rpc PayAppUserInvoice(structs.PayAppUserInvoiceRequest) returns (structs.PayInvoiceResponse) {
|
||||||
option (auth_type) = "App";
|
option (auth_type) = "App";
|
||||||
option (http_method) = "post";
|
option (http_method) = "post";
|
||||||
option (http_route) = "/api/app/invoice/pay";
|
option (http_route) = "/api/app/invoice/pay";
|
||||||
}
|
}
|
||||||
|
|
||||||
rpc SendAppUserToAppUserPayment(structs.SendAppUserToAppUserPaymentRequest) returns (structs.Empty) {
|
rpc SendAppUserToAppUserPayment(structs.SendAppUserToAppUserPaymentRequest) returns (structs.Empty) {
|
||||||
option (auth_type) = "App";
|
option (auth_type) = "App";
|
||||||
option (http_method) = "post";
|
option (http_method) = "post";
|
||||||
option (http_route) = "/api/app/user/internal/pay";
|
option (http_route) = "/api/app/user/internal/pay";
|
||||||
}
|
}
|
||||||
|
|
||||||
rpc SendAppUserToAppPayment(structs.SendAppUserToAppPaymentRequest) returns (structs.Empty) {
|
rpc SendAppUserToAppPayment(structs.SendAppUserToAppPaymentRequest) returns (structs.Empty) {
|
||||||
option (auth_type) = "App";
|
option (auth_type) = "App";
|
||||||
option (http_method) = "post";
|
option (http_method) = "post";
|
||||||
option (http_route) = "/api/app/internal/pay";
|
option (http_route) = "/api/app/internal/pay";
|
||||||
}
|
}
|
||||||
|
|
||||||
rpc GetAppUserLNURLInfo(structs.GetAppUserLNURLInfoRequest) returns (structs.LnurlPayInfoResponse) {
|
rpc GetAppUserLNURLInfo(structs.GetAppUserLNURLInfoRequest) returns (structs.LnurlPayInfoResponse) {
|
||||||
option (auth_type) = "App";
|
option (auth_type) = "App";
|
||||||
option (http_method) = "post";
|
option (http_method) = "post";
|
||||||
option (http_route) = "/api/app/user/lnurl/pay/info";
|
option (http_route) = "/api/app/user/lnurl/pay/info";
|
||||||
}
|
}
|
||||||
rpc SetMockAppUserBalance(structs.SetMockAppUserBalanceRequest) returns (structs.Empty) {
|
rpc SetMockAppUserBalance(structs.SetMockAppUserBalanceRequest) returns (structs.Empty) {
|
||||||
option (auth_type) = "App";
|
option (auth_type) = "App";
|
||||||
option (http_method) = "post";
|
option (http_method) = "post";
|
||||||
option (http_route) = "/api/app/mock/user/blance/set";
|
option (http_route) = "/api/app/mock/user/blance/set";
|
||||||
}
|
}
|
||||||
rpc SetMockAppBalance(structs.SetMockAppBalanceRequest) returns (structs.Empty) {
|
rpc SetMockAppBalance(structs.SetMockAppBalanceRequest) returns (structs.Empty) {
|
||||||
option (auth_type) = "App";
|
option (auth_type) = "App";
|
||||||
option (http_method) = "post";
|
option (http_method) = "post";
|
||||||
option (http_route) = "/api/app/mock/blance/set";
|
option (http_route) = "/api/app/mock/blance/set";
|
||||||
}
|
}
|
||||||
rpc RequestNPubLinkingToken(structs.RequestNPubLinkingTokenRequest) returns (structs.RequestNPubLinkingTokenResponse) {
|
rpc RequestNPubLinkingToken(structs.RequestNPubLinkingTokenRequest) returns (structs.RequestNPubLinkingTokenResponse) {
|
||||||
option (auth_type) = "App";
|
option (auth_type) = "App";
|
||||||
option(http_method) = "post";
|
option(http_method) = "post";
|
||||||
option (http_route) = "/api/app/user/npub/token";
|
option (http_route) = "/api/app/user/npub/token";
|
||||||
}
|
}
|
||||||
// </App>
|
// </App>
|
||||||
|
|
||||||
// <User>
|
// <User>
|
||||||
rpc UserHealth(structs.Empty)returns(structs.Empty){
|
rpc UserHealth(structs.Empty)returns(structs.Empty){
|
||||||
option (auth_type) = "User";
|
option (auth_type) = "User";
|
||||||
option (http_method) = "post";
|
option (http_method) = "post";
|
||||||
option (http_route) = "/api/user/health";
|
option (http_route) = "/api/user/health";
|
||||||
option (nostr) = true;
|
option (nostr) = true;
|
||||||
}
|
}
|
||||||
rpc GetUserInfo(structs.Empty)returns(structs.UserInfo){
|
rpc GetUserInfo(structs.Empty)returns(structs.UserInfo){
|
||||||
option (auth_type) = "User";
|
option (auth_type) = "User";
|
||||||
option (http_method) = "post";
|
option (http_method) = "post";
|
||||||
option (http_route) = "/api/user/info";
|
option (http_route) = "/api/user/info";
|
||||||
option (nostr) = true;
|
option (nostr) = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
rpc AddProduct(structs.AddProductRequest) returns (structs.Product){
|
rpc AddProduct(structs.AddProductRequest) returns (structs.Product){
|
||||||
option (auth_type) = "User";
|
option (auth_type) = "User";
|
||||||
option (http_method) = "post";
|
option (http_method) = "post";
|
||||||
option (http_route) = "/api/user/product/add";
|
option (http_route) = "/api/user/product/add";
|
||||||
option (nostr) = true;
|
option (nostr) = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
rpc NewProductInvoice(structs.Empty) returns (structs.NewInvoiceResponse){
|
rpc NewProductInvoice(structs.Empty) returns (structs.NewInvoiceResponse){
|
||||||
option (auth_type) = "User";
|
option (auth_type) = "User";
|
||||||
option (http_method) = "get";
|
option (http_method) = "get";
|
||||||
option (http_route) = "/api/user/product/get/invoice";
|
option (http_route) = "/api/user/product/get/invoice";
|
||||||
option (query) = {items: ["id"]};
|
option (query) = {items: ["id"]};
|
||||||
option (nostr) = true;
|
option (nostr) = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
rpc GetUserOperations(structs.GetUserOperationsRequest) returns (structs.GetUserOperationsResponse) {
|
rpc GetUserOperations(structs.GetUserOperationsRequest) returns (structs.GetUserOperationsResponse) {
|
||||||
option (auth_type) = "User";
|
option (auth_type) = "User";
|
||||||
option (http_method) = "post";
|
option (http_method) = "post";
|
||||||
option (http_route) = "/api/user/operations";
|
option (http_route) = "/api/user/operations";
|
||||||
option (nostr) = true;
|
option (nostr) = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
rpc NewAddress(structs.NewAddressRequest) returns (structs.NewAddressResponse) {
|
rpc NewAddress(structs.NewAddressRequest) returns (structs.NewAddressResponse) {
|
||||||
option (auth_type) = "User";
|
option (auth_type) = "User";
|
||||||
option (http_method) = "post";
|
option (http_method) = "post";
|
||||||
option (http_route) = "/api/user/chain/new";
|
option (http_route) = "/api/user/chain/new";
|
||||||
option (nostr) = true;
|
option (nostr) = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
rpc PayAddress(structs.PayAddressRequest) returns (structs.PayAddressResponse){
|
rpc PayAddress(structs.PayAddressRequest) returns (structs.PayAddressResponse){
|
||||||
option (auth_type) = "User";
|
option (auth_type) = "User";
|
||||||
option (http_method) = "post";
|
option (http_method) = "post";
|
||||||
option (http_route) = "/api/user/chain/pay";
|
option (http_route) = "/api/user/chain/pay";
|
||||||
option (nostr) = true;
|
option (nostr) = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
rpc NewInvoice(structs.NewInvoiceRequest) returns (structs.NewInvoiceResponse){
|
rpc NewInvoice(structs.NewInvoiceRequest) returns (structs.NewInvoiceResponse){
|
||||||
option (auth_type) = "User";
|
option (auth_type) = "User";
|
||||||
option (http_method) = "post";
|
option (http_method) = "post";
|
||||||
option (http_route) = "/api/user/invoice/new";
|
option (http_route) = "/api/user/invoice/new";
|
||||||
option (nostr) = true;
|
option (nostr) = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
rpc DecodeInvoice(structs.DecodeInvoiceRequest) returns (structs.DecodeInvoiceResponse){
|
rpc DecodeInvoice(structs.DecodeInvoiceRequest) returns (structs.DecodeInvoiceResponse){
|
||||||
option (auth_type) = "User";
|
option (auth_type) = "User";
|
||||||
option (http_method) = "post";
|
option (http_method) = "post";
|
||||||
option (http_route) = "/api/user/invoice/decode";
|
option (http_route) = "/api/user/invoice/decode";
|
||||||
option (nostr) = true;
|
option (nostr) = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
rpc PayInvoice(structs.PayInvoiceRequest) returns (structs.PayInvoiceResponse){
|
rpc PayInvoice(structs.PayInvoiceRequest) returns (structs.PayInvoiceResponse){
|
||||||
option (auth_type) = "User";
|
option (auth_type) = "User";
|
||||||
option (http_method) = "post";
|
option (http_method) = "post";
|
||||||
option (http_route) = "/api/user/invoice/pay";
|
option (http_route) = "/api/user/invoice/pay";
|
||||||
option (nostr) = true;
|
option (nostr) = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
rpc OpenChannel(structs.OpenChannelRequest) returns (structs.OpenChannelResponse){
|
rpc OpenChannel(structs.OpenChannelRequest) returns (structs.OpenChannelResponse){
|
||||||
option (auth_type) = "User";
|
option (auth_type) = "User";
|
||||||
option (http_method) = "post";
|
option (http_method) = "post";
|
||||||
option (http_route) = "/api/user/open/channel";
|
option (http_route) = "/api/user/open/channel";
|
||||||
option (nostr) = true;
|
option (nostr) = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
rpc GetLnurlWithdrawLink(structs.Empty) returns (structs.LnurlLinkResponse){
|
rpc GetLnurlWithdrawLink(structs.Empty) returns (structs.LnurlLinkResponse){
|
||||||
option (auth_type) = "User";
|
option (auth_type) = "User";
|
||||||
option (http_method) = "get";
|
option (http_method) = "get";
|
||||||
option (http_route) = "/api/user/lnurl_withdraw/link";
|
option (http_route) = "/api/user/lnurl_withdraw/link";
|
||||||
option (nostr) = true;
|
option (nostr) = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
rpc GetLnurlPayLink(structs.Empty) returns (structs.LnurlLinkResponse){
|
rpc GetLnurlPayLink(structs.Empty) returns (structs.LnurlLinkResponse){
|
||||||
option (auth_type) = "User";
|
option (auth_type) = "User";
|
||||||
option (http_method) = "get";
|
option (http_method) = "get";
|
||||||
option (http_route) = "/api/user/lnurl_pay/link";
|
option (http_route) = "/api/user/lnurl_pay/link";
|
||||||
option (nostr) = true;
|
option (nostr) = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
rpc GetLNURLChannelLink(structs.Empty) returns (structs.LnurlLinkResponse){
|
rpc GetLNURLChannelLink(structs.Empty) returns (structs.LnurlLinkResponse){
|
||||||
option (auth_type) = "User";
|
option (auth_type) = "User";
|
||||||
option (http_method) = "post";
|
option (http_method) = "post";
|
||||||
option (http_route) = "/api/user/lnurl_channel/url";
|
option (http_route) = "/api/user/lnurl_channel/url";
|
||||||
option (nostr) = true;
|
option (nostr) = true;
|
||||||
}
|
}
|
||||||
rpc GetLiveUserOperations(structs.Empty) returns (stream structs.LiveUserOperation){
|
rpc GetLiveUserOperations(structs.Empty) returns (stream structs.LiveUserOperation){
|
||||||
option (auth_type) = "User";
|
option (auth_type) = "User";
|
||||||
option (http_method) = "post";
|
option (http_method) = "post";
|
||||||
option (http_route) = "/api/user/operations/sub";
|
option (http_route) = "/api/user/operations/sub";
|
||||||
option (nostr) = true;
|
option (nostr) = true;
|
||||||
}
|
}
|
||||||
rpc GetMigrationUpdate(structs.Empty) returns (stream structs.MigrationUpdate){
|
rpc GetMigrationUpdate(structs.Empty) returns (stream structs.MigrationUpdate){
|
||||||
option (auth_type) = "User";
|
option (auth_type) = "User";
|
||||||
option (http_method) = "post";
|
option (http_method) = "post";
|
||||||
option (http_route) = "/api/user/migrations/sub";
|
option (http_route) = "/api/user/migrations/sub";
|
||||||
option (nostr) = true;
|
option (nostr) = true;
|
||||||
}
|
}
|
||||||
rpc GetHttpCreds(structs.Empty) returns (stream structs.HttpCreds){
|
rpc GetHttpCreds(structs.Empty) returns (stream structs.HttpCreds){
|
||||||
option (auth_type) = "User";
|
option (auth_type) = "User";
|
||||||
option (http_method) = "post";
|
option (http_method) = "post";
|
||||||
option (http_route) = "/api/user/http_creds";
|
option (http_route) = "/api/user/http_creds";
|
||||||
option (nostr) = true;
|
option (nostr) = true;
|
||||||
}
|
}
|
||||||
rpc BatchUser(structs.Empty) returns (structs.Empty){
|
rpc BatchUser(structs.Empty) returns (structs.Empty){
|
||||||
option (auth_type) = "User";
|
option (auth_type) = "User";
|
||||||
option (http_method) = "post";
|
option (http_method) = "post";
|
||||||
option (http_route) = "/api/user/batch";
|
option (http_route) = "/api/user/batch";
|
||||||
option (nostr) = true;
|
option (nostr) = true;
|
||||||
option (batch) = true;
|
option (batch) = true;
|
||||||
}
|
}
|
||||||
// </User>
|
// </User>
|
||||||
}
|
}
|
||||||
|
|
@ -1,449 +1,449 @@
|
||||||
syntax = "proto3";
|
syntax = "proto3";
|
||||||
|
|
||||||
package structs;
|
package structs;
|
||||||
|
|
||||||
option go_package = "github.com/shocknet/lightning.pub";
|
option go_package = "github.com/shocknet/lightning.pub";
|
||||||
|
|
||||||
message Empty {}
|
message Empty {}
|
||||||
|
|
||||||
|
|
||||||
message EncryptionExchangeRequest {
|
message EncryptionExchangeRequest {
|
||||||
string publicKey = 1;
|
string publicKey = 1;
|
||||||
string deviceId = 2;
|
string deviceId = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
message UsageMetric {
|
message UsageMetric {
|
||||||
int64 processed_at_ms = 1;
|
int64 processed_at_ms = 1;
|
||||||
int64 parsed_in_nano = 2;
|
int64 parsed_in_nano = 2;
|
||||||
int64 auth_in_nano = 3;
|
int64 auth_in_nano = 3;
|
||||||
int64 validate_in_nano = 4;
|
int64 validate_in_nano = 4;
|
||||||
int64 handle_in_nano = 5;
|
int64 handle_in_nano = 5;
|
||||||
string rpc_name = 6;
|
string rpc_name = 6;
|
||||||
bool batch = 7;
|
bool batch = 7;
|
||||||
bool nostr = 8;
|
bool nostr = 8;
|
||||||
int64 batch_size = 9;
|
int64 batch_size = 9;
|
||||||
}
|
}
|
||||||
|
|
||||||
message UsageMetrics {
|
message UsageMetrics {
|
||||||
repeated UsageMetric metrics = 1;
|
repeated UsageMetric metrics = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
message AppsMetricsRequest {
|
message AppsMetricsRequest {
|
||||||
optional int64 from_unix = 1;
|
optional int64 from_unix = 1;
|
||||||
optional int64 to_unix = 2;
|
optional int64 to_unix = 2;
|
||||||
optional bool include_operations = 3;
|
optional bool include_operations = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
message UsersInfo {
|
message UsersInfo {
|
||||||
int64 total = 1;
|
int64 total = 1;
|
||||||
int64 no_balance = 2;
|
int64 no_balance = 2;
|
||||||
int64 negative_balance = 3;
|
int64 negative_balance = 3;
|
||||||
int64 always_been_inactive = 4;
|
int64 always_been_inactive = 4;
|
||||||
|
|
||||||
int64 balance_avg = 5;
|
int64 balance_avg = 5;
|
||||||
int64 balance_median = 6;
|
int64 balance_median = 6;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
message AppMetrics {
|
message AppMetrics {
|
||||||
Application app = 1;
|
Application app = 1;
|
||||||
|
|
||||||
UsersInfo users = 2;
|
UsersInfo users = 2;
|
||||||
|
|
||||||
int64 received = 5;
|
int64 received = 5;
|
||||||
int64 spent = 6;
|
int64 spent = 6;
|
||||||
int64 available = 7;
|
int64 available = 7;
|
||||||
int64 fees = 8;
|
int64 fees = 8;
|
||||||
int64 invoices = 9;
|
int64 invoices = 9;
|
||||||
|
|
||||||
int64 total_fees = 10;
|
int64 total_fees = 10;
|
||||||
|
|
||||||
repeated UserOperation operations = 100;
|
repeated UserOperation operations = 100;
|
||||||
}
|
}
|
||||||
|
|
||||||
message AppsMetrics {
|
message AppsMetrics {
|
||||||
repeated AppMetrics apps = 1;
|
repeated AppMetrics apps = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
message LndMetricsRequest {
|
message LndMetricsRequest {
|
||||||
optional int64 from_unix = 1;
|
optional int64 from_unix = 1;
|
||||||
optional int64 to_unix = 2;
|
optional int64 to_unix = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
message RoutingEvent {
|
message RoutingEvent {
|
||||||
int64 incoming_channel_id = 1;
|
int64 incoming_channel_id = 1;
|
||||||
int64 incoming_htlc_id=2;
|
int64 incoming_htlc_id=2;
|
||||||
int64 outgoing_channel_id = 3;
|
int64 outgoing_channel_id = 3;
|
||||||
int64 outgoing_htlc_id =4;
|
int64 outgoing_htlc_id =4;
|
||||||
int64 timestamp_ns = 5;
|
int64 timestamp_ns = 5;
|
||||||
string event_type = 6;
|
string event_type = 6;
|
||||||
int64 incoming_amt_msat = 7;
|
int64 incoming_amt_msat = 7;
|
||||||
int64 outgoing_amt_msat = 8;
|
int64 outgoing_amt_msat = 8;
|
||||||
string failure_string = 9;
|
string failure_string = 9;
|
||||||
bool settled = 10;
|
bool settled = 10;
|
||||||
bool offchain = 11;
|
bool offchain = 11;
|
||||||
bool forward_fail_event = 12;
|
bool forward_fail_event = 12;
|
||||||
}
|
}
|
||||||
message ChannelBalanceEvent {
|
message ChannelBalanceEvent {
|
||||||
int64 block_height = 1;
|
int64 block_height = 1;
|
||||||
string channel_id = 2;
|
string channel_id = 2;
|
||||||
int64 local_balance_sats = 3;
|
int64 local_balance_sats = 3;
|
||||||
int64 remote_balance_sats = 4;
|
int64 remote_balance_sats = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
message ChainBalanceEvent {
|
message ChainBalanceEvent {
|
||||||
int64 block_height = 1;
|
int64 block_height = 1;
|
||||||
int64 confirmed_balance = 2;
|
int64 confirmed_balance = 2;
|
||||||
int64 unconfirmed_balance = 3;
|
int64 unconfirmed_balance = 3;
|
||||||
int64 total_balance = 4;
|
int64 total_balance = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
message OpenChannel {
|
message OpenChannel {
|
||||||
string channel_id = 1;
|
string channel_id = 1;
|
||||||
int64 capacity = 2;
|
int64 capacity = 2;
|
||||||
bool active = 3;
|
bool active = 3;
|
||||||
int64 lifetime =4 ;
|
int64 lifetime =4 ;
|
||||||
int64 local_balance=5;
|
int64 local_balance=5;
|
||||||
int64 remote_balance = 6;
|
int64 remote_balance = 6;
|
||||||
}
|
}
|
||||||
message ClosedChannel {
|
message ClosedChannel {
|
||||||
string channel_id = 1;
|
string channel_id = 1;
|
||||||
int64 capacity = 2;
|
int64 capacity = 2;
|
||||||
int64 closed_height =4;
|
int64 closed_height =4;
|
||||||
}
|
}
|
||||||
|
|
||||||
message ChannelRouting {
|
message ChannelRouting {
|
||||||
string channel_id = 1;
|
string channel_id = 1;
|
||||||
int64 send_errors = 2;
|
int64 send_errors = 2;
|
||||||
int64 receive_errors = 3;
|
int64 receive_errors = 3;
|
||||||
int64 forward_errors_as_input = 4;
|
int64 forward_errors_as_input = 4;
|
||||||
int64 forward_errors_as_output = 5;
|
int64 forward_errors_as_output = 5;
|
||||||
int64 missed_forward_fee_as_input = 6;
|
int64 missed_forward_fee_as_input = 6;
|
||||||
int64 missed_forward_fee_as_output = 7;
|
int64 missed_forward_fee_as_output = 7;
|
||||||
int64 forward_fee_as_input = 8;
|
int64 forward_fee_as_input = 8;
|
||||||
int64 forward_fee_as_output = 9;
|
int64 forward_fee_as_output = 9;
|
||||||
int64 events_number = 10;
|
int64 events_number = 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
message LndNodeMetrics {
|
message LndNodeMetrics {
|
||||||
repeated ChannelBalanceEvent channels_balance_events = 1;
|
repeated ChannelBalanceEvent channels_balance_events = 1;
|
||||||
repeated ChainBalanceEvent chain_balance_events = 2;
|
repeated ChainBalanceEvent chain_balance_events = 2;
|
||||||
int64 offline_channels = 4;
|
int64 offline_channels = 4;
|
||||||
int64 online_channels = 5;
|
int64 online_channels = 5;
|
||||||
int64 pending_channels = 6;
|
int64 pending_channels = 6;
|
||||||
int64 closing_channels = 7;
|
int64 closing_channels = 7;
|
||||||
repeated OpenChannel open_channels = 8;
|
repeated OpenChannel open_channels = 8;
|
||||||
repeated ClosedChannel closed_channels = 9;
|
repeated ClosedChannel closed_channels = 9;
|
||||||
repeated ChannelRouting channel_routing = 10;
|
repeated ChannelRouting channel_routing = 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
message LndMetrics {
|
message LndMetrics {
|
||||||
repeated LndNodeMetrics nodes = 1;
|
repeated LndNodeMetrics nodes = 1;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
message LndGetInfoRequest {
|
message LndGetInfoRequest {
|
||||||
int64 nodeId = 1;
|
int64 nodeId = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
message SetMockInvoiceAsPaidRequest {
|
message SetMockInvoiceAsPaidRequest {
|
||||||
string invoice = 1;
|
string invoice = 1;
|
||||||
int64 amount =2;
|
int64 amount =2;
|
||||||
}
|
}
|
||||||
|
|
||||||
message LndGetInfoResponse {
|
message LndGetInfoResponse {
|
||||||
string alias = 1;
|
string alias = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
message BanUserRequest {
|
message BanUserRequest {
|
||||||
string user_id = 1;
|
string user_id = 1;
|
||||||
}
|
}
|
||||||
message BannedAppUser {
|
message BannedAppUser {
|
||||||
string app_name = 1;
|
string app_name = 1;
|
||||||
string app_id = 2;
|
string app_id = 2;
|
||||||
string user_identifier = 3;
|
string user_identifier = 3;
|
||||||
string nostr_pub = 4;
|
string nostr_pub = 4;
|
||||||
|
|
||||||
}
|
}
|
||||||
message BanUserResponse {
|
message BanUserResponse {
|
||||||
int64 balance_sats = 1;
|
int64 balance_sats = 1;
|
||||||
repeated BannedAppUser banned_app_users = 2;
|
repeated BannedAppUser banned_app_users = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
message AddAppRequest {
|
message AddAppRequest {
|
||||||
string name = 1;
|
string name = 1;
|
||||||
bool allow_user_creation = 2;
|
bool allow_user_creation = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
message AuthAppRequest {
|
message AuthAppRequest {
|
||||||
string name = 1;
|
string name = 1;
|
||||||
optional bool allow_user_creation = 2;
|
optional bool allow_user_creation = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
message Application {
|
message Application {
|
||||||
string name = 1;
|
string name = 1;
|
||||||
string id = 2;
|
string id = 2;
|
||||||
int64 balance = 3;
|
int64 balance = 3;
|
||||||
string npub = 4;
|
string npub = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
message AuthApp {
|
message AuthApp {
|
||||||
Application app = 1;
|
Application app = 1;
|
||||||
string auth_token = 2;
|
string auth_token = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
message AddAppUserRequest {
|
message AddAppUserRequest {
|
||||||
string identifier = 1;
|
string identifier = 1;
|
||||||
bool fail_if_exists = 2;
|
bool fail_if_exists = 2;
|
||||||
int64 balance = 3;
|
int64 balance = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
message AppUser {
|
message AppUser {
|
||||||
string identifier = 1;
|
string identifier = 1;
|
||||||
UserInfo info = 2;
|
UserInfo info = 2;
|
||||||
int64 max_withdrawable = 3;
|
int64 max_withdrawable = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
message AddAppInvoiceRequest {
|
message AddAppInvoiceRequest {
|
||||||
string payer_identifier = 1;
|
string payer_identifier = 1;
|
||||||
string http_callback_url = 2;
|
string http_callback_url = 2;
|
||||||
NewInvoiceRequest invoice_req = 3;
|
NewInvoiceRequest invoice_req = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
message AddAppUserInvoiceRequest {
|
message AddAppUserInvoiceRequest {
|
||||||
string receiver_identifier = 1;
|
string receiver_identifier = 1;
|
||||||
string payer_identifier = 2;
|
string payer_identifier = 2;
|
||||||
string http_callback_url = 3;
|
string http_callback_url = 3;
|
||||||
NewInvoiceRequest invoice_req = 4;
|
NewInvoiceRequest invoice_req = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
message GetAppUserRequest {
|
message GetAppUserRequest {
|
||||||
string user_identifier = 1;
|
string user_identifier = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
message PayAppUserInvoiceRequest {
|
message PayAppUserInvoiceRequest {
|
||||||
string user_identifier = 1;
|
string user_identifier = 1;
|
||||||
string invoice = 2;
|
string invoice = 2;
|
||||||
int64 amount = 3;
|
int64 amount = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
message SendAppUserToAppUserPaymentRequest {
|
message SendAppUserToAppUserPaymentRequest {
|
||||||
string from_user_identifier = 1;
|
string from_user_identifier = 1;
|
||||||
string to_user_identifier = 2;
|
string to_user_identifier = 2;
|
||||||
int64 amount = 3;
|
int64 amount = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
message SendAppUserToAppPaymentRequest {
|
message SendAppUserToAppPaymentRequest {
|
||||||
string from_user_identifier = 1;
|
string from_user_identifier = 1;
|
||||||
int64 amount = 2;
|
int64 amount = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
message GetAppUserLNURLInfoRequest {
|
message GetAppUserLNURLInfoRequest {
|
||||||
string user_identifier = 1;
|
string user_identifier = 1;
|
||||||
string base_url_override = 2;
|
string base_url_override = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
message SetMockAppUserBalanceRequest {
|
message SetMockAppUserBalanceRequest {
|
||||||
string user_identifier = 1;
|
string user_identifier = 1;
|
||||||
int64 amount = 2;
|
int64 amount = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
message SetMockAppBalanceRequest {
|
message SetMockAppBalanceRequest {
|
||||||
int64 amount = 1;
|
int64 amount = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum AddressType {
|
enum AddressType {
|
||||||
WITNESS_PUBKEY_HASH = 0;
|
WITNESS_PUBKEY_HASH = 0;
|
||||||
NESTED_PUBKEY_HASH = 1;
|
NESTED_PUBKEY_HASH = 1;
|
||||||
TAPROOT_PUBKEY = 2;
|
TAPROOT_PUBKEY = 2;
|
||||||
}
|
}
|
||||||
message NewAddressRequest {
|
message NewAddressRequest {
|
||||||
AddressType addressType = 1;
|
AddressType addressType = 1;
|
||||||
}
|
}
|
||||||
message NewAddressResponse{
|
message NewAddressResponse{
|
||||||
string address = 1;
|
string address = 1;
|
||||||
}
|
}
|
||||||
message PayAddressRequest{
|
message PayAddressRequest{
|
||||||
string address = 1;
|
string address = 1;
|
||||||
int64 amoutSats = 2;
|
int64 amoutSats = 2;
|
||||||
int64 satsPerVByte = 3;
|
int64 satsPerVByte = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
message PayAddressResponse{
|
message PayAddressResponse{
|
||||||
string txId = 1;
|
string txId = 1;
|
||||||
string operation_id = 2;
|
string operation_id = 2;
|
||||||
int64 service_fee = 3;
|
int64 service_fee = 3;
|
||||||
int64 network_fee = 4;
|
int64 network_fee = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
message NewInvoiceRequest{
|
message NewInvoiceRequest{
|
||||||
int64 amountSats = 1;
|
int64 amountSats = 1;
|
||||||
string memo = 2;
|
string memo = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
message NewInvoiceResponse{
|
message NewInvoiceResponse{
|
||||||
string invoice = 1;
|
string invoice = 1;
|
||||||
}
|
}
|
||||||
message DecodeInvoiceRequest{
|
message DecodeInvoiceRequest{
|
||||||
string invoice = 1;
|
string invoice = 1;
|
||||||
}
|
}
|
||||||
message DecodeInvoiceResponse{
|
message DecodeInvoiceResponse{
|
||||||
int64 amount=1;
|
int64 amount=1;
|
||||||
}
|
}
|
||||||
message PayInvoiceRequest{
|
message PayInvoiceRequest{
|
||||||
string invoice = 1;
|
string invoice = 1;
|
||||||
int64 amount = 2;
|
int64 amount = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
message PayInvoiceResponse{
|
message PayInvoiceResponse{
|
||||||
string preimage = 1;
|
string preimage = 1;
|
||||||
int64 amount_paid = 2;
|
int64 amount_paid = 2;
|
||||||
string operation_id = 3;
|
string operation_id = 3;
|
||||||
int64 service_fee = 4;
|
int64 service_fee = 4;
|
||||||
int64 network_fee = 5;
|
int64 network_fee = 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
message OpenChannelRequest{
|
message OpenChannelRequest{
|
||||||
string destination = 1;
|
string destination = 1;
|
||||||
int64 fundingAmount = 2;
|
int64 fundingAmount = 2;
|
||||||
int64 pushAmount = 3;
|
int64 pushAmount = 3;
|
||||||
string closeAddress = 4;
|
string closeAddress = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
message OpenChannelResponse{
|
message OpenChannelResponse{
|
||||||
string channelId = 1;
|
string channelId = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
message LnurlLinkResponse{
|
message LnurlLinkResponse{
|
||||||
string lnurl = 1;
|
string lnurl = 1;
|
||||||
string k1 = 2;
|
string k1 = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
message LnurlWithdrawInfoResponse {
|
message LnurlWithdrawInfoResponse {
|
||||||
string tag = 1;
|
string tag = 1;
|
||||||
string callback = 2;
|
string callback = 2;
|
||||||
string k1 = 3;
|
string k1 = 3;
|
||||||
string defaultDescription = 4;
|
string defaultDescription = 4;
|
||||||
int64 minWithdrawable = 5; // millisatoshi - unsafe overflow possible, but very unlikely
|
int64 minWithdrawable = 5; // millisatoshi - unsafe overflow possible, but very unlikely
|
||||||
int64 maxWithdrawable = 6; // millisatoshi - unsafe overflow possible, but very unlikely
|
int64 maxWithdrawable = 6; // millisatoshi - unsafe overflow possible, but very unlikely
|
||||||
string balanceCheck = 7;
|
string balanceCheck = 7;
|
||||||
string payLink = 8;
|
string payLink = 8;
|
||||||
}
|
}
|
||||||
message LnurlPayInfoResponse {
|
message LnurlPayInfoResponse {
|
||||||
string tag = 1;
|
string tag = 1;
|
||||||
string callback = 2;
|
string callback = 2;
|
||||||
int64 maxSendable = 3; // millisatoshi - unsafe overflow possible, but very unlikely
|
int64 maxSendable = 3; // millisatoshi - unsafe overflow possible, but very unlikely
|
||||||
int64 minSendable = 4; // millisatoshi - unsafe overflow possible, but very unlikely
|
int64 minSendable = 4; // millisatoshi - unsafe overflow possible, but very unlikely
|
||||||
string metadata = 5;
|
string metadata = 5;
|
||||||
bool allowsNostr = 6;
|
bool allowsNostr = 6;
|
||||||
string nostrPubkey = 7;
|
string nostrPubkey = 7;
|
||||||
}
|
}
|
||||||
message HandleLnurlPayResponse {
|
message HandleLnurlPayResponse {
|
||||||
string pr = 1;
|
string pr = 1;
|
||||||
repeated Empty routes = 2;
|
repeated Empty routes = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
message UserInfo{
|
message UserInfo{
|
||||||
string userId = 1;
|
string userId = 1;
|
||||||
int64 balance = 2;
|
int64 balance = 2;
|
||||||
int64 max_withdrawable = 3;
|
int64 max_withdrawable = 3;
|
||||||
string user_identifier = 4;
|
string user_identifier = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
message GetUserOperationsRequest{
|
message GetUserOperationsRequest{
|
||||||
int64 latestIncomingInvoice = 1;
|
int64 latestIncomingInvoice = 1;
|
||||||
int64 latestOutgoingInvoice = 2;
|
int64 latestOutgoingInvoice = 2;
|
||||||
int64 latestIncomingTx = 3;
|
int64 latestIncomingTx = 3;
|
||||||
int64 latestOutgoingTx = 4;
|
int64 latestOutgoingTx = 4;
|
||||||
int64 latestIncomingUserToUserPayment = 5;
|
int64 latestIncomingUserToUserPayment = 5;
|
||||||
int64 latestOutgoingUserToUserPayment = 6;
|
int64 latestOutgoingUserToUserPayment = 6;
|
||||||
int64 max_size = 7;
|
int64 max_size = 7;
|
||||||
}
|
}
|
||||||
enum UserOperationType {
|
enum UserOperationType {
|
||||||
INCOMING_TX =0;
|
INCOMING_TX =0;
|
||||||
OUTGOING_TX =1;
|
OUTGOING_TX =1;
|
||||||
INCOMING_INVOICE =2;
|
INCOMING_INVOICE =2;
|
||||||
OUTGOING_INVOICE=3;
|
OUTGOING_INVOICE=3;
|
||||||
OUTGOING_USER_TO_USER=4;
|
OUTGOING_USER_TO_USER=4;
|
||||||
INCOMING_USER_TO_USER=5;
|
INCOMING_USER_TO_USER=5;
|
||||||
}
|
}
|
||||||
|
|
||||||
message UserOperation {
|
message UserOperation {
|
||||||
int64 paidAtUnix=1;
|
int64 paidAtUnix=1;
|
||||||
UserOperationType type = 2;
|
UserOperationType type = 2;
|
||||||
bool inbound =3;
|
bool inbound =3;
|
||||||
int64 amount = 4;
|
int64 amount = 4;
|
||||||
string identifier = 5;
|
string identifier = 5;
|
||||||
string operationId = 6;
|
string operationId = 6;
|
||||||
int64 service_fee = 7;
|
int64 service_fee = 7;
|
||||||
int64 network_fee = 8;
|
int64 network_fee = 8;
|
||||||
bool confirmed = 9;
|
bool confirmed = 9;
|
||||||
string tx_hash = 10;
|
string tx_hash = 10;
|
||||||
bool internal = 11;
|
bool internal = 11;
|
||||||
}
|
}
|
||||||
message UserOperations {
|
message UserOperations {
|
||||||
int64 fromIndex=1;
|
int64 fromIndex=1;
|
||||||
int64 toIndex=2;
|
int64 toIndex=2;
|
||||||
repeated UserOperation operations=3;
|
repeated UserOperation operations=3;
|
||||||
}
|
}
|
||||||
message GetUserOperationsResponse{
|
message GetUserOperationsResponse{
|
||||||
UserOperations latestOutgoingInvoiceOperations=1;
|
UserOperations latestOutgoingInvoiceOperations=1;
|
||||||
UserOperations latestIncomingInvoiceOperations=2;
|
UserOperations latestIncomingInvoiceOperations=2;
|
||||||
UserOperations latestOutgoingTxOperations=3;
|
UserOperations latestOutgoingTxOperations=3;
|
||||||
UserOperations latestIncomingTxOperations=4;
|
UserOperations latestIncomingTxOperations=4;
|
||||||
UserOperations latestOutgoingUserToUserPayemnts=5;
|
UserOperations latestOutgoingUserToUserPayemnts=5;
|
||||||
UserOperations latestIncomingUserToUserPayemnts=6;
|
UserOperations latestIncomingUserToUserPayemnts=6;
|
||||||
}
|
}
|
||||||
|
|
||||||
message AddProductRequest {
|
message AddProductRequest {
|
||||||
string name = 1;
|
string name = 1;
|
||||||
int64 price_sats = 2;
|
int64 price_sats = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
message Product {
|
message Product {
|
||||||
string id = 1;
|
string id = 1;
|
||||||
string name = 2;
|
string name = 2;
|
||||||
int64 price_sats = 3;
|
int64 price_sats = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
message GetProductBuyLinkResponse {
|
message GetProductBuyLinkResponse {
|
||||||
string link = 1;
|
string link = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
message LiveUserOperation {
|
message LiveUserOperation {
|
||||||
UserOperation operation = 1;
|
UserOperation operation = 1;
|
||||||
}
|
}
|
||||||
message MigrationUpdate {
|
message MigrationUpdate {
|
||||||
optional ClosureMigration closure = 1;
|
optional ClosureMigration closure = 1;
|
||||||
optional RelaysMigration relays = 2;
|
optional RelaysMigration relays = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
message ClosureMigration {
|
message ClosureMigration {
|
||||||
int64 closes_at_unix = 1;
|
int64 closes_at_unix = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
message RelaysMigration {
|
message RelaysMigration {
|
||||||
repeated string relays = 1;
|
repeated string relays = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
message RequestNPubLinkingTokenRequest {
|
message RequestNPubLinkingTokenRequest {
|
||||||
string user_identifier = 1;
|
string user_identifier = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
message RequestNPubLinkingTokenResponse {
|
message RequestNPubLinkingTokenResponse {
|
||||||
string token = 1;
|
string token = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
message LinkNPubThroughTokenRequest {
|
message LinkNPubThroughTokenRequest {
|
||||||
string token = 1;
|
string token = 1;
|
||||||
string nostr_pub = 2;
|
string nostr_pub = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
message HttpCreds {
|
message HttpCreds {
|
||||||
string url = 1;
|
string url = 1;
|
||||||
string token = 2;
|
string token = 2;
|
||||||
}
|
}
|
||||||
139
src/auth.ts
139
src/auth.ts
|
|
@ -1,69 +1,72 @@
|
||||||
import { ServerOptions } from "../proto/autogenerated/ts/express_server";
|
import express from 'express';
|
||||||
import { AdminContext, MetricsContext } from "../proto/autogenerated/ts/types";
|
import path from 'path';
|
||||||
import Main from './services/main'
|
import { ServerOptions } from "../proto/autogenerated/ts/express_server";
|
||||||
import { ERROR, getLogger } from './services/helpers/logger.js'
|
import { AdminContext, MetricsContext } from "../proto/autogenerated/ts/types";
|
||||||
const serverOptions = (mainHandler: Main): ServerOptions => {
|
import Main from './services/main'
|
||||||
const log = getLogger({})
|
import { ERROR, getLogger } from './services/helpers/logger.js'
|
||||||
return {
|
const serverOptions = (mainHandler: Main): ServerOptions => {
|
||||||
logger: { log, error: err => log(ERROR, err) },
|
const log = getLogger({})
|
||||||
AdminAuthGuard: adminAuth,
|
return {
|
||||||
MetricsAuthGuard: metricsAuth,
|
logger: { log, error: err => log(ERROR, err) },
|
||||||
AppAuthGuard: async (authHeader) => { return { app_id: mainHandler.applicationManager.DecodeAppToken(stripBearer(authHeader)) } },
|
staticFiles: path.resolve('static'),
|
||||||
UserAuthGuard: async (authHeader) => { return mainHandler.appUserManager.DecodeUserToken(stripBearer(authHeader)) },
|
AdminAuthGuard: adminAuth,
|
||||||
GuestAuthGuard: async (_) => ({}),
|
MetricsAuthGuard: metricsAuth,
|
||||||
metricsCallback: metrics => mainHandler.settings.recordPerformance ? mainHandler.metricsManager.AddMetrics(metrics) : null,
|
AppAuthGuard: async (authHeader) => { return { app_id: mainHandler.applicationManager.DecodeAppToken(stripBearer(authHeader)) } },
|
||||||
allowCors: true,
|
UserAuthGuard: async (authHeader) => { return mainHandler.appUserManager.DecodeUserToken(stripBearer(authHeader)) },
|
||||||
logMethod: true,
|
GuestAuthGuard: async (_) => ({}),
|
||||||
logBody: true
|
metricsCallback: metrics => mainHandler.settings.recordPerformance ? mainHandler.metricsManager.AddMetrics(metrics) : null,
|
||||||
//throwErrors: true
|
allowCors: true,
|
||||||
}
|
logMethod: true,
|
||||||
}
|
logBody: true
|
||||||
|
//throwErrors: true
|
||||||
const stripBearer = (header?: string) => {
|
}
|
||||||
if (!header) {
|
}
|
||||||
return ""
|
|
||||||
}
|
const stripBearer = (header?: string) => {
|
||||||
if (header.startsWith("Bearer ")) {
|
if (!header) {
|
||||||
return header.substring("Bearer ".length)
|
return ""
|
||||||
}
|
}
|
||||||
return header
|
if (header.startsWith("Bearer ")) {
|
||||||
}
|
return header.substring("Bearer ".length)
|
||||||
|
}
|
||||||
const adminAuth = async (header: string | undefined): Promise<AdminContext> => {
|
return header
|
||||||
const AdminToken = process.env.ADMIN_TOKEN
|
}
|
||||||
if (!AdminToken) {
|
|
||||||
throw new Error("admin auth disabled")
|
const adminAuth = async (header: string | undefined): Promise<AdminContext> => {
|
||||||
}
|
const AdminToken = process.env.ADMIN_TOKEN
|
||||||
if (!header) {
|
if (!AdminToken) {
|
||||||
throw new Error("admin header not found")
|
throw new Error("admin auth disabled")
|
||||||
}
|
}
|
||||||
let h = header
|
if (!header) {
|
||||||
|
throw new Error("admin header not found")
|
||||||
if (header.startsWith("Bearer ")) {
|
}
|
||||||
h = header.substring("Bearer ".length)
|
let h = header
|
||||||
}
|
|
||||||
if (h !== AdminToken) {
|
if (header.startsWith("Bearer ")) {
|
||||||
throw new Error("admin token invalid")
|
h = header.substring("Bearer ".length)
|
||||||
}
|
}
|
||||||
return { admin_id: "admin1" }
|
if (h !== AdminToken) {
|
||||||
}
|
throw new Error("admin token invalid")
|
||||||
|
}
|
||||||
const metricsAuth = async (header: string | undefined): Promise<MetricsContext> => {
|
return { admin_id: "admin1" }
|
||||||
const metricsToken = process.env.METRICS_TOKEN || process.env.ADMIN_TOKEN
|
}
|
||||||
if (!metricsToken) {
|
|
||||||
throw new Error("metrics auth disabled")
|
const metricsAuth = async (header: string | undefined): Promise<MetricsContext> => {
|
||||||
}
|
const metricsToken = process.env.METRICS_TOKEN || process.env.ADMIN_TOKEN
|
||||||
if (!header) {
|
if (!metricsToken) {
|
||||||
throw new Error("metrics header not found")
|
throw new Error("metrics auth disabled")
|
||||||
}
|
}
|
||||||
let h = header
|
if (!header) {
|
||||||
|
throw new Error("metrics header not found")
|
||||||
if (header.startsWith("Bearer ")) {
|
}
|
||||||
h = header.substring("Bearer ".length)
|
let h = header
|
||||||
}
|
|
||||||
if (h !== metricsToken) {
|
if (header.startsWith("Bearer ")) {
|
||||||
throw new Error("metrics token invalid")
|
h = header.substring("Bearer ".length)
|
||||||
}
|
}
|
||||||
return { operator_id: "metrics1" }
|
if (h !== metricsToken) {
|
||||||
}
|
throw new Error("metrics token invalid")
|
||||||
|
}
|
||||||
|
return { operator_id: "metrics1" }
|
||||||
|
}
|
||||||
export default serverOptions
|
export default serverOptions
|
||||||
|
|
@ -1,88 +1,88 @@
|
||||||
/*
|
/*
|
||||||
This file contains functions that deal with encoding and decoding nprofiles,
|
This file contains functions that deal with encoding and decoding nprofiles,
|
||||||
but with he addition of bridge urls in the nprofile.
|
but with he addition of bridge urls in the nprofile.
|
||||||
These functions are basically the same functions from nostr-tools package
|
These functions are basically the same functions from nostr-tools package
|
||||||
but with some tweaks to allow for the bridge inclusion.
|
but with some tweaks to allow for the bridge inclusion.
|
||||||
*/
|
*/
|
||||||
import { bytesToHex, concatBytes, hexToBytes } from '@noble/hashes/utils';
|
import { bytesToHex, concatBytes, hexToBytes } from '@noble/hashes/utils';
|
||||||
import { bech32 } from 'bech32';
|
import { bech32 } from 'bech32';
|
||||||
|
|
||||||
export const utf8Decoder = new TextDecoder('utf-8')
|
export const utf8Decoder = new TextDecoder('utf-8')
|
||||||
export const utf8Encoder = new TextEncoder()
|
export const utf8Encoder = new TextEncoder()
|
||||||
|
|
||||||
|
|
||||||
export type CustomProfilePointer = {
|
export type CustomProfilePointer = {
|
||||||
pubkey: string
|
pubkey: string
|
||||||
relays?: string[]
|
relays?: string[]
|
||||||
bridge?: string[] // one bridge
|
bridge?: string[] // one bridge
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
type TLV = { [t: number]: Uint8Array[] }
|
type TLV = { [t: number]: Uint8Array[] }
|
||||||
|
|
||||||
|
|
||||||
const encodeTLV = (tlv: TLV): Uint8Array => {
|
const encodeTLV = (tlv: TLV): Uint8Array => {
|
||||||
const entries: Uint8Array[] = []
|
const entries: Uint8Array[] = []
|
||||||
|
|
||||||
Object.entries(tlv)
|
Object.entries(tlv)
|
||||||
/*
|
/*
|
||||||
the original function does a reverse() here,
|
the original function does a reverse() here,
|
||||||
but here it causes the nprofile string to be different,
|
but here it causes the nprofile string to be different,
|
||||||
even though it would still decode to the correct original inputs
|
even though it would still decode to the correct original inputs
|
||||||
*/
|
*/
|
||||||
//.reverse()
|
//.reverse()
|
||||||
.forEach(([t, vs]) => {
|
.forEach(([t, vs]) => {
|
||||||
vs.forEach(v => {
|
vs.forEach(v => {
|
||||||
const entry = new Uint8Array(v.length + 2)
|
const entry = new Uint8Array(v.length + 2)
|
||||||
entry.set([parseInt(t)], 0)
|
entry.set([parseInt(t)], 0)
|
||||||
entry.set([v.length], 1)
|
entry.set([v.length], 1)
|
||||||
entry.set(v, 2)
|
entry.set(v, 2)
|
||||||
entries.push(entry)
|
entries.push(entry)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
return concatBytes(...entries);
|
return concatBytes(...entries);
|
||||||
}
|
}
|
||||||
|
|
||||||
export const encodeNprofile = (profile: CustomProfilePointer): string => {
|
export const encodeNprofile = (profile: CustomProfilePointer): string => {
|
||||||
const data = encodeTLV({
|
const data = encodeTLV({
|
||||||
0: [hexToBytes(profile.pubkey)],
|
0: [hexToBytes(profile.pubkey)],
|
||||||
1: (profile.relays || []).map(url => utf8Encoder.encode(url)),
|
1: (profile.relays || []).map(url => utf8Encoder.encode(url)),
|
||||||
2: (profile.bridge || []).map(url => utf8Encoder.encode(url))
|
2: (profile.bridge || []).map(url => utf8Encoder.encode(url))
|
||||||
});
|
});
|
||||||
const words = bech32.toWords(data)
|
const words = bech32.toWords(data)
|
||||||
return bech32.encode("nprofile", words, 5000);
|
return bech32.encode("nprofile", words, 5000);
|
||||||
}
|
}
|
||||||
|
|
||||||
const parseTLV = (data: Uint8Array): TLV => {
|
const parseTLV = (data: Uint8Array): TLV => {
|
||||||
const result: TLV = {}
|
const result: TLV = {}
|
||||||
let rest = data
|
let rest = data
|
||||||
while (rest.length > 0) {
|
while (rest.length > 0) {
|
||||||
const t = rest[0]
|
const t = rest[0]
|
||||||
const l = rest[1]
|
const l = rest[1]
|
||||||
const v = rest.slice(2, 2 + l)
|
const v = rest.slice(2, 2 + l)
|
||||||
rest = rest.slice(2 + l)
|
rest = rest.slice(2 + l)
|
||||||
if (v.length < l) throw new Error(`not enough data to read on TLV ${t}`)
|
if (v.length < l) throw new Error(`not enough data to read on TLV ${t}`)
|
||||||
result[t] = result[t] || []
|
result[t] = result[t] || []
|
||||||
result[t].push(v)
|
result[t].push(v)
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
export const decodeNprofile = (nprofile: string): CustomProfilePointer => {
|
export const decodeNprofile = (nprofile: string): CustomProfilePointer => {
|
||||||
const { prefix, words } = bech32.decode(nprofile, 5000)
|
const { prefix, words } = bech32.decode(nprofile, 5000)
|
||||||
if (prefix !== "nprofile") {
|
if (prefix !== "nprofile") {
|
||||||
throw new Error ("Expected nprofile prefix");
|
throw new Error ("Expected nprofile prefix");
|
||||||
}
|
}
|
||||||
const data = new Uint8Array(bech32.fromWords(words))
|
const data = new Uint8Array(bech32.fromWords(words))
|
||||||
|
|
||||||
const tlv = parseTLV(data);
|
const tlv = parseTLV(data);
|
||||||
if (!tlv[0]?.[0]) throw new Error('missing TLV 0 for nprofile')
|
if (!tlv[0]?.[0]) throw new Error('missing TLV 0 for nprofile')
|
||||||
if (tlv[0][0].length !== 32) throw new Error('TLV 0 should be 32 bytes')
|
if (tlv[0][0].length !== 32) throw new Error('TLV 0 should be 32 bytes')
|
||||||
|
|
||||||
return {
|
return {
|
||||||
pubkey: bytesToHex(tlv[0][0]),
|
pubkey: bytesToHex(tlv[0][0]),
|
||||||
relays: tlv[1] ? tlv[1].map(d => utf8Decoder.decode(d)) : [],
|
relays: tlv[1] ? tlv[1].map(d => utf8Decoder.decode(d)) : [],
|
||||||
bridge: tlv[2] ? tlv[2].map(d => utf8Decoder.decode(d)): []
|
bridge: tlv[2] ? tlv[2].map(d => utf8Decoder.decode(d)): []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,41 +1,41 @@
|
||||||
import Main from "./services/main/index.js"
|
import Main from "./services/main/index.js"
|
||||||
import Nostr from "./services/nostr/index.js"
|
import Nostr from "./services/nostr/index.js"
|
||||||
import { NostrSend, NostrSettings } from "./services/nostr/handler.js"
|
import { NostrSend, NostrSettings } from "./services/nostr/handler.js"
|
||||||
import * as Types from '../proto/autogenerated/ts/types.js'
|
import * as Types from '../proto/autogenerated/ts/types.js'
|
||||||
import NewNostrTransport, { NostrRequest } from '../proto/autogenerated/ts/nostr_transport.js';
|
import NewNostrTransport, { NostrRequest } from '../proto/autogenerated/ts/nostr_transport.js';
|
||||||
import { ERROR, getLogger } from "./services/helpers/logger.js";
|
import { ERROR, getLogger } from "./services/helpers/logger.js";
|
||||||
|
|
||||||
export default (serverMethods: Types.ServerMethods, mainHandler: Main, nostrSettings: NostrSettings, onClientEvent: (e: { requestId: string }, fromPub: string) => void): { Stop: () => void, Send: NostrSend } => {
|
export default (serverMethods: Types.ServerMethods, mainHandler: Main, nostrSettings: NostrSettings, onClientEvent: (e: { requestId: string }, fromPub: string) => void): { Stop: () => void, Send: NostrSend } => {
|
||||||
const log = getLogger({})
|
const log = getLogger({})
|
||||||
const nostrTransport = NewNostrTransport(serverMethods, {
|
const nostrTransport = NewNostrTransport(serverMethods, {
|
||||||
NostrUserAuthGuard: async (appId, pub) => {
|
NostrUserAuthGuard: async (appId, pub) => {
|
||||||
const app = await mainHandler.storage.applicationStorage.GetApplication(appId || "")
|
const app = await mainHandler.storage.applicationStorage.GetApplication(appId || "")
|
||||||
const nostrUser = await mainHandler.storage.applicationStorage.GetOrCreateNostrAppUser(app, pub || "")
|
const nostrUser = await mainHandler.storage.applicationStorage.GetOrCreateNostrAppUser(app, pub || "")
|
||||||
return { user_id: nostrUser.user.user_id, app_user_id: nostrUser.identifier, app_id: appId || "" }
|
return { user_id: nostrUser.user.user_id, app_user_id: nostrUser.identifier, app_id: appId || "" }
|
||||||
},
|
},
|
||||||
metricsCallback: metrics => mainHandler.settings.recordPerformance ? mainHandler.metricsManager.AddMetrics(metrics) : null,
|
metricsCallback: metrics => mainHandler.settings.recordPerformance ? mainHandler.metricsManager.AddMetrics(metrics) : null,
|
||||||
logger: { log: console.log, error: err => log(ERROR, err) }
|
logger: { log: console.log, error: err => log(ERROR, err) }
|
||||||
})
|
})
|
||||||
const nostr = new Nostr(nostrSettings, event => {
|
const nostr = new Nostr(nostrSettings, event => {
|
||||||
let j: NostrRequest
|
let j: NostrRequest
|
||||||
try {
|
try {
|
||||||
j = JSON.parse(event.content)
|
j = JSON.parse(event.content)
|
||||||
log("nostr event", j.rpcName || 'no rpc name')
|
log("nostr event", j.rpcName || 'no rpc name')
|
||||||
} catch {
|
} catch {
|
||||||
log(ERROR, "invalid json event received", event.content)
|
log(ERROR, "invalid json event received", event.content)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (!j.rpcName) {
|
if (!j.rpcName) {
|
||||||
onClientEvent(j as { requestId: string }, event.pub)
|
onClientEvent(j as { requestId: string }, event.pub)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (j.authIdentifier !== event.pub) {
|
if (j.authIdentifier !== event.pub) {
|
||||||
log(ERROR, "authIdentifier does not match", j.authIdentifier || "--", event.pub)
|
log(ERROR, "authIdentifier does not match", j.authIdentifier || "--", event.pub)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
nostrTransport({ ...j, appId: event.appId }, res => {
|
nostrTransport({ ...j, appId: event.appId }, res => {
|
||||||
nostr.Send({ type: 'app', appId: event.appId }, { type: 'content', pub: event.pub, content: JSON.stringify({ ...res, requestId: j.requestId }) })
|
nostr.Send({ type: 'app', appId: event.appId }, { type: 'content', pub: event.pub, content: JSON.stringify({ ...res, requestId: j.requestId }) })
|
||||||
}, event.startAtNano, event.startAtMs)
|
}, event.startAtNano, event.startAtMs)
|
||||||
})
|
})
|
||||||
return { Stop: () => nostr.Stop, Send: (...args) => nostr.Send(...args) }
|
return { Stop: () => nostr.Stop, Send: (...args) => nostr.Send(...args) }
|
||||||
}
|
}
|
||||||
|
|
@ -1,28 +1,28 @@
|
||||||
export const EnvMustBeNonEmptyString = (name: string): string => {
|
export const EnvMustBeNonEmptyString = (name: string): string => {
|
||||||
const env = process.env[name]
|
const env = process.env[name]
|
||||||
if (!env) throw new Error(`${name} ENV must be non empty`)
|
if (!env) throw new Error(`${name} ENV must be non empty`)
|
||||||
return env
|
return env
|
||||||
}
|
}
|
||||||
export const EnvMustBeInteger = (name: string): number => {
|
export const EnvMustBeInteger = (name: string): number => {
|
||||||
const env = EnvMustBeNonEmptyString(name)
|
const env = EnvMustBeNonEmptyString(name)
|
||||||
if (isNaN(+env) || !Number.isInteger(+env)) {
|
if (isNaN(+env) || !Number.isInteger(+env)) {
|
||||||
throw new Error(`${name} ENV must be an integer number`);
|
throw new Error(`${name} ENV must be an integer number`);
|
||||||
}
|
}
|
||||||
return +env
|
return +env
|
||||||
}
|
}
|
||||||
export const EnvCanBeInteger = (name: string, defaultValue = 0): number => {
|
export const EnvCanBeInteger = (name: string, defaultValue = 0): number => {
|
||||||
const env = process.env[name]
|
const env = process.env[name]
|
||||||
if (!env) {
|
if (!env) {
|
||||||
return defaultValue
|
return defaultValue
|
||||||
}
|
}
|
||||||
const envNum = +env
|
const envNum = +env
|
||||||
if (isNaN(envNum) || !Number.isInteger(envNum)) {
|
if (isNaN(envNum) || !Number.isInteger(envNum)) {
|
||||||
throw new Error(`${name} ENV must be an integer number or nothing`);
|
throw new Error(`${name} ENV must be an integer number or nothing`);
|
||||||
}
|
}
|
||||||
return envNum
|
return envNum
|
||||||
}
|
}
|
||||||
export const EnvCanBeBoolean = (name: string): boolean => {
|
export const EnvCanBeBoolean = (name: string): boolean => {
|
||||||
const env = process.env[name]
|
const env = process.env[name]
|
||||||
if (!env) return false
|
if (!env) return false
|
||||||
return env.toLowerCase() === 'true'
|
return env.toLowerCase() === 'true'
|
||||||
}
|
}
|
||||||
|
|
@ -1,34 +1,34 @@
|
||||||
import { PubLogger, getLogger } from "../helpers/logger.js"
|
import { PubLogger, getLogger } from "../helpers/logger.js"
|
||||||
|
|
||||||
type Item<T> = { res: (v: T) => void, rej: (message: string) => void }
|
type Item<T> = { res: (v: T) => void, rej: (message: string) => void }
|
||||||
export default class FunctionQueue<T> {
|
export default class FunctionQueue<T> {
|
||||||
log: PubLogger
|
log: PubLogger
|
||||||
queue: Item<T>[] = []
|
queue: Item<T>[] = []
|
||||||
running: boolean = false
|
running: boolean = false
|
||||||
f: () => Promise<T>
|
f: () => Promise<T>
|
||||||
constructor(name: string, f: () => Promise<T>) {
|
constructor(name: string, f: () => Promise<T>) {
|
||||||
this.log = getLogger({ component: name })
|
this.log = getLogger({ component: name })
|
||||||
this.f = f
|
this.f = f
|
||||||
}
|
}
|
||||||
|
|
||||||
Run = (item: Item<T>) => {
|
Run = (item: Item<T>) => {
|
||||||
this.queue.push(item)
|
this.queue.push(item)
|
||||||
if (!this.running) {
|
if (!this.running) {
|
||||||
this.execF()
|
this.execF()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
execF = async () => {
|
execF = async () => {
|
||||||
this.running = true
|
this.running = true
|
||||||
try {
|
try {
|
||||||
const res = await this.f()
|
const res = await this.f()
|
||||||
this.queue.forEach(q => q.res(res))
|
this.queue.forEach(q => q.res(res))
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
this.queue.forEach(q => q.rej((err as any).message))
|
this.queue.forEach(q => q.rej((err as any).message))
|
||||||
}
|
}
|
||||||
this.queue = []
|
this.queue = []
|
||||||
this.running = false
|
this.running = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -111,4 +111,4 @@ const disableFromEnv = () => {
|
||||||
disableLoggers(loggers, loggers)
|
disableLoggers(loggers, loggers)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
disableFromEnv()
|
disableFromEnv()
|
||||||
|
|
|
||||||
|
|
@ -1,34 +1,34 @@
|
||||||
import { OpenChannelRequest, Invoice } from "../../../proto/lnd/lightning";
|
import { OpenChannelRequest, Invoice } from "../../../proto/lnd/lightning";
|
||||||
|
|
||||||
export const AddInvoiceReq = (value: number, expiry = 60 * 60, privateHints = false, memo?: string): Invoice => ({
|
export const AddInvoiceReq = (value: number, expiry = 60 * 60, privateHints = false, memo?: string): Invoice => ({
|
||||||
expiry: BigInt(expiry),
|
expiry: BigInt(expiry),
|
||||||
memo: memo || "",
|
memo: memo || "",
|
||||||
private: privateHints,
|
private: privateHints,
|
||||||
value: BigInt(value),
|
value: BigInt(value),
|
||||||
|
|
||||||
fallbackAddr: "",
|
fallbackAddr: "",
|
||||||
cltvExpiry: 0n,
|
cltvExpiry: 0n,
|
||||||
descriptionHash: Buffer.alloc(0),
|
descriptionHash: Buffer.alloc(0),
|
||||||
features: {},
|
features: {},
|
||||||
isAmp: false,
|
isAmp: false,
|
||||||
rPreimage: Buffer.alloc(0),
|
rPreimage: Buffer.alloc(0),
|
||||||
routeHints: [],
|
routeHints: [],
|
||||||
valueMsat: 0n,
|
valueMsat: 0n,
|
||||||
|
|
||||||
addIndex: 0n,
|
addIndex: 0n,
|
||||||
ampInvoiceState: {},
|
ampInvoiceState: {},
|
||||||
amtPaidMsat: 0n,
|
amtPaidMsat: 0n,
|
||||||
amtPaidSat: 0n,
|
amtPaidSat: 0n,
|
||||||
creationDate: 0n,
|
creationDate: 0n,
|
||||||
htlcs: [],
|
htlcs: [],
|
||||||
isKeysend: false,
|
isKeysend: false,
|
||||||
paymentAddr: Buffer.alloc(0),
|
paymentAddr: Buffer.alloc(0),
|
||||||
paymentRequest: "",
|
paymentRequest: "",
|
||||||
rHash: Buffer.alloc(0),
|
rHash: Buffer.alloc(0),
|
||||||
settleDate: 0n,
|
settleDate: 0n,
|
||||||
settleIndex: 0n,
|
settleIndex: 0n,
|
||||||
state: 0,
|
state: 0,
|
||||||
|
|
||||||
amtPaid: 0n,
|
amtPaid: 0n,
|
||||||
settled: false,
|
settled: false,
|
||||||
})
|
})
|
||||||
|
|
@ -1,11 +1,21 @@
|
||||||
import { EnvMustBeNonEmptyString, EnvMustBeInteger, EnvCanBeBoolean, EnvCanBeInteger } from '../helpers/envParser.js'
|
import { EnvMustBeNonEmptyString, EnvMustBeInteger, EnvCanBeBoolean, EnvCanBeInteger } from '../helpers/envParser.js'
|
||||||
import { LndSettings } from './settings.js'
|
import { LndSettings } from './settings.js'
|
||||||
export const LoadLndSettingsFromEnv = (): LndSettings => {
|
import os from 'os'
|
||||||
const lndAddr = process.env.LND_ADDRESS || "127.0.0.1:10009"
|
import path from 'path'
|
||||||
const lndCertPath = process.env.LND_CERT_PATH || "~/.lnd/tls.cert"
|
|
||||||
const lndMacaroonPath = process.env.LND_MACAROON_PATH || "~/.lnd/data/chain/bitcoin/mainnet/admin.macaroon"
|
const resolveHome = (filepath: string) => {
|
||||||
const feeRateLimit = EnvCanBeInteger("OUTBOUND_MAX_FEE_BPS", 60) / 10000
|
if (filepath[0] === '~') {
|
||||||
const feeFixedLimit = EnvCanBeInteger("OUTBOUND_MAX_FEE_EXTRA_SATS", 100)
|
return path.join(os.homedir(), filepath.slice(1))
|
||||||
const mockLnd = EnvCanBeBoolean("MOCK_LND")
|
}
|
||||||
return { mainNode: { lndAddr, lndCertPath, lndMacaroonPath }, feeRateLimit, feeFixedLimit, mockLnd }
|
return 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 }
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,33 +1,33 @@
|
||||||
import { CommitmentType, OpenChannelRequest } from "../../../proto/lnd/lightning.js";
|
import { CommitmentType, OpenChannelRequest } from "../../../proto/lnd/lightning.js";
|
||||||
|
|
||||||
export const OpenChannelReq = (destination: string, closeAddress: string, fundingAmount: number, pushSats: number): OpenChannelRequest => ({
|
export const OpenChannelReq = (destination: string, closeAddress: string, fundingAmount: number, pushSats: number): OpenChannelRequest => ({
|
||||||
nodePubkey: Buffer.from(destination, 'hex'),
|
nodePubkey: Buffer.from(destination, 'hex'),
|
||||||
closeAddress: closeAddress,
|
closeAddress: closeAddress,
|
||||||
localFundingAmount: BigInt(fundingAmount),
|
localFundingAmount: BigInt(fundingAmount),
|
||||||
pushSat: BigInt(pushSats),
|
pushSat: BigInt(pushSats),
|
||||||
|
|
||||||
satPerVbyte: 0n, // TBD
|
satPerVbyte: 0n, // TBD
|
||||||
private: false,
|
private: false,
|
||||||
minConfs: 0, // TBD
|
minConfs: 0, // TBD
|
||||||
baseFee: 1n, // TBD
|
baseFee: 1n, // TBD
|
||||||
feeRate: 1n, // TBD
|
feeRate: 1n, // TBD
|
||||||
targetConf: 0,
|
targetConf: 0,
|
||||||
zeroConf: false,
|
zeroConf: false,
|
||||||
maxLocalCsv: 0,
|
maxLocalCsv: 0,
|
||||||
remoteCsvDelay: 0,
|
remoteCsvDelay: 0,
|
||||||
spendUnconfirmed: false,
|
spendUnconfirmed: false,
|
||||||
minHtlcMsat: 1n,
|
minHtlcMsat: 1n,
|
||||||
remoteChanReserveSat: 10000n,
|
remoteChanReserveSat: 10000n,
|
||||||
remoteMaxHtlcs: 483,
|
remoteMaxHtlcs: 483,
|
||||||
remoteMaxValueInFlightMsat: 990000000n,
|
remoteMaxValueInFlightMsat: 990000000n,
|
||||||
useBaseFee: true,
|
useBaseFee: true,
|
||||||
useFeeRate: true,
|
useFeeRate: true,
|
||||||
|
|
||||||
// Default stuff
|
// Default stuff
|
||||||
commitmentType: CommitmentType.ANCHORS,
|
commitmentType: CommitmentType.ANCHORS,
|
||||||
scidAlias: false,
|
scidAlias: false,
|
||||||
nodePubkeyString: "",
|
nodePubkeyString: "",
|
||||||
satPerByte: 0n,
|
satPerByte: 0n,
|
||||||
|
|
||||||
fundingShim: undefined
|
fundingShim: undefined
|
||||||
})
|
})
|
||||||
|
|
@ -1,13 +1,13 @@
|
||||||
import { SendCoinsRequest } from "../../../proto/lnd/lightning";
|
import { SendCoinsRequest } from "../../../proto/lnd/lightning";
|
||||||
|
|
||||||
export const SendCoinsReq = (address: string, amount: number, satPerVByte: number, label = ""): SendCoinsRequest => ({
|
export const SendCoinsReq = (address: string, amount: number, satPerVByte: number, label = ""): SendCoinsRequest => ({
|
||||||
addr: address,
|
addr: address,
|
||||||
amount: BigInt(amount),
|
amount: BigInt(amount),
|
||||||
label: label,
|
label: label,
|
||||||
satPerVbyte: BigInt(satPerVByte),
|
satPerVbyte: BigInt(satPerVByte),
|
||||||
targetConf: 0,
|
targetConf: 0,
|
||||||
minConfs: 1,
|
minConfs: 1,
|
||||||
sendAll: false,
|
sendAll: false,
|
||||||
spendUnconfirmed: false,
|
spendUnconfirmed: false,
|
||||||
satPerByte: BigInt(0)
|
satPerByte: BigInt(0)
|
||||||
})
|
})
|
||||||
|
|
@ -1,86 +1,86 @@
|
||||||
import jwt from 'jsonwebtoken'
|
import jwt from 'jsonwebtoken'
|
||||||
import Storage from '../storage/index.js'
|
import Storage from '../storage/index.js'
|
||||||
import * as Types from '../../../proto/autogenerated/ts/types.js'
|
import * as Types from '../../../proto/autogenerated/ts/types.js'
|
||||||
|
|
||||||
import { MainSettings } from './settings.js'
|
import { MainSettings } from './settings.js'
|
||||||
import ApplicationManager from './applicationManager.js'
|
import ApplicationManager from './applicationManager.js'
|
||||||
export default class {
|
export default class {
|
||||||
storage: Storage
|
storage: Storage
|
||||||
settings: MainSettings
|
settings: MainSettings
|
||||||
applicationManager: ApplicationManager
|
applicationManager: ApplicationManager
|
||||||
constructor(storage: Storage, settings: MainSettings, applicationManager: ApplicationManager) {
|
constructor(storage: Storage, settings: MainSettings, applicationManager: ApplicationManager) {
|
||||||
this.storage = storage
|
this.storage = storage
|
||||||
this.settings = settings
|
this.settings = settings
|
||||||
this.applicationManager = applicationManager
|
this.applicationManager = applicationManager
|
||||||
}
|
}
|
||||||
SignUserToken(userId: string, appId: string, userIdentifier: string): string {
|
SignUserToken(userId: string, appId: string, userIdentifier: string): string {
|
||||||
return jwt.sign({ user_id: userId, app_id: appId, app_user_id: userIdentifier }, this.settings.jwtSecret);
|
return jwt.sign({ user_id: userId, app_id: appId, app_user_id: userIdentifier }, this.settings.jwtSecret);
|
||||||
}
|
}
|
||||||
|
|
||||||
DecodeUserToken(token?: string): { user_id: string, app_id: string, app_user_id: string } {
|
DecodeUserToken(token?: string): { user_id: string, app_id: string, app_user_id: string } {
|
||||||
if (!token) throw new Error("empty user token provided")
|
if (!token) throw new Error("empty user token provided")
|
||||||
let t = token
|
let t = token
|
||||||
if (token.startsWith("Bearer ")) {
|
if (token.startsWith("Bearer ")) {
|
||||||
t = token.substring("Bearer ".length)
|
t = token.substring("Bearer ".length)
|
||||||
}
|
}
|
||||||
if (!t) throw new Error("no user token provided")
|
if (!t) throw new Error("no user token provided")
|
||||||
const decoded = jwt.verify(token, this.settings.jwtSecret) as { user_id: string, app_id: string, app_user_id: string }
|
const decoded = jwt.verify(token, this.settings.jwtSecret) as { user_id: string, app_id: string, app_user_id: string }
|
||||||
if (!decoded.user_id || !decoded.app_id || !decoded.app_user_id) {
|
if (!decoded.user_id || !decoded.app_id || !decoded.app_user_id) {
|
||||||
throw new Error("the provided token is not a valid app user token token")
|
throw new Error("the provided token is not a valid app user token token")
|
||||||
}
|
}
|
||||||
return decoded
|
return decoded
|
||||||
}
|
}
|
||||||
|
|
||||||
async BanUser(userId: string): Promise<Types.BanUserResponse> {
|
async BanUser(userId: string): Promise<Types.BanUserResponse> {
|
||||||
const banned = await this.storage.userStorage.BanUser(userId)
|
const banned = await this.storage.userStorage.BanUser(userId)
|
||||||
const appUsers = await this.storage.applicationStorage.GetAllAppUsersFromUser(userId)
|
const appUsers = await this.storage.applicationStorage.GetAllAppUsersFromUser(userId)
|
||||||
return {
|
return {
|
||||||
balance_sats: banned.balance_sats,
|
balance_sats: banned.balance_sats,
|
||||||
banned_app_users: appUsers.map(appUser => ({
|
banned_app_users: appUsers.map(appUser => ({
|
||||||
app_id: appUser.application.app_id,
|
app_id: appUser.application.app_id,
|
||||||
app_name: appUser.application.name,
|
app_name: appUser.application.name,
|
||||||
user_identifier: appUser.identifier,
|
user_identifier: appUser.identifier,
|
||||||
nostr_pub: appUser.nostr_public_key || ""
|
nostr_pub: appUser.nostr_public_key || ""
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async GetUserInfo(ctx: Types.UserContext): Promise<Types.UserInfo> {
|
async GetUserInfo(ctx: Types.UserContext): Promise<Types.UserInfo> {
|
||||||
const user = await this.storage.userStorage.GetUser(ctx.user_id)
|
const user = await this.storage.userStorage.GetUser(ctx.user_id)
|
||||||
const app = await this.storage.applicationStorage.GetApplication(ctx.app_id)
|
const app = await this.storage.applicationStorage.GetApplication(ctx.app_id)
|
||||||
const appUser = await this.storage.applicationStorage.GetAppUserFromUser(app, user.user_id)
|
const appUser = await this.storage.applicationStorage.GetAppUserFromUser(app, user.user_id)
|
||||||
if (!appUser) {
|
if (!appUser) {
|
||||||
throw new Error(`app user ${ctx.user_id} not found`) // TODO: fix logs doxing
|
throw new Error(`app user ${ctx.user_id} not found`) // TODO: fix logs doxing
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
userId: ctx.user_id,
|
userId: ctx.user_id,
|
||||||
balance: user.balance_sats,
|
balance: user.balance_sats,
|
||||||
max_withdrawable: this.applicationManager.paymentManager.GetMaxPayableInvoice(user.balance_sats, true),
|
max_withdrawable: this.applicationManager.paymentManager.GetMaxPayableInvoice(user.balance_sats, true),
|
||||||
user_identifier: appUser.identifier
|
user_identifier: appUser.identifier
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async NewInvoice(ctx: Types.UserContext, req: Types.NewInvoiceRequest): Promise<Types.NewInvoiceResponse> {
|
async NewInvoice(ctx: Types.UserContext, req: Types.NewInvoiceRequest): Promise<Types.NewInvoiceResponse> {
|
||||||
return this.applicationManager.AddAppUserInvoice(ctx.app_id, {
|
return this.applicationManager.AddAppUserInvoice(ctx.app_id, {
|
||||||
http_callback_url: "",
|
http_callback_url: "",
|
||||||
invoice_req: req,
|
invoice_req: req,
|
||||||
payer_identifier: ctx.app_user_id,
|
payer_identifier: ctx.app_user_id,
|
||||||
receiver_identifier: ctx.app_user_id
|
receiver_identifier: ctx.app_user_id
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async PayInvoice(ctx: Types.UserContext, req: Types.PayInvoiceRequest): Promise<Types.PayInvoiceResponse> {
|
async PayInvoice(ctx: Types.UserContext, req: Types.PayInvoiceRequest): Promise<Types.PayInvoiceResponse> {
|
||||||
return this.applicationManager.PayAppUserInvoice(ctx.app_id, {
|
return this.applicationManager.PayAppUserInvoice(ctx.app_id, {
|
||||||
amount: req.amount,
|
amount: req.amount,
|
||||||
invoice: req.invoice,
|
invoice: req.invoice,
|
||||||
user_identifier: ctx.app_user_id
|
user_identifier: ctx.app_user_id
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
async PayAddress(ctx: Types.UserContext, req: Types.PayInvoiceRequest): Promise<Types.PayInvoiceResponse> {
|
async PayAddress(ctx: Types.UserContext, req: Types.PayInvoiceRequest): Promise<Types.PayInvoiceResponse> {
|
||||||
return this.applicationManager.PayAppUserInvoice(ctx.app_id, {
|
return this.applicationManager.PayAppUserInvoice(ctx.app_id, {
|
||||||
amount: req.amount,
|
amount: req.amount,
|
||||||
invoice: req.invoice,
|
invoice: req.invoice,
|
||||||
user_identifier: ctx.app_user_id
|
user_identifier: ctx.app_user_id
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,265 +1,265 @@
|
||||||
import jwt from 'jsonwebtoken'
|
import jwt from 'jsonwebtoken'
|
||||||
import Storage from '../storage/index.js'
|
import Storage from '../storage/index.js'
|
||||||
import * as Types from '../../../proto/autogenerated/ts/types.js'
|
import * as Types from '../../../proto/autogenerated/ts/types.js'
|
||||||
import { MainSettings } from './settings.js'
|
import { MainSettings } from './settings.js'
|
||||||
import PaymentManager from './paymentManager.js'
|
import PaymentManager from './paymentManager.js'
|
||||||
import { InboundOptionals, defaultInvoiceExpiry } from '../storage/paymentStorage.js'
|
import { InboundOptionals, defaultInvoiceExpiry } from '../storage/paymentStorage.js'
|
||||||
import { ApplicationUser } from '../storage/entity/ApplicationUser.js'
|
import { ApplicationUser } from '../storage/entity/ApplicationUser.js'
|
||||||
import { PubLogger, getLogger } from '../helpers/logger.js'
|
import { PubLogger, getLogger } from '../helpers/logger.js'
|
||||||
import crypto from 'crypto'
|
import crypto from 'crypto'
|
||||||
import { Application } from '../storage/entity/Application.js'
|
import { Application } from '../storage/entity/Application.js'
|
||||||
|
|
||||||
const TOKEN_EXPIRY_TIME = 2 * 60 * 1000 // 2 minutes, in milliseconds
|
const TOKEN_EXPIRY_TIME = 2 * 60 * 1000 // 2 minutes, in milliseconds
|
||||||
|
|
||||||
type NsecLinkingData = {
|
type NsecLinkingData = {
|
||||||
serialId: number,
|
serialId: number,
|
||||||
expiry: number
|
expiry: number
|
||||||
}
|
}
|
||||||
export default class {
|
export default class {
|
||||||
storage: Storage
|
storage: Storage
|
||||||
settings: MainSettings
|
settings: MainSettings
|
||||||
paymentManager: PaymentManager
|
paymentManager: PaymentManager
|
||||||
nPubLinkingTokens = new Map<string, NsecLinkingData>();
|
nPubLinkingTokens = new Map<string, NsecLinkingData>();
|
||||||
linkingTokenInterval: NodeJS.Timeout | null = null
|
linkingTokenInterval: NodeJS.Timeout | null = null
|
||||||
serviceBeaconInterval: NodeJS.Timeout | null = null
|
serviceBeaconInterval: NodeJS.Timeout | null = null
|
||||||
log: PubLogger
|
log: PubLogger
|
||||||
constructor(storage: Storage, settings: MainSettings, paymentManager: PaymentManager) {
|
constructor(storage: Storage, settings: MainSettings, paymentManager: PaymentManager) {
|
||||||
this.log = getLogger({ component: "ApplicationManager" })
|
this.log = getLogger({ component: "ApplicationManager" })
|
||||||
this.storage = storage
|
this.storage = storage
|
||||||
this.settings = settings
|
this.settings = settings
|
||||||
this.paymentManager = paymentManager
|
this.paymentManager = paymentManager
|
||||||
this.StartLinkingTokenInterval()
|
this.StartLinkingTokenInterval()
|
||||||
}
|
}
|
||||||
|
|
||||||
StartLinkingTokenInterval() {
|
StartLinkingTokenInterval() {
|
||||||
this.linkingTokenInterval = setInterval(() => {
|
this.linkingTokenInterval = setInterval(() => {
|
||||||
const now = Date.now();
|
const now = Date.now();
|
||||||
for (let [token, data] of this.nPubLinkingTokens) {
|
for (let [token, data] of this.nPubLinkingTokens) {
|
||||||
if (data.expiry <= now) {
|
if (data.expiry <= now) {
|
||||||
const copy = { ...data }
|
const copy = { ...data }
|
||||||
if (this.nPubLinkingTokens.delete(token)) {
|
if (this.nPubLinkingTokens.delete(token)) {
|
||||||
console.log("Expired an npub linking token for user serial id: ", copy.serialId)
|
console.log("Expired an npub linking token for user serial id: ", copy.serialId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, 60 * 1000); // 1 minute
|
}, 60 * 1000); // 1 minute
|
||||||
}
|
}
|
||||||
|
|
||||||
async StartAppsServiceBeacon(publishBeacon: (app: Application) => void) {
|
async StartAppsServiceBeacon(publishBeacon: (app: Application) => void) {
|
||||||
this.serviceBeaconInterval = setInterval(async () => {
|
this.serviceBeaconInterval = setInterval(async () => {
|
||||||
try {
|
try {
|
||||||
const apps = await this.storage.applicationStorage.GetApplications()
|
const apps = await this.storage.applicationStorage.GetApplications()
|
||||||
apps.forEach(app => {
|
apps.forEach(app => {
|
||||||
publishBeacon(app)
|
publishBeacon(app)
|
||||||
})
|
})
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.log("error in beacon", (e as any).message)
|
this.log("error in beacon", (e as any).message)
|
||||||
}
|
}
|
||||||
}, 60 * 1000)
|
}, 60 * 1000)
|
||||||
}
|
}
|
||||||
|
|
||||||
Stop() {
|
Stop() {
|
||||||
if (this.linkingTokenInterval) {
|
if (this.linkingTokenInterval) {
|
||||||
clearInterval(this.linkingTokenInterval)
|
clearInterval(this.linkingTokenInterval)
|
||||||
}
|
}
|
||||||
if (this.serviceBeaconInterval) {
|
if (this.serviceBeaconInterval) {
|
||||||
clearInterval(this.serviceBeaconInterval)
|
clearInterval(this.serviceBeaconInterval)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SignAppToken(appId: string): string {
|
SignAppToken(appId: string): string {
|
||||||
return jwt.sign({ appId }, this.settings.jwtSecret);
|
return jwt.sign({ appId }, this.settings.jwtSecret);
|
||||||
}
|
}
|
||||||
DecodeAppToken(token?: string): string {
|
DecodeAppToken(token?: string): string {
|
||||||
if (!token) throw new Error("empty app token provided")
|
if (!token) throw new Error("empty app token provided")
|
||||||
let t = token
|
let t = token
|
||||||
if (token.startsWith("Bearer ")) {
|
if (token.startsWith("Bearer ")) {
|
||||||
t = token.substring("Bearer ".length)
|
t = token.substring("Bearer ".length)
|
||||||
}
|
}
|
||||||
if (!t) throw new Error("no app token provided")
|
if (!t) throw new Error("no app token provided")
|
||||||
const decoded = jwt.verify(token, this.settings.jwtSecret) as { appId?: string }
|
const decoded = jwt.verify(token, this.settings.jwtSecret) as { appId?: string }
|
||||||
if (!decoded.appId) {
|
if (!decoded.appId) {
|
||||||
throw new Error("the provided token is not an app token")
|
throw new Error("the provided token is not an app token")
|
||||||
}
|
}
|
||||||
return decoded.appId
|
return decoded.appId
|
||||||
}
|
}
|
||||||
|
|
||||||
async SetMockAppUserBalance(appId: string, req: Types.SetMockAppUserBalanceRequest) {
|
async SetMockAppUserBalance(appId: string, req: Types.SetMockAppUserBalanceRequest) {
|
||||||
const app = await this.storage.applicationStorage.GetApplication(appId)
|
const app = await this.storage.applicationStorage.GetApplication(appId)
|
||||||
const { user } = await this.storage.applicationStorage.GetOrCreateApplicationUser(app, req.user_identifier, 0)
|
const { user } = await this.storage.applicationStorage.GetOrCreateApplicationUser(app, req.user_identifier, 0)
|
||||||
await this.paymentManager.SetMockUserBalance(user.user.user_id, req.amount)
|
await this.paymentManager.SetMockUserBalance(user.user.user_id, req.amount)
|
||||||
}
|
}
|
||||||
|
|
||||||
async SetMockAppBalance(appId: string, req: Types.SetMockAppBalanceRequest) {
|
async SetMockAppBalance(appId: string, req: Types.SetMockAppBalanceRequest) {
|
||||||
const app = await this.storage.applicationStorage.GetApplication(appId)
|
const app = await this.storage.applicationStorage.GetApplication(appId)
|
||||||
await this.paymentManager.SetMockUserBalance(app.owner.user_id, req.amount)
|
await this.paymentManager.SetMockUserBalance(app.owner.user_id, req.amount)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
async AddApp(req: Types.AddAppRequest): Promise<Types.AuthApp> {
|
async AddApp(req: Types.AddAppRequest): Promise<Types.AuthApp> {
|
||||||
const app = await this.storage.applicationStorage.AddApplication(req.name, req.allow_user_creation)
|
const app = await this.storage.applicationStorage.AddApplication(req.name, req.allow_user_creation)
|
||||||
getLogger({ appName: app.name })("app created")
|
getLogger({ appName: app.name })("app created")
|
||||||
|
|
||||||
return {
|
return {
|
||||||
app: {
|
app: {
|
||||||
id: app.app_id,
|
id: app.app_id,
|
||||||
name: app.name,
|
name: app.name,
|
||||||
balance: app.owner.balance_sats,
|
balance: app.owner.balance_sats,
|
||||||
npub: app.nostr_public_key || ""
|
npub: app.nostr_public_key || ""
|
||||||
},
|
},
|
||||||
auth_token: this.SignAppToken(app.app_id)
|
auth_token: this.SignAppToken(app.app_id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async AuthApp(req: Types.AuthAppRequest): Promise<Types.AuthApp> {
|
async AuthApp(req: Types.AuthAppRequest): Promise<Types.AuthApp> {
|
||||||
const app = await this.storage.applicationStorage.GetApplicationByName(req.name)
|
const app = await this.storage.applicationStorage.GetApplicationByName(req.name)
|
||||||
if (typeof req.allow_user_creation === 'boolean') {
|
if (typeof req.allow_user_creation === 'boolean') {
|
||||||
await this.storage.applicationStorage.UpdateApplication(app, { allow_user_creation: req.allow_user_creation })
|
await this.storage.applicationStorage.UpdateApplication(app, { allow_user_creation: req.allow_user_creation })
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
app: {
|
app: {
|
||||||
id: app.app_id,
|
id: app.app_id,
|
||||||
name: app.name,
|
name: app.name,
|
||||||
balance: app.owner.balance_sats,
|
balance: app.owner.balance_sats,
|
||||||
npub: app.nostr_public_key || ""
|
npub: app.nostr_public_key || ""
|
||||||
},
|
},
|
||||||
auth_token: this.SignAppToken(app.app_id)
|
auth_token: this.SignAppToken(app.app_id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async GetApp(appId: string): Promise<Types.Application> {
|
async GetApp(appId: string): Promise<Types.Application> {
|
||||||
const app = await this.storage.applicationStorage.GetApplication(appId)
|
const app = await this.storage.applicationStorage.GetApplication(appId)
|
||||||
return {
|
return {
|
||||||
name: app.name,
|
name: app.name,
|
||||||
id: app.app_id,
|
id: app.app_id,
|
||||||
balance: app.owner.balance_sats,
|
balance: app.owner.balance_sats,
|
||||||
npub: app.nostr_public_key || ""
|
npub: app.nostr_public_key || ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async AddAppUser(appId: string, req: Types.AddAppUserRequest): Promise<Types.AppUser> {
|
async AddAppUser(appId: string, req: Types.AddAppUserRequest): Promise<Types.AppUser> {
|
||||||
const app = await this.storage.applicationStorage.GetApplication(appId)
|
const app = await this.storage.applicationStorage.GetApplication(appId)
|
||||||
const log = getLogger({ appName: app.name })
|
const log = getLogger({ appName: app.name })
|
||||||
let u: ApplicationUser
|
let u: ApplicationUser
|
||||||
if (req.fail_if_exists) {
|
if (req.fail_if_exists) {
|
||||||
u = await this.storage.applicationStorage.AddApplicationUser(app, req.identifier, req.balance)
|
u = await this.storage.applicationStorage.AddApplicationUser(app, req.identifier, req.balance)
|
||||||
log(u.identifier, u.user.user_id, "user created")
|
log(u.identifier, u.user.user_id, "user created")
|
||||||
} else {
|
} else {
|
||||||
const { user, created } = await this.storage.applicationStorage.GetOrCreateApplicationUser(app, req.identifier, req.balance)
|
const { user, created } = await this.storage.applicationStorage.GetOrCreateApplicationUser(app, req.identifier, req.balance)
|
||||||
u = user
|
u = user
|
||||||
if (created) log(u.identifier, u.user.user_id, "user created")
|
if (created) log(u.identifier, u.user.user_id, "user created")
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
identifier: u.identifier,
|
identifier: u.identifier,
|
||||||
info: {
|
info: {
|
||||||
userId: u.user.user_id,
|
userId: u.user.user_id,
|
||||||
balance: u.user.balance_sats,
|
balance: u.user.balance_sats,
|
||||||
max_withdrawable: this.paymentManager.GetMaxPayableInvoice(u.user.balance_sats, true),
|
max_withdrawable: this.paymentManager.GetMaxPayableInvoice(u.user.balance_sats, true),
|
||||||
user_identifier: u.identifier
|
user_identifier: u.identifier
|
||||||
},
|
},
|
||||||
max_withdrawable: this.paymentManager.GetMaxPayableInvoice(u.user.balance_sats, true)
|
max_withdrawable: this.paymentManager.GetMaxPayableInvoice(u.user.balance_sats, true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async AddAppInvoice(appId: string, req: Types.AddAppInvoiceRequest): Promise<Types.NewInvoiceResponse> {
|
async AddAppInvoice(appId: string, req: Types.AddAppInvoiceRequest): Promise<Types.NewInvoiceResponse> {
|
||||||
const app = await this.storage.applicationStorage.GetApplication(appId)
|
const app = await this.storage.applicationStorage.GetApplication(appId)
|
||||||
const { user: payer } = await this.storage.applicationStorage.GetOrCreateApplicationUser(app, req.payer_identifier, 0)
|
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 }
|
const opts: InboundOptionals = { callbackUrl: req.http_callback_url, expiry: defaultInvoiceExpiry, expectedPayer: payer.user, linkedApplication: app }
|
||||||
const invoice = await this.paymentManager.NewInvoice(app.owner.user_id, req.invoice_req, opts)
|
const invoice = await this.paymentManager.NewInvoice(app.owner.user_id, req.invoice_req, opts)
|
||||||
getLogger({ appName: app.name })("app invoice created to be paid by", payer.identifier)
|
getLogger({ appName: app.name })("app invoice created to be paid by", payer.identifier)
|
||||||
return invoice
|
return invoice
|
||||||
}
|
}
|
||||||
|
|
||||||
async AddAppUserInvoice(appId: string, req: Types.AddAppUserInvoiceRequest): Promise<Types.NewInvoiceResponse> {
|
async AddAppUserInvoice(appId: string, req: Types.AddAppUserInvoiceRequest): Promise<Types.NewInvoiceResponse> {
|
||||||
const app = await this.storage.applicationStorage.GetApplication(appId)
|
const app = await this.storage.applicationStorage.GetApplication(appId)
|
||||||
const log = getLogger({ appName: app.name })
|
const log = getLogger({ appName: app.name })
|
||||||
const receiver = await this.storage.applicationStorage.GetApplicationUser(app, req.receiver_identifier)
|
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 { 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 }
|
const opts: InboundOptionals = { callbackUrl: req.http_callback_url, expiry: defaultInvoiceExpiry, expectedPayer: payer.user, linkedApplication: app }
|
||||||
log("generating invoice...")
|
log("generating invoice...")
|
||||||
const appUserInvoice = await this.paymentManager.NewInvoice(receiver.user.user_id, req.invoice_req, opts)
|
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)
|
log(receiver.identifier, "invoice created to be paid by", payer.identifier)
|
||||||
return {
|
return {
|
||||||
invoice: appUserInvoice.invoice
|
invoice: appUserInvoice.invoice
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async GetAppUser(appId: string, req: Types.GetAppUserRequest): Promise<Types.AppUser> {
|
async GetAppUser(appId: string, req: Types.GetAppUserRequest): Promise<Types.AppUser> {
|
||||||
const app = await this.storage.applicationStorage.GetApplication(appId)
|
const app = await this.storage.applicationStorage.GetApplication(appId)
|
||||||
const user = await this.storage.applicationStorage.GetApplicationUser(app, req.user_identifier)
|
const user = await this.storage.applicationStorage.GetApplicationUser(app, req.user_identifier)
|
||||||
const max = this.paymentManager.GetMaxPayableInvoice(user.user.balance_sats, true)
|
const max = this.paymentManager.GetMaxPayableInvoice(user.user.balance_sats, true)
|
||||||
return {
|
return {
|
||||||
max_withdrawable: max, identifier: req.user_identifier, info: {
|
max_withdrawable: max, identifier: req.user_identifier, info: {
|
||||||
userId: user.user.user_id, balance: user.user.balance_sats,
|
userId: user.user.user_id, balance: user.user.balance_sats,
|
||||||
max_withdrawable: this.paymentManager.GetMaxPayableInvoice(user.user.balance_sats, true),
|
max_withdrawable: this.paymentManager.GetMaxPayableInvoice(user.user.balance_sats, true),
|
||||||
user_identifier: user.identifier
|
user_identifier: user.identifier
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async PayAppUserInvoice(appId: string, req: Types.PayAppUserInvoiceRequest): Promise<Types.PayInvoiceResponse> {
|
async PayAppUserInvoice(appId: string, req: Types.PayAppUserInvoiceRequest): Promise<Types.PayInvoiceResponse> {
|
||||||
const app = await this.storage.applicationStorage.GetApplication(appId)
|
const app = await this.storage.applicationStorage.GetApplication(appId)
|
||||||
const appUser = await this.storage.applicationStorage.GetApplicationUser(app, req.user_identifier)
|
const appUser = await this.storage.applicationStorage.GetApplicationUser(app, req.user_identifier)
|
||||||
const paid = await this.paymentManager.PayInvoice(appUser.user.user_id, req, app)
|
const paid = await this.paymentManager.PayInvoice(appUser.user.user_id, req, app)
|
||||||
getLogger({ appName: app.name })(appUser.identifier, "invoice paid", paid.amount_paid, "sats")
|
getLogger({ appName: app.name })(appUser.identifier, "invoice paid", paid.amount_paid, "sats")
|
||||||
return paid
|
return paid
|
||||||
}
|
}
|
||||||
|
|
||||||
async SendAppUserToAppUserPayment(appId: string, req: Types.SendAppUserToAppUserPaymentRequest): Promise<void> {
|
async SendAppUserToAppUserPayment(appId: string, req: Types.SendAppUserToAppUserPaymentRequest): Promise<void> {
|
||||||
const app = await this.storage.applicationStorage.GetApplication(appId)
|
const app = await this.storage.applicationStorage.GetApplication(appId)
|
||||||
const fromUser = await this.storage.applicationStorage.GetApplicationUser(app, req.from_user_identifier)
|
const fromUser = await this.storage.applicationStorage.GetApplicationUser(app, req.from_user_identifier)
|
||||||
const { user: toUser } = await this.storage.applicationStorage.GetOrCreateApplicationUser(app, req.to_user_identifier, 0)
|
const { user: toUser } = await this.storage.applicationStorage.GetOrCreateApplicationUser(app, req.to_user_identifier, 0)
|
||||||
await this.paymentManager.SendUserToUserPayment(fromUser.user.user_id, toUser.user.user_id, req.amount, app)
|
await this.paymentManager.SendUserToUserPayment(fromUser.user.user_id, toUser.user.user_id, req.amount, app)
|
||||||
getLogger({ appName: app.name })(toUser.identifier, "received internal payment by", fromUser.identifier, "of", req.amount, "sats")
|
getLogger({ appName: app.name })(toUser.identifier, "received internal payment by", fromUser.identifier, "of", req.amount, "sats")
|
||||||
}
|
}
|
||||||
|
|
||||||
async SendAppUserToAppPayment(appId: string, req: Types.SendAppUserToAppPaymentRequest): Promise<void> {
|
async SendAppUserToAppPayment(appId: string, req: Types.SendAppUserToAppPaymentRequest): Promise<void> {
|
||||||
const app = await this.storage.applicationStorage.GetApplication(appId)
|
const app = await this.storage.applicationStorage.GetApplication(appId)
|
||||||
const fromUser = await this.storage.applicationStorage.GetApplicationUser(app, req.from_user_identifier)
|
const fromUser = await this.storage.applicationStorage.GetApplicationUser(app, req.from_user_identifier)
|
||||||
await this.paymentManager.SendUserToUserPayment(fromUser.user.user_id, app.owner.user_id, req.amount, app)
|
await this.paymentManager.SendUserToUserPayment(fromUser.user.user_id, app.owner.user_id, req.amount, app)
|
||||||
getLogger({ appName: app.name })("app received internal payment by", fromUser.identifier, "of", req.amount, "sats")
|
getLogger({ appName: app.name })("app received internal payment by", fromUser.identifier, "of", req.amount, "sats")
|
||||||
}
|
}
|
||||||
async GetAppUserLNURLInfo(appId: string, req: Types.GetAppUserLNURLInfoRequest): Promise<Types.LnurlPayInfoResponse> {
|
async GetAppUserLNURLInfo(appId: string, req: Types.GetAppUserLNURLInfoRequest): Promise<Types.LnurlPayInfoResponse> {
|
||||||
const app = await this.storage.applicationStorage.GetApplication(appId)
|
const app = await this.storage.applicationStorage.GetApplication(appId)
|
||||||
const user = await this.storage.applicationStorage.GetApplicationUser(app, req.user_identifier)
|
const user = await this.storage.applicationStorage.GetApplicationUser(app, req.user_identifier)
|
||||||
return this.paymentManager.GetLnurlPayInfoFromUser(user.user.user_id, app, req.base_url_override)
|
return this.paymentManager.GetLnurlPayInfoFromUser(user.user.user_id, app, req.base_url_override)
|
||||||
}
|
}
|
||||||
async RequestNPubLinkingToken(appId: string, req: Types.RequestNPubLinkingTokenRequest): Promise<Types.RequestNPubLinkingTokenResponse> {
|
async RequestNPubLinkingToken(appId: string, req: Types.RequestNPubLinkingTokenRequest): Promise<Types.RequestNPubLinkingTokenResponse> {
|
||||||
const app = await this.storage.applicationStorage.GetApplication(appId);
|
const app = await this.storage.applicationStorage.GetApplication(appId);
|
||||||
const user = await this.storage.applicationStorage.GetApplicationUser(app, req.user_identifier);
|
const user = await this.storage.applicationStorage.GetApplicationUser(app, req.user_identifier);
|
||||||
if (Array.from(this.nPubLinkingTokens.values()).find(t => t.serialId === user.serial_id)) {
|
if (Array.from(this.nPubLinkingTokens.values()).find(t => t.serialId === user.serial_id)) {
|
||||||
throw new Error("App user already waiting on linking");
|
throw new Error("App user already waiting on linking");
|
||||||
}
|
}
|
||||||
if (user.nostr_public_key) {
|
if (user.nostr_public_key) {
|
||||||
throw new Error("User already has an npub");
|
throw new Error("User already has an npub");
|
||||||
}
|
}
|
||||||
const token = crypto.randomBytes(32).toString("hex");
|
const token = crypto.randomBytes(32).toString("hex");
|
||||||
this.nPubLinkingTokens.set(token, { serialId: user.serial_id, expiry: Date.now() + TOKEN_EXPIRY_TIME })
|
this.nPubLinkingTokens.set(token, { serialId: user.serial_id, expiry: Date.now() + TOKEN_EXPIRY_TIME })
|
||||||
return { token };
|
return { token };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
async LinkNpubThroughToken(ctx: Types.UserContext, req: Types.LinkNPubThroughTokenRequest): Promise<void> {
|
async LinkNpubThroughToken(ctx: Types.UserContext, req: Types.LinkNPubThroughTokenRequest): Promise<void> {
|
||||||
const { app_id: appId, app_user_id: appUserId } = ctx
|
const { app_id: appId, app_user_id: appUserId } = ctx
|
||||||
const app = await this.storage.applicationStorage.GetApplication(appId)
|
const app = await this.storage.applicationStorage.GetApplication(appId)
|
||||||
const appUser = await this.storage.applicationStorage.GetApplicationUser(app, appUserId)
|
const appUser = await this.storage.applicationStorage.GetApplicationUser(app, appUserId)
|
||||||
await this.storage.txQueue.PushToQueue({
|
await this.storage.txQueue.PushToQueue({
|
||||||
dbTx: true,
|
dbTx: true,
|
||||||
exec: async tx => {
|
exec: async tx => {
|
||||||
await this.storage.applicationStorage.RemoveApplicationUserAndBaseUser(appUser, tx);
|
await this.storage.applicationStorage.RemoveApplicationUserAndBaseUser(appUser, tx);
|
||||||
const entry = this.nPubLinkingTokens.get(req.token)
|
const entry = this.nPubLinkingTokens.get(req.token)
|
||||||
if (entry && entry.expiry > Date.now()) {
|
if (entry && entry.expiry > Date.now()) {
|
||||||
const copy = { ...entry }
|
const copy = { ...entry }
|
||||||
const deleted = this.nPubLinkingTokens.delete(req.token)
|
const deleted = this.nPubLinkingTokens.delete(req.token)
|
||||||
if (deleted) {
|
if (deleted) {
|
||||||
await this.storage.applicationStorage.AddNPubToApplicationUser(copy.serialId, req.nostr_pub, tx)
|
await this.storage.applicationStorage.AddNPubToApplicationUser(copy.serialId, req.nostr_pub, tx)
|
||||||
} else {
|
} else {
|
||||||
throw new Error("An uknown error occured")
|
throw new Error("An uknown error occured")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
throw new Error("Token invalid or expired")
|
throw new Error("Token invalid or expired")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,39 +1,39 @@
|
||||||
import Storage from '../storage/index.js'
|
import Storage from '../storage/index.js'
|
||||||
import * as Types from '../../../proto/autogenerated/ts/types.js'
|
import * as Types from '../../../proto/autogenerated/ts/types.js'
|
||||||
|
|
||||||
|
|
||||||
import { MainSettings } from './settings.js'
|
import { MainSettings } from './settings.js'
|
||||||
import PaymentManager from './paymentManager.js'
|
import PaymentManager from './paymentManager.js'
|
||||||
import { defaultInvoiceExpiry } from '../storage/paymentStorage.js'
|
import { defaultInvoiceExpiry } from '../storage/paymentStorage.js'
|
||||||
|
|
||||||
export default class {
|
export default class {
|
||||||
storage: Storage
|
storage: Storage
|
||||||
settings: MainSettings
|
settings: MainSettings
|
||||||
paymentManager: PaymentManager
|
paymentManager: PaymentManager
|
||||||
|
|
||||||
constructor(storage: Storage, paymentManager: PaymentManager, settings: MainSettings) {
|
constructor(storage: Storage, paymentManager: PaymentManager, settings: MainSettings) {
|
||||||
this.storage = storage
|
this.storage = storage
|
||||||
this.settings = settings
|
this.settings = settings
|
||||||
this.paymentManager = paymentManager
|
this.paymentManager = paymentManager
|
||||||
}
|
}
|
||||||
|
|
||||||
async AddProduct(userId: string, req: Types.AddProductRequest): Promise<Types.Product> {
|
async AddProduct(userId: string, req: Types.AddProductRequest): Promise<Types.Product> {
|
||||||
const user = await this.storage.userStorage.GetUser(userId)
|
const user = await this.storage.userStorage.GetUser(userId)
|
||||||
const newProduct = await this.storage.productStorage.AddProduct(req.name, req.price_sats, user)
|
const newProduct = await this.storage.productStorage.AddProduct(req.name, req.price_sats, user)
|
||||||
return {
|
return {
|
||||||
id: newProduct.product_id,
|
id: newProduct.product_id,
|
||||||
name: newProduct.name,
|
name: newProduct.name,
|
||||||
price_sats: newProduct.price_sats,
|
price_sats: newProduct.price_sats,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async NewProductInvoice(id: string): Promise<Types.NewInvoiceResponse> {
|
async NewProductInvoice(id: string): Promise<Types.NewInvoiceResponse> {
|
||||||
const product = await this.storage.productStorage.GetProduct(id)
|
const product = await this.storage.productStorage.GetProduct(id)
|
||||||
const productInvoice = await this.paymentManager.NewInvoice(product.owner.user_id, {
|
const productInvoice = await this.paymentManager.NewInvoice(product.owner.user_id, {
|
||||||
amountSats: product.price_sats, memo: product.name
|
amountSats: product.price_sats, memo: product.name
|
||||||
}, { product, expiry: defaultInvoiceExpiry })
|
}, { product, expiry: defaultInvoiceExpiry })
|
||||||
return {
|
return {
|
||||||
invoice: productInvoice.invoice
|
invoice: productInvoice.invoice
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,132 +1,132 @@
|
||||||
import Storage from '../storage/index.js'
|
import Storage from '../storage/index.js'
|
||||||
import { ForwardEvent, HtlcEvent, HtlcEvent_EventType } from "../../../proto/lnd/router.js";
|
import { ForwardEvent, HtlcEvent, HtlcEvent_EventType } from "../../../proto/lnd/router.js";
|
||||||
import { getLogger } from "../helpers/logger.js";
|
import { getLogger } from "../helpers/logger.js";
|
||||||
type EventInfo = {
|
type EventInfo = {
|
||||||
eventType: HtlcEvent_EventType
|
eventType: HtlcEvent_EventType
|
||||||
outgoingHtlcId: number
|
outgoingHtlcId: number
|
||||||
incomingHtlcId: number
|
incomingHtlcId: number
|
||||||
outgoingChannelId: number
|
outgoingChannelId: number
|
||||||
incomingChannelId: number
|
incomingChannelId: number
|
||||||
}
|
}
|
||||||
export default class HtlcTracker {
|
export default class HtlcTracker {
|
||||||
storage: Storage
|
storage: Storage
|
||||||
pendingSendHtlcs: Map<number, number> = new Map()
|
pendingSendHtlcs: Map<number, number> = new Map()
|
||||||
pendingReceiveHtlcs: Map<number, number> = new Map()
|
pendingReceiveHtlcs: Map<number, number> = new Map()
|
||||||
pendingForwardHtlcs: Map<number, number> = new Map()
|
pendingForwardHtlcs: Map<number, number> = new Map()
|
||||||
constructor(storage: Storage) {
|
constructor(storage: Storage) {
|
||||||
this.storage = storage
|
this.storage = storage
|
||||||
}
|
}
|
||||||
log = getLogger({ component: 'htlcTracker' })
|
log = getLogger({ component: 'htlcTracker' })
|
||||||
onHtlcEvent = async (htlc: HtlcEvent) => {
|
onHtlcEvent = async (htlc: HtlcEvent) => {
|
||||||
getLogger({ component: 'debugHtlcs' })(htlc)
|
getLogger({ component: 'debugHtlcs' })(htlc)
|
||||||
const htlcEvent = htlc.event
|
const htlcEvent = htlc.event
|
||||||
if (htlcEvent.oneofKind === 'subscribedEvent') {
|
if (htlcEvent.oneofKind === 'subscribedEvent') {
|
||||||
this.log("htlc subscribed")
|
this.log("htlc subscribed")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const outgoingHtlcId = Number(htlc.outgoingHtlcId)
|
const outgoingHtlcId = Number(htlc.outgoingHtlcId)
|
||||||
const incomingHtlcId = Number(htlc.incomingHtlcId)
|
const incomingHtlcId = Number(htlc.incomingHtlcId)
|
||||||
const outgoingChannelId = Number(htlc.outgoingChannelId)
|
const outgoingChannelId = Number(htlc.outgoingChannelId)
|
||||||
const incomingChannelId = Number(htlc.incomingChannelId)
|
const incomingChannelId = Number(htlc.incomingChannelId)
|
||||||
const info: EventInfo = { eventType: htlc.eventType, outgoingChannelId, incomingChannelId, outgoingHtlcId, incomingHtlcId }
|
const info: EventInfo = { eventType: htlc.eventType, outgoingChannelId, incomingChannelId, outgoingHtlcId, incomingHtlcId }
|
||||||
switch (htlcEvent.oneofKind) {
|
switch (htlcEvent.oneofKind) {
|
||||||
case 'forwardEvent':
|
case 'forwardEvent':
|
||||||
return this.handleForward(htlcEvent.forwardEvent, info)
|
return this.handleForward(htlcEvent.forwardEvent, info)
|
||||||
case 'forwardFailEvent':
|
case 'forwardFailEvent':
|
||||||
return this.handleFailure(info)
|
return this.handleFailure(info)
|
||||||
case 'linkFailEvent':
|
case 'linkFailEvent':
|
||||||
return this.handleFailure(info)
|
return this.handleFailure(info)
|
||||||
case 'finalHtlcEvent':
|
case 'finalHtlcEvent':
|
||||||
if (!htlcEvent.finalHtlcEvent.settled) {
|
if (!htlcEvent.finalHtlcEvent.settled) {
|
||||||
return this.handleFailure(info)
|
return this.handleFailure(info)
|
||||||
} else {
|
} else {
|
||||||
return this.handleSuccess(info)
|
return this.handleSuccess(info)
|
||||||
}
|
}
|
||||||
case 'settleEvent':
|
case 'settleEvent':
|
||||||
return this.handleSuccess(info)
|
return this.handleSuccess(info)
|
||||||
default:
|
default:
|
||||||
this.log("unknown htlc event type")
|
this.log("unknown htlc event type")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
handleForward = (fwe: ForwardEvent, { eventType, outgoingHtlcId, incomingHtlcId }: EventInfo) => {
|
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)
|
this.log("new forward event, currently tracked htlcs: (s,r,f)", this.pendingSendHtlcs.size, this.pendingReceiveHtlcs.size, this.pendingForwardHtlcs.size)
|
||||||
const { info } = fwe
|
const { info } = fwe
|
||||||
const incomingAmtMsat = info ? Number(info.incomingAmtMsat) : 0
|
const incomingAmtMsat = info ? Number(info.incomingAmtMsat) : 0
|
||||||
const outgoingAmtMsat = info ? Number(info.outgoingAmtMsat) : 0
|
const outgoingAmtMsat = info ? Number(info.outgoingAmtMsat) : 0
|
||||||
if (eventType === HtlcEvent_EventType.SEND) {
|
if (eventType === HtlcEvent_EventType.SEND) {
|
||||||
this.pendingSendHtlcs.set(outgoingHtlcId, outgoingAmtMsat - incomingAmtMsat)
|
this.pendingSendHtlcs.set(outgoingHtlcId, outgoingAmtMsat - incomingAmtMsat)
|
||||||
} else if (eventType === HtlcEvent_EventType.RECEIVE) {
|
} else if (eventType === HtlcEvent_EventType.RECEIVE) {
|
||||||
this.pendingReceiveHtlcs.set(incomingHtlcId, incomingAmtMsat - outgoingAmtMsat)
|
this.pendingReceiveHtlcs.set(incomingHtlcId, incomingAmtMsat - outgoingAmtMsat)
|
||||||
} else if (eventType === HtlcEvent_EventType.FORWARD) {
|
} else if (eventType === HtlcEvent_EventType.FORWARD) {
|
||||||
this.pendingForwardHtlcs.set(outgoingHtlcId, outgoingAmtMsat - incomingAmtMsat)
|
this.pendingForwardHtlcs.set(outgoingHtlcId, outgoingAmtMsat - incomingAmtMsat)
|
||||||
} else {
|
} else {
|
||||||
this.log("unknown htlc event type for forward event")
|
this.log("unknown htlc event type for forward event")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
handleFailure = ({ eventType, outgoingHtlcId, incomingHtlcId, incomingChannelId, outgoingChannelId }: EventInfo) => {
|
handleFailure = ({ eventType, outgoingHtlcId, incomingHtlcId, incomingChannelId, outgoingChannelId }: EventInfo) => {
|
||||||
if (eventType === HtlcEvent_EventType.SEND && this.deleteMapEntry(outgoingHtlcId, this.pendingSendHtlcs) !== null) {
|
if (eventType === HtlcEvent_EventType.SEND && this.deleteMapEntry(outgoingHtlcId, this.pendingSendHtlcs) !== null) {
|
||||||
return this.incrementSendFailures(outgoingChannelId)
|
return this.incrementSendFailures(outgoingChannelId)
|
||||||
}
|
}
|
||||||
if (eventType === HtlcEvent_EventType.RECEIVE && this.deleteMapEntry(incomingHtlcId, this.pendingReceiveHtlcs) !== null) {
|
if (eventType === HtlcEvent_EventType.RECEIVE && this.deleteMapEntry(incomingHtlcId, this.pendingReceiveHtlcs) !== null) {
|
||||||
return this.incrementReceiveFailures(incomingChannelId)
|
return this.incrementReceiveFailures(incomingChannelId)
|
||||||
}
|
}
|
||||||
if (eventType === HtlcEvent_EventType.FORWARD) {
|
if (eventType === HtlcEvent_EventType.FORWARD) {
|
||||||
const amt = this.deleteMapEntry(outgoingHtlcId, this.pendingForwardHtlcs)
|
const amt = this.deleteMapEntry(outgoingHtlcId, this.pendingForwardHtlcs)
|
||||||
if (amt !== null) {
|
if (amt !== null) {
|
||||||
return this.incrementForwardFailures(incomingChannelId, outgoingChannelId, amt)
|
return this.incrementForwardFailures(incomingChannelId, outgoingChannelId, amt)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (eventType === HtlcEvent_EventType.UNKNOWN) {
|
if (eventType === HtlcEvent_EventType.UNKNOWN) {
|
||||||
const fwdAmt = this.deleteMapEntry(outgoingHtlcId, this.pendingForwardHtlcs)
|
const fwdAmt = this.deleteMapEntry(outgoingHtlcId, this.pendingForwardHtlcs)
|
||||||
if (fwdAmt !== null) {
|
if (fwdAmt !== null) {
|
||||||
return this.incrementForwardFailures(incomingChannelId, outgoingChannelId, fwdAmt)
|
return this.incrementForwardFailures(incomingChannelId, outgoingChannelId, fwdAmt)
|
||||||
}
|
}
|
||||||
if (this.deleteMapEntry(outgoingHtlcId, this.pendingSendHtlcs) !== null) {
|
if (this.deleteMapEntry(outgoingHtlcId, this.pendingSendHtlcs) !== null) {
|
||||||
return this.incrementSendFailures(outgoingChannelId)
|
return this.incrementSendFailures(outgoingChannelId)
|
||||||
}
|
}
|
||||||
if (this.deleteMapEntry(incomingHtlcId, this.pendingReceiveHtlcs) !== null) {
|
if (this.deleteMapEntry(incomingHtlcId, this.pendingReceiveHtlcs) !== null) {
|
||||||
return this.incrementReceiveFailures(incomingChannelId)
|
return this.incrementReceiveFailures(incomingChannelId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.log("unknown htlc event type for failure event", eventType)
|
this.log("unknown htlc event type for failure event", eventType)
|
||||||
}
|
}
|
||||||
|
|
||||||
handleSuccess = ({ eventType, outgoingHtlcId, incomingHtlcId }: EventInfo) => {
|
handleSuccess = ({ eventType, outgoingHtlcId, incomingHtlcId }: EventInfo) => {
|
||||||
if (eventType === HtlcEvent_EventType.SEND) {
|
if (eventType === HtlcEvent_EventType.SEND) {
|
||||||
this.deleteMapEntry(outgoingHtlcId, this.pendingSendHtlcs)
|
this.deleteMapEntry(outgoingHtlcId, this.pendingSendHtlcs)
|
||||||
} else if (eventType === HtlcEvent_EventType.RECEIVE) {
|
} else if (eventType === HtlcEvent_EventType.RECEIVE) {
|
||||||
this.deleteMapEntry(incomingHtlcId, this.pendingReceiveHtlcs)
|
this.deleteMapEntry(incomingHtlcId, this.pendingReceiveHtlcs)
|
||||||
} else if (eventType === HtlcEvent_EventType.FORWARD) {
|
} else if (eventType === HtlcEvent_EventType.FORWARD) {
|
||||||
this.deleteMapEntry(outgoingHtlcId, this.pendingForwardHtlcs)
|
this.deleteMapEntry(outgoingHtlcId, this.pendingForwardHtlcs)
|
||||||
} else if (eventType === HtlcEvent_EventType.UNKNOWN) {
|
} else if (eventType === HtlcEvent_EventType.UNKNOWN) {
|
||||||
if (this.deleteMapEntry(outgoingHtlcId, this.pendingSendHtlcs) !== null) return
|
if (this.deleteMapEntry(outgoingHtlcId, this.pendingSendHtlcs) !== null) return
|
||||||
if (this.deleteMapEntry(incomingHtlcId, this.pendingReceiveHtlcs) !== null) return
|
if (this.deleteMapEntry(incomingHtlcId, this.pendingReceiveHtlcs) !== null) return
|
||||||
if (this.deleteMapEntry(outgoingHtlcId, this.pendingForwardHtlcs) !== null) return
|
if (this.deleteMapEntry(outgoingHtlcId, this.pendingForwardHtlcs) !== null) return
|
||||||
} else {
|
} else {
|
||||||
this.log("unknown htlc event type for success event", eventType)
|
this.log("unknown htlc event type for success event", eventType)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
deleteMapEntry = (key: number, map: Map<number, number>) => {
|
deleteMapEntry = (key: number, map: Map<number, number>) => {
|
||||||
if (!map.has(key)) {
|
if (!map.has(key)) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
const v = map.get(key)
|
const v = map.get(key)
|
||||||
map.delete(key)
|
map.delete(key)
|
||||||
return v || null
|
return v || null
|
||||||
}
|
}
|
||||||
|
|
||||||
incrementSendFailures = async (outgoingChannelId: number) => {
|
incrementSendFailures = async (outgoingChannelId: number) => {
|
||||||
await this.storage.metricsStorage.IncrementChannelRouting(outgoingChannelId.toString(), { send_errors: 1 })
|
await this.storage.metricsStorage.IncrementChannelRouting(outgoingChannelId.toString(), { send_errors: 1 })
|
||||||
}
|
}
|
||||||
incrementReceiveFailures = async (incomingChannelId: number) => {
|
incrementReceiveFailures = async (incomingChannelId: number) => {
|
||||||
await this.storage.metricsStorage.IncrementChannelRouting(incomingChannelId.toString(), { receive_errors: 1 })
|
await this.storage.metricsStorage.IncrementChannelRouting(incomingChannelId.toString(), { receive_errors: 1 })
|
||||||
}
|
}
|
||||||
incrementForwardFailures = async (incomingChannelId: number, outgoingChannelId: number, amt: number) => {
|
incrementForwardFailures = async (incomingChannelId: number, outgoingChannelId: number, amt: number) => {
|
||||||
await this.storage.metricsStorage.IncrementChannelRouting(incomingChannelId.toString(), { forward_errors_as_input: 1, missed_forward_fee_as_input: amt })
|
await this.storage.metricsStorage.IncrementChannelRouting(incomingChannelId.toString(), { forward_errors_as_input: 1, missed_forward_fee_as_input: amt })
|
||||||
await this.storage.metricsStorage.IncrementChannelRouting(outgoingChannelId.toString(), { forward_errors_as_output: 1, missed_forward_fee_as_output: amt })
|
await this.storage.metricsStorage.IncrementChannelRouting(outgoingChannelId.toString(), { forward_errors_as_output: 1, missed_forward_fee_as_output: amt })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,262 +1,262 @@
|
||||||
import Storage from '../storage/index.js'
|
import Storage from '../storage/index.js'
|
||||||
import * as Types from '../../../proto/autogenerated/ts/types.js'
|
import * as Types from '../../../proto/autogenerated/ts/types.js'
|
||||||
import { Application } from '../storage/entity/Application.js'
|
import { Application } from '../storage/entity/Application.js'
|
||||||
import { HtlcEvent, HtlcEvent_EventType } from '../../../proto/lnd/router.js'
|
import { HtlcEvent, HtlcEvent_EventType } from '../../../proto/lnd/router.js'
|
||||||
import { BalanceInfo } from '../lnd/settings.js'
|
import { BalanceInfo } from '../lnd/settings.js'
|
||||||
import { BalanceEvent } from '../storage/entity/BalanceEvent.js'
|
import { BalanceEvent } from '../storage/entity/BalanceEvent.js'
|
||||||
import { ChannelBalanceEvent } from '../storage/entity/ChannelsBalanceEvent.js'
|
import { ChannelBalanceEvent } from '../storage/entity/ChannelsBalanceEvent.js'
|
||||||
import LND from '../lnd/lnd.js'
|
import LND from '../lnd/lnd.js'
|
||||||
import HtlcTracker from './htlcTracker.js'
|
import HtlcTracker from './htlcTracker.js'
|
||||||
const maxEvents = 100_000
|
const maxEvents = 100_000
|
||||||
export default class Handler {
|
export default class Handler {
|
||||||
storage: Storage
|
storage: Storage
|
||||||
lnd: LND
|
lnd: LND
|
||||||
htlcTracker: HtlcTracker
|
htlcTracker: HtlcTracker
|
||||||
metrics: Types.UsageMetric[] = []
|
metrics: Types.UsageMetric[] = []
|
||||||
constructor(storage: Storage, lnd: LND) {
|
constructor(storage: Storage, lnd: LND) {
|
||||||
this.storage = storage
|
this.storage = storage
|
||||||
this.lnd = lnd
|
this.lnd = lnd
|
||||||
this.htlcTracker = new HtlcTracker(this.storage)
|
this.htlcTracker = new HtlcTracker(this.storage)
|
||||||
}
|
}
|
||||||
|
|
||||||
async HtlcCb(htlc: HtlcEvent) {
|
async HtlcCb(htlc: HtlcEvent) {
|
||||||
await this.htlcTracker.onHtlcEvent(htlc)
|
await this.htlcTracker.onHtlcEvent(htlc)
|
||||||
}
|
}
|
||||||
|
|
||||||
async NewBlockCb(height: number, balanceInfo: BalanceInfo) {
|
async NewBlockCb(height: number, balanceInfo: BalanceInfo) {
|
||||||
const balanceEvent: Partial<BalanceEvent> = {
|
const balanceEvent: Partial<BalanceEvent> = {
|
||||||
block_height: height,
|
block_height: height,
|
||||||
confirmed_chain_balance: balanceInfo.confirmedBalance,
|
confirmed_chain_balance: balanceInfo.confirmedBalance,
|
||||||
unconfirmed_chain_balance: balanceInfo.unconfirmedBalance,
|
unconfirmed_chain_balance: balanceInfo.unconfirmedBalance,
|
||||||
total_chain_balance: balanceInfo.totalBalance,
|
total_chain_balance: balanceInfo.totalBalance,
|
||||||
}
|
}
|
||||||
const channelsEvents: Partial<ChannelBalanceEvent>[] = balanceInfo.channelsBalance.map(c => ({
|
const channelsEvents: Partial<ChannelBalanceEvent>[] = balanceInfo.channelsBalance.map(c => ({
|
||||||
channel_id: c.channelId,
|
channel_id: c.channelId,
|
||||||
local_balance_sats: c.localBalanceSats,
|
local_balance_sats: c.localBalanceSats,
|
||||||
remote_balance_sats: c.remoteBalanceSats,
|
remote_balance_sats: c.remoteBalanceSats,
|
||||||
}))
|
}))
|
||||||
await this.storage.metricsStorage.SaveBalanceEvents(balanceEvent, channelsEvents)
|
await this.storage.metricsStorage.SaveBalanceEvents(balanceEvent, channelsEvents)
|
||||||
}
|
}
|
||||||
|
|
||||||
async FetchLatestForwardingEvents() {
|
async FetchLatestForwardingEvents() {
|
||||||
const latestIndex = await this.storage.metricsStorage.GetLatestForwardingIndexOffset()
|
const latestIndex = await this.storage.metricsStorage.GetLatestForwardingIndexOffset()
|
||||||
const res = await this.lnd.GetForwardingHistory(latestIndex)
|
const res = await this.lnd.GetForwardingHistory(latestIndex)
|
||||||
const forwards = res.forwardingEvents.map(e => ({ fee: Number(e.fee), chanIdIn: e.chanIdIn, chanIdOut: e.chanIdOut, timestampNs: e.timestampNs.toString(), offset: res.lastOffsetIndex }))
|
const forwards = res.forwardingEvents.map(e => ({ fee: Number(e.fee), chanIdIn: e.chanIdIn, chanIdOut: e.chanIdOut, timestampNs: e.timestampNs.toString(), offset: res.lastOffsetIndex }))
|
||||||
await Promise.all(forwards.map(async f => {
|
await Promise.all(forwards.map(async f => {
|
||||||
await this.storage.metricsStorage.IncrementChannelRouting(f.chanIdIn, { forward_fee_as_input: f.fee, latest_index_offset: f.offset })
|
await this.storage.metricsStorage.IncrementChannelRouting(f.chanIdIn, { forward_fee_as_input: f.fee, latest_index_offset: f.offset })
|
||||||
await this.storage.metricsStorage.IncrementChannelRouting(f.chanIdOut, { forward_fee_as_output: f.fee, latest_index_offset: f.offset })
|
await this.storage.metricsStorage.IncrementChannelRouting(f.chanIdOut, { forward_fee_as_output: f.fee, latest_index_offset: f.offset })
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
AddMetrics(newMetrics: (Types.RequestMetric & { app_id?: string })[]) {
|
AddMetrics(newMetrics: (Types.RequestMetric & { app_id?: string })[]) {
|
||||||
const parsed: Types.UsageMetric[] = newMetrics.map(m => ({
|
const parsed: Types.UsageMetric[] = newMetrics.map(m => ({
|
||||||
rpc_name: m.rpcName,
|
rpc_name: m.rpcName,
|
||||||
batch: m.batch,
|
batch: m.batch,
|
||||||
nostr: m.nostr,
|
nostr: m.nostr,
|
||||||
batch_size: m.batchSize,
|
batch_size: m.batchSize,
|
||||||
parsed_in_nano: Number(m.parse - m.start),
|
parsed_in_nano: Number(m.parse - m.start),
|
||||||
auth_in_nano: Number(m.guard - m.parse),
|
auth_in_nano: Number(m.guard - m.parse),
|
||||||
validate_in_nano: Number(m.validate - m.guard),
|
validate_in_nano: Number(m.validate - m.guard),
|
||||||
handle_in_nano: Number(m.handle - m.validate),
|
handle_in_nano: Number(m.handle - m.validate),
|
||||||
success: !m.error,
|
success: !m.error,
|
||||||
app_id: m.app_id ? m.app_id : "",
|
app_id: m.app_id ? m.app_id : "",
|
||||||
processed_at_ms: m.startMs
|
processed_at_ms: m.startMs
|
||||||
}))
|
}))
|
||||||
const len = this.metrics.push(...parsed)
|
const len = this.metrics.push(...parsed)
|
||||||
if (len > maxEvents) {
|
if (len > maxEvents) {
|
||||||
this.metrics.splice(0, len - maxEvents)
|
this.metrics.splice(0, len - maxEvents)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
async GetUsageMetrics(): Promise<Types.UsageMetrics> {
|
async GetUsageMetrics(): Promise<Types.UsageMetrics> {
|
||||||
return {
|
return {
|
||||||
metrics: this.metrics
|
metrics: this.metrics
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
async GetAppsMetrics(req: Types.AppsMetricsRequest): Promise<Types.AppsMetrics> {
|
async GetAppsMetrics(req: Types.AppsMetricsRequest): Promise<Types.AppsMetrics> {
|
||||||
const dbApps = await this.storage.applicationStorage.GetApplications()
|
const dbApps = await this.storage.applicationStorage.GetApplications()
|
||||||
const apps = await Promise.all(dbApps.map(app => this.GetAppMetrics(req, app)))
|
const apps = await Promise.all(dbApps.map(app => this.GetAppMetrics(req, app)))
|
||||||
const unlinked = await this.GetAppMetrics(req, null)
|
const unlinked = await this.GetAppMetrics(req, null)
|
||||||
apps.push(unlinked)
|
apps.push(unlinked)
|
||||||
return {
|
return {
|
||||||
apps
|
apps
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async GetAppMetrics(req: Types.AppsMetricsRequest, app: Application | null): Promise<Types.AppMetrics> {
|
async GetAppMetrics(req: Types.AppsMetricsRequest, app: Application | null): Promise<Types.AppMetrics> {
|
||||||
const totalFees = await this.storage.paymentStorage.GetTotalFeesPaidInApp(app)
|
const totalFees = await this.storage.paymentStorage.GetTotalFeesPaidInApp(app)
|
||||||
const { receivingInvoices, receivingTransactions, outgoingInvoices, outgoingTransactions, receivingAddresses, userToUser } = await this.storage.paymentStorage.GetAppOperations(app, { from: req.from_unix, to: req.to_unix })
|
const { receivingInvoices, receivingTransactions, outgoingInvoices, outgoingTransactions, receivingAddresses, userToUser } = await this.storage.paymentStorage.GetAppOperations(app, { from: req.from_unix, to: req.to_unix })
|
||||||
let totalReceived = 0
|
let totalReceived = 0
|
||||||
let totalSpent = 0
|
let totalSpent = 0
|
||||||
let unpaidInvoices = 0
|
let unpaidInvoices = 0
|
||||||
let feesInRange = 0
|
let feesInRange = 0
|
||||||
const operations: Types.UserOperation[] = []
|
const operations: Types.UserOperation[] = []
|
||||||
receivingInvoices.forEach(i => {
|
receivingInvoices.forEach(i => {
|
||||||
if (i.paid_at_unix > 0) {
|
if (i.paid_at_unix > 0) {
|
||||||
totalReceived += i.paid_amount
|
totalReceived += i.paid_amount
|
||||||
feesInRange += i.service_fee
|
feesInRange += i.service_fee
|
||||||
if (req.include_operations) operations.push({ type: Types.UserOperationType.INCOMING_INVOICE, amount: i.paid_amount, inbound: true, paidAtUnix: i.paid_at_unix, confirmed: true, service_fee: i.service_fee, network_fee: 0, identifier: "", operationId: "", tx_hash: "", internal: i.internal })
|
if (req.include_operations) operations.push({ type: Types.UserOperationType.INCOMING_INVOICE, amount: i.paid_amount, inbound: true, paidAtUnix: i.paid_at_unix, confirmed: true, service_fee: i.service_fee, network_fee: 0, identifier: "", operationId: "", tx_hash: "", internal: i.internal })
|
||||||
} else {
|
} else {
|
||||||
unpaidInvoices++
|
unpaidInvoices++
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
receivingTransactions.forEach(txs => {
|
receivingTransactions.forEach(txs => {
|
||||||
txs.forEach(tx => {
|
txs.forEach(tx => {
|
||||||
if (req.include_operations) operations.push({ type: Types.UserOperationType.INCOMING_TX, amount: tx.paid_amount, inbound: true, paidAtUnix: tx.paid_at_unix, confirmed: tx.confs > 1, service_fee: tx.service_fee, network_fee: 0, identifier: "", operationId: "", tx_hash: tx.tx_hash, internal: tx.internal })
|
if (req.include_operations) operations.push({ type: Types.UserOperationType.INCOMING_TX, amount: tx.paid_amount, inbound: true, paidAtUnix: tx.paid_at_unix, confirmed: tx.confs > 1, service_fee: tx.service_fee, network_fee: 0, identifier: "", operationId: "", tx_hash: tx.tx_hash, internal: tx.internal })
|
||||||
if (tx.confs > 1) {
|
if (tx.confs > 1) {
|
||||||
feesInRange += tx.service_fee
|
feesInRange += tx.service_fee
|
||||||
totalReceived += tx.paid_amount
|
totalReceived += tx.paid_amount
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
outgoingInvoices.forEach(i => {
|
outgoingInvoices.forEach(i => {
|
||||||
if (req.include_operations) operations.push({ type: Types.UserOperationType.OUTGOING_INVOICE, amount: i.paid_amount, inbound: false, paidAtUnix: i.paid_at_unix, confirmed: true, service_fee: i.service_fees, network_fee: i.routing_fees, identifier: "", operationId: "", tx_hash: "", internal: i.internal })
|
if (req.include_operations) operations.push({ type: Types.UserOperationType.OUTGOING_INVOICE, amount: i.paid_amount, inbound: false, paidAtUnix: i.paid_at_unix, confirmed: true, service_fee: i.service_fees, network_fee: i.routing_fees, identifier: "", operationId: "", tx_hash: "", internal: i.internal })
|
||||||
totalSpent += i.paid_amount
|
totalSpent += i.paid_amount
|
||||||
feesInRange += i.service_fees
|
feesInRange += i.service_fees
|
||||||
})
|
})
|
||||||
outgoingTransactions.forEach(tx => {
|
outgoingTransactions.forEach(tx => {
|
||||||
if (req.include_operations) operations.push({ type: Types.UserOperationType.OUTGOING_TX, amount: tx.paid_amount, inbound: false, paidAtUnix: tx.paid_at_unix, confirmed: tx.confs > 1, service_fee: tx.service_fees, network_fee: tx.chain_fees, identifier: "", operationId: "", tx_hash: tx.tx_hash, internal: tx.internal })
|
if (req.include_operations) operations.push({ type: Types.UserOperationType.OUTGOING_TX, amount: tx.paid_amount, inbound: false, paidAtUnix: tx.paid_at_unix, confirmed: tx.confs > 1, service_fee: tx.service_fees, network_fee: tx.chain_fees, identifier: "", operationId: "", tx_hash: tx.tx_hash, internal: tx.internal })
|
||||||
totalSpent += tx.paid_amount
|
totalSpent += tx.paid_amount
|
||||||
feesInRange += tx.service_fees
|
feesInRange += tx.service_fees
|
||||||
})
|
})
|
||||||
|
|
||||||
userToUser.forEach(op => {
|
userToUser.forEach(op => {
|
||||||
if (req.include_operations) operations.push({ type: Types.UserOperationType.INCOMING_USER_TO_USER, amount: op.paid_amount, inbound: true, paidAtUnix: op.paid_at_unix, confirmed: true, service_fee: op.service_fees, network_fee: 0, identifier: "", operationId: "", tx_hash: "", internal: true })
|
if (req.include_operations) operations.push({ type: Types.UserOperationType.INCOMING_USER_TO_USER, amount: op.paid_amount, inbound: true, paidAtUnix: op.paid_at_unix, confirmed: true, service_fee: op.service_fees, network_fee: 0, identifier: "", operationId: "", tx_hash: "", internal: true })
|
||||||
feesInRange += op.service_fees
|
feesInRange += op.service_fees
|
||||||
})
|
})
|
||||||
|
|
||||||
const users = await this.storage.applicationStorage.GetApplicationUsers(app, { from: req.from_unix, to: req.to_unix })
|
const users = await this.storage.applicationStorage.GetApplicationUsers(app, { from: req.from_unix, to: req.to_unix })
|
||||||
|
|
||||||
let totalUserWithBalance = 0
|
let totalUserWithBalance = 0
|
||||||
let totalUserWithNoBalance = 0
|
let totalUserWithNoBalance = 0
|
||||||
let totalUsersWithNegativeBalance = 0
|
let totalUsersWithNegativeBalance = 0
|
||||||
let totalAlwaysBeenInactive = 0
|
let totalAlwaysBeenInactive = 0
|
||||||
let balanceSum = 0
|
let balanceSum = 0
|
||||||
let minBalance = Number.MAX_SAFE_INTEGER
|
let minBalance = Number.MAX_SAFE_INTEGER
|
||||||
let maxBalance = 0
|
let maxBalance = 0
|
||||||
await Promise.all(users.map(async u => {
|
await Promise.all(users.map(async u => {
|
||||||
if (u.user.balance_sats < 0) {
|
if (u.user.balance_sats < 0) {
|
||||||
totalUsersWithNegativeBalance++
|
totalUsersWithNegativeBalance++
|
||||||
} else if (u.user.balance_sats === 0) {
|
} else if (u.user.balance_sats === 0) {
|
||||||
const wasActive = await this.storage.paymentStorage.UserHasOutgoingOperation(u.user.user_id)
|
const wasActive = await this.storage.paymentStorage.UserHasOutgoingOperation(u.user.user_id)
|
||||||
totalUserWithNoBalance++
|
totalUserWithNoBalance++
|
||||||
if (!wasActive) {
|
if (!wasActive) {
|
||||||
totalAlwaysBeenInactive++
|
totalAlwaysBeenInactive++
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
balanceSum += u.user.balance_sats
|
balanceSum += u.user.balance_sats
|
||||||
totalUserWithBalance++
|
totalUserWithBalance++
|
||||||
if (u.user.balance_sats < minBalance) {
|
if (u.user.balance_sats < minBalance) {
|
||||||
minBalance = u.user.balance_sats
|
minBalance = u.user.balance_sats
|
||||||
}
|
}
|
||||||
if (u.user.balance_sats > maxBalance) {
|
if (u.user.balance_sats > maxBalance) {
|
||||||
maxBalance = u.user.balance_sats
|
maxBalance = u.user.balance_sats
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
return {
|
return {
|
||||||
app: {
|
app: {
|
||||||
name: app ? app.name : "unlinked to app",
|
name: app ? app.name : "unlinked to app",
|
||||||
id: app ? app.app_id : "unlinked",
|
id: app ? app.app_id : "unlinked",
|
||||||
npub: app ? (app.nostr_public_key || "") : "",
|
npub: app ? (app.nostr_public_key || "") : "",
|
||||||
balance: app ? app.owner.balance_sats : 0,
|
balance: app ? app.owner.balance_sats : 0,
|
||||||
},
|
},
|
||||||
users: {
|
users: {
|
||||||
total: users.length,
|
total: users.length,
|
||||||
always_been_inactive: totalAlwaysBeenInactive,
|
always_been_inactive: totalAlwaysBeenInactive,
|
||||||
balance_avg: Math.round(balanceSum / totalUserWithBalance),
|
balance_avg: Math.round(balanceSum / totalUserWithBalance),
|
||||||
balance_median: Math.round((maxBalance + minBalance) / 2),
|
balance_median: Math.round((maxBalance + minBalance) / 2),
|
||||||
no_balance: totalUserWithNoBalance,
|
no_balance: totalUserWithNoBalance,
|
||||||
negative_balance: totalUsersWithNegativeBalance,
|
negative_balance: totalUsersWithNegativeBalance,
|
||||||
},
|
},
|
||||||
|
|
||||||
received: totalReceived,
|
received: totalReceived,
|
||||||
spent: totalSpent,
|
spent: totalSpent,
|
||||||
available: balanceSum,
|
available: balanceSum,
|
||||||
fees: feesInRange,
|
fees: feesInRange,
|
||||||
total_fees: totalFees,
|
total_fees: totalFees,
|
||||||
invoices: receivingInvoices.length,
|
invoices: receivingInvoices.length,
|
||||||
|
|
||||||
operations
|
operations
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async GetChannelsInfo() {
|
async GetChannelsInfo() {
|
||||||
const { channels } = await this.lnd.ListChannels()
|
const { channels } = await this.lnd.ListChannels()
|
||||||
let totalActive = 0
|
let totalActive = 0
|
||||||
let totalInactive = 0
|
let totalInactive = 0
|
||||||
channels.forEach(c => {
|
channels.forEach(c => {
|
||||||
if (c.active) {
|
if (c.active) {
|
||||||
totalActive++
|
totalActive++
|
||||||
} else {
|
} else {
|
||||||
totalInactive++
|
totalInactive++
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
return {
|
return {
|
||||||
totalActive, totalInactive, openChannels: channels
|
totalActive, totalInactive, openChannels: channels
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
async GetPendingChannelsInfo() {
|
async GetPendingChannelsInfo() {
|
||||||
const { pendingForceClosingChannels, pendingOpenChannels } = await this.lnd.ListPendingChannels()
|
const { pendingForceClosingChannels, pendingOpenChannels } = await this.lnd.ListPendingChannels()
|
||||||
return { totalPendingClose: pendingForceClosingChannels.length, totalPendingOpen: pendingOpenChannels.length }
|
return { totalPendingClose: pendingForceClosingChannels.length, totalPendingOpen: pendingOpenChannels.length }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
async GetLndMetrics(req: Types.LndMetricsRequest): Promise<Types.LndMetrics> {
|
async GetLndMetrics(req: Types.LndMetricsRequest): Promise<Types.LndMetrics> {
|
||||||
const { openChannels, totalActive, totalInactive } = await this.GetChannelsInfo()
|
const { openChannels, totalActive, totalInactive } = await this.GetChannelsInfo()
|
||||||
const { totalPendingOpen, totalPendingClose } = await this.GetPendingChannelsInfo()
|
const { totalPendingOpen, totalPendingClose } = await this.GetPendingChannelsInfo()
|
||||||
const { channels: closedChannels } = await this.lnd.ListClosedChannels()
|
const { channels: closedChannels } = await this.lnd.ListClosedChannels()
|
||||||
const rawRouting = await this.storage.metricsStorage.GetChannelRouting({ from: req.from_unix, to: req.to_unix })
|
const rawRouting = await this.storage.metricsStorage.GetChannelRouting({ from: req.from_unix, to: req.to_unix })
|
||||||
const routingMap: Record<string, Types.ChannelRouting> = {}
|
const routingMap: Record<string, Types.ChannelRouting> = {}
|
||||||
rawRouting.forEach(r => {
|
rawRouting.forEach(r => {
|
||||||
if (!routingMap[r.channel_id]) {
|
if (!routingMap[r.channel_id]) {
|
||||||
routingMap[r.channel_id] = {
|
routingMap[r.channel_id] = {
|
||||||
channel_id: r.channel_id,
|
channel_id: r.channel_id,
|
||||||
send_errors: 0,
|
send_errors: 0,
|
||||||
receive_errors: 0,
|
receive_errors: 0,
|
||||||
forward_errors_as_input: 0,
|
forward_errors_as_input: 0,
|
||||||
forward_errors_as_output: 0,
|
forward_errors_as_output: 0,
|
||||||
missed_forward_fee_as_input: 0,
|
missed_forward_fee_as_input: 0,
|
||||||
missed_forward_fee_as_output: 0,
|
missed_forward_fee_as_output: 0,
|
||||||
forward_fee_as_input: 0,
|
forward_fee_as_input: 0,
|
||||||
forward_fee_as_output: 0,
|
forward_fee_as_output: 0,
|
||||||
events_number: 0
|
events_number: 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
routingMap[r.channel_id].send_errors += r.send_errors
|
routingMap[r.channel_id].send_errors += r.send_errors
|
||||||
routingMap[r.channel_id].receive_errors += r.receive_errors
|
routingMap[r.channel_id].receive_errors += r.receive_errors
|
||||||
routingMap[r.channel_id].forward_errors_as_input += r.forward_errors_as_input
|
routingMap[r.channel_id].forward_errors_as_input += r.forward_errors_as_input
|
||||||
routingMap[r.channel_id].forward_errors_as_output += r.forward_errors_as_output
|
routingMap[r.channel_id].forward_errors_as_output += r.forward_errors_as_output
|
||||||
routingMap[r.channel_id].missed_forward_fee_as_input += r.missed_forward_fee_as_input
|
routingMap[r.channel_id].missed_forward_fee_as_input += r.missed_forward_fee_as_input
|
||||||
routingMap[r.channel_id].missed_forward_fee_as_output += r.missed_forward_fee_as_output
|
routingMap[r.channel_id].missed_forward_fee_as_output += r.missed_forward_fee_as_output
|
||||||
routingMap[r.channel_id].forward_fee_as_input += r.forward_fee_as_input
|
routingMap[r.channel_id].forward_fee_as_input += r.forward_fee_as_input
|
||||||
routingMap[r.channel_id].forward_fee_as_output += r.forward_fee_as_output
|
routingMap[r.channel_id].forward_fee_as_output += r.forward_fee_as_output
|
||||||
routingMap[r.channel_id].events_number++
|
routingMap[r.channel_id].events_number++
|
||||||
})
|
})
|
||||||
const { channelsBalanceEvents, chainBalanceEvents } = await this.storage.metricsStorage.GetBalanceEvents({ from: req.from_unix, to: req.to_unix })
|
const { channelsBalanceEvents, chainBalanceEvents } = await this.storage.metricsStorage.GetBalanceEvents({ from: req.from_unix, to: req.to_unix })
|
||||||
return {
|
return {
|
||||||
nodes: [{
|
nodes: [{
|
||||||
chain_balance_events: chainBalanceEvents.map(e => ({
|
chain_balance_events: chainBalanceEvents.map(e => ({
|
||||||
block_height: e.block_height,
|
block_height: e.block_height,
|
||||||
confirmed_balance: e.confirmed_chain_balance,
|
confirmed_balance: e.confirmed_chain_balance,
|
||||||
unconfirmed_balance: e.unconfirmed_chain_balance,
|
unconfirmed_balance: e.unconfirmed_chain_balance,
|
||||||
total_balance: e.total_chain_balance
|
total_balance: e.total_chain_balance
|
||||||
})),
|
})),
|
||||||
channels_balance_events: channelsBalanceEvents.map(e => ({
|
channels_balance_events: channelsBalanceEvents.map(e => ({
|
||||||
block_height: e.balance_event.block_height,
|
block_height: e.balance_event.block_height,
|
||||||
channel_id: e.channel_id,
|
channel_id: e.channel_id,
|
||||||
local_balance_sats: e.local_balance_sats,
|
local_balance_sats: e.local_balance_sats,
|
||||||
remote_balance_sats: e.remote_balance_sats
|
remote_balance_sats: e.remote_balance_sats
|
||||||
})),
|
})),
|
||||||
closing_channels: totalPendingClose,
|
closing_channels: totalPendingClose,
|
||||||
pending_channels: totalPendingOpen,
|
pending_channels: totalPendingOpen,
|
||||||
offline_channels: totalInactive,
|
offline_channels: totalInactive,
|
||||||
online_channels: totalActive,
|
online_channels: totalActive,
|
||||||
closed_channels: closedChannels.map(c => ({ capacity: Number(c.capacity), channel_id: c.chanId, closed_height: c.closeHeight })),
|
closed_channels: closedChannels.map(c => ({ capacity: Number(c.capacity), channel_id: c.chanId, closed_height: c.closeHeight })),
|
||||||
open_channels: openChannels.map(c => ({ active: c.active, capacity: Number(c.capacity), channel_id: c.chanId, lifetime: Number(c.lifetime), local_balance: Number(c.localBalance), remote_balance: Number(c.remoteBalance) })),
|
open_channels: openChannels.map(c => ({ active: c.active, capacity: Number(c.capacity), channel_id: c.chanId, lifetime: Number(c.lifetime), local_balance: Number(c.localBalance), remote_balance: Number(c.remoteBalance) })),
|
||||||
channel_routing: Object.values(routingMap)
|
channel_routing: Object.values(routingMap)
|
||||||
}],
|
}],
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,40 +1,47 @@
|
||||||
import { ChildProcess, fork } from 'child_process'
|
import { ChildProcess, fork } from 'child_process'
|
||||||
import { EnvMustBeNonEmptyString } from "../helpers/envParser.js"
|
import { EnvMustBeNonEmptyString } from "../helpers/envParser.js"
|
||||||
import { NostrSettings, NostrEvent, ChildProcessRequest, ChildProcessResponse, SendData, SendInitiator } from "./handler.js"
|
import { NostrSettings, NostrEvent, ChildProcessRequest, ChildProcessResponse, SendData, SendInitiator } from "./handler.js"
|
||||||
type EventCallback = (event: NostrEvent) => void
|
type EventCallback = (event: NostrEvent) => void
|
||||||
export const LoadNosrtSettingsFromEnv = (test = false) => {
|
|
||||||
return {
|
const getEnvOrDefault = (name: string, defaultValue: string): string => {
|
||||||
relays: EnvMustBeNonEmptyString("NOSTR_RELAYS").split(' ')
|
return process.env[name] || defaultValue;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
export default class NostrSubprocess {
|
export const LoadNosrtSettingsFromEnv = (test = false) => {
|
||||||
settings: NostrSettings
|
const relaysEnv = getEnvOrDefault("NOSTR_RELAYS", "wss://strfry.shock.network");
|
||||||
childProcess: ChildProcess
|
return {
|
||||||
constructor(settings: NostrSettings, eventCallback: EventCallback) {
|
relays: relaysEnv.split(' ')
|
||||||
this.childProcess = fork("./build/src/services/nostr/handler")
|
}
|
||||||
this.childProcess.on("error", console.error)
|
}
|
||||||
this.childProcess.on("message", (message: ChildProcessResponse) => {
|
|
||||||
switch (message.type) {
|
export default class NostrSubprocess {
|
||||||
case 'ready':
|
settings: NostrSettings
|
||||||
this.sendToChildProcess({ type: 'settings', settings: settings })
|
childProcess: ChildProcess
|
||||||
break;
|
constructor(settings: NostrSettings, eventCallback: EventCallback) {
|
||||||
case 'event':
|
this.childProcess = fork("./build/src/services/nostr/handler")
|
||||||
eventCallback(message.event)
|
this.childProcess.on("error", console.error)
|
||||||
break
|
this.childProcess.on("message", (message: ChildProcessResponse) => {
|
||||||
default:
|
switch (message.type) {
|
||||||
console.error("unknown nostr event response", message)
|
case 'ready':
|
||||||
break;
|
this.sendToChildProcess({ type: 'settings', settings: settings })
|
||||||
}
|
break;
|
||||||
})
|
case 'event':
|
||||||
}
|
eventCallback(message.event)
|
||||||
sendToChildProcess(message: ChildProcessRequest) {
|
break
|
||||||
this.childProcess.send(message)
|
default:
|
||||||
}
|
console.error("unknown nostr event response", message)
|
||||||
|
break;
|
||||||
Send(initiator: SendInitiator, data: SendData, relays?: string[]) {
|
}
|
||||||
this.sendToChildProcess({ type: 'send', data, initiator, relays })
|
})
|
||||||
}
|
}
|
||||||
Stop() {
|
sendToChildProcess(message: ChildProcessRequest) {
|
||||||
this.childProcess.kill()
|
this.childProcess.send(message)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
Send(initiator: SendInitiator, data: SendData, relays?: string[]) {
|
||||||
|
this.sendToChildProcess({ type: 'send', data, initiator, relays })
|
||||||
|
}
|
||||||
|
Stop() {
|
||||||
|
this.childProcess.kill()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,55 +1,55 @@
|
||||||
import { base64 } from "@scure/base";
|
import { base64 } from "@scure/base";
|
||||||
import { randomBytes } from "@noble/hashes/utils";
|
import { randomBytes } from "@noble/hashes/utils";
|
||||||
import { streamXOR as xchacha20 } from "@stablelib/xchacha20";
|
import { streamXOR as xchacha20 } from "@stablelib/xchacha20";
|
||||||
import { secp256k1 } from "@noble/curves/secp256k1";
|
import { secp256k1 } from "@noble/curves/secp256k1";
|
||||||
import { sha256 } from "@noble/hashes/sha256";
|
import { sha256 } from "@noble/hashes/sha256";
|
||||||
type EncryptedData = {
|
type EncryptedData = {
|
||||||
ciphertext: Uint8Array;
|
ciphertext: Uint8Array;
|
||||||
nonce: Uint8Array;
|
nonce: Uint8Array;
|
||||||
}
|
}
|
||||||
export const getSharedSecret = (privateKey: string, publicKey: string) => {
|
export const getSharedSecret = (privateKey: string, publicKey: string) => {
|
||||||
const key = secp256k1.getSharedSecret(privateKey, "02" + publicKey);
|
const key = secp256k1.getSharedSecret(privateKey, "02" + publicKey);
|
||||||
return sha256(key.slice(1, 33));
|
return sha256(key.slice(1, 33));
|
||||||
}
|
}
|
||||||
|
|
||||||
export const encryptData = (content: string, sharedSecret: Uint8Array) => {
|
export const encryptData = (content: string, sharedSecret: Uint8Array) => {
|
||||||
const nonce = randomBytes(24);
|
const nonce = randomBytes(24);
|
||||||
const plaintext = new TextEncoder().encode(content);
|
const plaintext = new TextEncoder().encode(content);
|
||||||
const ciphertext = xchacha20(sharedSecret, nonce, plaintext, plaintext);
|
const ciphertext = xchacha20(sharedSecret, nonce, plaintext, plaintext);
|
||||||
return {
|
return {
|
||||||
ciphertext: Uint8Array.from(ciphertext),
|
ciphertext: Uint8Array.from(ciphertext),
|
||||||
nonce: nonce,
|
nonce: nonce,
|
||||||
} as EncryptedData;
|
} as EncryptedData;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const decryptData = (payload: EncryptedData, sharedSecret: Uint8Array) => {
|
export const decryptData = (payload: EncryptedData, sharedSecret: Uint8Array) => {
|
||||||
const dst = xchacha20(sharedSecret, payload.nonce, payload.ciphertext, payload.ciphertext);
|
const dst = xchacha20(sharedSecret, payload.nonce, payload.ciphertext, payload.ciphertext);
|
||||||
const decoded = new TextDecoder().decode(dst);
|
const decoded = new TextDecoder().decode(dst);
|
||||||
return decoded;
|
return decoded;
|
||||||
}
|
}
|
||||||
const xchacha20EncryptionVersion = 1
|
const xchacha20EncryptionVersion = 1
|
||||||
export const decodePayload = (p: string) => {
|
export const decodePayload = (p: string) => {
|
||||||
if (p.startsWith("{") && p.endsWith("}")) {
|
if (p.startsWith("{") && p.endsWith("}")) {
|
||||||
const pj = JSON.parse(p) as { v: number; nonce: string; ciphertext: string };
|
const pj = JSON.parse(p) as { v: number; nonce: string; ciphertext: string };
|
||||||
if (pj.v !== xchacha20EncryptionVersion) {
|
if (pj.v !== xchacha20EncryptionVersion) {
|
||||||
throw new Error("Encryption version unsupported")
|
throw new Error("Encryption version unsupported")
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
nonce: base64.decode(pj.nonce),
|
nonce: base64.decode(pj.nonce),
|
||||||
ciphertext: base64.decode(pj.ciphertext),
|
ciphertext: base64.decode(pj.ciphertext),
|
||||||
} as EncryptedData;
|
} as EncryptedData;
|
||||||
} else {
|
} else {
|
||||||
const buf = base64.decode(p);
|
const buf = base64.decode(p);
|
||||||
if (buf[0] !== xchacha20EncryptionVersion) {
|
if (buf[0] !== xchacha20EncryptionVersion) {
|
||||||
throw new Error("Encryption version unsupported")
|
throw new Error("Encryption version unsupported")
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
nonce: buf.subarray(1, 25),
|
nonce: buf.subarray(1, 25),
|
||||||
ciphertext: buf.subarray(25),
|
ciphertext: buf.subarray(25),
|
||||||
} as EncryptedData;
|
} as EncryptedData;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const encodePayload = (p: EncryptedData) => {
|
export const encodePayload = (p: EncryptedData) => {
|
||||||
return base64.encode(new Uint8Array([xchacha20EncryptionVersion, ...p.nonce, ...p.ciphertext]));
|
return base64.encode(new Uint8Array([xchacha20EncryptionVersion, ...p.nonce, ...p.ciphertext]));
|
||||||
}
|
}
|
||||||
|
|
@ -1,144 +1,144 @@
|
||||||
import { schnorr } from '@noble/curves/secp256k1'
|
import { schnorr } from '@noble/curves/secp256k1'
|
||||||
import { sha256 } from '@noble/hashes/sha256'
|
import { sha256 } from '@noble/hashes/sha256'
|
||||||
import { bytesToHex } from '@noble/hashes/utils'
|
import { bytesToHex } from '@noble/hashes/utils'
|
||||||
|
|
||||||
import { getPublicKey } from './keys.js'
|
import { getPublicKey } from './keys.js'
|
||||||
import { utf8Encoder } from './utils.js'
|
import { utf8Encoder } from './utils.js'
|
||||||
|
|
||||||
/** Designates a verified event signature. */
|
/** Designates a verified event signature. */
|
||||||
export const verifiedSymbol = Symbol('verified')
|
export const verifiedSymbol = Symbol('verified')
|
||||||
|
|
||||||
/** @deprecated Use numbers instead. */
|
/** @deprecated Use numbers instead. */
|
||||||
/* eslint-disable no-unused-vars */
|
/* eslint-disable no-unused-vars */
|
||||||
export enum Kind {
|
export enum Kind {
|
||||||
Metadata = 0,
|
Metadata = 0,
|
||||||
Text = 1,
|
Text = 1,
|
||||||
RecommendRelay = 2,
|
RecommendRelay = 2,
|
||||||
Contacts = 3,
|
Contacts = 3,
|
||||||
EncryptedDirectMessage = 4,
|
EncryptedDirectMessage = 4,
|
||||||
EventDeletion = 5,
|
EventDeletion = 5,
|
||||||
Repost = 6,
|
Repost = 6,
|
||||||
Reaction = 7,
|
Reaction = 7,
|
||||||
BadgeAward = 8,
|
BadgeAward = 8,
|
||||||
ChannelCreation = 40,
|
ChannelCreation = 40,
|
||||||
ChannelMetadata = 41,
|
ChannelMetadata = 41,
|
||||||
ChannelMessage = 42,
|
ChannelMessage = 42,
|
||||||
ChannelHideMessage = 43,
|
ChannelHideMessage = 43,
|
||||||
ChannelMuteUser = 44,
|
ChannelMuteUser = 44,
|
||||||
Blank = 255,
|
Blank = 255,
|
||||||
Report = 1984,
|
Report = 1984,
|
||||||
ZapRequest = 9734,
|
ZapRequest = 9734,
|
||||||
Zap = 9735,
|
Zap = 9735,
|
||||||
RelayList = 10002,
|
RelayList = 10002,
|
||||||
ClientAuth = 22242,
|
ClientAuth = 22242,
|
||||||
HttpAuth = 27235,
|
HttpAuth = 27235,
|
||||||
ProfileBadge = 30008,
|
ProfileBadge = 30008,
|
||||||
BadgeDefinition = 30009,
|
BadgeDefinition = 30009,
|
||||||
Article = 30023,
|
Article = 30023,
|
||||||
FileMetadata = 1063,
|
FileMetadata = 1063,
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Event<K extends number = number> {
|
export interface Event<K extends number = number> {
|
||||||
kind: K
|
kind: K
|
||||||
tags: string[][]
|
tags: string[][]
|
||||||
content: string
|
content: string
|
||||||
created_at: number
|
created_at: number
|
||||||
pubkey: string
|
pubkey: string
|
||||||
id: string
|
id: string
|
||||||
sig: string
|
sig: string
|
||||||
[verifiedSymbol]?: boolean
|
[verifiedSymbol]?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export type EventTemplate<K extends number = number> = Pick<Event<K>, 'kind' | 'tags' | 'content' | 'created_at'>
|
export type EventTemplate<K extends number = number> = Pick<Event<K>, 'kind' | 'tags' | 'content' | 'created_at'>
|
||||||
export type UnsignedEvent<K extends number = number> = Pick<
|
export type UnsignedEvent<K extends number = number> = Pick<
|
||||||
Event<K>,
|
Event<K>,
|
||||||
'kind' | 'tags' | 'content' | 'created_at' | 'pubkey'
|
'kind' | 'tags' | 'content' | 'created_at' | 'pubkey'
|
||||||
>
|
>
|
||||||
|
|
||||||
/** An event whose signature has been verified. */
|
/** An event whose signature has been verified. */
|
||||||
export interface VerifiedEvent<K extends number = number> extends Event<K> {
|
export interface VerifiedEvent<K extends number = number> extends Event<K> {
|
||||||
[verifiedSymbol]: true
|
[verifiedSymbol]: true
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getBlankEvent(): EventTemplate<Kind.Blank>
|
export function getBlankEvent(): EventTemplate<Kind.Blank>
|
||||||
export function getBlankEvent<K extends number>(kind: K): EventTemplate<K>
|
export function getBlankEvent<K extends number>(kind: K): EventTemplate<K>
|
||||||
export function getBlankEvent<K>(kind: K | Kind.Blank = Kind.Blank) {
|
export function getBlankEvent<K>(kind: K | Kind.Blank = Kind.Blank) {
|
||||||
return {
|
return {
|
||||||
kind,
|
kind,
|
||||||
content: '',
|
content: '',
|
||||||
tags: [],
|
tags: [],
|
||||||
created_at: 0,
|
created_at: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function finishEvent<K extends number = number>(t: EventTemplate<K>, privateKey: string): VerifiedEvent<K> {
|
export function finishEvent<K extends number = number>(t: EventTemplate<K>, privateKey: string): VerifiedEvent<K> {
|
||||||
const event = t as VerifiedEvent<K>
|
const event = t as VerifiedEvent<K>
|
||||||
event.pubkey = getPublicKey(privateKey)
|
event.pubkey = getPublicKey(privateKey)
|
||||||
event.id = getEventHash(event)
|
event.id = getEventHash(event)
|
||||||
event.sig = getSignature(event, privateKey)
|
event.sig = getSignature(event, privateKey)
|
||||||
event[verifiedSymbol] = true
|
event[verifiedSymbol] = true
|
||||||
return event
|
return event
|
||||||
}
|
}
|
||||||
|
|
||||||
export function serializeEvent(evt: UnsignedEvent<number>): string {
|
export function serializeEvent(evt: UnsignedEvent<number>): string {
|
||||||
if (!validateEvent(evt)) throw new Error("can't serialize event with wrong or missing properties")
|
if (!validateEvent(evt)) throw new Error("can't serialize event with wrong or missing properties")
|
||||||
|
|
||||||
return JSON.stringify([0, evt.pubkey, evt.created_at, evt.kind, evt.tags, evt.content])
|
return JSON.stringify([0, evt.pubkey, evt.created_at, evt.kind, evt.tags, evt.content])
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getEventHash(event: UnsignedEvent<number>): string {
|
export function getEventHash(event: UnsignedEvent<number>): string {
|
||||||
let eventHash = sha256(utf8Encoder.encode(serializeEvent(event)))
|
let eventHash = sha256(utf8Encoder.encode(serializeEvent(event)))
|
||||||
return bytesToHex(eventHash)
|
return bytesToHex(eventHash)
|
||||||
}
|
}
|
||||||
|
|
||||||
const isRecord = (obj: unknown): obj is Record<string, unknown> => obj instanceof Object
|
const isRecord = (obj: unknown): obj is Record<string, unknown> => obj instanceof Object
|
||||||
|
|
||||||
export function validateEvent<T>(event: T): event is T & UnsignedEvent<number> {
|
export function validateEvent<T>(event: T): event is T & UnsignedEvent<number> {
|
||||||
if (!isRecord(event)) return false
|
if (!isRecord(event)) return false
|
||||||
if (typeof event.kind !== 'number') return false
|
if (typeof event.kind !== 'number') return false
|
||||||
if (typeof event.content !== 'string') return false
|
if (typeof event.content !== 'string') return false
|
||||||
if (typeof event.created_at !== 'number') return false
|
if (typeof event.created_at !== 'number') return false
|
||||||
if (typeof event.pubkey !== 'string') return false
|
if (typeof event.pubkey !== 'string') return false
|
||||||
if (!event.pubkey.match(/^[a-f0-9]{64}$/)) return false
|
if (!event.pubkey.match(/^[a-f0-9]{64}$/)) return false
|
||||||
|
|
||||||
if (!Array.isArray(event.tags)) return false
|
if (!Array.isArray(event.tags)) return false
|
||||||
for (let i = 0; i < event.tags.length; i++) {
|
for (let i = 0; i < event.tags.length; i++) {
|
||||||
let tag = event.tags[i]
|
let tag = event.tags[i]
|
||||||
if (!Array.isArray(tag)) return false
|
if (!Array.isArray(tag)) return false
|
||||||
for (let j = 0; j < tag.length; j++) {
|
for (let j = 0; j < tag.length; j++) {
|
||||||
if (typeof tag[j] === 'object') return false
|
if (typeof tag[j] === 'object') return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Verify the event's signature. This function mutates the event with a `verified` symbol, making it idempotent. */
|
/** Verify the event's signature. This function mutates the event with a `verified` symbol, making it idempotent. */
|
||||||
export function verifySignature<K extends number>(event: Event<K>): event is VerifiedEvent<K> {
|
export function verifySignature<K extends number>(event: Event<K>): event is VerifiedEvent<K> {
|
||||||
//@ts-ignore
|
//@ts-ignore
|
||||||
if (typeof event[verifiedSymbol] === 'boolean') return event[verifiedSymbol]
|
if (typeof event[verifiedSymbol] === 'boolean') return event[verifiedSymbol]
|
||||||
|
|
||||||
const hash = getEventHash(event)
|
const hash = getEventHash(event)
|
||||||
if (hash !== event.id) {
|
if (hash !== event.id) {
|
||||||
return (event[verifiedSymbol] = false)
|
return (event[verifiedSymbol] = false)
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return (event[verifiedSymbol] = schnorr.verify(event.sig, hash, event.pubkey))
|
return (event[verifiedSymbol] = schnorr.verify(event.sig, hash, event.pubkey))
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
return (event[verifiedSymbol] = false)
|
return (event[verifiedSymbol] = false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @deprecated Use `getSignature` instead. */
|
/** @deprecated Use `getSignature` instead. */
|
||||||
export function signEvent(event: UnsignedEvent<number>, key: string): string {
|
export function signEvent(event: UnsignedEvent<number>, key: string): string {
|
||||||
console.warn(
|
console.warn(
|
||||||
'nostr-tools: `signEvent` is deprecated and will be removed or changed in the future. Please use `getSignature` instead.',
|
'nostr-tools: `signEvent` is deprecated and will be removed or changed in the future. Please use `getSignature` instead.',
|
||||||
)
|
)
|
||||||
return getSignature(event, key)
|
return getSignature(event, key)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Calculate the signature for an event. */
|
/** Calculate the signature for an event. */
|
||||||
export function getSignature(event: UnsignedEvent<number>, key: string): string {
|
export function getSignature(event: UnsignedEvent<number>, key: string): string {
|
||||||
return bytesToHex(schnorr.sign(getEventHash(event), key))
|
return bytesToHex(schnorr.sign(getEventHash(event), key))
|
||||||
}
|
}
|
||||||
|
|
@ -1,41 +1,41 @@
|
||||||
export function getHex64(json: string, field: string): string {
|
export function getHex64(json: string, field: string): string {
|
||||||
let len = field.length + 3
|
let len = field.length + 3
|
||||||
let idx = json.indexOf(`"${field}":`) + len
|
let idx = json.indexOf(`"${field}":`) + len
|
||||||
let s = json.slice(idx).indexOf(`"`) + idx + 1
|
let s = json.slice(idx).indexOf(`"`) + idx + 1
|
||||||
return json.slice(s, s + 64)
|
return json.slice(s, s + 64)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getInt(json: string, field: string): number {
|
export function getInt(json: string, field: string): number {
|
||||||
let len = field.length
|
let len = field.length
|
||||||
let idx = json.indexOf(`"${field}":`) + len + 3
|
let idx = json.indexOf(`"${field}":`) + len + 3
|
||||||
let sliced = json.slice(idx)
|
let sliced = json.slice(idx)
|
||||||
let end = Math.min(sliced.indexOf(','), sliced.indexOf('}'))
|
let end = Math.min(sliced.indexOf(','), sliced.indexOf('}'))
|
||||||
return parseInt(sliced.slice(0, end), 10)
|
return parseInt(sliced.slice(0, end), 10)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getSubscriptionId(json: string): string | null {
|
export function getSubscriptionId(json: string): string | null {
|
||||||
let idx = json.slice(0, 22).indexOf(`"EVENT"`)
|
let idx = json.slice(0, 22).indexOf(`"EVENT"`)
|
||||||
if (idx === -1) return null
|
if (idx === -1) return null
|
||||||
|
|
||||||
let pstart = json.slice(idx + 7 + 1).indexOf(`"`)
|
let pstart = json.slice(idx + 7 + 1).indexOf(`"`)
|
||||||
if (pstart === -1) return null
|
if (pstart === -1) return null
|
||||||
let start = idx + 7 + 1 + pstart
|
let start = idx + 7 + 1 + pstart
|
||||||
|
|
||||||
let pend = json.slice(start + 1, 80).indexOf(`"`)
|
let pend = json.slice(start + 1, 80).indexOf(`"`)
|
||||||
if (pend === -1) return null
|
if (pend === -1) return null
|
||||||
let end = start + 1 + pend
|
let end = start + 1 + pend
|
||||||
|
|
||||||
return json.slice(start + 1, end)
|
return json.slice(start + 1, end)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function matchEventId(json: string, id: string): boolean {
|
export function matchEventId(json: string, id: string): boolean {
|
||||||
return id === getHex64(json, 'id')
|
return id === getHex64(json, 'id')
|
||||||
}
|
}
|
||||||
|
|
||||||
export function matchEventPubkey(json: string, pubkey: string): boolean {
|
export function matchEventPubkey(json: string, pubkey: string): boolean {
|
||||||
return pubkey === getHex64(json, 'pubkey')
|
return pubkey === getHex64(json, 'pubkey')
|
||||||
}
|
}
|
||||||
|
|
||||||
export function matchEventKind(json: string, kind: number): boolean {
|
export function matchEventKind(json: string, kind: number): boolean {
|
||||||
return kind === getInt(json, 'kind')
|
return kind === getInt(json, 'kind')
|
||||||
}
|
}
|
||||||
|
|
@ -1,72 +1,72 @@
|
||||||
import { Event } from './event.js'
|
import { Event } from './event.js'
|
||||||
|
|
||||||
export type Filter<K extends number = number> = {
|
export type Filter<K extends number = number> = {
|
||||||
ids?: string[]
|
ids?: string[]
|
||||||
kinds?: K[]
|
kinds?: K[]
|
||||||
authors?: string[]
|
authors?: string[]
|
||||||
since?: number
|
since?: number
|
||||||
until?: number
|
until?: number
|
||||||
limit?: number
|
limit?: number
|
||||||
search?: string
|
search?: string
|
||||||
[key: `#${string}`]: string[] | undefined
|
[key: `#${string}`]: string[] | undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
export function matchFilter(filter: Filter<number>, event: Event<number>): boolean {
|
export function matchFilter(filter: Filter<number>, event: Event<number>): boolean {
|
||||||
if (filter.ids && filter.ids.indexOf(event.id) === -1) {
|
if (filter.ids && filter.ids.indexOf(event.id) === -1) {
|
||||||
if (!filter.ids.some(prefix => event.id.startsWith(prefix))) {
|
if (!filter.ids.some(prefix => event.id.startsWith(prefix))) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (filter.kinds && filter.kinds.indexOf(event.kind) === -1) return false
|
if (filter.kinds && filter.kinds.indexOf(event.kind) === -1) return false
|
||||||
if (filter.authors && filter.authors.indexOf(event.pubkey) === -1) {
|
if (filter.authors && filter.authors.indexOf(event.pubkey) === -1) {
|
||||||
if (!filter.authors.some(prefix => event.pubkey.startsWith(prefix))) {
|
if (!filter.authors.some(prefix => event.pubkey.startsWith(prefix))) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let f in filter) {
|
for (let f in filter) {
|
||||||
if (f[0] === '#') {
|
if (f[0] === '#') {
|
||||||
let tagName = f.slice(1)
|
let tagName = f.slice(1)
|
||||||
let values = filter[`#${tagName}`]
|
let values = filter[`#${tagName}`]
|
||||||
if (values && !event.tags.find(([t, v]) => t === f.slice(1) && values!.indexOf(v) !== -1)) return false
|
if (values && !event.tags.find(([t, v]) => t === f.slice(1) && values!.indexOf(v) !== -1)) return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (filter.since && event.created_at < filter.since) return false
|
if (filter.since && event.created_at < filter.since) return false
|
||||||
if (filter.until && event.created_at > filter.until) return false
|
if (filter.until && event.created_at > filter.until) return false
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
export function matchFilters(filters: Filter<number>[], event: Event<number>): boolean {
|
export function matchFilters(filters: Filter<number>[], event: Event<number>): boolean {
|
||||||
for (let i = 0; i < filters.length; i++) {
|
for (let i = 0; i < filters.length; i++) {
|
||||||
if (matchFilter(filters[i], event)) return true
|
if (matchFilter(filters[i], event)) return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
export function mergeFilters(...filters: Filter<number>[]): Filter<number> {
|
export function mergeFilters(...filters: Filter<number>[]): Filter<number> {
|
||||||
let result: Filter<number> = {}
|
let result: Filter<number> = {}
|
||||||
for (let i = 0; i < filters.length; i++) {
|
for (let i = 0; i < filters.length; i++) {
|
||||||
let filter = filters[i]
|
let filter = filters[i]
|
||||||
Object.entries(filter).forEach(([property, values]) => {
|
Object.entries(filter).forEach(([property, values]) => {
|
||||||
if (property === 'kinds' || property === 'ids' || property === 'authors' || property[0] === '#') {
|
if (property === 'kinds' || property === 'ids' || property === 'authors' || property[0] === '#') {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
result[property] = result[property] || []
|
result[property] = result[property] || []
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
for (let v = 0; v < values.length; v++) {
|
for (let v = 0; v < values.length; v++) {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
let value = values[v]
|
let value = values[v]
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
if (!result[property].includes(value)) result[property].push(value)
|
if (!result[property].includes(value)) result[property].push(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
if (filter.limit && (!result.limit || filter.limit > result.limit)) result.limit = filter.limit
|
if (filter.limit && (!result.limit || filter.limit > result.limit)) result.limit = filter.limit
|
||||||
if (filter.until && (!result.until || filter.until > result.until)) result.until = filter.until
|
if (filter.until && (!result.until || filter.until > result.until)) result.until = filter.until
|
||||||
if (filter.since && (!result.since || filter.since < result.since)) result.since = filter.since
|
if (filter.since && (!result.since || filter.since < result.since)) result.since = filter.since
|
||||||
}
|
}
|
||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
export * from './event.js'
|
export * from './event.js'
|
||||||
export * from './fakejson.js'
|
export * from './fakejson.js'
|
||||||
export * from './filter.js'
|
export * from './filter.js'
|
||||||
export * from './keys.js'
|
export * from './keys.js'
|
||||||
export * from './pool.js'
|
export * from './pool.js'
|
||||||
export * from './relay.js'
|
export * from './relay.js'
|
||||||
export * from './utils.js'
|
export * from './utils.js'
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
import { schnorr } from '@noble/curves/secp256k1'
|
import { schnorr } from '@noble/curves/secp256k1'
|
||||||
import { bytesToHex } from '@noble/hashes/utils'
|
import { bytesToHex } from '@noble/hashes/utils'
|
||||||
|
|
||||||
export function generatePrivateKey(): string {
|
export function generatePrivateKey(): string {
|
||||||
return bytesToHex(schnorr.utils.randomPrivateKey())
|
return bytesToHex(schnorr.utils.randomPrivateKey())
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getPublicKey(privateKey: string): string {
|
export function getPublicKey(privateKey: string): string {
|
||||||
return bytesToHex(schnorr.getPublicKey(privateKey))
|
return bytesToHex(schnorr.getPublicKey(privateKey))
|
||||||
}
|
}
|
||||||
|
|
@ -1,249 +1,249 @@
|
||||||
import { relayInit, eventsGenerator, type Relay, type Sub, type SubscriptionOptions } from './relay.js'
|
import { relayInit, eventsGenerator, type Relay, type Sub, type SubscriptionOptions } from './relay.js'
|
||||||
import { normalizeURL } from './utils.js'
|
import { normalizeURL } from './utils.js'
|
||||||
|
|
||||||
import type { Event } from './event.js'
|
import type { Event } from './event.js'
|
||||||
import { matchFilters, type Filter } from './filter.js'
|
import { matchFilters, type Filter } from './filter.js'
|
||||||
|
|
||||||
type BatchedRequest = {
|
type BatchedRequest = {
|
||||||
filters: Filter<any>[]
|
filters: Filter<any>[]
|
||||||
relays: string[]
|
relays: string[]
|
||||||
resolve: (events: Event<any>[]) => void
|
resolve: (events: Event<any>[]) => void
|
||||||
events: Event<any>[]
|
events: Event<any>[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export class SimplePool {
|
export class SimplePool {
|
||||||
private _conn: { [url: string]: Relay }
|
private _conn: { [url: string]: Relay }
|
||||||
private _seenOn: { [id: string]: Set<string> } = {} // a map of all events we've seen in each relay
|
private _seenOn: { [id: string]: Set<string> } = {} // a map of all events we've seen in each relay
|
||||||
private batchedByKey: { [batchKey: string]: BatchedRequest[] } = {}
|
private batchedByKey: { [batchKey: string]: BatchedRequest[] } = {}
|
||||||
|
|
||||||
private eoseSubTimeout: number
|
private eoseSubTimeout: number
|
||||||
private getTimeout: number
|
private getTimeout: number
|
||||||
private seenOnEnabled: boolean = true
|
private seenOnEnabled: boolean = true
|
||||||
private batchInterval: number = 100
|
private batchInterval: number = 100
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
options: {
|
options: {
|
||||||
eoseSubTimeout?: number
|
eoseSubTimeout?: number
|
||||||
getTimeout?: number
|
getTimeout?: number
|
||||||
seenOnEnabled?: boolean
|
seenOnEnabled?: boolean
|
||||||
batchInterval?: number
|
batchInterval?: number
|
||||||
} = {},
|
} = {},
|
||||||
) {
|
) {
|
||||||
this._conn = {}
|
this._conn = {}
|
||||||
this.eoseSubTimeout = options.eoseSubTimeout || 3400
|
this.eoseSubTimeout = options.eoseSubTimeout || 3400
|
||||||
this.getTimeout = options.getTimeout || 3400
|
this.getTimeout = options.getTimeout || 3400
|
||||||
this.seenOnEnabled = options.seenOnEnabled !== false
|
this.seenOnEnabled = options.seenOnEnabled !== false
|
||||||
this.batchInterval = options.batchInterval || 100
|
this.batchInterval = options.batchInterval || 100
|
||||||
}
|
}
|
||||||
|
|
||||||
close(relays: string[]): void {
|
close(relays: string[]): void {
|
||||||
relays.forEach(url => {
|
relays.forEach(url => {
|
||||||
let relay = this._conn[normalizeURL(url)]
|
let relay = this._conn[normalizeURL(url)]
|
||||||
if (relay) relay.close()
|
if (relay) relay.close()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async ensureRelay(url: string): Promise<Relay> {
|
async ensureRelay(url: string): Promise<Relay> {
|
||||||
const nm = normalizeURL(url)
|
const nm = normalizeURL(url)
|
||||||
|
|
||||||
if (!this._conn[nm]) {
|
if (!this._conn[nm]) {
|
||||||
this._conn[nm] = relayInit(nm, {
|
this._conn[nm] = relayInit(nm, {
|
||||||
getTimeout: this.getTimeout * 0.9,
|
getTimeout: this.getTimeout * 0.9,
|
||||||
listTimeout: this.getTimeout * 0.9,
|
listTimeout: this.getTimeout * 0.9,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const relay = this._conn[nm]
|
const relay = this._conn[nm]
|
||||||
await relay.connect()
|
await relay.connect()
|
||||||
return relay
|
return relay
|
||||||
}
|
}
|
||||||
|
|
||||||
sub<K extends number = number>(relays: string[], filters: Filter<K>[], opts?: SubscriptionOptions): Sub<K> {
|
sub<K extends number = number>(relays: string[], filters: Filter<K>[], opts?: SubscriptionOptions): Sub<K> {
|
||||||
let _knownIds: Set<string> = new Set()
|
let _knownIds: Set<string> = new Set()
|
||||||
let modifiedOpts = { ...(opts || {}) }
|
let modifiedOpts = { ...(opts || {}) }
|
||||||
modifiedOpts.alreadyHaveEvent = (id, url) => {
|
modifiedOpts.alreadyHaveEvent = (id, url) => {
|
||||||
if (opts?.alreadyHaveEvent?.(id, url)) {
|
if (opts?.alreadyHaveEvent?.(id, url)) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
if (this.seenOnEnabled) {
|
if (this.seenOnEnabled) {
|
||||||
let set = this._seenOn[id] || new Set()
|
let set = this._seenOn[id] || new Set()
|
||||||
set.add(url)
|
set.add(url)
|
||||||
this._seenOn[id] = set
|
this._seenOn[id] = set
|
||||||
}
|
}
|
||||||
return _knownIds.has(id)
|
return _knownIds.has(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
let subs: Sub[] = []
|
let subs: Sub[] = []
|
||||||
let eventListeners: Set<any> = new Set()
|
let eventListeners: Set<any> = new Set()
|
||||||
let eoseListeners: Set<() => void> = new Set()
|
let eoseListeners: Set<() => void> = new Set()
|
||||||
let eosesMissing = relays.length
|
let eosesMissing = relays.length
|
||||||
|
|
||||||
let eoseSent = false
|
let eoseSent = false
|
||||||
let eoseTimeout = setTimeout(
|
let eoseTimeout = setTimeout(
|
||||||
() => {
|
() => {
|
||||||
eoseSent = true
|
eoseSent = true
|
||||||
for (let cb of eoseListeners.values()) cb()
|
for (let cb of eoseListeners.values()) cb()
|
||||||
},
|
},
|
||||||
opts?.eoseSubTimeout || this.eoseSubTimeout,
|
opts?.eoseSubTimeout || this.eoseSubTimeout,
|
||||||
)
|
)
|
||||||
|
|
||||||
relays
|
relays
|
||||||
.filter((r, i, a) => a.indexOf(r) === i)
|
.filter((r, i, a) => a.indexOf(r) === i)
|
||||||
.forEach(async relay => {
|
.forEach(async relay => {
|
||||||
let r
|
let r
|
||||||
try {
|
try {
|
||||||
r = await this.ensureRelay(relay)
|
r = await this.ensureRelay(relay)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
handleEose()
|
handleEose()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (!r) return
|
if (!r) return
|
||||||
let s = r.sub(filters, modifiedOpts)
|
let s = r.sub(filters, modifiedOpts)
|
||||||
s.on('event', event => {
|
s.on('event', event => {
|
||||||
_knownIds.add(event.id as string)
|
_knownIds.add(event.id as string)
|
||||||
for (let cb of eventListeners.values()) cb(event)
|
for (let cb of eventListeners.values()) cb(event)
|
||||||
})
|
})
|
||||||
s.on('eose', () => {
|
s.on('eose', () => {
|
||||||
if (eoseSent) return
|
if (eoseSent) return
|
||||||
handleEose()
|
handleEose()
|
||||||
})
|
})
|
||||||
subs.push(s)
|
subs.push(s)
|
||||||
|
|
||||||
function handleEose() {
|
function handleEose() {
|
||||||
eosesMissing--
|
eosesMissing--
|
||||||
if (eosesMissing === 0) {
|
if (eosesMissing === 0) {
|
||||||
clearTimeout(eoseTimeout)
|
clearTimeout(eoseTimeout)
|
||||||
for (let cb of eoseListeners.values()) cb()
|
for (let cb of eoseListeners.values()) cb()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
let greaterSub: Sub<K> = {
|
let greaterSub: Sub<K> = {
|
||||||
sub(filters, opts) {
|
sub(filters, opts) {
|
||||||
subs.forEach(sub => sub.sub(filters, opts))
|
subs.forEach(sub => sub.sub(filters, opts))
|
||||||
return greaterSub as any
|
return greaterSub as any
|
||||||
},
|
},
|
||||||
unsub() {
|
unsub() {
|
||||||
subs.forEach(sub => sub.unsub())
|
subs.forEach(sub => sub.unsub())
|
||||||
},
|
},
|
||||||
on(type, cb) {
|
on(type, cb) {
|
||||||
if (type === 'event') {
|
if (type === 'event') {
|
||||||
eventListeners.add(cb)
|
eventListeners.add(cb)
|
||||||
} else if (type === 'eose') {
|
} else if (type === 'eose') {
|
||||||
eoseListeners.add(cb as () => void | Promise<void>)
|
eoseListeners.add(cb as () => void | Promise<void>)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
off(type, cb) {
|
off(type, cb) {
|
||||||
if (type === 'event') {
|
if (type === 'event') {
|
||||||
eventListeners.delete(cb)
|
eventListeners.delete(cb)
|
||||||
} else if (type === 'eose') eoseListeners.delete(cb as () => void | Promise<void>)
|
} else if (type === 'eose') eoseListeners.delete(cb as () => void | Promise<void>)
|
||||||
},
|
},
|
||||||
get events() {
|
get events() {
|
||||||
return eventsGenerator(greaterSub)
|
return eventsGenerator(greaterSub)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
return greaterSub
|
return greaterSub
|
||||||
}
|
}
|
||||||
|
|
||||||
get<K extends number = number>(
|
get<K extends number = number>(
|
||||||
relays: string[],
|
relays: string[],
|
||||||
filter: Filter<K>,
|
filter: Filter<K>,
|
||||||
opts?: SubscriptionOptions,
|
opts?: SubscriptionOptions,
|
||||||
): Promise<Event<K> | null> {
|
): Promise<Event<K> | null> {
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
let sub = this.sub(relays, [filter], opts)
|
let sub = this.sub(relays, [filter], opts)
|
||||||
let timeout = setTimeout(() => {
|
let timeout = setTimeout(() => {
|
||||||
sub.unsub()
|
sub.unsub()
|
||||||
resolve(null)
|
resolve(null)
|
||||||
}, this.getTimeout)
|
}, this.getTimeout)
|
||||||
sub.on('event', event => {
|
sub.on('event', event => {
|
||||||
resolve(event)
|
resolve(event)
|
||||||
clearTimeout(timeout)
|
clearTimeout(timeout)
|
||||||
sub.unsub()
|
sub.unsub()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
list<K extends number = number>(
|
list<K extends number = number>(
|
||||||
relays: string[],
|
relays: string[],
|
||||||
filters: Filter<K>[],
|
filters: Filter<K>[],
|
||||||
opts?: SubscriptionOptions,
|
opts?: SubscriptionOptions,
|
||||||
): Promise<Event<K>[]> {
|
): Promise<Event<K>[]> {
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
let events: Event<K>[] = []
|
let events: Event<K>[] = []
|
||||||
let sub = this.sub(relays, filters, opts)
|
let sub = this.sub(relays, filters, opts)
|
||||||
|
|
||||||
sub.on('event', event => {
|
sub.on('event', event => {
|
||||||
events.push(event)
|
events.push(event)
|
||||||
})
|
})
|
||||||
|
|
||||||
// we can rely on an eose being emitted here because pool.sub() will fake one
|
// we can rely on an eose being emitted here because pool.sub() will fake one
|
||||||
sub.on('eose', () => {
|
sub.on('eose', () => {
|
||||||
sub.unsub()
|
sub.unsub()
|
||||||
resolve(events)
|
resolve(events)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
batchedList<K extends number = number>(
|
batchedList<K extends number = number>(
|
||||||
batchKey: string,
|
batchKey: string,
|
||||||
relays: string[],
|
relays: string[],
|
||||||
filters: Filter<K>[],
|
filters: Filter<K>[],
|
||||||
): Promise<Event<K>[]> {
|
): Promise<Event<K>[]> {
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
if (!this.batchedByKey[batchKey]) {
|
if (!this.batchedByKey[batchKey]) {
|
||||||
this.batchedByKey[batchKey] = [
|
this.batchedByKey[batchKey] = [
|
||||||
{
|
{
|
||||||
filters,
|
filters,
|
||||||
relays,
|
relays,
|
||||||
resolve,
|
resolve,
|
||||||
events: [],
|
events: [],
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
Object.keys(this.batchedByKey).forEach(async batchKey => {
|
Object.keys(this.batchedByKey).forEach(async batchKey => {
|
||||||
const batchedRequests = this.batchedByKey[batchKey]
|
const batchedRequests = this.batchedByKey[batchKey]
|
||||||
|
|
||||||
const filters = [] as Filter[]
|
const filters = [] as Filter[]
|
||||||
const relays = [] as string[]
|
const relays = [] as string[]
|
||||||
batchedRequests.forEach(br => {
|
batchedRequests.forEach(br => {
|
||||||
filters.push(...br.filters)
|
filters.push(...br.filters)
|
||||||
relays.push(...br.relays)
|
relays.push(...br.relays)
|
||||||
})
|
})
|
||||||
|
|
||||||
const sub = this.sub(relays, filters)
|
const sub = this.sub(relays, filters)
|
||||||
sub.on('event', event => {
|
sub.on('event', event => {
|
||||||
batchedRequests.forEach(br => matchFilters(br.filters, event) && br.events.push(event))
|
batchedRequests.forEach(br => matchFilters(br.filters, event) && br.events.push(event))
|
||||||
})
|
})
|
||||||
sub.on('eose', () => {
|
sub.on('eose', () => {
|
||||||
sub.unsub()
|
sub.unsub()
|
||||||
batchedRequests.forEach(br => br.resolve(br.events))
|
batchedRequests.forEach(br => br.resolve(br.events))
|
||||||
})
|
})
|
||||||
|
|
||||||
delete this.batchedByKey[batchKey]
|
delete this.batchedByKey[batchKey]
|
||||||
})
|
})
|
||||||
}, this.batchInterval)
|
}, this.batchInterval)
|
||||||
} else {
|
} else {
|
||||||
this.batchedByKey[batchKey].push({
|
this.batchedByKey[batchKey].push({
|
||||||
filters,
|
filters,
|
||||||
relays,
|
relays,
|
||||||
resolve,
|
resolve,
|
||||||
events: [],
|
events: [],
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
publish(relays: string[], event: Event<number>): Promise<void>[] {
|
publish(relays: string[], event: Event<number>): Promise<void>[] {
|
||||||
return relays.map(async relay => {
|
return relays.map(async relay => {
|
||||||
let r = await this.ensureRelay(relay)
|
let r = await this.ensureRelay(relay)
|
||||||
return r.publish(event)
|
return r.publish(event)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
seenOn(id: string): string[] {
|
seenOn(id: string): string[] {
|
||||||
return Array.from(this._seenOn[id]?.values?.() || [])
|
return Array.from(this._seenOn[id]?.values?.() || [])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,402 +1,402 @@
|
||||||
/* global WebSocket */
|
/* global WebSocket */
|
||||||
import "websocket-polyfill"
|
import "websocket-polyfill"
|
||||||
import { verifySignature, validateEvent, type Event } from './event.js'
|
import { verifySignature, validateEvent, type Event } from './event.js'
|
||||||
import { matchFilters, type Filter } from './filter.js'
|
import { matchFilters, type Filter } from './filter.js'
|
||||||
import { getHex64, getSubscriptionId } from './fakejson.js'
|
import { getHex64, getSubscriptionId } from './fakejson.js'
|
||||||
import { MessageQueue } from './utils.js'
|
import { MessageQueue } from './utils.js'
|
||||||
|
|
||||||
type RelayEvent = {
|
type RelayEvent = {
|
||||||
connect: () => void | Promise<void>
|
connect: () => void | Promise<void>
|
||||||
disconnect: () => void | Promise<void>
|
disconnect: () => void | Promise<void>
|
||||||
error: () => void | Promise<void>
|
error: () => void | Promise<void>
|
||||||
notice: (msg: string) => void | Promise<void>
|
notice: (msg: string) => void | Promise<void>
|
||||||
auth: (challenge: string) => void | Promise<void>
|
auth: (challenge: string) => void | Promise<void>
|
||||||
}
|
}
|
||||||
export type CountPayload = {
|
export type CountPayload = {
|
||||||
count: number
|
count: number
|
||||||
}
|
}
|
||||||
export type SubEvent<K extends number> = {
|
export type SubEvent<K extends number> = {
|
||||||
event: (event: Event<K>) => void | Promise<void>
|
event: (event: Event<K>) => void | Promise<void>
|
||||||
count: (payload: CountPayload) => void | Promise<void>
|
count: (payload: CountPayload) => void | Promise<void>
|
||||||
eose: () => void | Promise<void>
|
eose: () => void | Promise<void>
|
||||||
}
|
}
|
||||||
export type Relay = {
|
export type Relay = {
|
||||||
url: string
|
url: string
|
||||||
status: number
|
status: number
|
||||||
connect: () => Promise<void>
|
connect: () => Promise<void>
|
||||||
close: () => void
|
close: () => void
|
||||||
sub: <K extends number = number>(filters: Filter<K>[], opts?: SubscriptionOptions) => Sub<K>
|
sub: <K extends number = number>(filters: Filter<K>[], opts?: SubscriptionOptions) => Sub<K>
|
||||||
list: <K extends number = number>(filters: Filter<K>[], opts?: SubscriptionOptions) => Promise<Event<K>[]>
|
list: <K extends number = number>(filters: Filter<K>[], opts?: SubscriptionOptions) => Promise<Event<K>[]>
|
||||||
get: <K extends number = number>(filter: Filter<K>, opts?: SubscriptionOptions) => Promise<Event<K> | null>
|
get: <K extends number = number>(filter: Filter<K>, opts?: SubscriptionOptions) => Promise<Event<K> | null>
|
||||||
count: (filters: Filter[], opts?: SubscriptionOptions) => Promise<CountPayload | null>
|
count: (filters: Filter[], opts?: SubscriptionOptions) => Promise<CountPayload | null>
|
||||||
publish: (event: Event<number>) => Promise<void>
|
publish: (event: Event<number>) => Promise<void>
|
||||||
auth: (event: Event<number>) => Promise<void>
|
auth: (event: Event<number>) => Promise<void>
|
||||||
off: <T extends keyof RelayEvent, U extends RelayEvent[T]>(event: T, listener: U) => void
|
off: <T extends keyof RelayEvent, U extends RelayEvent[T]>(event: T, listener: U) => void
|
||||||
on: <T extends keyof RelayEvent, U extends RelayEvent[T]>(event: T, listener: U) => void
|
on: <T extends keyof RelayEvent, U extends RelayEvent[T]>(event: T, listener: U) => void
|
||||||
}
|
}
|
||||||
export type Sub<K extends number = number> = {
|
export type Sub<K extends number = number> = {
|
||||||
sub: <K extends number = number>(filters: Filter<K>[], opts: SubscriptionOptions) => Sub<K>
|
sub: <K extends number = number>(filters: Filter<K>[], opts: SubscriptionOptions) => Sub<K>
|
||||||
unsub: () => void
|
unsub: () => void
|
||||||
on: <T extends keyof SubEvent<K>, U extends SubEvent<K>[T]>(event: T, listener: U) => void
|
on: <T extends keyof SubEvent<K>, U extends SubEvent<K>[T]>(event: T, listener: U) => void
|
||||||
off: <T extends keyof SubEvent<K>, U extends SubEvent<K>[T]>(event: T, listener: U) => void
|
off: <T extends keyof SubEvent<K>, U extends SubEvent<K>[T]>(event: T, listener: U) => void
|
||||||
events: AsyncGenerator<Event<K>, void, unknown>
|
events: AsyncGenerator<Event<K>, void, unknown>
|
||||||
}
|
}
|
||||||
|
|
||||||
export type SubscriptionOptions = {
|
export type SubscriptionOptions = {
|
||||||
id?: string
|
id?: string
|
||||||
verb?: 'REQ' | 'COUNT'
|
verb?: 'REQ' | 'COUNT'
|
||||||
skipVerification?: boolean
|
skipVerification?: boolean
|
||||||
alreadyHaveEvent?: null | ((id: string, relay: string) => boolean)
|
alreadyHaveEvent?: null | ((id: string, relay: string) => boolean)
|
||||||
eoseSubTimeout?: number
|
eoseSubTimeout?: number
|
||||||
}
|
}
|
||||||
|
|
||||||
const newListeners = (): { [TK in keyof RelayEvent]: RelayEvent[TK][] } => ({
|
const newListeners = (): { [TK in keyof RelayEvent]: RelayEvent[TK][] } => ({
|
||||||
connect: [],
|
connect: [],
|
||||||
disconnect: [],
|
disconnect: [],
|
||||||
error: [],
|
error: [],
|
||||||
notice: [],
|
notice: [],
|
||||||
auth: [],
|
auth: [],
|
||||||
})
|
})
|
||||||
|
|
||||||
export function relayInit(
|
export function relayInit(
|
||||||
url: string,
|
url: string,
|
||||||
options: {
|
options: {
|
||||||
getTimeout?: number
|
getTimeout?: number
|
||||||
listTimeout?: number
|
listTimeout?: number
|
||||||
countTimeout?: number
|
countTimeout?: number
|
||||||
} = {},
|
} = {},
|
||||||
): Relay {
|
): Relay {
|
||||||
let { listTimeout = 3000, getTimeout = 3000, countTimeout = 3000 } = options
|
let { listTimeout = 3000, getTimeout = 3000, countTimeout = 3000 } = options
|
||||||
|
|
||||||
var ws: WebSocket
|
var ws: WebSocket
|
||||||
var openSubs: { [id: string]: { filters: Filter[] } & SubscriptionOptions } = {}
|
var openSubs: { [id: string]: { filters: Filter[] } & SubscriptionOptions } = {}
|
||||||
var listeners = newListeners()
|
var listeners = newListeners()
|
||||||
var subListeners: {
|
var subListeners: {
|
||||||
[subid: string]: { [TK in keyof SubEvent<any>]: SubEvent<any>[TK][] }
|
[subid: string]: { [TK in keyof SubEvent<any>]: SubEvent<any>[TK][] }
|
||||||
} = {}
|
} = {}
|
||||||
var pubListeners: {
|
var pubListeners: {
|
||||||
[eventid: string]: {
|
[eventid: string]: {
|
||||||
resolve: (_: unknown) => void
|
resolve: (_: unknown) => void
|
||||||
reject: (err: Error) => void
|
reject: (err: Error) => void
|
||||||
}
|
}
|
||||||
} = {}
|
} = {}
|
||||||
|
|
||||||
var connectionPromise: Promise<void> | undefined
|
var connectionPromise: Promise<void> | undefined
|
||||||
async function connectRelay(): Promise<void> {
|
async function connectRelay(): Promise<void> {
|
||||||
if (connectionPromise) return connectionPromise
|
if (connectionPromise) return connectionPromise
|
||||||
connectionPromise = new Promise((resolve, reject) => {
|
connectionPromise = new Promise((resolve, reject) => {
|
||||||
try {
|
try {
|
||||||
ws = new WebSocket(url)
|
ws = new WebSocket(url)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
reject(err)
|
reject(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
ws.onopen = () => {
|
ws.onopen = () => {
|
||||||
listeners.connect.forEach(cb => cb())
|
listeners.connect.forEach(cb => cb())
|
||||||
resolve()
|
resolve()
|
||||||
}
|
}
|
||||||
ws.onerror = () => {
|
ws.onerror = () => {
|
||||||
connectionPromise = undefined
|
connectionPromise = undefined
|
||||||
listeners.error.forEach(cb => cb())
|
listeners.error.forEach(cb => cb())
|
||||||
reject()
|
reject()
|
||||||
}
|
}
|
||||||
ws.onclose = async () => {
|
ws.onclose = async () => {
|
||||||
connectionPromise = undefined
|
connectionPromise = undefined
|
||||||
listeners.disconnect.forEach(cb => cb())
|
listeners.disconnect.forEach(cb => cb())
|
||||||
}
|
}
|
||||||
|
|
||||||
let incomingMessageQueue: MessageQueue = new MessageQueue()
|
let incomingMessageQueue: MessageQueue = new MessageQueue()
|
||||||
let handleNextInterval: any
|
let handleNextInterval: any
|
||||||
|
|
||||||
ws.onmessage = e => {
|
ws.onmessage = e => {
|
||||||
incomingMessageQueue.enqueue(e.data)
|
incomingMessageQueue.enqueue(e.data)
|
||||||
if (!handleNextInterval) {
|
if (!handleNextInterval) {
|
||||||
handleNextInterval = setInterval(handleNext, 0)
|
handleNextInterval = setInterval(handleNext, 0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleNext() {
|
function handleNext() {
|
||||||
if (incomingMessageQueue.size === 0) {
|
if (incomingMessageQueue.size === 0) {
|
||||||
clearInterval(handleNextInterval)
|
clearInterval(handleNextInterval)
|
||||||
handleNextInterval = null
|
handleNextInterval = null
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var json = incomingMessageQueue.dequeue()
|
var json = incomingMessageQueue.dequeue()
|
||||||
if (!json) return
|
if (!json) return
|
||||||
|
|
||||||
let subid = getSubscriptionId(json)
|
let subid = getSubscriptionId(json)
|
||||||
if (subid) {
|
if (subid) {
|
||||||
let so = openSubs[subid]
|
let so = openSubs[subid]
|
||||||
if (so && so.alreadyHaveEvent && so.alreadyHaveEvent(getHex64(json, 'id'), url)) {
|
if (so && so.alreadyHaveEvent && so.alreadyHaveEvent(getHex64(json, 'id'), url)) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
let data = JSON.parse(json)
|
let data = JSON.parse(json)
|
||||||
|
|
||||||
// we won't do any checks against the data since all failures (i.e. invalid messages from relays)
|
// we won't do any checks against the data since all failures (i.e. invalid messages from relays)
|
||||||
// will naturally be caught by the encompassing try..catch block
|
// will naturally be caught by the encompassing try..catch block
|
||||||
|
|
||||||
switch (data[0]) {
|
switch (data[0]) {
|
||||||
case 'EVENT': {
|
case 'EVENT': {
|
||||||
let id = data[1]
|
let id = data[1]
|
||||||
let event = data[2]
|
let event = data[2]
|
||||||
if (
|
if (
|
||||||
validateEvent(event) &&
|
validateEvent(event) &&
|
||||||
openSubs[id] &&
|
openSubs[id] &&
|
||||||
(openSubs[id].skipVerification || verifySignature(event)) &&
|
(openSubs[id].skipVerification || verifySignature(event)) &&
|
||||||
matchFilters(openSubs[id].filters, event)
|
matchFilters(openSubs[id].filters, event)
|
||||||
) {
|
) {
|
||||||
openSubs[id]
|
openSubs[id]
|
||||||
; (subListeners[id]?.event || []).forEach(cb => cb(event))
|
; (subListeners[id]?.event || []).forEach(cb => cb(event))
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
case 'COUNT':
|
case 'COUNT':
|
||||||
let id = data[1]
|
let id = data[1]
|
||||||
let payload = data[2]
|
let payload = data[2]
|
||||||
if (openSubs[id]) {
|
if (openSubs[id]) {
|
||||||
; (subListeners[id]?.count || []).forEach(cb => cb(payload))
|
; (subListeners[id]?.count || []).forEach(cb => cb(payload))
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
case 'EOSE': {
|
case 'EOSE': {
|
||||||
let id = data[1]
|
let id = data[1]
|
||||||
if (id in subListeners) {
|
if (id in subListeners) {
|
||||||
subListeners[id].eose.forEach(cb => cb())
|
subListeners[id].eose.forEach(cb => cb())
|
||||||
subListeners[id].eose = [] // 'eose' only happens once per sub, so stop listeners here
|
subListeners[id].eose = [] // 'eose' only happens once per sub, so stop listeners here
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
case 'OK': {
|
case 'OK': {
|
||||||
let id: string = data[1]
|
let id: string = data[1]
|
||||||
let ok: boolean = data[2]
|
let ok: boolean = data[2]
|
||||||
let reason: string = data[3] || ''
|
let reason: string = data[3] || ''
|
||||||
if (id in pubListeners) {
|
if (id in pubListeners) {
|
||||||
let { resolve, reject } = pubListeners[id]
|
let { resolve, reject } = pubListeners[id]
|
||||||
if (ok) resolve(null)
|
if (ok) resolve(null)
|
||||||
else reject(new Error(reason))
|
else reject(new Error(reason))
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
case 'NOTICE':
|
case 'NOTICE':
|
||||||
let notice = data[1]
|
let notice = data[1]
|
||||||
listeners.notice.forEach(cb => cb(notice))
|
listeners.notice.forEach(cb => cb(notice))
|
||||||
return
|
return
|
||||||
case 'AUTH': {
|
case 'AUTH': {
|
||||||
let challenge = data[1]
|
let challenge = data[1]
|
||||||
listeners.auth?.forEach(cb => cb(challenge))
|
listeners.auth?.forEach(cb => cb(challenge))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
return connectionPromise
|
return connectionPromise
|
||||||
}
|
}
|
||||||
|
|
||||||
function connected() {
|
function connected() {
|
||||||
return ws?.readyState === 1
|
return ws?.readyState === 1
|
||||||
}
|
}
|
||||||
|
|
||||||
async function connect(): Promise<void> {
|
async function connect(): Promise<void> {
|
||||||
if (connected()) return // ws already open
|
if (connected()) return // ws already open
|
||||||
await connectRelay()
|
await connectRelay()
|
||||||
}
|
}
|
||||||
|
|
||||||
async function trySend(params: [string, ...any]) {
|
async function trySend(params: [string, ...any]) {
|
||||||
let msg = JSON.stringify(params)
|
let msg = JSON.stringify(params)
|
||||||
if (!connected()) {
|
if (!connected()) {
|
||||||
await new Promise(resolve => setTimeout(resolve, 1000))
|
await new Promise(resolve => setTimeout(resolve, 1000))
|
||||||
if (!connected()) {
|
if (!connected()) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
ws.send(msg)
|
ws.send(msg)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(err)
|
console.log(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const sub = <K extends number = number>(
|
const sub = <K extends number = number>(
|
||||||
filters: Filter<K>[],
|
filters: Filter<K>[],
|
||||||
{
|
{
|
||||||
verb = 'REQ',
|
verb = 'REQ',
|
||||||
skipVerification = false,
|
skipVerification = false,
|
||||||
alreadyHaveEvent = null,
|
alreadyHaveEvent = null,
|
||||||
id = Math.random().toString().slice(2),
|
id = Math.random().toString().slice(2),
|
||||||
}: SubscriptionOptions = {},
|
}: SubscriptionOptions = {},
|
||||||
): Sub<K> => {
|
): Sub<K> => {
|
||||||
let subid = id
|
let subid = id
|
||||||
|
|
||||||
openSubs[subid] = {
|
openSubs[subid] = {
|
||||||
id: subid,
|
id: subid,
|
||||||
filters,
|
filters,
|
||||||
skipVerification,
|
skipVerification,
|
||||||
alreadyHaveEvent,
|
alreadyHaveEvent,
|
||||||
}
|
}
|
||||||
trySend([verb, subid, ...filters])
|
trySend([verb, subid, ...filters])
|
||||||
|
|
||||||
let subscription: Sub<K> = {
|
let subscription: Sub<K> = {
|
||||||
sub: (newFilters, newOpts = {}) =>
|
sub: (newFilters, newOpts = {}) =>
|
||||||
sub(newFilters || filters, {
|
sub(newFilters || filters, {
|
||||||
skipVerification: newOpts.skipVerification || skipVerification,
|
skipVerification: newOpts.skipVerification || skipVerification,
|
||||||
alreadyHaveEvent: newOpts.alreadyHaveEvent || alreadyHaveEvent,
|
alreadyHaveEvent: newOpts.alreadyHaveEvent || alreadyHaveEvent,
|
||||||
id: subid,
|
id: subid,
|
||||||
}),
|
}),
|
||||||
unsub: () => {
|
unsub: () => {
|
||||||
delete openSubs[subid]
|
delete openSubs[subid]
|
||||||
delete subListeners[subid]
|
delete subListeners[subid]
|
||||||
trySend(['CLOSE', subid])
|
trySend(['CLOSE', subid])
|
||||||
},
|
},
|
||||||
on: (type, cb) => {
|
on: (type, cb) => {
|
||||||
subListeners[subid] = subListeners[subid] || {
|
subListeners[subid] = subListeners[subid] || {
|
||||||
event: [],
|
event: [],
|
||||||
count: [],
|
count: [],
|
||||||
eose: [],
|
eose: [],
|
||||||
}
|
}
|
||||||
//@ts-ignore
|
//@ts-ignore
|
||||||
subListeners[subid][type].push(cb)
|
subListeners[subid][type].push(cb)
|
||||||
},
|
},
|
||||||
off: (type, cb): void => {
|
off: (type, cb): void => {
|
||||||
let listeners = subListeners[subid]
|
let listeners = subListeners[subid]
|
||||||
//@ts-ignore
|
//@ts-ignore
|
||||||
let idx = listeners[type].indexOf(cb)
|
let idx = listeners[type].indexOf(cb)
|
||||||
if (idx >= 0) listeners[type].splice(idx, 1)
|
if (idx >= 0) listeners[type].splice(idx, 1)
|
||||||
},
|
},
|
||||||
get events() {
|
get events() {
|
||||||
return eventsGenerator(subscription)
|
return eventsGenerator(subscription)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
return subscription
|
return subscription
|
||||||
}
|
}
|
||||||
|
|
||||||
function _publishEvent(event: Event<number>, type: string) {
|
function _publishEvent(event: Event<number>, type: string) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
if (!event.id) {
|
if (!event.id) {
|
||||||
reject(new Error(`event ${event} has no id`))
|
reject(new Error(`event ${event} has no id`))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
let id = event.id
|
let id = event.id
|
||||||
trySend([type, event])
|
trySend([type, event])
|
||||||
pubListeners[id] = { resolve, reject }
|
pubListeners[id] = { resolve, reject }
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
url,
|
url,
|
||||||
sub,
|
sub,
|
||||||
on: <T extends keyof RelayEvent, U extends RelayEvent[T]>(type: T, cb: U): void => {
|
on: <T extends keyof RelayEvent, U extends RelayEvent[T]>(type: T, cb: U): void => {
|
||||||
//@ts-ignore
|
//@ts-ignore
|
||||||
listeners[type].push(cb)
|
listeners[type].push(cb)
|
||||||
if (type === 'connect' && ws?.readyState === 1) {
|
if (type === 'connect' && ws?.readyState === 1) {
|
||||||
// i would love to know why we need this
|
// i would love to know why we need this
|
||||||
; (cb as () => void)()
|
; (cb as () => void)()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
off: <T extends keyof RelayEvent, U extends RelayEvent[T]>(type: T, cb: U): void => {
|
off: <T extends keyof RelayEvent, U extends RelayEvent[T]>(type: T, cb: U): void => {
|
||||||
//@ts-ignore
|
//@ts-ignore
|
||||||
let index = listeners[type].indexOf(cb)
|
let index = listeners[type].indexOf(cb)
|
||||||
if (index !== -1) listeners[type].splice(index, 1)
|
if (index !== -1) listeners[type].splice(index, 1)
|
||||||
},
|
},
|
||||||
list: (filters, opts?: SubscriptionOptions) =>
|
list: (filters, opts?: SubscriptionOptions) =>
|
||||||
new Promise(resolve => {
|
new Promise(resolve => {
|
||||||
let s = sub(filters, opts)
|
let s = sub(filters, opts)
|
||||||
let events: Event<any>[] = []
|
let events: Event<any>[] = []
|
||||||
let timeout = setTimeout(() => {
|
let timeout = setTimeout(() => {
|
||||||
s.unsub()
|
s.unsub()
|
||||||
resolve(events)
|
resolve(events)
|
||||||
}, listTimeout)
|
}, listTimeout)
|
||||||
s.on('eose', () => {
|
s.on('eose', () => {
|
||||||
s.unsub()
|
s.unsub()
|
||||||
clearTimeout(timeout)
|
clearTimeout(timeout)
|
||||||
resolve(events)
|
resolve(events)
|
||||||
})
|
})
|
||||||
s.on('event', event => {
|
s.on('event', event => {
|
||||||
events.push(event)
|
events.push(event)
|
||||||
})
|
})
|
||||||
}),
|
}),
|
||||||
get: (filter, opts?: SubscriptionOptions) =>
|
get: (filter, opts?: SubscriptionOptions) =>
|
||||||
new Promise(resolve => {
|
new Promise(resolve => {
|
||||||
let s = sub([filter], opts)
|
let s = sub([filter], opts)
|
||||||
let timeout = setTimeout(() => {
|
let timeout = setTimeout(() => {
|
||||||
s.unsub()
|
s.unsub()
|
||||||
resolve(null)
|
resolve(null)
|
||||||
}, getTimeout)
|
}, getTimeout)
|
||||||
s.on('event', event => {
|
s.on('event', event => {
|
||||||
s.unsub()
|
s.unsub()
|
||||||
clearTimeout(timeout)
|
clearTimeout(timeout)
|
||||||
resolve(event)
|
resolve(event)
|
||||||
})
|
})
|
||||||
}),
|
}),
|
||||||
count: (filters: Filter[]): Promise<CountPayload | null> =>
|
count: (filters: Filter[]): Promise<CountPayload | null> =>
|
||||||
new Promise(resolve => {
|
new Promise(resolve => {
|
||||||
let s = sub(filters, { ...sub, verb: 'COUNT' })
|
let s = sub(filters, { ...sub, verb: 'COUNT' })
|
||||||
let timeout = setTimeout(() => {
|
let timeout = setTimeout(() => {
|
||||||
s.unsub()
|
s.unsub()
|
||||||
resolve(null)
|
resolve(null)
|
||||||
}, countTimeout)
|
}, countTimeout)
|
||||||
s.on('count', (event: CountPayload) => {
|
s.on('count', (event: CountPayload) => {
|
||||||
s.unsub()
|
s.unsub()
|
||||||
clearTimeout(timeout)
|
clearTimeout(timeout)
|
||||||
resolve(event)
|
resolve(event)
|
||||||
})
|
})
|
||||||
}),
|
}),
|
||||||
async publish(event): Promise<void> {
|
async publish(event): Promise<void> {
|
||||||
await _publishEvent(event, 'EVENT')
|
await _publishEvent(event, 'EVENT')
|
||||||
},
|
},
|
||||||
async auth(event): Promise<void> {
|
async auth(event): Promise<void> {
|
||||||
await _publishEvent(event, 'AUTH')
|
await _publishEvent(event, 'AUTH')
|
||||||
},
|
},
|
||||||
connect,
|
connect,
|
||||||
close(): void {
|
close(): void {
|
||||||
listeners = newListeners()
|
listeners = newListeners()
|
||||||
subListeners = {}
|
subListeners = {}
|
||||||
pubListeners = {}
|
pubListeners = {}
|
||||||
if (ws?.readyState === WebSocket.OPEN) {
|
if (ws?.readyState === WebSocket.OPEN) {
|
||||||
ws.close()
|
ws.close()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
get status() {
|
get status() {
|
||||||
return ws?.readyState ?? 3
|
return ws?.readyState ?? 3
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function* eventsGenerator<K extends number>(sub: Sub<K>): AsyncGenerator<Event<K>, void, unknown> {
|
export async function* eventsGenerator<K extends number>(sub: Sub<K>): AsyncGenerator<Event<K>, void, unknown> {
|
||||||
let nextResolve: ((event: Event<K>) => void) | undefined
|
let nextResolve: ((event: Event<K>) => void) | undefined
|
||||||
const eventQueue: Event<K>[] = []
|
const eventQueue: Event<K>[] = []
|
||||||
|
|
||||||
const pushToQueue = (event: Event<K>) => {
|
const pushToQueue = (event: Event<K>) => {
|
||||||
if (nextResolve) {
|
if (nextResolve) {
|
||||||
nextResolve(event)
|
nextResolve(event)
|
||||||
nextResolve = undefined
|
nextResolve = undefined
|
||||||
} else {
|
} else {
|
||||||
eventQueue.push(event)
|
eventQueue.push(event)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sub.on('event', pushToQueue)
|
sub.on('event', pushToQueue)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
while (true) {
|
while (true) {
|
||||||
if (eventQueue.length > 0) {
|
if (eventQueue.length > 0) {
|
||||||
yield eventQueue.shift()!
|
yield eventQueue.shift()!
|
||||||
} else {
|
} else {
|
||||||
const event = await new Promise<Event<K>>(resolve => {
|
const event = await new Promise<Event<K>>(resolve => {
|
||||||
nextResolve = resolve
|
nextResolve = resolve
|
||||||
})
|
})
|
||||||
yield event
|
yield event
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
sub.off('event', pushToQueue)
|
sub.off('event', pushToQueue)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,169 +1,169 @@
|
||||||
import type { Event } from './event.js'
|
import type { Event } from './event.js'
|
||||||
|
|
||||||
export const utf8Decoder = new TextDecoder('utf-8')
|
export const utf8Decoder = new TextDecoder('utf-8')
|
||||||
export const utf8Encoder = new TextEncoder()
|
export const utf8Encoder = new TextEncoder()
|
||||||
|
|
||||||
export function normalizeURL(url: string): string {
|
export function normalizeURL(url: string): string {
|
||||||
let p = new URL(url)
|
let p = new URL(url)
|
||||||
p.pathname = p.pathname.replace(/\/+/g, '/')
|
p.pathname = p.pathname.replace(/\/+/g, '/')
|
||||||
if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1)
|
if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1)
|
||||||
if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = ''
|
if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = ''
|
||||||
p.searchParams.sort()
|
p.searchParams.sort()
|
||||||
p.hash = ''
|
p.hash = ''
|
||||||
return p.toString()
|
return p.toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// fast insert-into-sorted-array functions adapted from https://github.com/terrymorse58/fast-sorted-array
|
// fast insert-into-sorted-array functions adapted from https://github.com/terrymorse58/fast-sorted-array
|
||||||
//
|
//
|
||||||
export function insertEventIntoDescendingList(sortedArray: Event<number>[], event: Event<number>) {
|
export function insertEventIntoDescendingList(sortedArray: Event<number>[], event: Event<number>) {
|
||||||
let start = 0
|
let start = 0
|
||||||
let end = sortedArray.length - 1
|
let end = sortedArray.length - 1
|
||||||
let midPoint
|
let midPoint
|
||||||
let position = start
|
let position = start
|
||||||
|
|
||||||
if (end < 0) {
|
if (end < 0) {
|
||||||
position = 0
|
position = 0
|
||||||
} else if (event.created_at < sortedArray[end].created_at) {
|
} else if (event.created_at < sortedArray[end].created_at) {
|
||||||
position = end + 1
|
position = end + 1
|
||||||
} else if (event.created_at >= sortedArray[start].created_at) {
|
} else if (event.created_at >= sortedArray[start].created_at) {
|
||||||
position = start
|
position = start
|
||||||
} else
|
} else
|
||||||
while (true) {
|
while (true) {
|
||||||
if (end <= start + 1) {
|
if (end <= start + 1) {
|
||||||
position = end
|
position = end
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
midPoint = Math.floor(start + (end - start) / 2)
|
midPoint = Math.floor(start + (end - start) / 2)
|
||||||
if (sortedArray[midPoint].created_at > event.created_at) {
|
if (sortedArray[midPoint].created_at > event.created_at) {
|
||||||
start = midPoint
|
start = midPoint
|
||||||
} else if (sortedArray[midPoint].created_at < event.created_at) {
|
} else if (sortedArray[midPoint].created_at < event.created_at) {
|
||||||
end = midPoint
|
end = midPoint
|
||||||
} else {
|
} else {
|
||||||
// aMidPoint === num
|
// aMidPoint === num
|
||||||
position = midPoint
|
position = midPoint
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// insert when num is NOT already in (no duplicates)
|
// insert when num is NOT already in (no duplicates)
|
||||||
if (sortedArray[position]?.id !== event.id) {
|
if (sortedArray[position]?.id !== event.id) {
|
||||||
return [...sortedArray.slice(0, position), event, ...sortedArray.slice(position)]
|
return [...sortedArray.slice(0, position), event, ...sortedArray.slice(position)]
|
||||||
}
|
}
|
||||||
|
|
||||||
return sortedArray
|
return sortedArray
|
||||||
}
|
}
|
||||||
|
|
||||||
export function insertEventIntoAscendingList(sortedArray: Event<number>[], event: Event<number>) {
|
export function insertEventIntoAscendingList(sortedArray: Event<number>[], event: Event<number>) {
|
||||||
let start = 0
|
let start = 0
|
||||||
let end = sortedArray.length - 1
|
let end = sortedArray.length - 1
|
||||||
let midPoint
|
let midPoint
|
||||||
let position = start
|
let position = start
|
||||||
|
|
||||||
if (end < 0) {
|
if (end < 0) {
|
||||||
position = 0
|
position = 0
|
||||||
} else if (event.created_at > sortedArray[end].created_at) {
|
} else if (event.created_at > sortedArray[end].created_at) {
|
||||||
position = end + 1
|
position = end + 1
|
||||||
} else if (event.created_at <= sortedArray[start].created_at) {
|
} else if (event.created_at <= sortedArray[start].created_at) {
|
||||||
position = start
|
position = start
|
||||||
} else
|
} else
|
||||||
while (true) {
|
while (true) {
|
||||||
if (end <= start + 1) {
|
if (end <= start + 1) {
|
||||||
position = end
|
position = end
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
midPoint = Math.floor(start + (end - start) / 2)
|
midPoint = Math.floor(start + (end - start) / 2)
|
||||||
if (sortedArray[midPoint].created_at < event.created_at) {
|
if (sortedArray[midPoint].created_at < event.created_at) {
|
||||||
start = midPoint
|
start = midPoint
|
||||||
} else if (sortedArray[midPoint].created_at > event.created_at) {
|
} else if (sortedArray[midPoint].created_at > event.created_at) {
|
||||||
end = midPoint
|
end = midPoint
|
||||||
} else {
|
} else {
|
||||||
// aMidPoint === num
|
// aMidPoint === num
|
||||||
position = midPoint
|
position = midPoint
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// insert when num is NOT already in (no duplicates)
|
// insert when num is NOT already in (no duplicates)
|
||||||
if (sortedArray[position]?.id !== event.id) {
|
if (sortedArray[position]?.id !== event.id) {
|
||||||
return [...sortedArray.slice(0, position), event, ...sortedArray.slice(position)]
|
return [...sortedArray.slice(0, position), event, ...sortedArray.slice(position)]
|
||||||
}
|
}
|
||||||
|
|
||||||
return sortedArray
|
return sortedArray
|
||||||
}
|
}
|
||||||
|
|
||||||
export class MessageNode {
|
export class MessageNode {
|
||||||
private _value: string
|
private _value: string
|
||||||
private _next: MessageNode | null
|
private _next: MessageNode | null
|
||||||
|
|
||||||
public get value(): string {
|
public get value(): string {
|
||||||
return this._value
|
return this._value
|
||||||
}
|
}
|
||||||
public set value(message: string) {
|
public set value(message: string) {
|
||||||
this._value = message
|
this._value = message
|
||||||
}
|
}
|
||||||
public get next(): MessageNode | null {
|
public get next(): MessageNode | null {
|
||||||
return this._next
|
return this._next
|
||||||
}
|
}
|
||||||
public set next(node: MessageNode | null) {
|
public set next(node: MessageNode | null) {
|
||||||
this._next = node
|
this._next = node
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(message: string) {
|
constructor(message: string) {
|
||||||
this._value = message
|
this._value = message
|
||||||
this._next = null
|
this._next = null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class MessageQueue {
|
export class MessageQueue {
|
||||||
private _first: MessageNode | null
|
private _first: MessageNode | null
|
||||||
private _last: MessageNode | null
|
private _last: MessageNode | null
|
||||||
|
|
||||||
public get first(): MessageNode | null {
|
public get first(): MessageNode | null {
|
||||||
return this._first
|
return this._first
|
||||||
}
|
}
|
||||||
public set first(messageNode: MessageNode | null) {
|
public set first(messageNode: MessageNode | null) {
|
||||||
this._first = messageNode
|
this._first = messageNode
|
||||||
}
|
}
|
||||||
public get last(): MessageNode | null {
|
public get last(): MessageNode | null {
|
||||||
return this._last
|
return this._last
|
||||||
}
|
}
|
||||||
public set last(messageNode: MessageNode | null) {
|
public set last(messageNode: MessageNode | null) {
|
||||||
this._last = messageNode
|
this._last = messageNode
|
||||||
}
|
}
|
||||||
private _size: number
|
private _size: number
|
||||||
public get size(): number {
|
public get size(): number {
|
||||||
return this._size
|
return this._size
|
||||||
}
|
}
|
||||||
public set size(v: number) {
|
public set size(v: number) {
|
||||||
this._size = v
|
this._size = v
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this._first = null
|
this._first = null
|
||||||
this._last = null
|
this._last = null
|
||||||
this._size = 0
|
this._size = 0
|
||||||
}
|
}
|
||||||
enqueue(message: string): boolean {
|
enqueue(message: string): boolean {
|
||||||
const newNode = new MessageNode(message)
|
const newNode = new MessageNode(message)
|
||||||
if (this._size === 0 || !this._last) {
|
if (this._size === 0 || !this._last) {
|
||||||
this._first = newNode
|
this._first = newNode
|
||||||
this._last = newNode
|
this._last = newNode
|
||||||
} else {
|
} else {
|
||||||
this._last.next = newNode
|
this._last.next = newNode
|
||||||
this._last = newNode
|
this._last = newNode
|
||||||
}
|
}
|
||||||
this._size++
|
this._size++
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
dequeue(): string | null {
|
dequeue(): string | null {
|
||||||
if (this._size === 0 || !this._first) return null
|
if (this._size === 0 || !this._first) return null
|
||||||
|
|
||||||
let prev = this._first
|
let prev = this._first
|
||||||
this._first = prev.next
|
this._first = prev.next
|
||||||
prev.next = null
|
prev.next = null
|
||||||
|
|
||||||
this._size--
|
this._size--
|
||||||
return prev.value
|
return prev.value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,219 +1,219 @@
|
||||||
import * as Types from '../../../proto/autogenerated/ts/types.js'
|
import * as Types from '../../../proto/autogenerated/ts/types.js'
|
||||||
import { getLogger } from '../helpers/logger.js'
|
import { getLogger } from '../helpers/logger.js'
|
||||||
import main from '../main/index.js'
|
import main from '../main/index.js'
|
||||||
import Main from '../main/index.js'
|
import Main from '../main/index.js'
|
||||||
export default (mainHandler: Main): Types.ServerMethods => {
|
export default (mainHandler: Main): Types.ServerMethods => {
|
||||||
return {
|
return {
|
||||||
GetUsageMetrics: async ({ ctx }) => {
|
GetUsageMetrics: async ({ ctx }) => {
|
||||||
return mainHandler.metricsManager.GetUsageMetrics()
|
return mainHandler.metricsManager.GetUsageMetrics()
|
||||||
},
|
},
|
||||||
GetAppsMetrics: async ({ ctx, req }) => {
|
GetAppsMetrics: async ({ ctx, req }) => {
|
||||||
return mainHandler.metricsManager.GetAppsMetrics(req)
|
return mainHandler.metricsManager.GetAppsMetrics(req)
|
||||||
},
|
},
|
||||||
GetLndMetrics: async ({ ctx, req }) => {
|
GetLndMetrics: async ({ ctx, req }) => {
|
||||||
return mainHandler.metricsManager.GetLndMetrics(req)
|
return mainHandler.metricsManager.GetLndMetrics(req)
|
||||||
},
|
},
|
||||||
EncryptionExchange: async () => { },
|
EncryptionExchange: async () => { },
|
||||||
Health: async () => { await mainHandler.lnd.Health() },
|
Health: async () => { await mainHandler.lnd.Health() },
|
||||||
LndGetInfo: async ({ ctx }) => {
|
LndGetInfo: async ({ ctx }) => {
|
||||||
const info = await mainHandler.lnd.GetInfo()
|
const info = await mainHandler.lnd.GetInfo()
|
||||||
return { alias: info.alias }
|
return { alias: info.alias }
|
||||||
},
|
},
|
||||||
BanUser: async ({ ctx, req }) => {
|
BanUser: async ({ ctx, req }) => {
|
||||||
const err = Types.BanUserRequestValidate(req, {
|
const err = Types.BanUserRequestValidate(req, {
|
||||||
user_id_CustomCheck: id => id !== ''
|
user_id_CustomCheck: id => id !== ''
|
||||||
})
|
})
|
||||||
if (err != null) throw new Error(err.message)
|
if (err != null) throw new Error(err.message)
|
||||||
return mainHandler.appUserManager.BanUser(req.user_id)
|
return mainHandler.appUserManager.BanUser(req.user_id)
|
||||||
},
|
},
|
||||||
SetMockInvoiceAsPaid: async ({ ctx, req }) => {
|
SetMockInvoiceAsPaid: async ({ ctx, req }) => {
|
||||||
const err = Types.SetMockInvoiceAsPaidRequestValidate(req, {
|
const err = Types.SetMockInvoiceAsPaidRequestValidate(req, {
|
||||||
invoice_CustomCheck: invoice => invoice !== '',
|
invoice_CustomCheck: invoice => invoice !== '',
|
||||||
})
|
})
|
||||||
if (err != null) throw new Error(err.message)
|
if (err != null) throw new Error(err.message)
|
||||||
await mainHandler.paymentManager.SetMockInvoiceAsPaid(req)
|
await mainHandler.paymentManager.SetMockInvoiceAsPaid(req)
|
||||||
},
|
},
|
||||||
UserHealth: async () => { },
|
UserHealth: async () => { },
|
||||||
GetUserInfo: ({ ctx }) => mainHandler.appUserManager.GetUserInfo(ctx),
|
GetUserInfo: ({ ctx }) => mainHandler.appUserManager.GetUserInfo(ctx),
|
||||||
GetUserOperations: async ({ ctx, req }) => {
|
GetUserOperations: async ({ ctx, req }) => {
|
||||||
return mainHandler.paymentManager.GetUserOperations(ctx.user_id, req)
|
return mainHandler.paymentManager.GetUserOperations(ctx.user_id, req)
|
||||||
},
|
},
|
||||||
OpenChannel: async ({ ctx, req }) => {
|
OpenChannel: async ({ ctx, req }) => {
|
||||||
const err = Types.OpenChannelRequestValidate(req, {
|
const err = Types.OpenChannelRequestValidate(req, {
|
||||||
fundingAmount_CustomCheck: amt => amt > 0,
|
fundingAmount_CustomCheck: amt => amt > 0,
|
||||||
pushAmount_CustomCheck: amt => amt > 0,
|
pushAmount_CustomCheck: amt => amt > 0,
|
||||||
destination_CustomCheck: dest => dest !== ""
|
destination_CustomCheck: dest => dest !== ""
|
||||||
})
|
})
|
||||||
if (err != null) throw new Error(err.message)
|
if (err != null) throw new Error(err.message)
|
||||||
return mainHandler.paymentManager.OpenChannel(ctx.user_id, req)
|
return mainHandler.paymentManager.OpenChannel(ctx.user_id, req)
|
||||||
},
|
},
|
||||||
NewAddress: ({ ctx, req }) => mainHandler.paymentManager.NewAddress(ctx, req),
|
NewAddress: ({ ctx, req }) => mainHandler.paymentManager.NewAddress(ctx, req),
|
||||||
PayAddress: async ({ ctx, req }) => {
|
PayAddress: async ({ ctx, req }) => {
|
||||||
const err = Types.PayAddressRequestValidate(req, {
|
const err = Types.PayAddressRequestValidate(req, {
|
||||||
address_CustomCheck: addr => addr !== '',
|
address_CustomCheck: addr => addr !== '',
|
||||||
amoutSats_CustomCheck: amt => amt > 0,
|
amoutSats_CustomCheck: amt => amt > 0,
|
||||||
satsPerVByte_CustomCheck: spb => spb > 0
|
satsPerVByte_CustomCheck: spb => spb > 0
|
||||||
})
|
})
|
||||||
if (err != null) throw new Error(err.message)
|
if (err != null) throw new Error(err.message)
|
||||||
return mainHandler.paymentManager.PayAddress(ctx, req)
|
return mainHandler.paymentManager.PayAddress(ctx, req)
|
||||||
},
|
},
|
||||||
NewInvoice: ({ ctx, req }) => mainHandler.appUserManager.NewInvoice(ctx, req),
|
NewInvoice: ({ ctx, req }) => mainHandler.appUserManager.NewInvoice(ctx, req),
|
||||||
DecodeInvoice: async ({ ctx, req }) => {
|
DecodeInvoice: async ({ ctx, req }) => {
|
||||||
return mainHandler.paymentManager.DecodeInvoice(req)
|
return mainHandler.paymentManager.DecodeInvoice(req)
|
||||||
},
|
},
|
||||||
PayInvoice: async ({ ctx, req }) => {
|
PayInvoice: async ({ ctx, req }) => {
|
||||||
const err = Types.PayInvoiceRequestValidate(req, {
|
const err = Types.PayInvoiceRequestValidate(req, {
|
||||||
invoice_CustomCheck: invoice => invoice !== ''
|
invoice_CustomCheck: invoice => invoice !== ''
|
||||||
})
|
})
|
||||||
if (err != null) throw new Error(err.message)
|
if (err != null) throw new Error(err.message)
|
||||||
return mainHandler.appUserManager.PayInvoice(ctx, req)
|
return mainHandler.appUserManager.PayInvoice(ctx, req)
|
||||||
},
|
},
|
||||||
GetLnurlWithdrawLink: ({ ctx }) => mainHandler.paymentManager.GetLnurlWithdrawLink(ctx),
|
GetLnurlWithdrawLink: ({ ctx }) => mainHandler.paymentManager.GetLnurlWithdrawLink(ctx),
|
||||||
GetLnurlWithdrawInfo: async ({ ctx, query }) => {
|
GetLnurlWithdrawInfo: async ({ ctx, query }) => {
|
||||||
if (!query.k1) {
|
if (!query.k1) {
|
||||||
throw new Error("invalid lnurl withdraw to get info")
|
throw new Error("invalid lnurl withdraw to get info")
|
||||||
}
|
}
|
||||||
return mainHandler.paymentManager.GetLnurlWithdrawInfo(query.k1)
|
return mainHandler.paymentManager.GetLnurlWithdrawInfo(query.k1)
|
||||||
},
|
},
|
||||||
HandleLnurlWithdraw: async ({ query }) => {
|
HandleLnurlWithdraw: async ({ query }) => {
|
||||||
if (!query.k1 || !query.pr) {
|
if (!query.k1 || !query.pr) {
|
||||||
throw new Error("invalid lnurl withdraw to handle")
|
throw new Error("invalid lnurl withdraw to handle")
|
||||||
}
|
}
|
||||||
return mainHandler.paymentManager.HandleLnurlWithdraw(query.k1, query.pr)
|
return mainHandler.paymentManager.HandleLnurlWithdraw(query.k1, query.pr)
|
||||||
},
|
},
|
||||||
GetLnurlPayLink: ({ ctx }) => mainHandler.paymentManager.GetLnurlPayLink(ctx),
|
GetLnurlPayLink: ({ ctx }) => mainHandler.paymentManager.GetLnurlPayLink(ctx),
|
||||||
GetLnurlPayInfo: async ({ ctx, query }) => {
|
GetLnurlPayInfo: async ({ ctx, query }) => {
|
||||||
if (!query.k1) {
|
if (!query.k1) {
|
||||||
throw new Error("invalid lnurl pay to get info")
|
throw new Error("invalid lnurl pay to get info")
|
||||||
}
|
}
|
||||||
return mainHandler.paymentManager.GetLnurlPayInfo(query.k1)
|
return mainHandler.paymentManager.GetLnurlPayInfo(query.k1)
|
||||||
},
|
},
|
||||||
HandleLnurlPay: async ({ ctx, query }) => {
|
HandleLnurlPay: async ({ ctx, query }) => {
|
||||||
return mainHandler.paymentManager.HandleLnurlPay(query)
|
return mainHandler.paymentManager.HandleLnurlPay(query)
|
||||||
},
|
},
|
||||||
HandleLnurlAddress: async ({ ctx, params }) => {
|
HandleLnurlAddress: async ({ ctx, params }) => {
|
||||||
if (!params.address_name) {
|
if (!params.address_name) {
|
||||||
throw new Error("invalid address_name to lnurl address")
|
throw new Error("invalid address_name to lnurl address")
|
||||||
}
|
}
|
||||||
return mainHandler.paymentManager.HandleLnurlAddress(params.address_name)
|
return mainHandler.paymentManager.HandleLnurlAddress(params.address_name)
|
||||||
},
|
},
|
||||||
AddProduct: async ({ ctx, req }) => {
|
AddProduct: async ({ ctx, req }) => {
|
||||||
return mainHandler.productManager.AddProduct(ctx.user_id, req)
|
return mainHandler.productManager.AddProduct(ctx.user_id, req)
|
||||||
},
|
},
|
||||||
NewProductInvoice: async ({ query }) => {
|
NewProductInvoice: async ({ query }) => {
|
||||||
if (!query.id) {
|
if (!query.id) {
|
||||||
throw new Error("product id must be non empty")
|
throw new Error("product id must be non empty")
|
||||||
}
|
}
|
||||||
return mainHandler.productManager.NewProductInvoice(query.id)
|
return mainHandler.productManager.NewProductInvoice(query.id)
|
||||||
},
|
},
|
||||||
GetLNURLChannelLink: async ({ ctx }) => {
|
GetLNURLChannelLink: async ({ ctx }) => {
|
||||||
throw new Error("unimplemented")
|
throw new Error("unimplemented")
|
||||||
},
|
},
|
||||||
AddApp: async ({ ctx, req }) => {
|
AddApp: async ({ ctx, req }) => {
|
||||||
const err = Types.AuthAppRequestValidate(req, {
|
const err = Types.AuthAppRequestValidate(req, {
|
||||||
name_CustomCheck: name => name !== ''
|
name_CustomCheck: name => name !== ''
|
||||||
})
|
})
|
||||||
if (err != null) throw new Error(err.message)
|
if (err != null) throw new Error(err.message)
|
||||||
return mainHandler.applicationManager.AddApp(req)
|
return mainHandler.applicationManager.AddApp(req)
|
||||||
},
|
},
|
||||||
AuthApp: async ({ ctx, req }) => {
|
AuthApp: async ({ ctx, req }) => {
|
||||||
const err = Types.AuthAppRequestValidate(req, {
|
const err = Types.AuthAppRequestValidate(req, {
|
||||||
name_CustomCheck: name => name !== ''
|
name_CustomCheck: name => name !== ''
|
||||||
})
|
})
|
||||||
if (err != null) throw new Error(err.message)
|
if (err != null) throw new Error(err.message)
|
||||||
return mainHandler.applicationManager.AuthApp(req)
|
return mainHandler.applicationManager.AuthApp(req)
|
||||||
},
|
},
|
||||||
GetApp: async ({ ctx }) => {
|
GetApp: async ({ ctx }) => {
|
||||||
return mainHandler.applicationManager.GetApp(ctx.app_id)
|
return mainHandler.applicationManager.GetApp(ctx.app_id)
|
||||||
},
|
},
|
||||||
AddAppUser: async ({ ctx, req }) => {
|
AddAppUser: async ({ ctx, req }) => {
|
||||||
const err = Types.AddAppUserRequestValidate(req, {
|
const err = Types.AddAppUserRequestValidate(req, {
|
||||||
identifier_CustomCheck: id => id !== ''
|
identifier_CustomCheck: id => id !== ''
|
||||||
})
|
})
|
||||||
if (err != null) throw new Error(err.message)
|
if (err != null) throw new Error(err.message)
|
||||||
return mainHandler.applicationManager.AddAppUser(ctx.app_id, req)
|
return mainHandler.applicationManager.AddAppUser(ctx.app_id, req)
|
||||||
},
|
},
|
||||||
AddAppInvoice: async ({ ctx, req }) => {
|
AddAppInvoice: async ({ ctx, req }) => {
|
||||||
const err = Types.AddAppInvoiceRequestValidate(req, {
|
const err = Types.AddAppInvoiceRequestValidate(req, {
|
||||||
payer_identifier_CustomCheck: id => id !== '',
|
payer_identifier_CustomCheck: id => id !== '',
|
||||||
})
|
})
|
||||||
if (err != null) throw new Error(err.message)
|
if (err != null) throw new Error(err.message)
|
||||||
return mainHandler.applicationManager.AddAppInvoice(ctx.app_id, req)
|
return mainHandler.applicationManager.AddAppInvoice(ctx.app_id, req)
|
||||||
},
|
},
|
||||||
AddAppUserInvoice: async ({ ctx, req }) => {
|
AddAppUserInvoice: async ({ ctx, req }) => {
|
||||||
const err = Types.AddAppUserInvoiceRequestValidate(req, {
|
const err = Types.AddAppUserInvoiceRequestValidate(req, {
|
||||||
payer_identifier_CustomCheck: id => id !== '',
|
payer_identifier_CustomCheck: id => id !== '',
|
||||||
receiver_identifier_CustomCheck: id => id !== '',
|
receiver_identifier_CustomCheck: id => id !== '',
|
||||||
})
|
})
|
||||||
if (err != null) throw new Error(err.message)
|
if (err != null) throw new Error(err.message)
|
||||||
return mainHandler.applicationManager.AddAppUserInvoice(ctx.app_id, req)
|
return mainHandler.applicationManager.AddAppUserInvoice(ctx.app_id, req)
|
||||||
},
|
},
|
||||||
GetAppUser: async ({ ctx, req }) => {
|
GetAppUser: async ({ ctx, req }) => {
|
||||||
const err = Types.GetAppUserRequestValidate(req, {
|
const err = Types.GetAppUserRequestValidate(req, {
|
||||||
user_identifier_CustomCheck: id => id !== '',
|
user_identifier_CustomCheck: id => id !== '',
|
||||||
})
|
})
|
||||||
if (err != null) throw new Error(err.message)
|
if (err != null) throw new Error(err.message)
|
||||||
return mainHandler.applicationManager.GetAppUser(ctx.app_id, req)
|
return mainHandler.applicationManager.GetAppUser(ctx.app_id, req)
|
||||||
},
|
},
|
||||||
PayAppUserInvoice: async ({ ctx, req }) => {
|
PayAppUserInvoice: async ({ ctx, req }) => {
|
||||||
const err = Types.PayAppUserInvoiceRequestValidate(req, {
|
const err = Types.PayAppUserInvoiceRequestValidate(req, {
|
||||||
user_identifier_CustomCheck: id => id !== '',
|
user_identifier_CustomCheck: id => id !== '',
|
||||||
})
|
})
|
||||||
if (err != null) throw new Error(err.message)
|
if (err != null) throw new Error(err.message)
|
||||||
return mainHandler.applicationManager.PayAppUserInvoice(ctx.app_id, req)
|
return mainHandler.applicationManager.PayAppUserInvoice(ctx.app_id, req)
|
||||||
},
|
},
|
||||||
SendAppUserToAppUserPayment: async ({ ctx, req }) => {
|
SendAppUserToAppUserPayment: async ({ ctx, req }) => {
|
||||||
const err = Types.SendAppUserToAppUserPaymentRequestValidate(req, {
|
const err = Types.SendAppUserToAppUserPaymentRequestValidate(req, {
|
||||||
to_user_identifier_CustomCheck: id => id !== '',
|
to_user_identifier_CustomCheck: id => id !== '',
|
||||||
from_user_identifier_CustomCheck: id => id !== '',
|
from_user_identifier_CustomCheck: id => id !== '',
|
||||||
amount_CustomCheck: amount => amount > 0
|
amount_CustomCheck: amount => amount > 0
|
||||||
})
|
})
|
||||||
if (err != null) throw new Error(err.message)
|
if (err != null) throw new Error(err.message)
|
||||||
await mainHandler.applicationManager.SendAppUserToAppUserPayment(ctx.app_id, req)
|
await mainHandler.applicationManager.SendAppUserToAppUserPayment(ctx.app_id, req)
|
||||||
},
|
},
|
||||||
SendAppUserToAppPayment: async ({ ctx, req }) => {
|
SendAppUserToAppPayment: async ({ ctx, req }) => {
|
||||||
const err = Types.SendAppUserToAppPaymentRequestValidate(req, {
|
const err = Types.SendAppUserToAppPaymentRequestValidate(req, {
|
||||||
from_user_identifier_CustomCheck: id => id !== '',
|
from_user_identifier_CustomCheck: id => id !== '',
|
||||||
amount_CustomCheck: amount => amount > 0
|
amount_CustomCheck: amount => amount > 0
|
||||||
})
|
})
|
||||||
if (err != null) throw new Error(err.message)
|
if (err != null) throw new Error(err.message)
|
||||||
await mainHandler.applicationManager.SendAppUserToAppPayment(ctx.app_id, req)
|
await mainHandler.applicationManager.SendAppUserToAppPayment(ctx.app_id, req)
|
||||||
},
|
},
|
||||||
GetAppUserLNURLInfo: async ({ ctx, req }) => {
|
GetAppUserLNURLInfo: async ({ ctx, req }) => {
|
||||||
const err = Types.GetAppUserLNURLInfoRequestValidate(req, {
|
const err = Types.GetAppUserLNURLInfoRequestValidate(req, {
|
||||||
user_identifier_CustomCheck: id => id !== ''
|
user_identifier_CustomCheck: id => id !== ''
|
||||||
})
|
})
|
||||||
if (err != null) throw new Error(err.message)
|
if (err != null) throw new Error(err.message)
|
||||||
return mainHandler.applicationManager.GetAppUserLNURLInfo(ctx.app_id, req)
|
return mainHandler.applicationManager.GetAppUserLNURLInfo(ctx.app_id, req)
|
||||||
},
|
},
|
||||||
SetMockAppUserBalance: async ({ ctx, req }) => {
|
SetMockAppUserBalance: async ({ ctx, req }) => {
|
||||||
const err = Types.SetMockAppUserBalanceRequestValidate(req, {
|
const err = Types.SetMockAppUserBalanceRequestValidate(req, {
|
||||||
user_identifier_CustomCheck: id => id !== ''
|
user_identifier_CustomCheck: id => id !== ''
|
||||||
})
|
})
|
||||||
if (err != null) throw new Error(err.message)
|
if (err != null) throw new Error(err.message)
|
||||||
await mainHandler.applicationManager.SetMockAppUserBalance(ctx.app_id, req)
|
await mainHandler.applicationManager.SetMockAppUserBalance(ctx.app_id, req)
|
||||||
},
|
},
|
||||||
SetMockAppBalance: async ({ ctx, req }) => {
|
SetMockAppBalance: async ({ ctx, req }) => {
|
||||||
await mainHandler.applicationManager.SetMockAppBalance(ctx.app_id, req)
|
await mainHandler.applicationManager.SetMockAppBalance(ctx.app_id, req)
|
||||||
},
|
},
|
||||||
GetLiveUserOperations: async ({ ctx, cb }) => {
|
GetLiveUserOperations: async ({ ctx, cb }) => {
|
||||||
},
|
},
|
||||||
GetMigrationUpdate: async ({ ctx, cb }) => {
|
GetMigrationUpdate: async ({ ctx, cb }) => {
|
||||||
},
|
},
|
||||||
RequestNPubLinkingToken: async ({ ctx, req }) => {
|
RequestNPubLinkingToken: async ({ ctx, req }) => {
|
||||||
const err = Types.RequestNPubLinkingTokenRequestValidate(req, {
|
const err = Types.RequestNPubLinkingTokenRequestValidate(req, {
|
||||||
user_identifier_CustomCheck: userIdentifier => userIdentifier !== '',
|
user_identifier_CustomCheck: userIdentifier => userIdentifier !== '',
|
||||||
})
|
})
|
||||||
if (err != null) throw new Error(err.message)
|
if (err != null) throw new Error(err.message)
|
||||||
return mainHandler.applicationManager.RequestNPubLinkingToken(ctx.app_id, req)
|
return mainHandler.applicationManager.RequestNPubLinkingToken(ctx.app_id, req)
|
||||||
},
|
},
|
||||||
LinkNPubThroughToken: async ({ ctx, req }) => {
|
LinkNPubThroughToken: async ({ ctx, req }) => {
|
||||||
const err = Types.LinkNPubThroughTokenRequestValidate(req, {
|
const err = Types.LinkNPubThroughTokenRequestValidate(req, {
|
||||||
nostr_pub_CustomCheck: nostrPub => nostrPub !== '',
|
nostr_pub_CustomCheck: nostrPub => nostrPub !== '',
|
||||||
token_CustomCheck: token => token !== ''
|
token_CustomCheck: token => token !== ''
|
||||||
})
|
})
|
||||||
if (err != null) throw new Error(err.message)
|
if (err != null) throw new Error(err.message)
|
||||||
return mainHandler.applicationManager.LinkNpubThroughToken(ctx, req)
|
return mainHandler.applicationManager.LinkNpubThroughToken(ctx, req)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,172 +1,172 @@
|
||||||
import crypto from 'crypto';
|
import crypto from 'crypto';
|
||||||
import { Between, DataSource, EntityManager, FindOperator, IsNull, LessThanOrEqual, MoreThanOrEqual } from "typeorm"
|
import { Between, DataSource, EntityManager, FindOperator, IsNull, LessThanOrEqual, MoreThanOrEqual } from "typeorm"
|
||||||
import { generatePrivateKey, getPublicKey } from 'nostr-tools';
|
import { generatePrivateKey, getPublicKey } from 'nostr-tools';
|
||||||
import { Application } from "./entity/Application.js"
|
import { Application } from "./entity/Application.js"
|
||||||
import UserStorage from './userStorage.js';
|
import UserStorage from './userStorage.js';
|
||||||
import { ApplicationUser } from './entity/ApplicationUser.js';
|
import { ApplicationUser } from './entity/ApplicationUser.js';
|
||||||
import { getLogger } from '../helpers/logger.js';
|
import { getLogger } from '../helpers/logger.js';
|
||||||
import TransactionsQueue, { TX } from "./transactionsQueue.js";
|
import TransactionsQueue, { TX } from "./transactionsQueue.js";
|
||||||
import { User } from './entity/User.js';
|
import { User } from './entity/User.js';
|
||||||
export default class {
|
export default class {
|
||||||
DB: DataSource | EntityManager
|
DB: DataSource | EntityManager
|
||||||
userStorage: UserStorage
|
userStorage: UserStorage
|
||||||
txQueue: TransactionsQueue
|
txQueue: TransactionsQueue
|
||||||
constructor(DB: DataSource | EntityManager, userStorage: UserStorage, txQueue: TransactionsQueue) {
|
constructor(DB: DataSource | EntityManager, userStorage: UserStorage, txQueue: TransactionsQueue) {
|
||||||
this.DB = DB
|
this.DB = DB
|
||||||
this.userStorage = userStorage
|
this.userStorage = userStorage
|
||||||
this.txQueue = txQueue
|
this.txQueue = txQueue
|
||||||
}
|
}
|
||||||
|
|
||||||
async AddApplication(name: string, allowUserCreation: boolean): Promise<Application> {
|
async AddApplication(name: string, allowUserCreation: boolean): Promise<Application> {
|
||||||
return this.DB.transaction(async tx => {
|
return this.DB.transaction(async tx => {
|
||||||
const owner = await this.userStorage.AddUser(0, tx)
|
const owner = await this.userStorage.AddUser(0, tx)
|
||||||
const repo = this.DB.getRepository(Application)
|
const repo = this.DB.getRepository(Application)
|
||||||
const newApplication = repo.create({
|
const newApplication = repo.create({
|
||||||
app_id: crypto.randomBytes(32).toString('hex'),
|
app_id: crypto.randomBytes(32).toString('hex'),
|
||||||
name,
|
name,
|
||||||
owner,
|
owner,
|
||||||
allow_user_creation: allowUserCreation
|
allow_user_creation: allowUserCreation
|
||||||
})
|
})
|
||||||
return tx.getRepository(Application).save(newApplication)
|
return tx.getRepository(Application).save(newApplication)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async GetApplicationByName(name: string, entityManager = this.DB) {
|
async GetApplicationByName(name: string, entityManager = this.DB) {
|
||||||
const found = await entityManager.getRepository(Application).findOne({
|
const found = await entityManager.getRepository(Application).findOne({
|
||||||
where: {
|
where: {
|
||||||
name
|
name
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
if (!found) {
|
if (!found) {
|
||||||
throw new Error(`application ${name} not found`)
|
throw new Error(`application ${name} not found`)
|
||||||
}
|
}
|
||||||
return found
|
return found
|
||||||
}
|
}
|
||||||
|
|
||||||
async GetApplications(entityManager = this.DB): Promise<Application[]> {
|
async GetApplications(entityManager = this.DB): Promise<Application[]> {
|
||||||
return entityManager.getRepository(Application).find()
|
return entityManager.getRepository(Application).find()
|
||||||
}
|
}
|
||||||
async GetApplication(appId: string, entityManager = this.DB): Promise<Application> {
|
async GetApplication(appId: string, entityManager = this.DB): Promise<Application> {
|
||||||
if (!appId) {
|
if (!appId) {
|
||||||
throw new Error("invalid app id provided")
|
throw new Error("invalid app id provided")
|
||||||
}
|
}
|
||||||
const found = await entityManager.getRepository(Application).findOne({
|
const found = await entityManager.getRepository(Application).findOne({
|
||||||
where: {
|
where: {
|
||||||
app_id: appId
|
app_id: appId
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
if (!found) {
|
if (!found) {
|
||||||
throw new Error(`application ${appId} not found`)
|
throw new Error(`application ${appId} not found`)
|
||||||
}
|
}
|
||||||
return found
|
return found
|
||||||
}
|
}
|
||||||
|
|
||||||
async UpdateApplication(app: Application, update: Partial<Application>, entityManager = this.DB) {
|
async UpdateApplication(app: Application, update: Partial<Application>, entityManager = this.DB) {
|
||||||
await entityManager.getRepository(Application).update(app.serial_id, update)
|
await entityManager.getRepository(Application).update(app.serial_id, update)
|
||||||
}
|
}
|
||||||
|
|
||||||
async GenerateApplicationKeys(app: Application) {
|
async GenerateApplicationKeys(app: Application) {
|
||||||
const priv = generatePrivateKey()
|
const priv = generatePrivateKey()
|
||||||
const pub = getPublicKey(priv)
|
const pub = getPublicKey(priv)
|
||||||
await this.UpdateApplication(app, { nostr_private_key: priv, nostr_public_key: pub })
|
await this.UpdateApplication(app, { nostr_private_key: priv, nostr_public_key: pub })
|
||||||
return { privateKey: priv, publicKey: pub, appId: app.app_id, name: app.name }
|
return { privateKey: priv, publicKey: pub, appId: app.app_id, name: app.name }
|
||||||
}
|
}
|
||||||
|
|
||||||
async AddApplicationUser(application: Application, userIdentifier: string, balance: number, nostrPub?: string) {
|
async AddApplicationUser(application: Application, userIdentifier: string, balance: number, nostrPub?: string) {
|
||||||
return this.DB.transaction(async tx => {
|
return this.DB.transaction(async tx => {
|
||||||
const user = await this.userStorage.AddUser(balance, tx)
|
const user = await this.userStorage.AddUser(balance, tx)
|
||||||
const repo = tx.getRepository(ApplicationUser)
|
const repo = tx.getRepository(ApplicationUser)
|
||||||
const appUser = repo.create({
|
const appUser = repo.create({
|
||||||
user: user,
|
user: user,
|
||||||
application,
|
application,
|
||||||
identifier: userIdentifier,
|
identifier: userIdentifier,
|
||||||
nostr_public_key: nostrPub
|
nostr_public_key: nostrPub
|
||||||
})
|
})
|
||||||
return repo.save(appUser)
|
return repo.save(appUser)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async GetApplicationUserIfExists(application: Application, userIdentifier: string, entityManager = this.DB): Promise<ApplicationUser | null> {
|
async GetApplicationUserIfExists(application: Application, userIdentifier: string, entityManager = this.DB): Promise<ApplicationUser | null> {
|
||||||
return entityManager.getRepository(ApplicationUser).findOne({ where: { identifier: userIdentifier, application: { serial_id: application.serial_id } } })
|
return entityManager.getRepository(ApplicationUser).findOne({ where: { identifier: userIdentifier, application: { serial_id: application.serial_id } } })
|
||||||
}
|
}
|
||||||
|
|
||||||
async GetOrCreateNostrAppUser(application: Application, nostrPub: string, entityManager = this.DB): Promise<ApplicationUser> {
|
async GetOrCreateNostrAppUser(application: Application, nostrPub: string, entityManager = this.DB): Promise<ApplicationUser> {
|
||||||
if (!nostrPub) {
|
if (!nostrPub) {
|
||||||
throw new Error("no nostrPub provided")
|
throw new Error("no nostrPub provided")
|
||||||
}
|
}
|
||||||
const user = await entityManager.getRepository(ApplicationUser).findOne({ where: { nostr_public_key: nostrPub } })
|
const user = await entityManager.getRepository(ApplicationUser).findOne({ where: { nostr_public_key: nostrPub } })
|
||||||
if (user) {
|
if (user) {
|
||||||
//if (user.application.app_id !== application.app_id) {
|
//if (user.application.app_id !== application.app_id) {
|
||||||
// throw new Error("tried to access a user of application:" + user.application.app_id + "from application:" + application.app_id)
|
// throw new Error("tried to access a user of application:" + user.application.app_id + "from application:" + application.app_id)
|
||||||
//}
|
//}
|
||||||
return user
|
return user
|
||||||
}
|
}
|
||||||
if (!application.allow_user_creation) {
|
if (!application.allow_user_creation) {
|
||||||
throw new Error("user creation by client is not allowed in this app")
|
throw new Error("user creation by client is not allowed in this app")
|
||||||
}
|
}
|
||||||
return this.AddApplicationUser(application, crypto.randomBytes(32).toString('hex'), 0, nostrPub)
|
return this.AddApplicationUser(application, crypto.randomBytes(32).toString('hex'), 0, nostrPub)
|
||||||
}
|
}
|
||||||
|
|
||||||
async FindNostrAppUser(nostrPub: string, entityManager = this.DB) {
|
async FindNostrAppUser(nostrPub: string, entityManager = this.DB) {
|
||||||
return entityManager.getRepository(ApplicationUser).findOne({ where: { nostr_public_key: nostrPub } })
|
return entityManager.getRepository(ApplicationUser).findOne({ where: { nostr_public_key: nostrPub } })
|
||||||
}
|
}
|
||||||
|
|
||||||
async GetOrCreateApplicationUser(application: Application, userIdentifier: string, balance: number, entityManager = this.DB): Promise<{ user: ApplicationUser, created: boolean }> {
|
async GetOrCreateApplicationUser(application: Application, userIdentifier: string, balance: number, entityManager = this.DB): Promise<{ user: ApplicationUser, created: boolean }> {
|
||||||
const user = await this.GetApplicationUserIfExists(application, userIdentifier, entityManager)
|
const user = await this.GetApplicationUserIfExists(application, userIdentifier, entityManager)
|
||||||
if (user) {
|
if (user) {
|
||||||
return { user, created: false }
|
return { user, created: false }
|
||||||
}
|
}
|
||||||
return { user: await this.AddApplicationUser(application, userIdentifier, balance), created: true }
|
return { user: await this.AddApplicationUser(application, userIdentifier, balance), created: true }
|
||||||
}
|
}
|
||||||
|
|
||||||
async GetApplicationUser(application: Application, userIdentifier: string, entityManager = this.DB): Promise<ApplicationUser> {
|
async GetApplicationUser(application: Application, userIdentifier: string, entityManager = this.DB): Promise<ApplicationUser> {
|
||||||
const found = await this.GetApplicationUserIfExists(application, userIdentifier, entityManager)
|
const found = await this.GetApplicationUserIfExists(application, userIdentifier, entityManager)
|
||||||
if (!found) {
|
if (!found) {
|
||||||
getLogger({ appName: application.name })("user", userIdentifier, "not found", application.name)
|
getLogger({ appName: application.name })("user", userIdentifier, "not found", application.name)
|
||||||
throw new Error(`application user not found`)
|
throw new Error(`application user not found`)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (found.application.app_id !== application.app_id) {
|
if (found.application.app_id !== application.app_id) {
|
||||||
throw new Error("requested user does not belong to requestor application")
|
throw new Error("requested user does not belong to requestor application")
|
||||||
}
|
}
|
||||||
return found
|
return found
|
||||||
}
|
}
|
||||||
|
|
||||||
async GetApplicationUsers(application: Application | null, { from, to }: { from?: number, to?: number }, entityManager = this.DB) {
|
async GetApplicationUsers(application: Application | null, { from, to }: { from?: number, to?: number }, entityManager = this.DB) {
|
||||||
const q = application ? { app_id: application.app_id } : IsNull()
|
const q = application ? { app_id: application.app_id } : IsNull()
|
||||||
let time: { created_at?: FindOperator<Date> } = {}
|
let time: { created_at?: FindOperator<Date> } = {}
|
||||||
if (!!from && !!to) {
|
if (!!from && !!to) {
|
||||||
time.created_at = Between<Date>(new Date(from * 1000), new Date(to * 1000))
|
time.created_at = Between<Date>(new Date(from * 1000), new Date(to * 1000))
|
||||||
} else if (!!from) {
|
} else if (!!from) {
|
||||||
time.created_at = MoreThanOrEqual<Date>(new Date(from * 1000))
|
time.created_at = MoreThanOrEqual<Date>(new Date(from * 1000))
|
||||||
} else if (!!to) {
|
} else if (!!to) {
|
||||||
time.created_at = LessThanOrEqual<Date>(new Date(to * 1000))
|
time.created_at = LessThanOrEqual<Date>(new Date(to * 1000))
|
||||||
}
|
}
|
||||||
return entityManager.getRepository(ApplicationUser).find({ where: { application: q, ...time } })
|
return entityManager.getRepository(ApplicationUser).find({ where: { application: q, ...time } })
|
||||||
}
|
}
|
||||||
|
|
||||||
async GetAppUserFromUser(application: Application, userId: string, entityManager = this.DB): Promise<ApplicationUser | null> {
|
async GetAppUserFromUser(application: Application, userId: string, entityManager = this.DB): Promise<ApplicationUser | null> {
|
||||||
return entityManager.getRepository(ApplicationUser).findOne({ where: { user: { user_id: userId }, application: { app_id: application.app_id } } })
|
return entityManager.getRepository(ApplicationUser).findOne({ where: { user: { user_id: userId }, application: { app_id: application.app_id } } })
|
||||||
}
|
}
|
||||||
|
|
||||||
async GetAllAppUsersFromUser(userId: string, entityManager = this.DB): Promise<ApplicationUser[]> {
|
async GetAllAppUsersFromUser(userId: string, entityManager = this.DB): Promise<ApplicationUser[]> {
|
||||||
return entityManager.getRepository(ApplicationUser).find({ where: { user: { user_id: userId } } })
|
return entityManager.getRepository(ApplicationUser).find({ where: { user: { user_id: userId } } })
|
||||||
}
|
}
|
||||||
|
|
||||||
async IsApplicationOwner(userId: string, entityManager = this.DB) {
|
async IsApplicationOwner(userId: string, entityManager = this.DB) {
|
||||||
return entityManager.getRepository(Application).findOne({ where: { owner: { user_id: userId } } })
|
return entityManager.getRepository(Application).findOne({ where: { owner: { user_id: userId } } })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
async AddNPubToApplicationUser(serialId: number, nPub: string, entityManager = this.DB) {
|
async AddNPubToApplicationUser(serialId: number, nPub: string, entityManager = this.DB) {
|
||||||
return entityManager.getRepository(ApplicationUser).update(serialId, { nostr_public_key: nPub })
|
return entityManager.getRepository(ApplicationUser).update(serialId, { nostr_public_key: nPub })
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
async RemoveApplicationUserAndBaseUser(appUser: ApplicationUser, entityManager = this.DB) {
|
async RemoveApplicationUserAndBaseUser(appUser: ApplicationUser, entityManager = this.DB) {
|
||||||
const baseUser = appUser.user;
|
const baseUser = appUser.user;
|
||||||
await entityManager.getRepository(ApplicationUser).remove(appUser);
|
await entityManager.getRepository(ApplicationUser).remove(appUser);
|
||||||
await entityManager.getRepository(User).remove(baseUser);
|
await entityManager.getRepository(User).remove(baseUser);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,45 +1,45 @@
|
||||||
import { Entity, PrimaryGeneratedColumn, Column, Index, Check, ManyToOne, JoinColumn, CreateDateColumn, UpdateDateColumn } from "typeorm"
|
import { Entity, PrimaryGeneratedColumn, Column, Index, Check, ManyToOne, JoinColumn, CreateDateColumn, UpdateDateColumn } from "typeorm"
|
||||||
|
|
||||||
import { UserReceivingAddress } from "./UserReceivingAddress.js"
|
import { UserReceivingAddress } from "./UserReceivingAddress.js"
|
||||||
|
|
||||||
@Entity()
|
@Entity()
|
||||||
@Index("address_receiving_transaction_unique", ["tx_hash", "output_index"], { unique: true })
|
@Index("address_receiving_transaction_unique", ["tx_hash", "output_index"], { unique: true })
|
||||||
export class AddressReceivingTransaction {
|
export class AddressReceivingTransaction {
|
||||||
|
|
||||||
@PrimaryGeneratedColumn()
|
@PrimaryGeneratedColumn()
|
||||||
serial_id: number
|
serial_id: number
|
||||||
|
|
||||||
@ManyToOne(type => UserReceivingAddress, { eager: true })
|
@ManyToOne(type => UserReceivingAddress, { eager: true })
|
||||||
@JoinColumn()
|
@JoinColumn()
|
||||||
user_address: UserReceivingAddress
|
user_address: UserReceivingAddress
|
||||||
|
|
||||||
@Column()
|
@Column()
|
||||||
tx_hash: string
|
tx_hash: string
|
||||||
|
|
||||||
@Column()
|
@Column()
|
||||||
output_index: number
|
output_index: number
|
||||||
|
|
||||||
@Column()
|
@Column()
|
||||||
paid_amount: number
|
paid_amount: number
|
||||||
|
|
||||||
@Column()
|
@Column()
|
||||||
service_fee: number
|
service_fee: number
|
||||||
|
|
||||||
@Column()
|
@Column()
|
||||||
paid_at_unix: number
|
paid_at_unix: number
|
||||||
|
|
||||||
@Column({ default: false })
|
@Column({ default: false })
|
||||||
internal: boolean
|
internal: boolean
|
||||||
|
|
||||||
@Column({ default: 0 })
|
@Column({ default: 0 })
|
||||||
confs: number
|
confs: number
|
||||||
|
|
||||||
@Column({ default: 0 })
|
@Column({ default: 0 })
|
||||||
broadcast_height: number
|
broadcast_height: number
|
||||||
|
|
||||||
@CreateDateColumn()
|
@CreateDateColumn()
|
||||||
created_at: Date
|
created_at: Date
|
||||||
|
|
||||||
@UpdateDateColumn()
|
@UpdateDateColumn()
|
||||||
updated_at: Date
|
updated_at: Date
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,35 +1,35 @@
|
||||||
import { Entity, PrimaryGeneratedColumn, Column, Index, Check, CreateDateColumn, UpdateDateColumn, JoinColumn, ManyToOne } from "typeorm"
|
import { Entity, PrimaryGeneratedColumn, Column, Index, Check, CreateDateColumn, UpdateDateColumn, JoinColumn, ManyToOne } from "typeorm"
|
||||||
import { User } from "./User.js"
|
import { User } from "./User.js"
|
||||||
|
|
||||||
@Entity()
|
@Entity()
|
||||||
export class Application {
|
export class Application {
|
||||||
|
|
||||||
@PrimaryGeneratedColumn()
|
@PrimaryGeneratedColumn()
|
||||||
serial_id: number
|
serial_id: number
|
||||||
|
|
||||||
@Column()
|
@Column()
|
||||||
@Index({ unique: true })
|
@Index({ unique: true })
|
||||||
app_id: string
|
app_id: string
|
||||||
|
|
||||||
@Column({ unique: true })
|
@Column({ unique: true })
|
||||||
name: string
|
name: string
|
||||||
|
|
||||||
@ManyToOne(type => User, { eager: true })
|
@ManyToOne(type => User, { eager: true })
|
||||||
@JoinColumn()
|
@JoinColumn()
|
||||||
owner: User
|
owner: User
|
||||||
|
|
||||||
@Column({ default: false })
|
@Column({ default: false })
|
||||||
allow_user_creation: boolean
|
allow_user_creation: boolean
|
||||||
|
|
||||||
@Column({ nullable: true, unique: true })
|
@Column({ nullable: true, unique: true })
|
||||||
nostr_private_key?: string
|
nostr_private_key?: string
|
||||||
|
|
||||||
@Column({ nullable: true, unique: true })
|
@Column({ nullable: true, unique: true })
|
||||||
nostr_public_key?: string
|
nostr_public_key?: string
|
||||||
|
|
||||||
@CreateDateColumn()
|
@CreateDateColumn()
|
||||||
created_at: Date
|
created_at: Date
|
||||||
|
|
||||||
@UpdateDateColumn()
|
@UpdateDateColumn()
|
||||||
updated_at: Date
|
updated_at: Date
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,31 +1,31 @@
|
||||||
import { Entity, PrimaryGeneratedColumn, Column, Index, JoinColumn, OneToOne, OneToMany, ManyToOne, CreateDateColumn, UpdateDateColumn } from "typeorm"
|
import { Entity, PrimaryGeneratedColumn, Column, Index, JoinColumn, OneToOne, OneToMany, ManyToOne, CreateDateColumn, UpdateDateColumn } from "typeorm"
|
||||||
import { User } from "./User.js"
|
import { User } from "./User.js"
|
||||||
import { Application } from "./Application.js"
|
import { Application } from "./Application.js"
|
||||||
|
|
||||||
@Entity()
|
@Entity()
|
||||||
export class ApplicationUser {
|
export class ApplicationUser {
|
||||||
|
|
||||||
@PrimaryGeneratedColumn()
|
@PrimaryGeneratedColumn()
|
||||||
serial_id: number
|
serial_id: number
|
||||||
|
|
||||||
@OneToOne(type => User, { eager: true })
|
@OneToOne(type => User, { eager: true })
|
||||||
@JoinColumn()
|
@JoinColumn()
|
||||||
user: User
|
user: User
|
||||||
|
|
||||||
@ManyToOne(type => Application, { eager: true })
|
@ManyToOne(type => Application, { eager: true })
|
||||||
@JoinColumn()
|
@JoinColumn()
|
||||||
application: Application
|
application: Application
|
||||||
|
|
||||||
@Column()
|
@Column()
|
||||||
@Index({ unique: true })
|
@Index({ unique: true })
|
||||||
identifier: string
|
identifier: string
|
||||||
|
|
||||||
@Column({ nullable: true, unique: true })
|
@Column({ nullable: true, unique: true })
|
||||||
nostr_public_key?: string
|
nostr_public_key?: string
|
||||||
|
|
||||||
@CreateDateColumn()
|
@CreateDateColumn()
|
||||||
created_at: Date
|
created_at: Date
|
||||||
|
|
||||||
@UpdateDateColumn()
|
@UpdateDateColumn()
|
||||||
updated_at: Date
|
updated_at: Date
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,25 +1,25 @@
|
||||||
import { Entity, PrimaryGeneratedColumn, Column, Index, Check, CreateDateColumn, UpdateDateColumn } from "typeorm"
|
import { Entity, PrimaryGeneratedColumn, Column, Index, Check, CreateDateColumn, UpdateDateColumn } from "typeorm"
|
||||||
|
|
||||||
@Entity()
|
@Entity()
|
||||||
export class BalanceEvent {
|
export class BalanceEvent {
|
||||||
@PrimaryGeneratedColumn()
|
@PrimaryGeneratedColumn()
|
||||||
serial_id: number
|
serial_id: number
|
||||||
|
|
||||||
@Column()
|
@Column()
|
||||||
block_height: number
|
block_height: number
|
||||||
|
|
||||||
@Column()
|
@Column()
|
||||||
confirmed_chain_balance: number
|
confirmed_chain_balance: number
|
||||||
|
|
||||||
@Column()
|
@Column()
|
||||||
unconfirmed_chain_balance: number
|
unconfirmed_chain_balance: number
|
||||||
|
|
||||||
@Column()
|
@Column()
|
||||||
total_chain_balance: number
|
total_chain_balance: number
|
||||||
|
|
||||||
@CreateDateColumn()
|
@CreateDateColumn()
|
||||||
created_at: Date
|
created_at: Date
|
||||||
|
|
||||||
@UpdateDateColumn()
|
@UpdateDateColumn()
|
||||||
updated_at: Date
|
updated_at: Date
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,46 +1,46 @@
|
||||||
import { Entity, PrimaryGeneratedColumn, Column, Index, Check, CreateDateColumn, UpdateDateColumn } from "typeorm"
|
import { Entity, PrimaryGeneratedColumn, Column, Index, Check, CreateDateColumn, UpdateDateColumn } from "typeorm"
|
||||||
|
|
||||||
@Entity()
|
@Entity()
|
||||||
export class ChannelRouting {
|
export class ChannelRouting {
|
||||||
@PrimaryGeneratedColumn()
|
@PrimaryGeneratedColumn()
|
||||||
serial_id: number
|
serial_id: number
|
||||||
|
|
||||||
@Column()
|
@Column()
|
||||||
day_unix: number
|
day_unix: number
|
||||||
|
|
||||||
@Column()
|
@Column()
|
||||||
channel_id: string
|
channel_id: string
|
||||||
|
|
||||||
@Column({ default: 0 })
|
@Column({ default: 0 })
|
||||||
send_errors: number
|
send_errors: number
|
||||||
|
|
||||||
@Column({ default: 0 })
|
@Column({ default: 0 })
|
||||||
receive_errors: number
|
receive_errors: number
|
||||||
|
|
||||||
@Column({ default: 0 })
|
@Column({ default: 0 })
|
||||||
forward_errors_as_input: number
|
forward_errors_as_input: number
|
||||||
|
|
||||||
@Column({ default: 0 })
|
@Column({ default: 0 })
|
||||||
forward_errors_as_output: number
|
forward_errors_as_output: number
|
||||||
|
|
||||||
@Column({ default: 0 })
|
@Column({ default: 0 })
|
||||||
missed_forward_fee_as_input: number
|
missed_forward_fee_as_input: number
|
||||||
|
|
||||||
@Column({ default: 0 })
|
@Column({ default: 0 })
|
||||||
missed_forward_fee_as_output: number
|
missed_forward_fee_as_output: number
|
||||||
|
|
||||||
@Column({ default: 0 })
|
@Column({ default: 0 })
|
||||||
forward_fee_as_input: number
|
forward_fee_as_input: number
|
||||||
|
|
||||||
@Column({ default: 0 })
|
@Column({ default: 0 })
|
||||||
forward_fee_as_output: number
|
forward_fee_as_output: number
|
||||||
|
|
||||||
@Column({ default: 0 })
|
@Column({ default: 0 })
|
||||||
latest_index_offset: number
|
latest_index_offset: number
|
||||||
|
|
||||||
@CreateDateColumn()
|
@CreateDateColumn()
|
||||||
created_at: Date
|
created_at: Date
|
||||||
|
|
||||||
@UpdateDateColumn()
|
@UpdateDateColumn()
|
||||||
updated_at: Date
|
updated_at: Date
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,27 +1,27 @@
|
||||||
import { Entity, PrimaryGeneratedColumn, Column, Index, Check, CreateDateColumn, UpdateDateColumn, ManyToOne, JoinColumn } from "typeorm"
|
import { Entity, PrimaryGeneratedColumn, Column, Index, Check, CreateDateColumn, UpdateDateColumn, ManyToOne, JoinColumn } from "typeorm"
|
||||||
import { BalanceEvent } from "./BalanceEvent.js"
|
import { BalanceEvent } from "./BalanceEvent.js"
|
||||||
|
|
||||||
@Entity()
|
@Entity()
|
||||||
export class ChannelBalanceEvent {
|
export class ChannelBalanceEvent {
|
||||||
@PrimaryGeneratedColumn()
|
@PrimaryGeneratedColumn()
|
||||||
serial_id: number
|
serial_id: number
|
||||||
|
|
||||||
@ManyToOne(type => BalanceEvent, { eager: true })
|
@ManyToOne(type => BalanceEvent, { eager: true })
|
||||||
@JoinColumn()
|
@JoinColumn()
|
||||||
balance_event: BalanceEvent
|
balance_event: BalanceEvent
|
||||||
|
|
||||||
@Column()
|
@Column()
|
||||||
channel_id: string
|
channel_id: string
|
||||||
|
|
||||||
@Column()
|
@Column()
|
||||||
local_balance_sats: number
|
local_balance_sats: number
|
||||||
|
|
||||||
@Column()
|
@Column()
|
||||||
remote_balance_sats: number
|
remote_balance_sats: number
|
||||||
|
|
||||||
@CreateDateColumn()
|
@CreateDateColumn()
|
||||||
created_at: Date
|
created_at: Date
|
||||||
|
|
||||||
@UpdateDateColumn()
|
@UpdateDateColumn()
|
||||||
updated_at: Date
|
updated_at: Date
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,24 +1,24 @@
|
||||||
import { Entity, PrimaryGeneratedColumn, Column, ManyToOne, CreateDateColumn, UpdateDateColumn } from "typeorm"
|
import { Entity, PrimaryGeneratedColumn, Column, ManyToOne, CreateDateColumn, UpdateDateColumn } from "typeorm"
|
||||||
import { User } from "./User.js"
|
import { User } from "./User.js"
|
||||||
|
|
||||||
@Entity()
|
@Entity()
|
||||||
export class Product {
|
export class Product {
|
||||||
|
|
||||||
@PrimaryGeneratedColumn('uuid')
|
@PrimaryGeneratedColumn('uuid')
|
||||||
product_id: string
|
product_id: string
|
||||||
|
|
||||||
@ManyToOne(type => User, { eager: true })
|
@ManyToOne(type => User, { eager: true })
|
||||||
owner: User
|
owner: User
|
||||||
|
|
||||||
@Column()
|
@Column()
|
||||||
name: string
|
name: string
|
||||||
|
|
||||||
@Column()
|
@Column()
|
||||||
price_sats: number
|
price_sats: number
|
||||||
|
|
||||||
@CreateDateColumn()
|
@CreateDateColumn()
|
||||||
created_at: Date
|
created_at: Date
|
||||||
|
|
||||||
@UpdateDateColumn()
|
@UpdateDateColumn()
|
||||||
updated_at: Date
|
updated_at: Date
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,23 +1,23 @@
|
||||||
import { Entity, PrimaryGeneratedColumn, Column, Index, Check, CreateDateColumn, UpdateDateColumn } from "typeorm"
|
import { Entity, PrimaryGeneratedColumn, Column, Index, Check, CreateDateColumn, UpdateDateColumn } from "typeorm"
|
||||||
|
|
||||||
@Entity()
|
@Entity()
|
||||||
export class User {
|
export class User {
|
||||||
@PrimaryGeneratedColumn()
|
@PrimaryGeneratedColumn()
|
||||||
serial_id: number
|
serial_id: number
|
||||||
|
|
||||||
@Column()
|
@Column()
|
||||||
@Index({ unique: true })
|
@Index({ unique: true })
|
||||||
user_id: string
|
user_id: string
|
||||||
|
|
||||||
@Column({ type: 'integer', default: 0 })
|
@Column({ type: 'integer', default: 0 })
|
||||||
balance_sats: number
|
balance_sats: number
|
||||||
|
|
||||||
@Column({ default: false })
|
@Column({ default: false })
|
||||||
locked: boolean
|
locked: boolean
|
||||||
|
|
||||||
@CreateDateColumn()
|
@CreateDateColumn()
|
||||||
created_at: Date
|
created_at: Date
|
||||||
|
|
||||||
@UpdateDateColumn()
|
@UpdateDateColumn()
|
||||||
updated_at: Date
|
updated_at: Date
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,26 +1,26 @@
|
||||||
import { Entity, PrimaryGeneratedColumn, Column, Index, JoinColumn, OneToOne, CreateDateColumn, UpdateDateColumn } from "typeorm"
|
import { Entity, PrimaryGeneratedColumn, Column, Index, JoinColumn, OneToOne, CreateDateColumn, UpdateDateColumn } from "typeorm"
|
||||||
import { User } from "./User.js"
|
import { User } from "./User.js"
|
||||||
|
|
||||||
@Entity()
|
@Entity()
|
||||||
export class UserBasicAuth {
|
export class UserBasicAuth {
|
||||||
|
|
||||||
@PrimaryGeneratedColumn()
|
@PrimaryGeneratedColumn()
|
||||||
serial_id: number
|
serial_id: number
|
||||||
|
|
||||||
@OneToOne(type => User, { eager: true })
|
@OneToOne(type => User, { eager: true })
|
||||||
@JoinColumn()
|
@JoinColumn()
|
||||||
user: User
|
user: User
|
||||||
|
|
||||||
@Column()
|
@Column()
|
||||||
@Index({ unique: true })
|
@Index({ unique: true })
|
||||||
name: string
|
name: string
|
||||||
|
|
||||||
@Column()
|
@Column()
|
||||||
secret_sha256: string
|
secret_sha256: string
|
||||||
|
|
||||||
@CreateDateColumn()
|
@CreateDateColumn()
|
||||||
created_at: Date
|
created_at: Date
|
||||||
|
|
||||||
@UpdateDateColumn()
|
@UpdateDateColumn()
|
||||||
updated_at: Date
|
updated_at: Date
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,31 +1,31 @@
|
||||||
import { Entity, PrimaryGeneratedColumn, Column, Index, Check, ManyToOne, JoinColumn, CreateDateColumn, UpdateDateColumn } from "typeorm"
|
import { Entity, PrimaryGeneratedColumn, Column, Index, Check, ManyToOne, JoinColumn, CreateDateColumn, UpdateDateColumn } from "typeorm"
|
||||||
import { User } from "./User.js"
|
import { User } from "./User.js"
|
||||||
import { Application } from "./Application.js"
|
import { Application } from "./Application.js"
|
||||||
export type EphemeralKeyType = 'balanceCheck' | 'withdraw' | 'pay'
|
export type EphemeralKeyType = 'balanceCheck' | 'withdraw' | 'pay'
|
||||||
@Entity()
|
@Entity()
|
||||||
export class UserEphemeralKey {
|
export class UserEphemeralKey {
|
||||||
|
|
||||||
@PrimaryGeneratedColumn()
|
@PrimaryGeneratedColumn()
|
||||||
serial_id: number
|
serial_id: number
|
||||||
|
|
||||||
@ManyToOne(type => User, { eager: true })
|
@ManyToOne(type => User, { eager: true })
|
||||||
@JoinColumn()
|
@JoinColumn()
|
||||||
user: User
|
user: User
|
||||||
|
|
||||||
@ManyToOne(type => Application, { eager: true })
|
@ManyToOne(type => Application, { eager: true })
|
||||||
@JoinColumn()
|
@JoinColumn()
|
||||||
linkedApplication: Application | null
|
linkedApplication: Application | null
|
||||||
|
|
||||||
@Column()
|
@Column()
|
||||||
@Index({ unique: true })
|
@Index({ unique: true })
|
||||||
key: string
|
key: string
|
||||||
|
|
||||||
@Column()
|
@Column()
|
||||||
type: EphemeralKeyType
|
type: EphemeralKeyType
|
||||||
|
|
||||||
@CreateDateColumn()
|
@CreateDateColumn()
|
||||||
created_at: Date
|
created_at: Date
|
||||||
|
|
||||||
@UpdateDateColumn()
|
@UpdateDateColumn()
|
||||||
updated_at: Date
|
updated_at: Date
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,30 +1,30 @@
|
||||||
import { Entity, PrimaryGeneratedColumn, Column, Index, Check, ManyToOne, JoinColumn, CreateDateColumn, UpdateDateColumn } from "typeorm"
|
import { Entity, PrimaryGeneratedColumn, Column, Index, Check, ManyToOne, JoinColumn, CreateDateColumn, UpdateDateColumn } from "typeorm"
|
||||||
import { User } from "./User.js"
|
import { User } from "./User.js"
|
||||||
import { Application } from "./Application.js"
|
import { Application } from "./Application.js"
|
||||||
|
|
||||||
@Entity()
|
@Entity()
|
||||||
export class UserReceivingAddress {
|
export class UserReceivingAddress {
|
||||||
|
|
||||||
@PrimaryGeneratedColumn()
|
@PrimaryGeneratedColumn()
|
||||||
serial_id: number
|
serial_id: number
|
||||||
|
|
||||||
@ManyToOne(type => User, { eager: true })
|
@ManyToOne(type => User, { eager: true })
|
||||||
@JoinColumn()
|
@JoinColumn()
|
||||||
user: User
|
user: User
|
||||||
|
|
||||||
@Column()
|
@Column()
|
||||||
@Index({ unique: true })
|
@Index({ unique: true })
|
||||||
address: string
|
address: string
|
||||||
|
|
||||||
@Column()
|
@Column()
|
||||||
callbackUrl: string
|
callbackUrl: string
|
||||||
|
|
||||||
@ManyToOne(type => Application, { eager: true })
|
@ManyToOne(type => Application, { eager: true })
|
||||||
linkedApplication: Application | null
|
linkedApplication: Application | null
|
||||||
|
|
||||||
@CreateDateColumn()
|
@CreateDateColumn()
|
||||||
created_at: Date
|
created_at: Date
|
||||||
|
|
||||||
@UpdateDateColumn()
|
@UpdateDateColumn()
|
||||||
updated_at: Date
|
updated_at: Date
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,36 +1,36 @@
|
||||||
import { Entity, PrimaryGeneratedColumn, Column, Index, Check, ManyToOne, JoinColumn, CreateDateColumn, UpdateDateColumn } from "typeorm"
|
import { Entity, PrimaryGeneratedColumn, Column, Index, Check, ManyToOne, JoinColumn, CreateDateColumn, UpdateDateColumn } from "typeorm"
|
||||||
import { User } from "./User.js"
|
import { User } from "./User.js"
|
||||||
import { Application } from "./Application.js"
|
import { Application } from "./Application.js"
|
||||||
|
|
||||||
@Entity()
|
@Entity()
|
||||||
export class UserToUserPayment {
|
export class UserToUserPayment {
|
||||||
|
|
||||||
@PrimaryGeneratedColumn()
|
@PrimaryGeneratedColumn()
|
||||||
serial_id: number
|
serial_id: number
|
||||||
|
|
||||||
@ManyToOne(type => User, { eager: true })
|
@ManyToOne(type => User, { eager: true })
|
||||||
@JoinColumn()
|
@JoinColumn()
|
||||||
from_user: User
|
from_user: User
|
||||||
|
|
||||||
@ManyToOne(type => User, { eager: true })
|
@ManyToOne(type => User, { eager: true })
|
||||||
@JoinColumn()
|
@JoinColumn()
|
||||||
to_user: User
|
to_user: User
|
||||||
|
|
||||||
@Column()
|
@Column()
|
||||||
paid_amount: number
|
paid_amount: number
|
||||||
|
|
||||||
@Column()
|
@Column()
|
||||||
service_fees: number
|
service_fees: number
|
||||||
|
|
||||||
@Column()
|
@Column()
|
||||||
paid_at_unix: number
|
paid_at_unix: number
|
||||||
|
|
||||||
@ManyToOne(type => Application, { eager: true })
|
@ManyToOne(type => Application, { eager: true })
|
||||||
linkedApplication: Application | null
|
linkedApplication: Application | null
|
||||||
|
|
||||||
@CreateDateColumn()
|
@CreateDateColumn()
|
||||||
created_at: Date
|
created_at: Date
|
||||||
|
|
||||||
@UpdateDateColumn()
|
@UpdateDateColumn()
|
||||||
updated_at: Date
|
updated_at: Date
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,54 +1,54 @@
|
||||||
import { Entity, PrimaryGeneratedColumn, Column, Index, Check, ManyToOne, JoinColumn, CreateDateColumn, UpdateDateColumn } from "typeorm"
|
import { Entity, PrimaryGeneratedColumn, Column, Index, Check, ManyToOne, JoinColumn, CreateDateColumn, UpdateDateColumn } from "typeorm"
|
||||||
import { User } from "./User.js"
|
import { User } from "./User.js"
|
||||||
import { Application } from "./Application.js"
|
import { Application } from "./Application.js"
|
||||||
|
|
||||||
@Entity()
|
@Entity()
|
||||||
@Index("user_transaction_unique", ["tx_hash", "output_index"], { unique: true })
|
@Index("user_transaction_unique", ["tx_hash", "output_index"], { unique: true })
|
||||||
export class UserTransactionPayment {
|
export class UserTransactionPayment {
|
||||||
|
|
||||||
@PrimaryGeneratedColumn()
|
@PrimaryGeneratedColumn()
|
||||||
serial_id: number
|
serial_id: number
|
||||||
|
|
||||||
@ManyToOne(type => User, { eager: true })
|
@ManyToOne(type => User, { eager: true })
|
||||||
@JoinColumn()
|
@JoinColumn()
|
||||||
user: User
|
user: User
|
||||||
|
|
||||||
@Column()
|
@Column()
|
||||||
address: string
|
address: string
|
||||||
|
|
||||||
@Column()
|
@Column()
|
||||||
tx_hash: string
|
tx_hash: string
|
||||||
|
|
||||||
@Column()
|
@Column()
|
||||||
output_index: number
|
output_index: number
|
||||||
|
|
||||||
@Column()
|
@Column()
|
||||||
paid_amount: number
|
paid_amount: number
|
||||||
|
|
||||||
@Column()
|
@Column()
|
||||||
chain_fees: number
|
chain_fees: number
|
||||||
|
|
||||||
@Column()
|
@Column()
|
||||||
service_fees: number
|
service_fees: number
|
||||||
|
|
||||||
@Column()
|
@Column()
|
||||||
paid_at_unix: number
|
paid_at_unix: number
|
||||||
|
|
||||||
@Column({ default: false })
|
@Column({ default: false })
|
||||||
internal: boolean
|
internal: boolean
|
||||||
|
|
||||||
@Column({ default: 0 })
|
@Column({ default: 0 })
|
||||||
confs: number
|
confs: number
|
||||||
|
|
||||||
@Column({ default: 0 })
|
@Column({ default: 0 })
|
||||||
broadcast_height: number
|
broadcast_height: number
|
||||||
|
|
||||||
@ManyToOne(type => Application, { eager: true })
|
@ManyToOne(type => Application, { eager: true })
|
||||||
linkedApplication: Application | null
|
linkedApplication: Application | null
|
||||||
|
|
||||||
@CreateDateColumn()
|
@CreateDateColumn()
|
||||||
created_at: Date
|
created_at: Date
|
||||||
|
|
||||||
@UpdateDateColumn()
|
@UpdateDateColumn()
|
||||||
updated_at: Date
|
updated_at: Date
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,114 +1,114 @@
|
||||||
import { Between, DataSource, EntityManager, FindOperator, LessThanOrEqual, MoreThanOrEqual } from "typeorm"
|
import { Between, DataSource, EntityManager, FindOperator, LessThanOrEqual, MoreThanOrEqual } from "typeorm"
|
||||||
import { BalanceEvent } from "./entity/BalanceEvent.js"
|
import { BalanceEvent } from "./entity/BalanceEvent.js"
|
||||||
import { ChannelBalanceEvent } from "./entity/ChannelsBalanceEvent.js"
|
import { ChannelBalanceEvent } from "./entity/ChannelsBalanceEvent.js"
|
||||||
import TransactionsQueue, { TX } from "./transactionsQueue.js";
|
import TransactionsQueue, { TX } from "./transactionsQueue.js";
|
||||||
import { StorageSettings } from "./index.js";
|
import { StorageSettings } from "./index.js";
|
||||||
import { newMetricsDb } from "./db.js";
|
import { newMetricsDb } from "./db.js";
|
||||||
import { ChannelRouting } from "./entity/ChannelRouting.js";
|
import { ChannelRouting } from "./entity/ChannelRouting.js";
|
||||||
export default class {
|
export default class {
|
||||||
|
|
||||||
DB: DataSource | EntityManager
|
DB: DataSource | EntityManager
|
||||||
settings: StorageSettings
|
settings: StorageSettings
|
||||||
txQueue: TransactionsQueue
|
txQueue: TransactionsQueue
|
||||||
constructor(settings: StorageSettings) {
|
constructor(settings: StorageSettings) {
|
||||||
this.settings = settings;
|
this.settings = settings;
|
||||||
}
|
}
|
||||||
async Connect(metricsMigrations: Function[]) {
|
async Connect(metricsMigrations: Function[]) {
|
||||||
const { source, executedMigrations } = await newMetricsDb(this.settings.dbSettings, metricsMigrations)
|
const { source, executedMigrations } = await newMetricsDb(this.settings.dbSettings, metricsMigrations)
|
||||||
this.DB = source;
|
this.DB = source;
|
||||||
this.txQueue = new TransactionsQueue("metrics", this.DB)
|
this.txQueue = new TransactionsQueue("metrics", this.DB)
|
||||||
return executedMigrations;
|
return executedMigrations;
|
||||||
}
|
}
|
||||||
|
|
||||||
async SaveBalanceEvents(balanceEvent: Partial<BalanceEvent>, channelBalanceEvents: Partial<ChannelBalanceEvent>[]) {
|
async SaveBalanceEvents(balanceEvent: Partial<BalanceEvent>, channelBalanceEvents: Partial<ChannelBalanceEvent>[]) {
|
||||||
const blanceEventEntry = this.DB.getRepository(BalanceEvent).create(balanceEvent)
|
const blanceEventEntry = this.DB.getRepository(BalanceEvent).create(balanceEvent)
|
||||||
const balanceEntry = await this.txQueue.PushToQueue<BalanceEvent>({ exec: async db => db.getRepository(BalanceEvent).save(blanceEventEntry), dbTx: false })
|
const balanceEntry = await this.txQueue.PushToQueue<BalanceEvent>({ exec: async db => db.getRepository(BalanceEvent).save(blanceEventEntry), dbTx: false })
|
||||||
|
|
||||||
const channelsEntry = this.DB.getRepository(ChannelBalanceEvent).create(channelBalanceEvents.map(e => ({ ...e, balance_event: balanceEntry })))
|
const channelsEntry = this.DB.getRepository(ChannelBalanceEvent).create(channelBalanceEvents.map(e => ({ ...e, balance_event: balanceEntry })))
|
||||||
const channelsEntries = await this.txQueue.PushToQueue<ChannelBalanceEvent[]>({ exec: async db => db.getRepository(ChannelBalanceEvent).save(channelsEntry), dbTx: false })
|
const channelsEntries = await this.txQueue.PushToQueue<ChannelBalanceEvent[]>({ exec: async db => db.getRepository(ChannelBalanceEvent).save(channelsEntry), dbTx: false })
|
||||||
return { balanceEntry, channelsEntries }
|
return { balanceEntry, channelsEntries }
|
||||||
}
|
}
|
||||||
|
|
||||||
async GetBalanceEvents({ from, to }: { from?: number, to?: number }, entityManager = this.DB) {
|
async GetBalanceEvents({ from, to }: { from?: number, to?: number }, entityManager = this.DB) {
|
||||||
const q = getTimeQuery({ from, to })
|
const q = getTimeQuery({ from, to })
|
||||||
|
|
||||||
const [chainBalanceEvents, channelsBalanceEvents] = await Promise.all([
|
const [chainBalanceEvents, channelsBalanceEvents] = await Promise.all([
|
||||||
entityManager.getRepository(BalanceEvent).find(q),
|
entityManager.getRepository(BalanceEvent).find(q),
|
||||||
entityManager.getRepository(ChannelBalanceEvent).find(q),
|
entityManager.getRepository(ChannelBalanceEvent).find(q),
|
||||||
])
|
])
|
||||||
return { chainBalanceEvents, channelsBalanceEvents }
|
return { chainBalanceEvents, channelsBalanceEvents }
|
||||||
}
|
}
|
||||||
|
|
||||||
async initChannelRoutingEvent(dayUnix: number, channelId: string) {
|
async initChannelRoutingEvent(dayUnix: number, channelId: string) {
|
||||||
const existing = await this.DB.getRepository(ChannelRouting).findOne({ where: { day_unix: dayUnix, channel_id: channelId } })
|
const existing = await this.DB.getRepository(ChannelRouting).findOne({ where: { day_unix: dayUnix, channel_id: channelId } })
|
||||||
if (!existing) {
|
if (!existing) {
|
||||||
const entry = this.DB.getRepository(ChannelRouting).create({ day_unix: dayUnix, channel_id: channelId })
|
const entry = this.DB.getRepository(ChannelRouting).create({ day_unix: dayUnix, channel_id: channelId })
|
||||||
return this.txQueue.PushToQueue<ChannelRouting>({ exec: async db => db.getRepository(ChannelRouting).save(entry), dbTx: false })
|
return this.txQueue.PushToQueue<ChannelRouting>({ exec: async db => db.getRepository(ChannelRouting).save(entry), dbTx: false })
|
||||||
}
|
}
|
||||||
return existing
|
return existing
|
||||||
}
|
}
|
||||||
|
|
||||||
GetChannelRouting({ from, to }: { from?: number, to?: number }, entityManager = this.DB) {
|
GetChannelRouting({ from, to }: { from?: number, to?: number }, entityManager = this.DB) {
|
||||||
const q = getTimeQuery({ from, to })
|
const q = getTimeQuery({ from, to })
|
||||||
return entityManager.getRepository(ChannelRouting).find(q)
|
return entityManager.getRepository(ChannelRouting).find(q)
|
||||||
}
|
}
|
||||||
|
|
||||||
async GetLatestForwardingIndexOffset() {
|
async GetLatestForwardingIndexOffset() {
|
||||||
const latestIndex = await this.DB.getRepository(ChannelRouting).findOne({ order: { latest_index_offset: "DESC" } })
|
const latestIndex = await this.DB.getRepository(ChannelRouting).findOne({ order: { latest_index_offset: "DESC" } })
|
||||||
if (latestIndex) {
|
if (latestIndex) {
|
||||||
return latestIndex.latest_index_offset
|
return latestIndex.latest_index_offset
|
||||||
}
|
}
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
async IncrementChannelRouting(channelId: string, event: Partial<ChannelRouting>) {
|
async IncrementChannelRouting(channelId: string, event: Partial<ChannelRouting>) {
|
||||||
const dayUnix = getTodayUnix()
|
const dayUnix = getTodayUnix()
|
||||||
const existing = await this.initChannelRoutingEvent(dayUnix, channelId)
|
const existing = await this.initChannelRoutingEvent(dayUnix, channelId)
|
||||||
const repo = this.DB.getRepository(ChannelRouting)
|
const repo = this.DB.getRepository(ChannelRouting)
|
||||||
if (event.send_errors) {
|
if (event.send_errors) {
|
||||||
await repo.increment({ day_unix: dayUnix, channel_id: channelId }, "send_errors", event.send_errors)
|
await repo.increment({ day_unix: dayUnix, channel_id: channelId }, "send_errors", event.send_errors)
|
||||||
}
|
}
|
||||||
if (event.receive_errors) {
|
if (event.receive_errors) {
|
||||||
await repo.increment({ day_unix: dayUnix, channel_id: channelId }, "receive_errors", event.receive_errors)
|
await repo.increment({ day_unix: dayUnix, channel_id: channelId }, "receive_errors", event.receive_errors)
|
||||||
}
|
}
|
||||||
if (event.forward_errors_as_input) {
|
if (event.forward_errors_as_input) {
|
||||||
await repo.increment({ day_unix: dayUnix, channel_id: channelId }, "forward_errors_as_input", event.forward_errors_as_input)
|
await repo.increment({ day_unix: dayUnix, channel_id: channelId }, "forward_errors_as_input", event.forward_errors_as_input)
|
||||||
}
|
}
|
||||||
if (event.forward_errors_as_output) {
|
if (event.forward_errors_as_output) {
|
||||||
await repo.increment({ day_unix: dayUnix, channel_id: channelId }, "forward_errors_as_output", event.forward_errors_as_output)
|
await repo.increment({ day_unix: dayUnix, channel_id: channelId }, "forward_errors_as_output", event.forward_errors_as_output)
|
||||||
}
|
}
|
||||||
if (event.missed_forward_fee_as_input) {
|
if (event.missed_forward_fee_as_input) {
|
||||||
await repo.increment({ day_unix: dayUnix, channel_id: channelId }, "missed_forward_fee_as_input", event.missed_forward_fee_as_input)
|
await repo.increment({ day_unix: dayUnix, channel_id: channelId }, "missed_forward_fee_as_input", event.missed_forward_fee_as_input)
|
||||||
}
|
}
|
||||||
if (event.missed_forward_fee_as_output) {
|
if (event.missed_forward_fee_as_output) {
|
||||||
await repo.increment({ day_unix: dayUnix, channel_id: channelId }, "missed_forward_fee_as_output", event.missed_forward_fee_as_output)
|
await repo.increment({ day_unix: dayUnix, channel_id: channelId }, "missed_forward_fee_as_output", event.missed_forward_fee_as_output)
|
||||||
}
|
}
|
||||||
if (event.forward_fee_as_input) {
|
if (event.forward_fee_as_input) {
|
||||||
await repo.increment({ day_unix: dayUnix, channel_id: channelId }, "forward_fee_as_input", event.forward_fee_as_input)
|
await repo.increment({ day_unix: dayUnix, channel_id: channelId }, "forward_fee_as_input", event.forward_fee_as_input)
|
||||||
}
|
}
|
||||||
if (event.forward_fee_as_output) {
|
if (event.forward_fee_as_output) {
|
||||||
await repo.increment({ day_unix: dayUnix, channel_id: channelId }, "forward_fee_as_output", event.forward_fee_as_output)
|
await repo.increment({ day_unix: dayUnix, channel_id: channelId }, "forward_fee_as_output", event.forward_fee_as_output)
|
||||||
}
|
}
|
||||||
if (event.latest_index_offset) {
|
if (event.latest_index_offset) {
|
||||||
await repo.update(existing.serial_id, { latest_index_offset: event.latest_index_offset })
|
await repo.update(existing.serial_id, { latest_index_offset: event.latest_index_offset })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const getTimeQuery = ({ from, to }: { from?: number, to?: number }) => {
|
const getTimeQuery = ({ from, to }: { from?: number, to?: number }) => {
|
||||||
if (!!from && !!to) {
|
if (!!from && !!to) {
|
||||||
return { where: { created_at: Between<Date>(new Date(from * 1000), new Date(to * 1000)) } }
|
return { where: { created_at: Between<Date>(new Date(from * 1000), new Date(to * 1000)) } }
|
||||||
} else if (!!from) {
|
} else if (!!from) {
|
||||||
return { where: { created_at: MoreThanOrEqual<Date>(new Date(from * 1000)) } }
|
return { where: { created_at: MoreThanOrEqual<Date>(new Date(from * 1000)) } }
|
||||||
} else if (!!to) {
|
} else if (!!to) {
|
||||||
return { where: { created_at: LessThanOrEqual<Date>(new Date(to * 1000)) } }
|
return { where: { created_at: LessThanOrEqual<Date>(new Date(to * 1000)) } }
|
||||||
}
|
}
|
||||||
return {}
|
return {}
|
||||||
}
|
}
|
||||||
|
|
||||||
const getTodayUnix = () => {
|
const getTodayUnix = () => {
|
||||||
const now = new Date()
|
const now = new Date()
|
||||||
return new Date(now.getFullYear(), now.getMonth(), now.getDate()).getTime() / 1000
|
return new Date(now.getFullYear(), now.getMonth(), now.getDate()).getTime() / 1000
|
||||||
}
|
}
|
||||||
|
|
@ -1,180 +1,180 @@
|
||||||
import { MigrationInterface, QueryRunner } from "typeorm";
|
import { MigrationInterface, QueryRunner } from "typeorm";
|
||||||
|
|
||||||
export class Initial1703170309875 implements MigrationInterface {
|
export class Initial1703170309875 implements MigrationInterface {
|
||||||
name = 'Initial1703170309875'
|
name = 'Initial1703170309875'
|
||||||
|
|
||||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||||
await queryRunner.query(`CREATE TABLE "user" ("serial_id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "user_id" varchar NOT NULL, "balance_sats" integer NOT NULL DEFAULT (0), "locked" boolean NOT NULL DEFAULT (0), "created_at" datetime NOT NULL DEFAULT (datetime('now')), "updated_at" datetime NOT NULL DEFAULT (datetime('now')))`);
|
await queryRunner.query(`CREATE TABLE "user" ("serial_id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "user_id" varchar NOT NULL, "balance_sats" integer NOT NULL DEFAULT (0), "locked" boolean 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 "IDX_758b8ce7c18b9d347461b30228" ON "user" ("user_id") `);
|
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_758b8ce7c18b9d347461b30228" ON "user" ("user_id") `);
|
||||||
await queryRunner.query(`CREATE TABLE "product" ("product_id" varchar PRIMARY KEY NOT NULL, "name" varchar NOT NULL, "price_sats" integer NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "updated_at" datetime NOT NULL DEFAULT (datetime('now')), "ownerSerialId" integer)`);
|
await queryRunner.query(`CREATE TABLE "product" ("product_id" varchar PRIMARY KEY NOT NULL, "name" varchar NOT NULL, "price_sats" integer NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "updated_at" datetime NOT NULL DEFAULT (datetime('now')), "ownerSerialId" integer)`);
|
||||||
await queryRunner.query(`CREATE TABLE "application" ("serial_id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "app_id" varchar NOT NULL, "name" varchar NOT NULL, "allow_user_creation" boolean NOT NULL DEFAULT (0), "nostr_private_key" varchar, "nostr_public_key" varchar, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "updated_at" datetime NOT NULL DEFAULT (datetime('now')), "ownerSerialId" integer, CONSTRAINT "UQ_608bb41e7e1ef5f6d7abb07e394" UNIQUE ("name"), CONSTRAINT "UQ_f190e1a83a524035b84c1fe0696" UNIQUE ("nostr_private_key"), CONSTRAINT "UQ_87c12c4528183bf7a211221cc3c" UNIQUE ("nostr_public_key"))`);
|
await queryRunner.query(`CREATE TABLE "application" ("serial_id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "app_id" varchar NOT NULL, "name" varchar NOT NULL, "allow_user_creation" boolean NOT NULL DEFAULT (0), "nostr_private_key" varchar, "nostr_public_key" varchar, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "updated_at" datetime NOT NULL DEFAULT (datetime('now')), "ownerSerialId" integer, CONSTRAINT "UQ_608bb41e7e1ef5f6d7abb07e394" UNIQUE ("name"), CONSTRAINT "UQ_f190e1a83a524035b84c1fe0696" UNIQUE ("nostr_private_key"), CONSTRAINT "UQ_87c12c4528183bf7a211221cc3c" UNIQUE ("nostr_public_key"))`);
|
||||||
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_e04964210949f10bb25dc6e747" ON "application" ("app_id") `);
|
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_e04964210949f10bb25dc6e747" ON "application" ("app_id") `);
|
||||||
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)`);
|
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)`);
|
||||||
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_a131e6b58f084f1340538681b5" ON "user_receiving_invoice" ("invoice") `);
|
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_a131e6b58f084f1340538681b5" ON "user_receiving_invoice" ("invoice") `);
|
||||||
await queryRunner.query(`CREATE TABLE "user_receiving_address" ("serial_id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "address" varchar NOT NULL, "callbackUrl" varchar NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "updated_at" datetime NOT NULL DEFAULT (datetime('now')), "userSerialId" integer, "linkedApplicationSerialId" integer)`);
|
await queryRunner.query(`CREATE TABLE "user_receiving_address" ("serial_id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "address" varchar NOT NULL, "callbackUrl" varchar NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "updated_at" datetime NOT NULL DEFAULT (datetime('now')), "userSerialId" integer, "linkedApplicationSerialId" integer)`);
|
||||||
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_ecf415a7a0b2fa64aa03c5b067" ON "user_receiving_address" ("address") `);
|
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_ecf415a7a0b2fa64aa03c5b067" ON "user_receiving_address" ("address") `);
|
||||||
await queryRunner.query(`CREATE TABLE "address_receiving_transaction" ("serial_id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "tx_hash" varchar NOT NULL, "output_index" integer NOT NULL, "paid_amount" integer NOT NULL, "service_fee" integer NOT NULL, "paid_at_unix" integer NOT NULL, "internal" boolean NOT NULL DEFAULT (0), "confs" integer NOT NULL DEFAULT (0), "broadcast_height" integer NOT NULL DEFAULT (0), "created_at" datetime NOT NULL DEFAULT (datetime('now')), "updated_at" datetime NOT NULL DEFAULT (datetime('now')), "userAddressSerialId" integer)`);
|
await queryRunner.query(`CREATE TABLE "address_receiving_transaction" ("serial_id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "tx_hash" varchar NOT NULL, "output_index" integer NOT NULL, "paid_amount" integer NOT NULL, "service_fee" integer NOT NULL, "paid_at_unix" integer NOT NULL, "internal" boolean NOT NULL DEFAULT (0), "confs" integer NOT NULL DEFAULT (0), "broadcast_height" integer NOT NULL DEFAULT (0), "created_at" datetime NOT NULL DEFAULT (datetime('now')), "updated_at" datetime NOT NULL DEFAULT (datetime('now')), "userAddressSerialId" integer)`);
|
||||||
await queryRunner.query(`CREATE UNIQUE INDEX "address_receiving_transaction_unique" ON "address_receiving_transaction" ("tx_hash", "output_index") `);
|
await queryRunner.query(`CREATE UNIQUE INDEX "address_receiving_transaction_unique" ON "address_receiving_transaction" ("tx_hash", "output_index") `);
|
||||||
await queryRunner.query(`CREATE TABLE "application_user" ("serial_id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "identifier" varchar NOT NULL, "nostr_public_key" varchar, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "updated_at" datetime NOT NULL DEFAULT (datetime('now')), "userSerialId" integer, "applicationSerialId" integer, CONSTRAINT "UQ_3175dc397c8285d1e532554dea5" UNIQUE ("nostr_public_key"), CONSTRAINT "REL_0796a381bcc624f52e9a155712" UNIQUE ("userSerialId"))`);
|
await queryRunner.query(`CREATE TABLE "application_user" ("serial_id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "identifier" varchar NOT NULL, "nostr_public_key" varchar, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "updated_at" datetime NOT NULL DEFAULT (datetime('now')), "userSerialId" integer, "applicationSerialId" integer, CONSTRAINT "UQ_3175dc397c8285d1e532554dea5" UNIQUE ("nostr_public_key"), CONSTRAINT "REL_0796a381bcc624f52e9a155712" UNIQUE ("userSerialId"))`);
|
||||||
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_0a0dbb25a73306b037dec82251" ON "application_user" ("identifier") `);
|
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_0a0dbb25a73306b037dec82251" ON "application_user" ("identifier") `);
|
||||||
await queryRunner.query(`CREATE TABLE "user_basic_auth" ("serial_id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "name" varchar NOT NULL, "secret_sha256" varchar NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "updated_at" datetime NOT NULL DEFAULT (datetime('now')), "userSerialId" integer, CONSTRAINT "REL_4474a3cab08c387040d4c66f33" UNIQUE ("userSerialId"))`);
|
await queryRunner.query(`CREATE TABLE "user_basic_auth" ("serial_id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "name" varchar NOT NULL, "secret_sha256" varchar NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "updated_at" datetime NOT NULL DEFAULT (datetime('now')), "userSerialId" integer, CONSTRAINT "REL_4474a3cab08c387040d4c66f33" UNIQUE ("userSerialId"))`);
|
||||||
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_361b01c8e10453b2f979246535" ON "user_basic_auth" ("name") `);
|
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_361b01c8e10453b2f979246535" ON "user_basic_auth" ("name") `);
|
||||||
await queryRunner.query(`CREATE TABLE "user_ephemeral_key" ("serial_id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "key" varchar NOT NULL, "type" varchar NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "updated_at" datetime NOT NULL DEFAULT (datetime('now')), "userSerialId" integer, "linkedApplicationSerialId" integer)`);
|
await queryRunner.query(`CREATE TABLE "user_ephemeral_key" ("serial_id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "key" varchar NOT NULL, "type" varchar NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "updated_at" datetime NOT NULL DEFAULT (datetime('now')), "userSerialId" integer, "linkedApplicationSerialId" integer)`);
|
||||||
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_b9628a8315cdc6afed037563d9" ON "user_ephemeral_key" ("key") `);
|
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_b9628a8315cdc6afed037563d9" ON "user_ephemeral_key" ("key") `);
|
||||||
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)`);
|
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)`);
|
||||||
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_a609a4d3d8d9b07b90692a3c45" ON "user_invoice_payment" ("invoice") `);
|
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_a609a4d3d8d9b07b90692a3c45" ON "user_invoice_payment" ("invoice") `);
|
||||||
await queryRunner.query(`CREATE TABLE "user_to_user_payment" ("serial_id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "paid_amount" integer NOT NULL, "service_fees" integer NOT NULL, "paid_at_unix" integer NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "updated_at" datetime NOT NULL DEFAULT (datetime('now')), "fromUserSerialId" integer, "toUserSerialId" integer, "linkedApplicationSerialId" integer)`);
|
await queryRunner.query(`CREATE TABLE "user_to_user_payment" ("serial_id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "paid_amount" integer NOT NULL, "service_fees" integer NOT NULL, "paid_at_unix" integer NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "updated_at" datetime NOT NULL DEFAULT (datetime('now')), "fromUserSerialId" integer, "toUserSerialId" integer, "linkedApplicationSerialId" integer)`);
|
||||||
await queryRunner.query(`CREATE TABLE "user_transaction_payment" ("serial_id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "address" varchar NOT NULL, "tx_hash" varchar NOT NULL, "output_index" integer NOT NULL, "paid_amount" integer NOT NULL, "chain_fees" integer NOT NULL, "service_fees" integer NOT NULL, "paid_at_unix" integer NOT NULL, "internal" boolean NOT NULL DEFAULT (0), "confs" integer NOT NULL DEFAULT (0), "broadcast_height" integer NOT NULL DEFAULT (0), "something" integer NOT NULL DEFAULT (0), "created_at" datetime NOT NULL DEFAULT (datetime('now')), "updated_at" datetime NOT NULL DEFAULT (datetime('now')), "userSerialId" integer, "linkedApplicationSerialId" integer)`);
|
await queryRunner.query(`CREATE TABLE "user_transaction_payment" ("serial_id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "address" varchar NOT NULL, "tx_hash" varchar NOT NULL, "output_index" integer NOT NULL, "paid_amount" integer NOT NULL, "chain_fees" integer NOT NULL, "service_fees" integer NOT NULL, "paid_at_unix" integer NOT NULL, "internal" boolean NOT NULL DEFAULT (0), "confs" integer NOT NULL DEFAULT (0), "broadcast_height" integer NOT NULL DEFAULT (0), "something" integer NOT NULL DEFAULT (0), "created_at" datetime NOT NULL DEFAULT (datetime('now')), "updated_at" datetime NOT NULL DEFAULT (datetime('now')), "userSerialId" integer, "linkedApplicationSerialId" integer)`);
|
||||||
await queryRunner.query(`CREATE UNIQUE INDEX "user_transaction_unique" ON "user_transaction_payment" ("tx_hash", "output_index") `);
|
await queryRunner.query(`CREATE UNIQUE INDEX "user_transaction_unique" ON "user_transaction_payment" ("tx_hash", "output_index") `);
|
||||||
await queryRunner.query(`CREATE TABLE "temporary_product" ("product_id" varchar PRIMARY KEY NOT NULL, "name" varchar NOT NULL, "price_sats" integer NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "updated_at" datetime NOT NULL DEFAULT (datetime('now')), "ownerSerialId" integer, CONSTRAINT "FK_9e072a061430561c76a631f506c" FOREIGN KEY ("ownerSerialId") REFERENCES "user" ("serial_id") ON DELETE NO ACTION ON UPDATE NO ACTION)`);
|
await queryRunner.query(`CREATE TABLE "temporary_product" ("product_id" varchar PRIMARY KEY NOT NULL, "name" varchar NOT NULL, "price_sats" integer NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "updated_at" datetime NOT NULL DEFAULT (datetime('now')), "ownerSerialId" integer, CONSTRAINT "FK_9e072a061430561c76a631f506c" FOREIGN KEY ("ownerSerialId") REFERENCES "user" ("serial_id") ON DELETE NO ACTION ON UPDATE NO ACTION)`);
|
||||||
await queryRunner.query(`INSERT INTO "temporary_product"("product_id", "name", "price_sats", "created_at", "updated_at", "ownerSerialId") SELECT "product_id", "name", "price_sats", "created_at", "updated_at", "ownerSerialId" FROM "product"`);
|
await queryRunner.query(`INSERT INTO "temporary_product"("product_id", "name", "price_sats", "created_at", "updated_at", "ownerSerialId") SELECT "product_id", "name", "price_sats", "created_at", "updated_at", "ownerSerialId" FROM "product"`);
|
||||||
await queryRunner.query(`DROP TABLE "product"`);
|
await queryRunner.query(`DROP TABLE "product"`);
|
||||||
await queryRunner.query(`ALTER TABLE "temporary_product" RENAME TO "product"`);
|
await queryRunner.query(`ALTER TABLE "temporary_product" RENAME TO "product"`);
|
||||||
await queryRunner.query(`DROP INDEX "IDX_e04964210949f10bb25dc6e747"`);
|
await queryRunner.query(`DROP INDEX "IDX_e04964210949f10bb25dc6e747"`);
|
||||||
await queryRunner.query(`CREATE TABLE "temporary_application" ("serial_id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "app_id" varchar NOT NULL, "name" varchar NOT NULL, "allow_user_creation" boolean NOT NULL DEFAULT (0), "nostr_private_key" varchar, "nostr_public_key" varchar, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "updated_at" datetime NOT NULL DEFAULT (datetime('now')), "ownerSerialId" integer, CONSTRAINT "UQ_608bb41e7e1ef5f6d7abb07e394" UNIQUE ("name"), CONSTRAINT "UQ_f190e1a83a524035b84c1fe0696" UNIQUE ("nostr_private_key"), CONSTRAINT "UQ_87c12c4528183bf7a211221cc3c" UNIQUE ("nostr_public_key"), CONSTRAINT "FK_cf04162e14c4641072b08f263c5" FOREIGN KEY ("ownerSerialId") REFERENCES "user" ("serial_id") ON DELETE NO ACTION ON UPDATE NO ACTION)`);
|
await queryRunner.query(`CREATE TABLE "temporary_application" ("serial_id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "app_id" varchar NOT NULL, "name" varchar NOT NULL, "allow_user_creation" boolean NOT NULL DEFAULT (0), "nostr_private_key" varchar, "nostr_public_key" varchar, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "updated_at" datetime NOT NULL DEFAULT (datetime('now')), "ownerSerialId" integer, CONSTRAINT "UQ_608bb41e7e1ef5f6d7abb07e394" UNIQUE ("name"), CONSTRAINT "UQ_f190e1a83a524035b84c1fe0696" UNIQUE ("nostr_private_key"), CONSTRAINT "UQ_87c12c4528183bf7a211221cc3c" UNIQUE ("nostr_public_key"), CONSTRAINT "FK_cf04162e14c4641072b08f263c5" FOREIGN KEY ("ownerSerialId") REFERENCES "user" ("serial_id") ON DELETE NO ACTION ON UPDATE NO ACTION)`);
|
||||||
await queryRunner.query(`INSERT INTO "temporary_application"("serial_id", "app_id", "name", "allow_user_creation", "nostr_private_key", "nostr_public_key", "created_at", "updated_at", "ownerSerialId") SELECT "serial_id", "app_id", "name", "allow_user_creation", "nostr_private_key", "nostr_public_key", "created_at", "updated_at", "ownerSerialId" FROM "application"`);
|
await queryRunner.query(`INSERT INTO "temporary_application"("serial_id", "app_id", "name", "allow_user_creation", "nostr_private_key", "nostr_public_key", "created_at", "updated_at", "ownerSerialId") SELECT "serial_id", "app_id", "name", "allow_user_creation", "nostr_private_key", "nostr_public_key", "created_at", "updated_at", "ownerSerialId" FROM "application"`);
|
||||||
await queryRunner.query(`DROP TABLE "application"`);
|
await queryRunner.query(`DROP TABLE "application"`);
|
||||||
await queryRunner.query(`ALTER TABLE "temporary_application" RENAME TO "application"`);
|
await queryRunner.query(`ALTER TABLE "temporary_application" RENAME TO "application"`);
|
||||||
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_e04964210949f10bb25dc6e747" ON "application" ("app_id") `);
|
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_e04964210949f10bb25dc6e747" ON "application" ("app_id") `);
|
||||||
await queryRunner.query(`DROP INDEX "IDX_a131e6b58f084f1340538681b5"`);
|
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, CONSTRAINT "FK_2c0dfb3483f3e5e7e3cdd5dc71f" FOREIGN KEY ("userSerialId") 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_d4bb1e4c60e8a869f1f43ca2e31" FOREIGN KEY ("payerSerialId") REFERENCES "user" ("serial_id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_714a8b7d4f89f8a802ca181b789" FOREIGN KEY ("linkedApplicationSerialId") REFERENCES "application" ("serial_id") ON DELETE NO ACTION ON UPDATE NO ACTION)`);
|
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, CONSTRAINT "FK_2c0dfb3483f3e5e7e3cdd5dc71f" FOREIGN KEY ("userSerialId") 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_d4bb1e4c60e8a869f1f43ca2e31" FOREIGN KEY ("payerSerialId") REFERENCES "user" ("serial_id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_714a8b7d4f89f8a802ca181b789" FOREIGN KEY ("linkedApplicationSerialId") REFERENCES "application" ("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(`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(`DROP TABLE "user_receiving_invoice"`);
|
||||||
await queryRunner.query(`ALTER TABLE "temporary_user_receiving_invoice" RENAME TO "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(`CREATE UNIQUE INDEX "IDX_a131e6b58f084f1340538681b5" ON "user_receiving_invoice" ("invoice") `);
|
||||||
await queryRunner.query(`DROP INDEX "IDX_ecf415a7a0b2fa64aa03c5b067"`);
|
await queryRunner.query(`DROP INDEX "IDX_ecf415a7a0b2fa64aa03c5b067"`);
|
||||||
await queryRunner.query(`CREATE TABLE "temporary_user_receiving_address" ("serial_id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "address" varchar NOT NULL, "callbackUrl" varchar NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "updated_at" datetime NOT NULL DEFAULT (datetime('now')), "userSerialId" integer, "linkedApplicationSerialId" integer, CONSTRAINT "FK_823e78a588858598aa91766c7ff" FOREIGN KEY ("userSerialId") REFERENCES "user" ("serial_id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_58480f93d00174952e00a0c0a5d" FOREIGN KEY ("linkedApplicationSerialId") REFERENCES "application" ("serial_id") ON DELETE NO ACTION ON UPDATE NO ACTION)`);
|
await queryRunner.query(`CREATE TABLE "temporary_user_receiving_address" ("serial_id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "address" varchar NOT NULL, "callbackUrl" varchar NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "updated_at" datetime NOT NULL DEFAULT (datetime('now')), "userSerialId" integer, "linkedApplicationSerialId" integer, CONSTRAINT "FK_823e78a588858598aa91766c7ff" FOREIGN KEY ("userSerialId") REFERENCES "user" ("serial_id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_58480f93d00174952e00a0c0a5d" FOREIGN KEY ("linkedApplicationSerialId") REFERENCES "application" ("serial_id") ON DELETE NO ACTION ON UPDATE NO ACTION)`);
|
||||||
await queryRunner.query(`INSERT INTO "temporary_user_receiving_address"("serial_id", "address", "callbackUrl", "created_at", "updated_at", "userSerialId", "linkedApplicationSerialId") SELECT "serial_id", "address", "callbackUrl", "created_at", "updated_at", "userSerialId", "linkedApplicationSerialId" FROM "user_receiving_address"`);
|
await queryRunner.query(`INSERT INTO "temporary_user_receiving_address"("serial_id", "address", "callbackUrl", "created_at", "updated_at", "userSerialId", "linkedApplicationSerialId") SELECT "serial_id", "address", "callbackUrl", "created_at", "updated_at", "userSerialId", "linkedApplicationSerialId" FROM "user_receiving_address"`);
|
||||||
await queryRunner.query(`DROP TABLE "user_receiving_address"`);
|
await queryRunner.query(`DROP TABLE "user_receiving_address"`);
|
||||||
await queryRunner.query(`ALTER TABLE "temporary_user_receiving_address" RENAME TO "user_receiving_address"`);
|
await queryRunner.query(`ALTER TABLE "temporary_user_receiving_address" RENAME TO "user_receiving_address"`);
|
||||||
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_ecf415a7a0b2fa64aa03c5b067" ON "user_receiving_address" ("address") `);
|
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_ecf415a7a0b2fa64aa03c5b067" ON "user_receiving_address" ("address") `);
|
||||||
await queryRunner.query(`DROP INDEX "address_receiving_transaction_unique"`);
|
await queryRunner.query(`DROP INDEX "address_receiving_transaction_unique"`);
|
||||||
await queryRunner.query(`CREATE TABLE "temporary_address_receiving_transaction" ("serial_id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "tx_hash" varchar NOT NULL, "output_index" integer NOT NULL, "paid_amount" integer NOT NULL, "service_fee" integer NOT NULL, "paid_at_unix" integer NOT NULL, "internal" boolean NOT NULL DEFAULT (0), "confs" integer NOT NULL DEFAULT (0), "broadcast_height" integer NOT NULL DEFAULT (0), "created_at" datetime NOT NULL DEFAULT (datetime('now')), "updated_at" datetime NOT NULL DEFAULT (datetime('now')), "userAddressSerialId" integer, CONSTRAINT "FK_fa29dc074c2e067beca4aefeaad" FOREIGN KEY ("userAddressSerialId") REFERENCES "user_receiving_address" ("serial_id") ON DELETE NO ACTION ON UPDATE NO ACTION)`);
|
await queryRunner.query(`CREATE TABLE "temporary_address_receiving_transaction" ("serial_id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "tx_hash" varchar NOT NULL, "output_index" integer NOT NULL, "paid_amount" integer NOT NULL, "service_fee" integer NOT NULL, "paid_at_unix" integer NOT NULL, "internal" boolean NOT NULL DEFAULT (0), "confs" integer NOT NULL DEFAULT (0), "broadcast_height" integer NOT NULL DEFAULT (0), "created_at" datetime NOT NULL DEFAULT (datetime('now')), "updated_at" datetime NOT NULL DEFAULT (datetime('now')), "userAddressSerialId" integer, CONSTRAINT "FK_fa29dc074c2e067beca4aefeaad" FOREIGN KEY ("userAddressSerialId") REFERENCES "user_receiving_address" ("serial_id") ON DELETE NO ACTION ON UPDATE NO ACTION)`);
|
||||||
await queryRunner.query(`INSERT INTO "temporary_address_receiving_transaction"("serial_id", "tx_hash", "output_index", "paid_amount", "service_fee", "paid_at_unix", "internal", "confs", "broadcast_height", "created_at", "updated_at", "userAddressSerialId") SELECT "serial_id", "tx_hash", "output_index", "paid_amount", "service_fee", "paid_at_unix", "internal", "confs", "broadcast_height", "created_at", "updated_at", "userAddressSerialId" FROM "address_receiving_transaction"`);
|
await queryRunner.query(`INSERT INTO "temporary_address_receiving_transaction"("serial_id", "tx_hash", "output_index", "paid_amount", "service_fee", "paid_at_unix", "internal", "confs", "broadcast_height", "created_at", "updated_at", "userAddressSerialId") SELECT "serial_id", "tx_hash", "output_index", "paid_amount", "service_fee", "paid_at_unix", "internal", "confs", "broadcast_height", "created_at", "updated_at", "userAddressSerialId" FROM "address_receiving_transaction"`);
|
||||||
await queryRunner.query(`DROP TABLE "address_receiving_transaction"`);
|
await queryRunner.query(`DROP TABLE "address_receiving_transaction"`);
|
||||||
await queryRunner.query(`ALTER TABLE "temporary_address_receiving_transaction" RENAME TO "address_receiving_transaction"`);
|
await queryRunner.query(`ALTER TABLE "temporary_address_receiving_transaction" RENAME TO "address_receiving_transaction"`);
|
||||||
await queryRunner.query(`CREATE UNIQUE INDEX "address_receiving_transaction_unique" ON "address_receiving_transaction" ("tx_hash", "output_index") `);
|
await queryRunner.query(`CREATE UNIQUE INDEX "address_receiving_transaction_unique" ON "address_receiving_transaction" ("tx_hash", "output_index") `);
|
||||||
await queryRunner.query(`DROP INDEX "IDX_0a0dbb25a73306b037dec82251"`);
|
await queryRunner.query(`DROP INDEX "IDX_0a0dbb25a73306b037dec82251"`);
|
||||||
await queryRunner.query(`CREATE TABLE "temporary_application_user" ("serial_id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "identifier" varchar NOT NULL, "nostr_public_key" varchar, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "updated_at" datetime NOT NULL DEFAULT (datetime('now')), "userSerialId" integer, "applicationSerialId" integer, CONSTRAINT "UQ_3175dc397c8285d1e532554dea5" UNIQUE ("nostr_public_key"), CONSTRAINT "REL_0796a381bcc624f52e9a155712" UNIQUE ("userSerialId"), CONSTRAINT "FK_0796a381bcc624f52e9a155712b" FOREIGN KEY ("userSerialId") REFERENCES "user" ("serial_id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_1b3bdb6f660cd99533a1e673ef1" FOREIGN KEY ("applicationSerialId") REFERENCES "application" ("serial_id") ON DELETE NO ACTION ON UPDATE NO ACTION)`);
|
await queryRunner.query(`CREATE TABLE "temporary_application_user" ("serial_id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "identifier" varchar NOT NULL, "nostr_public_key" varchar, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "updated_at" datetime NOT NULL DEFAULT (datetime('now')), "userSerialId" integer, "applicationSerialId" integer, CONSTRAINT "UQ_3175dc397c8285d1e532554dea5" UNIQUE ("nostr_public_key"), CONSTRAINT "REL_0796a381bcc624f52e9a155712" UNIQUE ("userSerialId"), CONSTRAINT "FK_0796a381bcc624f52e9a155712b" FOREIGN KEY ("userSerialId") REFERENCES "user" ("serial_id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_1b3bdb6f660cd99533a1e673ef1" FOREIGN KEY ("applicationSerialId") REFERENCES "application" ("serial_id") ON DELETE NO ACTION ON UPDATE NO ACTION)`);
|
||||||
await queryRunner.query(`INSERT INTO "temporary_application_user"("serial_id", "identifier", "nostr_public_key", "created_at", "updated_at", "userSerialId", "applicationSerialId") SELECT "serial_id", "identifier", "nostr_public_key", "created_at", "updated_at", "userSerialId", "applicationSerialId" FROM "application_user"`);
|
await queryRunner.query(`INSERT INTO "temporary_application_user"("serial_id", "identifier", "nostr_public_key", "created_at", "updated_at", "userSerialId", "applicationSerialId") SELECT "serial_id", "identifier", "nostr_public_key", "created_at", "updated_at", "userSerialId", "applicationSerialId" FROM "application_user"`);
|
||||||
await queryRunner.query(`DROP TABLE "application_user"`);
|
await queryRunner.query(`DROP TABLE "application_user"`);
|
||||||
await queryRunner.query(`ALTER TABLE "temporary_application_user" RENAME TO "application_user"`);
|
await queryRunner.query(`ALTER TABLE "temporary_application_user" RENAME TO "application_user"`);
|
||||||
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_0a0dbb25a73306b037dec82251" ON "application_user" ("identifier") `);
|
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_0a0dbb25a73306b037dec82251" ON "application_user" ("identifier") `);
|
||||||
await queryRunner.query(`DROP INDEX "IDX_361b01c8e10453b2f979246535"`);
|
await queryRunner.query(`DROP INDEX "IDX_361b01c8e10453b2f979246535"`);
|
||||||
await queryRunner.query(`CREATE TABLE "temporary_user_basic_auth" ("serial_id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "name" varchar NOT NULL, "secret_sha256" varchar NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "updated_at" datetime NOT NULL DEFAULT (datetime('now')), "userSerialId" integer, CONSTRAINT "REL_4474a3cab08c387040d4c66f33" UNIQUE ("userSerialId"), CONSTRAINT "FK_4474a3cab08c387040d4c66f337" FOREIGN KEY ("userSerialId") REFERENCES "user" ("serial_id") ON DELETE NO ACTION ON UPDATE NO ACTION)`);
|
await queryRunner.query(`CREATE TABLE "temporary_user_basic_auth" ("serial_id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "name" varchar NOT NULL, "secret_sha256" varchar NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "updated_at" datetime NOT NULL DEFAULT (datetime('now')), "userSerialId" integer, CONSTRAINT "REL_4474a3cab08c387040d4c66f33" UNIQUE ("userSerialId"), CONSTRAINT "FK_4474a3cab08c387040d4c66f337" FOREIGN KEY ("userSerialId") REFERENCES "user" ("serial_id") ON DELETE NO ACTION ON UPDATE NO ACTION)`);
|
||||||
await queryRunner.query(`INSERT INTO "temporary_user_basic_auth"("serial_id", "name", "secret_sha256", "created_at", "updated_at", "userSerialId") SELECT "serial_id", "name", "secret_sha256", "created_at", "updated_at", "userSerialId" FROM "user_basic_auth"`);
|
await queryRunner.query(`INSERT INTO "temporary_user_basic_auth"("serial_id", "name", "secret_sha256", "created_at", "updated_at", "userSerialId") SELECT "serial_id", "name", "secret_sha256", "created_at", "updated_at", "userSerialId" FROM "user_basic_auth"`);
|
||||||
await queryRunner.query(`DROP TABLE "user_basic_auth"`);
|
await queryRunner.query(`DROP TABLE "user_basic_auth"`);
|
||||||
await queryRunner.query(`ALTER TABLE "temporary_user_basic_auth" RENAME TO "user_basic_auth"`);
|
await queryRunner.query(`ALTER TABLE "temporary_user_basic_auth" RENAME TO "user_basic_auth"`);
|
||||||
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_361b01c8e10453b2f979246535" ON "user_basic_auth" ("name") `);
|
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_361b01c8e10453b2f979246535" ON "user_basic_auth" ("name") `);
|
||||||
await queryRunner.query(`DROP INDEX "IDX_b9628a8315cdc6afed037563d9"`);
|
await queryRunner.query(`DROP INDEX "IDX_b9628a8315cdc6afed037563d9"`);
|
||||||
await queryRunner.query(`CREATE TABLE "temporary_user_ephemeral_key" ("serial_id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "key" varchar NOT NULL, "type" varchar NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "updated_at" datetime NOT NULL DEFAULT (datetime('now')), "userSerialId" integer, "linkedApplicationSerialId" integer, CONSTRAINT "FK_13af336122427a543067b13c453" FOREIGN KEY ("userSerialId") REFERENCES "user" ("serial_id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_9dff387698d432ff8b931ea954d" FOREIGN KEY ("linkedApplicationSerialId") REFERENCES "application" ("serial_id") ON DELETE NO ACTION ON UPDATE NO ACTION)`);
|
await queryRunner.query(`CREATE TABLE "temporary_user_ephemeral_key" ("serial_id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "key" varchar NOT NULL, "type" varchar NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "updated_at" datetime NOT NULL DEFAULT (datetime('now')), "userSerialId" integer, "linkedApplicationSerialId" integer, CONSTRAINT "FK_13af336122427a543067b13c453" FOREIGN KEY ("userSerialId") REFERENCES "user" ("serial_id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_9dff387698d432ff8b931ea954d" FOREIGN KEY ("linkedApplicationSerialId") REFERENCES "application" ("serial_id") ON DELETE NO ACTION ON UPDATE NO ACTION)`);
|
||||||
await queryRunner.query(`INSERT INTO "temporary_user_ephemeral_key"("serial_id", "key", "type", "created_at", "updated_at", "userSerialId", "linkedApplicationSerialId") SELECT "serial_id", "key", "type", "created_at", "updated_at", "userSerialId", "linkedApplicationSerialId" FROM "user_ephemeral_key"`);
|
await queryRunner.query(`INSERT INTO "temporary_user_ephemeral_key"("serial_id", "key", "type", "created_at", "updated_at", "userSerialId", "linkedApplicationSerialId") SELECT "serial_id", "key", "type", "created_at", "updated_at", "userSerialId", "linkedApplicationSerialId" FROM "user_ephemeral_key"`);
|
||||||
await queryRunner.query(`DROP TABLE "user_ephemeral_key"`);
|
await queryRunner.query(`DROP TABLE "user_ephemeral_key"`);
|
||||||
await queryRunner.query(`ALTER TABLE "temporary_user_ephemeral_key" RENAME TO "user_ephemeral_key"`);
|
await queryRunner.query(`ALTER TABLE "temporary_user_ephemeral_key" RENAME TO "user_ephemeral_key"`);
|
||||||
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_b9628a8315cdc6afed037563d9" ON "user_ephemeral_key" ("key") `);
|
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_b9628a8315cdc6afed037563d9" ON "user_ephemeral_key" ("key") `);
|
||||||
await queryRunner.query(`DROP INDEX "IDX_a609a4d3d8d9b07b90692a3c45"`);
|
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, CONSTRAINT "FK_ef2aa6761ab681bbbd5f94e0fcb" FOREIGN KEY ("userSerialId") REFERENCES "user" ("serial_id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_6bcac90887eea1dc61d37db2994" FOREIGN KEY ("linkedApplicationSerialId") REFERENCES "application" ("serial_id") ON DELETE NO ACTION ON UPDATE NO ACTION)`);
|
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, CONSTRAINT "FK_ef2aa6761ab681bbbd5f94e0fcb" FOREIGN KEY ("userSerialId") REFERENCES "user" ("serial_id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_6bcac90887eea1dc61d37db2994" FOREIGN KEY ("linkedApplicationSerialId") REFERENCES "application" ("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(`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(`DROP TABLE "user_invoice_payment"`);
|
||||||
await queryRunner.query(`ALTER TABLE "temporary_user_invoice_payment" RENAME TO "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") `);
|
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_a609a4d3d8d9b07b90692a3c45" ON "user_invoice_payment" ("invoice") `);
|
||||||
await queryRunner.query(`CREATE TABLE "temporary_user_to_user_payment" ("serial_id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "paid_amount" integer NOT NULL, "service_fees" integer NOT NULL, "paid_at_unix" integer NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "updated_at" datetime NOT NULL DEFAULT (datetime('now')), "fromUserSerialId" integer, "toUserSerialId" integer, "linkedApplicationSerialId" integer, CONSTRAINT "FK_239687f55807600edd2c515628a" FOREIGN KEY ("fromUserSerialId") REFERENCES "user" ("serial_id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_d88c97ca05db8d408682a5944d2" FOREIGN KEY ("toUserSerialId") REFERENCES "user" ("serial_id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_f08d33ed4949525faed9218ad25" FOREIGN KEY ("linkedApplicationSerialId") REFERENCES "application" ("serial_id") ON DELETE NO ACTION ON UPDATE NO ACTION)`);
|
await queryRunner.query(`CREATE TABLE "temporary_user_to_user_payment" ("serial_id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "paid_amount" integer NOT NULL, "service_fees" integer NOT NULL, "paid_at_unix" integer NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "updated_at" datetime NOT NULL DEFAULT (datetime('now')), "fromUserSerialId" integer, "toUserSerialId" integer, "linkedApplicationSerialId" integer, CONSTRAINT "FK_239687f55807600edd2c515628a" FOREIGN KEY ("fromUserSerialId") REFERENCES "user" ("serial_id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_d88c97ca05db8d408682a5944d2" FOREIGN KEY ("toUserSerialId") REFERENCES "user" ("serial_id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_f08d33ed4949525faed9218ad25" FOREIGN KEY ("linkedApplicationSerialId") REFERENCES "application" ("serial_id") ON DELETE NO ACTION ON UPDATE NO ACTION)`);
|
||||||
await queryRunner.query(`INSERT INTO "temporary_user_to_user_payment"("serial_id", "paid_amount", "service_fees", "paid_at_unix", "created_at", "updated_at", "fromUserSerialId", "toUserSerialId", "linkedApplicationSerialId") SELECT "serial_id", "paid_amount", "service_fees", "paid_at_unix", "created_at", "updated_at", "fromUserSerialId", "toUserSerialId", "linkedApplicationSerialId" FROM "user_to_user_payment"`);
|
await queryRunner.query(`INSERT INTO "temporary_user_to_user_payment"("serial_id", "paid_amount", "service_fees", "paid_at_unix", "created_at", "updated_at", "fromUserSerialId", "toUserSerialId", "linkedApplicationSerialId") SELECT "serial_id", "paid_amount", "service_fees", "paid_at_unix", "created_at", "updated_at", "fromUserSerialId", "toUserSerialId", "linkedApplicationSerialId" FROM "user_to_user_payment"`);
|
||||||
await queryRunner.query(`DROP TABLE "user_to_user_payment"`);
|
await queryRunner.query(`DROP TABLE "user_to_user_payment"`);
|
||||||
await queryRunner.query(`ALTER TABLE "temporary_user_to_user_payment" RENAME TO "user_to_user_payment"`);
|
await queryRunner.query(`ALTER TABLE "temporary_user_to_user_payment" RENAME TO "user_to_user_payment"`);
|
||||||
await queryRunner.query(`DROP INDEX "user_transaction_unique"`);
|
await queryRunner.query(`DROP INDEX "user_transaction_unique"`);
|
||||||
await queryRunner.query(`CREATE TABLE "temporary_user_transaction_payment" ("serial_id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "address" varchar NOT NULL, "tx_hash" varchar NOT NULL, "output_index" integer NOT NULL, "paid_amount" integer NOT NULL, "chain_fees" integer NOT NULL, "service_fees" integer NOT NULL, "paid_at_unix" integer NOT NULL, "internal" boolean NOT NULL DEFAULT (0), "confs" integer NOT NULL DEFAULT (0), "broadcast_height" integer NOT NULL DEFAULT (0), "something" integer 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_6f24c901b4103f7146eb615a5db" FOREIGN KEY ("userSerialId") REFERENCES "user" ("serial_id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_75abdd29270979e901da0dba7b9" FOREIGN KEY ("linkedApplicationSerialId") REFERENCES "application" ("serial_id") ON DELETE NO ACTION ON UPDATE NO ACTION)`);
|
await queryRunner.query(`CREATE TABLE "temporary_user_transaction_payment" ("serial_id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "address" varchar NOT NULL, "tx_hash" varchar NOT NULL, "output_index" integer NOT NULL, "paid_amount" integer NOT NULL, "chain_fees" integer NOT NULL, "service_fees" integer NOT NULL, "paid_at_unix" integer NOT NULL, "internal" boolean NOT NULL DEFAULT (0), "confs" integer NOT NULL DEFAULT (0), "broadcast_height" integer NOT NULL DEFAULT (0), "something" integer 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_6f24c901b4103f7146eb615a5db" FOREIGN KEY ("userSerialId") REFERENCES "user" ("serial_id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_75abdd29270979e901da0dba7b9" FOREIGN KEY ("linkedApplicationSerialId") REFERENCES "application" ("serial_id") ON DELETE NO ACTION ON UPDATE NO ACTION)`);
|
||||||
await queryRunner.query(`INSERT INTO "temporary_user_transaction_payment"("serial_id", "address", "tx_hash", "output_index", "paid_amount", "chain_fees", "service_fees", "paid_at_unix", "internal", "confs", "broadcast_height", "something", "created_at", "updated_at", "userSerialId", "linkedApplicationSerialId") SELECT "serial_id", "address", "tx_hash", "output_index", "paid_amount", "chain_fees", "service_fees", "paid_at_unix", "internal", "confs", "broadcast_height", "something", "created_at", "updated_at", "userSerialId", "linkedApplicationSerialId" FROM "user_transaction_payment"`);
|
await queryRunner.query(`INSERT INTO "temporary_user_transaction_payment"("serial_id", "address", "tx_hash", "output_index", "paid_amount", "chain_fees", "service_fees", "paid_at_unix", "internal", "confs", "broadcast_height", "something", "created_at", "updated_at", "userSerialId", "linkedApplicationSerialId") SELECT "serial_id", "address", "tx_hash", "output_index", "paid_amount", "chain_fees", "service_fees", "paid_at_unix", "internal", "confs", "broadcast_height", "something", "created_at", "updated_at", "userSerialId", "linkedApplicationSerialId" FROM "user_transaction_payment"`);
|
||||||
await queryRunner.query(`DROP TABLE "user_transaction_payment"`);
|
await queryRunner.query(`DROP TABLE "user_transaction_payment"`);
|
||||||
await queryRunner.query(`ALTER TABLE "temporary_user_transaction_payment" RENAME TO "user_transaction_payment"`);
|
await queryRunner.query(`ALTER TABLE "temporary_user_transaction_payment" RENAME TO "user_transaction_payment"`);
|
||||||
await queryRunner.query(`CREATE UNIQUE INDEX "user_transaction_unique" ON "user_transaction_payment" ("tx_hash", "output_index") `);
|
await queryRunner.query(`CREATE UNIQUE INDEX "user_transaction_unique" ON "user_transaction_payment" ("tx_hash", "output_index") `);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||||
await queryRunner.query(`DROP INDEX "user_transaction_unique"`);
|
await queryRunner.query(`DROP INDEX "user_transaction_unique"`);
|
||||||
await queryRunner.query(`ALTER TABLE "user_transaction_payment" RENAME TO "temporary_user_transaction_payment"`);
|
await queryRunner.query(`ALTER TABLE "user_transaction_payment" RENAME TO "temporary_user_transaction_payment"`);
|
||||||
await queryRunner.query(`CREATE TABLE "user_transaction_payment" ("serial_id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "address" varchar NOT NULL, "tx_hash" varchar NOT NULL, "output_index" integer NOT NULL, "paid_amount" integer NOT NULL, "chain_fees" integer NOT NULL, "service_fees" integer NOT NULL, "paid_at_unix" integer NOT NULL, "internal" boolean NOT NULL DEFAULT (0), "confs" integer NOT NULL DEFAULT (0), "broadcast_height" integer NOT NULL DEFAULT (0), "something" integer NOT NULL DEFAULT (0), "created_at" datetime NOT NULL DEFAULT (datetime('now')), "updated_at" datetime NOT NULL DEFAULT (datetime('now')), "userSerialId" integer, "linkedApplicationSerialId" integer)`);
|
await queryRunner.query(`CREATE TABLE "user_transaction_payment" ("serial_id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "address" varchar NOT NULL, "tx_hash" varchar NOT NULL, "output_index" integer NOT NULL, "paid_amount" integer NOT NULL, "chain_fees" integer NOT NULL, "service_fees" integer NOT NULL, "paid_at_unix" integer NOT NULL, "internal" boolean NOT NULL DEFAULT (0), "confs" integer NOT NULL DEFAULT (0), "broadcast_height" integer NOT NULL DEFAULT (0), "something" integer NOT NULL DEFAULT (0), "created_at" datetime NOT NULL DEFAULT (datetime('now')), "updated_at" datetime NOT NULL DEFAULT (datetime('now')), "userSerialId" integer, "linkedApplicationSerialId" integer)`);
|
||||||
await queryRunner.query(`INSERT INTO "user_transaction_payment"("serial_id", "address", "tx_hash", "output_index", "paid_amount", "chain_fees", "service_fees", "paid_at_unix", "internal", "confs", "broadcast_height", "something", "created_at", "updated_at", "userSerialId", "linkedApplicationSerialId") SELECT "serial_id", "address", "tx_hash", "output_index", "paid_amount", "chain_fees", "service_fees", "paid_at_unix", "internal", "confs", "broadcast_height", "something", "created_at", "updated_at", "userSerialId", "linkedApplicationSerialId" FROM "temporary_user_transaction_payment"`);
|
await queryRunner.query(`INSERT INTO "user_transaction_payment"("serial_id", "address", "tx_hash", "output_index", "paid_amount", "chain_fees", "service_fees", "paid_at_unix", "internal", "confs", "broadcast_height", "something", "created_at", "updated_at", "userSerialId", "linkedApplicationSerialId") SELECT "serial_id", "address", "tx_hash", "output_index", "paid_amount", "chain_fees", "service_fees", "paid_at_unix", "internal", "confs", "broadcast_height", "something", "created_at", "updated_at", "userSerialId", "linkedApplicationSerialId" FROM "temporary_user_transaction_payment"`);
|
||||||
await queryRunner.query(`DROP TABLE "temporary_user_transaction_payment"`);
|
await queryRunner.query(`DROP TABLE "temporary_user_transaction_payment"`);
|
||||||
await queryRunner.query(`CREATE UNIQUE INDEX "user_transaction_unique" ON "user_transaction_payment" ("tx_hash", "output_index") `);
|
await queryRunner.query(`CREATE UNIQUE INDEX "user_transaction_unique" ON "user_transaction_payment" ("tx_hash", "output_index") `);
|
||||||
await queryRunner.query(`ALTER TABLE "user_to_user_payment" RENAME TO "temporary_user_to_user_payment"`);
|
await queryRunner.query(`ALTER TABLE "user_to_user_payment" RENAME TO "temporary_user_to_user_payment"`);
|
||||||
await queryRunner.query(`CREATE TABLE "user_to_user_payment" ("serial_id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "paid_amount" integer NOT NULL, "service_fees" integer NOT NULL, "paid_at_unix" integer NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "updated_at" datetime NOT NULL DEFAULT (datetime('now')), "fromUserSerialId" integer, "toUserSerialId" integer, "linkedApplicationSerialId" integer)`);
|
await queryRunner.query(`CREATE TABLE "user_to_user_payment" ("serial_id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "paid_amount" integer NOT NULL, "service_fees" integer NOT NULL, "paid_at_unix" integer NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "updated_at" datetime NOT NULL DEFAULT (datetime('now')), "fromUserSerialId" integer, "toUserSerialId" integer, "linkedApplicationSerialId" integer)`);
|
||||||
await queryRunner.query(`INSERT INTO "user_to_user_payment"("serial_id", "paid_amount", "service_fees", "paid_at_unix", "created_at", "updated_at", "fromUserSerialId", "toUserSerialId", "linkedApplicationSerialId") SELECT "serial_id", "paid_amount", "service_fees", "paid_at_unix", "created_at", "updated_at", "fromUserSerialId", "toUserSerialId", "linkedApplicationSerialId" FROM "temporary_user_to_user_payment"`);
|
await queryRunner.query(`INSERT INTO "user_to_user_payment"("serial_id", "paid_amount", "service_fees", "paid_at_unix", "created_at", "updated_at", "fromUserSerialId", "toUserSerialId", "linkedApplicationSerialId") SELECT "serial_id", "paid_amount", "service_fees", "paid_at_unix", "created_at", "updated_at", "fromUserSerialId", "toUserSerialId", "linkedApplicationSerialId" FROM "temporary_user_to_user_payment"`);
|
||||||
await queryRunner.query(`DROP TABLE "temporary_user_to_user_payment"`);
|
await queryRunner.query(`DROP TABLE "temporary_user_to_user_payment"`);
|
||||||
await queryRunner.query(`DROP INDEX "IDX_a609a4d3d8d9b07b90692a3c45"`);
|
await queryRunner.query(`DROP INDEX "IDX_a609a4d3d8d9b07b90692a3c45"`);
|
||||||
await queryRunner.query(`ALTER TABLE "user_invoice_payment" RENAME TO "temporary_user_invoice_payment"`);
|
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)`);
|
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)`);
|
||||||
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(`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(`DROP TABLE "temporary_user_invoice_payment"`);
|
||||||
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_a609a4d3d8d9b07b90692a3c45" ON "user_invoice_payment" ("invoice") `);
|
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_a609a4d3d8d9b07b90692a3c45" ON "user_invoice_payment" ("invoice") `);
|
||||||
await queryRunner.query(`DROP INDEX "IDX_b9628a8315cdc6afed037563d9"`);
|
await queryRunner.query(`DROP INDEX "IDX_b9628a8315cdc6afed037563d9"`);
|
||||||
await queryRunner.query(`ALTER TABLE "user_ephemeral_key" RENAME TO "temporary_user_ephemeral_key"`);
|
await queryRunner.query(`ALTER TABLE "user_ephemeral_key" RENAME TO "temporary_user_ephemeral_key"`);
|
||||||
await queryRunner.query(`CREATE TABLE "user_ephemeral_key" ("serial_id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "key" varchar NOT NULL, "type" varchar NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "updated_at" datetime NOT NULL DEFAULT (datetime('now')), "userSerialId" integer, "linkedApplicationSerialId" integer)`);
|
await queryRunner.query(`CREATE TABLE "user_ephemeral_key" ("serial_id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "key" varchar NOT NULL, "type" varchar NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "updated_at" datetime NOT NULL DEFAULT (datetime('now')), "userSerialId" integer, "linkedApplicationSerialId" integer)`);
|
||||||
await queryRunner.query(`INSERT INTO "user_ephemeral_key"("serial_id", "key", "type", "created_at", "updated_at", "userSerialId", "linkedApplicationSerialId") SELECT "serial_id", "key", "type", "created_at", "updated_at", "userSerialId", "linkedApplicationSerialId" FROM "temporary_user_ephemeral_key"`);
|
await queryRunner.query(`INSERT INTO "user_ephemeral_key"("serial_id", "key", "type", "created_at", "updated_at", "userSerialId", "linkedApplicationSerialId") SELECT "serial_id", "key", "type", "created_at", "updated_at", "userSerialId", "linkedApplicationSerialId" FROM "temporary_user_ephemeral_key"`);
|
||||||
await queryRunner.query(`DROP TABLE "temporary_user_ephemeral_key"`);
|
await queryRunner.query(`DROP TABLE "temporary_user_ephemeral_key"`);
|
||||||
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_b9628a8315cdc6afed037563d9" ON "user_ephemeral_key" ("key") `);
|
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_b9628a8315cdc6afed037563d9" ON "user_ephemeral_key" ("key") `);
|
||||||
await queryRunner.query(`DROP INDEX "IDX_361b01c8e10453b2f979246535"`);
|
await queryRunner.query(`DROP INDEX "IDX_361b01c8e10453b2f979246535"`);
|
||||||
await queryRunner.query(`ALTER TABLE "user_basic_auth" RENAME TO "temporary_user_basic_auth"`);
|
await queryRunner.query(`ALTER TABLE "user_basic_auth" RENAME TO "temporary_user_basic_auth"`);
|
||||||
await queryRunner.query(`CREATE TABLE "user_basic_auth" ("serial_id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "name" varchar NOT NULL, "secret_sha256" varchar NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "updated_at" datetime NOT NULL DEFAULT (datetime('now')), "userSerialId" integer, CONSTRAINT "REL_4474a3cab08c387040d4c66f33" UNIQUE ("userSerialId"))`);
|
await queryRunner.query(`CREATE TABLE "user_basic_auth" ("serial_id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "name" varchar NOT NULL, "secret_sha256" varchar NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "updated_at" datetime NOT NULL DEFAULT (datetime('now')), "userSerialId" integer, CONSTRAINT "REL_4474a3cab08c387040d4c66f33" UNIQUE ("userSerialId"))`);
|
||||||
await queryRunner.query(`INSERT INTO "user_basic_auth"("serial_id", "name", "secret_sha256", "created_at", "updated_at", "userSerialId") SELECT "serial_id", "name", "secret_sha256", "created_at", "updated_at", "userSerialId" FROM "temporary_user_basic_auth"`);
|
await queryRunner.query(`INSERT INTO "user_basic_auth"("serial_id", "name", "secret_sha256", "created_at", "updated_at", "userSerialId") SELECT "serial_id", "name", "secret_sha256", "created_at", "updated_at", "userSerialId" FROM "temporary_user_basic_auth"`);
|
||||||
await queryRunner.query(`DROP TABLE "temporary_user_basic_auth"`);
|
await queryRunner.query(`DROP TABLE "temporary_user_basic_auth"`);
|
||||||
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_361b01c8e10453b2f979246535" ON "user_basic_auth" ("name") `);
|
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_361b01c8e10453b2f979246535" ON "user_basic_auth" ("name") `);
|
||||||
await queryRunner.query(`DROP INDEX "IDX_0a0dbb25a73306b037dec82251"`);
|
await queryRunner.query(`DROP INDEX "IDX_0a0dbb25a73306b037dec82251"`);
|
||||||
await queryRunner.query(`ALTER TABLE "application_user" RENAME TO "temporary_application_user"`);
|
await queryRunner.query(`ALTER TABLE "application_user" RENAME TO "temporary_application_user"`);
|
||||||
await queryRunner.query(`CREATE TABLE "application_user" ("serial_id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "identifier" varchar NOT NULL, "nostr_public_key" varchar, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "updated_at" datetime NOT NULL DEFAULT (datetime('now')), "userSerialId" integer, "applicationSerialId" integer, CONSTRAINT "UQ_3175dc397c8285d1e532554dea5" UNIQUE ("nostr_public_key"), CONSTRAINT "REL_0796a381bcc624f52e9a155712" UNIQUE ("userSerialId"))`);
|
await queryRunner.query(`CREATE TABLE "application_user" ("serial_id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "identifier" varchar NOT NULL, "nostr_public_key" varchar, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "updated_at" datetime NOT NULL DEFAULT (datetime('now')), "userSerialId" integer, "applicationSerialId" integer, CONSTRAINT "UQ_3175dc397c8285d1e532554dea5" UNIQUE ("nostr_public_key"), CONSTRAINT "REL_0796a381bcc624f52e9a155712" UNIQUE ("userSerialId"))`);
|
||||||
await queryRunner.query(`INSERT INTO "application_user"("serial_id", "identifier", "nostr_public_key", "created_at", "updated_at", "userSerialId", "applicationSerialId") SELECT "serial_id", "identifier", "nostr_public_key", "created_at", "updated_at", "userSerialId", "applicationSerialId" FROM "temporary_application_user"`);
|
await queryRunner.query(`INSERT INTO "application_user"("serial_id", "identifier", "nostr_public_key", "created_at", "updated_at", "userSerialId", "applicationSerialId") SELECT "serial_id", "identifier", "nostr_public_key", "created_at", "updated_at", "userSerialId", "applicationSerialId" FROM "temporary_application_user"`);
|
||||||
await queryRunner.query(`DROP TABLE "temporary_application_user"`);
|
await queryRunner.query(`DROP TABLE "temporary_application_user"`);
|
||||||
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_0a0dbb25a73306b037dec82251" ON "application_user" ("identifier") `);
|
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_0a0dbb25a73306b037dec82251" ON "application_user" ("identifier") `);
|
||||||
await queryRunner.query(`DROP INDEX "address_receiving_transaction_unique"`);
|
await queryRunner.query(`DROP INDEX "address_receiving_transaction_unique"`);
|
||||||
await queryRunner.query(`ALTER TABLE "address_receiving_transaction" RENAME TO "temporary_address_receiving_transaction"`);
|
await queryRunner.query(`ALTER TABLE "address_receiving_transaction" RENAME TO "temporary_address_receiving_transaction"`);
|
||||||
await queryRunner.query(`CREATE TABLE "address_receiving_transaction" ("serial_id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "tx_hash" varchar NOT NULL, "output_index" integer NOT NULL, "paid_amount" integer NOT NULL, "service_fee" integer NOT NULL, "paid_at_unix" integer NOT NULL, "internal" boolean NOT NULL DEFAULT (0), "confs" integer NOT NULL DEFAULT (0), "broadcast_height" integer NOT NULL DEFAULT (0), "created_at" datetime NOT NULL DEFAULT (datetime('now')), "updated_at" datetime NOT NULL DEFAULT (datetime('now')), "userAddressSerialId" integer)`);
|
await queryRunner.query(`CREATE TABLE "address_receiving_transaction" ("serial_id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "tx_hash" varchar NOT NULL, "output_index" integer NOT NULL, "paid_amount" integer NOT NULL, "service_fee" integer NOT NULL, "paid_at_unix" integer NOT NULL, "internal" boolean NOT NULL DEFAULT (0), "confs" integer NOT NULL DEFAULT (0), "broadcast_height" integer NOT NULL DEFAULT (0), "created_at" datetime NOT NULL DEFAULT (datetime('now')), "updated_at" datetime NOT NULL DEFAULT (datetime('now')), "userAddressSerialId" integer)`);
|
||||||
await queryRunner.query(`INSERT INTO "address_receiving_transaction"("serial_id", "tx_hash", "output_index", "paid_amount", "service_fee", "paid_at_unix", "internal", "confs", "broadcast_height", "created_at", "updated_at", "userAddressSerialId") SELECT "serial_id", "tx_hash", "output_index", "paid_amount", "service_fee", "paid_at_unix", "internal", "confs", "broadcast_height", "created_at", "updated_at", "userAddressSerialId" FROM "temporary_address_receiving_transaction"`);
|
await queryRunner.query(`INSERT INTO "address_receiving_transaction"("serial_id", "tx_hash", "output_index", "paid_amount", "service_fee", "paid_at_unix", "internal", "confs", "broadcast_height", "created_at", "updated_at", "userAddressSerialId") SELECT "serial_id", "tx_hash", "output_index", "paid_amount", "service_fee", "paid_at_unix", "internal", "confs", "broadcast_height", "created_at", "updated_at", "userAddressSerialId" FROM "temporary_address_receiving_transaction"`);
|
||||||
await queryRunner.query(`DROP TABLE "temporary_address_receiving_transaction"`);
|
await queryRunner.query(`DROP TABLE "temporary_address_receiving_transaction"`);
|
||||||
await queryRunner.query(`CREATE UNIQUE INDEX "address_receiving_transaction_unique" ON "address_receiving_transaction" ("tx_hash", "output_index") `);
|
await queryRunner.query(`CREATE UNIQUE INDEX "address_receiving_transaction_unique" ON "address_receiving_transaction" ("tx_hash", "output_index") `);
|
||||||
await queryRunner.query(`DROP INDEX "IDX_ecf415a7a0b2fa64aa03c5b067"`);
|
await queryRunner.query(`DROP INDEX "IDX_ecf415a7a0b2fa64aa03c5b067"`);
|
||||||
await queryRunner.query(`ALTER TABLE "user_receiving_address" RENAME TO "temporary_user_receiving_address"`);
|
await queryRunner.query(`ALTER TABLE "user_receiving_address" RENAME TO "temporary_user_receiving_address"`);
|
||||||
await queryRunner.query(`CREATE TABLE "user_receiving_address" ("serial_id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "address" varchar NOT NULL, "callbackUrl" varchar NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "updated_at" datetime NOT NULL DEFAULT (datetime('now')), "userSerialId" integer, "linkedApplicationSerialId" integer)`);
|
await queryRunner.query(`CREATE TABLE "user_receiving_address" ("serial_id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "address" varchar NOT NULL, "callbackUrl" varchar NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "updated_at" datetime NOT NULL DEFAULT (datetime('now')), "userSerialId" integer, "linkedApplicationSerialId" integer)`);
|
||||||
await queryRunner.query(`INSERT INTO "user_receiving_address"("serial_id", "address", "callbackUrl", "created_at", "updated_at", "userSerialId", "linkedApplicationSerialId") SELECT "serial_id", "address", "callbackUrl", "created_at", "updated_at", "userSerialId", "linkedApplicationSerialId" FROM "temporary_user_receiving_address"`);
|
await queryRunner.query(`INSERT INTO "user_receiving_address"("serial_id", "address", "callbackUrl", "created_at", "updated_at", "userSerialId", "linkedApplicationSerialId") SELECT "serial_id", "address", "callbackUrl", "created_at", "updated_at", "userSerialId", "linkedApplicationSerialId" FROM "temporary_user_receiving_address"`);
|
||||||
await queryRunner.query(`DROP TABLE "temporary_user_receiving_address"`);
|
await queryRunner.query(`DROP TABLE "temporary_user_receiving_address"`);
|
||||||
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_ecf415a7a0b2fa64aa03c5b067" ON "user_receiving_address" ("address") `);
|
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_ecf415a7a0b2fa64aa03c5b067" ON "user_receiving_address" ("address") `);
|
||||||
await queryRunner.query(`DROP INDEX "IDX_a131e6b58f084f1340538681b5"`);
|
await queryRunner.query(`DROP INDEX "IDX_a131e6b58f084f1340538681b5"`);
|
||||||
await queryRunner.query(`ALTER TABLE "user_receiving_invoice" RENAME TO "temporary_user_receiving_invoice"`);
|
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)`);
|
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)`);
|
||||||
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(`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(`DROP TABLE "temporary_user_receiving_invoice"`);
|
||||||
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_a131e6b58f084f1340538681b5" ON "user_receiving_invoice" ("invoice") `);
|
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_a131e6b58f084f1340538681b5" ON "user_receiving_invoice" ("invoice") `);
|
||||||
await queryRunner.query(`DROP INDEX "IDX_e04964210949f10bb25dc6e747"`);
|
await queryRunner.query(`DROP INDEX "IDX_e04964210949f10bb25dc6e747"`);
|
||||||
await queryRunner.query(`ALTER TABLE "application" RENAME TO "temporary_application"`);
|
await queryRunner.query(`ALTER TABLE "application" RENAME TO "temporary_application"`);
|
||||||
await queryRunner.query(`CREATE TABLE "application" ("serial_id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "app_id" varchar NOT NULL, "name" varchar NOT NULL, "allow_user_creation" boolean NOT NULL DEFAULT (0), "nostr_private_key" varchar, "nostr_public_key" varchar, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "updated_at" datetime NOT NULL DEFAULT (datetime('now')), "ownerSerialId" integer, CONSTRAINT "UQ_608bb41e7e1ef5f6d7abb07e394" UNIQUE ("name"), CONSTRAINT "UQ_f190e1a83a524035b84c1fe0696" UNIQUE ("nostr_private_key"), CONSTRAINT "UQ_87c12c4528183bf7a211221cc3c" UNIQUE ("nostr_public_key"))`);
|
await queryRunner.query(`CREATE TABLE "application" ("serial_id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "app_id" varchar NOT NULL, "name" varchar NOT NULL, "allow_user_creation" boolean NOT NULL DEFAULT (0), "nostr_private_key" varchar, "nostr_public_key" varchar, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "updated_at" datetime NOT NULL DEFAULT (datetime('now')), "ownerSerialId" integer, CONSTRAINT "UQ_608bb41e7e1ef5f6d7abb07e394" UNIQUE ("name"), CONSTRAINT "UQ_f190e1a83a524035b84c1fe0696" UNIQUE ("nostr_private_key"), CONSTRAINT "UQ_87c12c4528183bf7a211221cc3c" UNIQUE ("nostr_public_key"))`);
|
||||||
await queryRunner.query(`INSERT INTO "application"("serial_id", "app_id", "name", "allow_user_creation", "nostr_private_key", "nostr_public_key", "created_at", "updated_at", "ownerSerialId") SELECT "serial_id", "app_id", "name", "allow_user_creation", "nostr_private_key", "nostr_public_key", "created_at", "updated_at", "ownerSerialId" FROM "temporary_application"`);
|
await queryRunner.query(`INSERT INTO "application"("serial_id", "app_id", "name", "allow_user_creation", "nostr_private_key", "nostr_public_key", "created_at", "updated_at", "ownerSerialId") SELECT "serial_id", "app_id", "name", "allow_user_creation", "nostr_private_key", "nostr_public_key", "created_at", "updated_at", "ownerSerialId" FROM "temporary_application"`);
|
||||||
await queryRunner.query(`DROP TABLE "temporary_application"`);
|
await queryRunner.query(`DROP TABLE "temporary_application"`);
|
||||||
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_e04964210949f10bb25dc6e747" ON "application" ("app_id") `);
|
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_e04964210949f10bb25dc6e747" ON "application" ("app_id") `);
|
||||||
await queryRunner.query(`ALTER TABLE "product" RENAME TO "temporary_product"`);
|
await queryRunner.query(`ALTER TABLE "product" RENAME TO "temporary_product"`);
|
||||||
await queryRunner.query(`CREATE TABLE "product" ("product_id" varchar PRIMARY KEY NOT NULL, "name" varchar NOT NULL, "price_sats" integer NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "updated_at" datetime NOT NULL DEFAULT (datetime('now')), "ownerSerialId" integer)`);
|
await queryRunner.query(`CREATE TABLE "product" ("product_id" varchar PRIMARY KEY NOT NULL, "name" varchar NOT NULL, "price_sats" integer NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "updated_at" datetime NOT NULL DEFAULT (datetime('now')), "ownerSerialId" integer)`);
|
||||||
await queryRunner.query(`INSERT INTO "product"("product_id", "name", "price_sats", "created_at", "updated_at", "ownerSerialId") SELECT "product_id", "name", "price_sats", "created_at", "updated_at", "ownerSerialId" FROM "temporary_product"`);
|
await queryRunner.query(`INSERT INTO "product"("product_id", "name", "price_sats", "created_at", "updated_at", "ownerSerialId") SELECT "product_id", "name", "price_sats", "created_at", "updated_at", "ownerSerialId" FROM "temporary_product"`);
|
||||||
await queryRunner.query(`DROP TABLE "temporary_product"`);
|
await queryRunner.query(`DROP TABLE "temporary_product"`);
|
||||||
await queryRunner.query(`DROP INDEX "user_transaction_unique"`);
|
await queryRunner.query(`DROP INDEX "user_transaction_unique"`);
|
||||||
await queryRunner.query(`DROP TABLE "user_transaction_payment"`);
|
await queryRunner.query(`DROP TABLE "user_transaction_payment"`);
|
||||||
await queryRunner.query(`DROP TABLE "user_to_user_payment"`);
|
await queryRunner.query(`DROP TABLE "user_to_user_payment"`);
|
||||||
await queryRunner.query(`DROP INDEX "IDX_a609a4d3d8d9b07b90692a3c45"`);
|
await queryRunner.query(`DROP INDEX "IDX_a609a4d3d8d9b07b90692a3c45"`);
|
||||||
await queryRunner.query(`DROP TABLE "user_invoice_payment"`);
|
await queryRunner.query(`DROP TABLE "user_invoice_payment"`);
|
||||||
await queryRunner.query(`DROP INDEX "IDX_b9628a8315cdc6afed037563d9"`);
|
await queryRunner.query(`DROP INDEX "IDX_b9628a8315cdc6afed037563d9"`);
|
||||||
await queryRunner.query(`DROP TABLE "user_ephemeral_key"`);
|
await queryRunner.query(`DROP TABLE "user_ephemeral_key"`);
|
||||||
await queryRunner.query(`DROP INDEX "IDX_361b01c8e10453b2f979246535"`);
|
await queryRunner.query(`DROP INDEX "IDX_361b01c8e10453b2f979246535"`);
|
||||||
await queryRunner.query(`DROP TABLE "user_basic_auth"`);
|
await queryRunner.query(`DROP TABLE "user_basic_auth"`);
|
||||||
await queryRunner.query(`DROP INDEX "IDX_0a0dbb25a73306b037dec82251"`);
|
await queryRunner.query(`DROP INDEX "IDX_0a0dbb25a73306b037dec82251"`);
|
||||||
await queryRunner.query(`DROP TABLE "application_user"`);
|
await queryRunner.query(`DROP TABLE "application_user"`);
|
||||||
await queryRunner.query(`DROP INDEX "address_receiving_transaction_unique"`);
|
await queryRunner.query(`DROP INDEX "address_receiving_transaction_unique"`);
|
||||||
await queryRunner.query(`DROP TABLE "address_receiving_transaction"`);
|
await queryRunner.query(`DROP TABLE "address_receiving_transaction"`);
|
||||||
await queryRunner.query(`DROP INDEX "IDX_ecf415a7a0b2fa64aa03c5b067"`);
|
await queryRunner.query(`DROP INDEX "IDX_ecf415a7a0b2fa64aa03c5b067"`);
|
||||||
await queryRunner.query(`DROP TABLE "user_receiving_address"`);
|
await queryRunner.query(`DROP TABLE "user_receiving_address"`);
|
||||||
await queryRunner.query(`DROP INDEX "IDX_a131e6b58f084f1340538681b5"`);
|
await queryRunner.query(`DROP INDEX "IDX_a131e6b58f084f1340538681b5"`);
|
||||||
await queryRunner.query(`DROP TABLE "user_receiving_invoice"`);
|
await queryRunner.query(`DROP TABLE "user_receiving_invoice"`);
|
||||||
await queryRunner.query(`DROP INDEX "IDX_e04964210949f10bb25dc6e747"`);
|
await queryRunner.query(`DROP INDEX "IDX_e04964210949f10bb25dc6e747"`);
|
||||||
await queryRunner.query(`DROP TABLE "application"`);
|
await queryRunner.query(`DROP TABLE "application"`);
|
||||||
await queryRunner.query(`DROP TABLE "product"`);
|
await queryRunner.query(`DROP TABLE "product"`);
|
||||||
await queryRunner.query(`DROP INDEX "IDX_758b8ce7c18b9d347461b30228"`);
|
await queryRunner.query(`DROP INDEX "IDX_758b8ce7c18b9d347461b30228"`);
|
||||||
await queryRunner.query(`DROP TABLE "user"`);
|
await queryRunner.query(`DROP TABLE "user"`);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,26 +1,26 @@
|
||||||
import { MigrationInterface, QueryRunner } from "typeorm";
|
import { MigrationInterface, QueryRunner } from "typeorm";
|
||||||
|
|
||||||
export class LndMetrics1703170330183 implements MigrationInterface {
|
export class LndMetrics1703170330183 implements MigrationInterface {
|
||||||
name = 'LndMetrics1703170330183'
|
name = 'LndMetrics1703170330183'
|
||||||
|
|
||||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||||
await queryRunner.query(`CREATE TABLE "balance_event" ("serial_id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "block_height" integer NOT NULL, "confirmed_chain_balance" integer NOT NULL, "unconfirmed_chain_balance" integer NOT NULL, "total_chain_balance" integer NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "updated_at" datetime NOT NULL DEFAULT (datetime('now')))`);
|
await queryRunner.query(`CREATE TABLE "balance_event" ("serial_id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "block_height" integer NOT NULL, "confirmed_chain_balance" integer NOT NULL, "unconfirmed_chain_balance" integer NOT NULL, "total_chain_balance" integer NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "updated_at" datetime NOT NULL DEFAULT (datetime('now')))`);
|
||||||
await queryRunner.query(`CREATE TABLE "channel_balance_event" ("serial_id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "channel_id" varchar NOT NULL, "local_balance_sats" integer NOT NULL, "remote_balance_sats" integer NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "updated_at" datetime NOT NULL DEFAULT (datetime('now')), "balanceEventSerialId" integer)`);
|
await queryRunner.query(`CREATE TABLE "channel_balance_event" ("serial_id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "channel_id" varchar NOT NULL, "local_balance_sats" integer NOT NULL, "remote_balance_sats" integer NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "updated_at" datetime NOT NULL DEFAULT (datetime('now')), "balanceEventSerialId" integer)`);
|
||||||
await queryRunner.query(`CREATE TABLE "routing_event" ("serial_id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "incoming_channel_id" integer NOT NULL, "incoming_htlc_id" integer NOT NULL, "outgoing_channel_id" integer NOT NULL, "outgoing_htlc_id" integer NOT NULL, "timestamp_ns" integer NOT NULL, "event_type" varchar NOT NULL, "incoming_amt_msat" integer, "outgoing_amt_msat" integer, "failure_string" varchar, "settled" boolean, "offchain" boolean, "forward_fail_event" boolean, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "updated_at" datetime NOT NULL DEFAULT (datetime('now')))`);
|
await queryRunner.query(`CREATE TABLE "routing_event" ("serial_id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "incoming_channel_id" integer NOT NULL, "incoming_htlc_id" integer NOT NULL, "outgoing_channel_id" integer NOT NULL, "outgoing_htlc_id" integer NOT NULL, "timestamp_ns" integer NOT NULL, "event_type" varchar NOT NULL, "incoming_amt_msat" integer, "outgoing_amt_msat" integer, "failure_string" varchar, "settled" boolean, "offchain" boolean, "forward_fail_event" boolean, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "updated_at" datetime NOT NULL DEFAULT (datetime('now')))`);
|
||||||
await queryRunner.query(`CREATE TABLE "temporary_channel_balance_event" ("serial_id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "channel_id" varchar NOT NULL, "local_balance_sats" integer NOT NULL, "remote_balance_sats" integer NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "updated_at" datetime NOT NULL DEFAULT (datetime('now')), "balanceEventSerialId" integer, CONSTRAINT "FK_e203090b07e770fe2e21a32e7c1" FOREIGN KEY ("balanceEventSerialId") REFERENCES "balance_event" ("serial_id") ON DELETE NO ACTION ON UPDATE NO ACTION)`);
|
await queryRunner.query(`CREATE TABLE "temporary_channel_balance_event" ("serial_id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "channel_id" varchar NOT NULL, "local_balance_sats" integer NOT NULL, "remote_balance_sats" integer NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "updated_at" datetime NOT NULL DEFAULT (datetime('now')), "balanceEventSerialId" integer, CONSTRAINT "FK_e203090b07e770fe2e21a32e7c1" FOREIGN KEY ("balanceEventSerialId") REFERENCES "balance_event" ("serial_id") ON DELETE NO ACTION ON UPDATE NO ACTION)`);
|
||||||
await queryRunner.query(`INSERT INTO "temporary_channel_balance_event"("serial_id", "channel_id", "local_balance_sats", "remote_balance_sats", "created_at", "updated_at", "balanceEventSerialId") SELECT "serial_id", "channel_id", "local_balance_sats", "remote_balance_sats", "created_at", "updated_at", "balanceEventSerialId" FROM "channel_balance_event"`);
|
await queryRunner.query(`INSERT INTO "temporary_channel_balance_event"("serial_id", "channel_id", "local_balance_sats", "remote_balance_sats", "created_at", "updated_at", "balanceEventSerialId") SELECT "serial_id", "channel_id", "local_balance_sats", "remote_balance_sats", "created_at", "updated_at", "balanceEventSerialId" FROM "channel_balance_event"`);
|
||||||
await queryRunner.query(`DROP TABLE "channel_balance_event"`);
|
await queryRunner.query(`DROP TABLE "channel_balance_event"`);
|
||||||
await queryRunner.query(`ALTER TABLE "temporary_channel_balance_event" RENAME TO "channel_balance_event"`);
|
await queryRunner.query(`ALTER TABLE "temporary_channel_balance_event" RENAME TO "channel_balance_event"`);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||||
await queryRunner.query(`ALTER TABLE "channel_balance_event" RENAME TO "temporary_channel_balance_event"`);
|
await queryRunner.query(`ALTER TABLE "channel_balance_event" RENAME TO "temporary_channel_balance_event"`);
|
||||||
await queryRunner.query(`CREATE TABLE "channel_balance_event" ("serial_id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "channel_id" varchar NOT NULL, "local_balance_sats" integer NOT NULL, "remote_balance_sats" integer NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "updated_at" datetime NOT NULL DEFAULT (datetime('now')), "balanceEventSerialId" integer)`);
|
await queryRunner.query(`CREATE TABLE "channel_balance_event" ("serial_id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "channel_id" varchar NOT NULL, "local_balance_sats" integer NOT NULL, "remote_balance_sats" integer NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "updated_at" datetime NOT NULL DEFAULT (datetime('now')), "balanceEventSerialId" integer)`);
|
||||||
await queryRunner.query(`INSERT INTO "channel_balance_event"("serial_id", "channel_id", "local_balance_sats", "remote_balance_sats", "created_at", "updated_at", "balanceEventSerialId") SELECT "serial_id", "channel_id", "local_balance_sats", "remote_balance_sats", "created_at", "updated_at", "balanceEventSerialId" FROM "temporary_channel_balance_event"`);
|
await queryRunner.query(`INSERT INTO "channel_balance_event"("serial_id", "channel_id", "local_balance_sats", "remote_balance_sats", "created_at", "updated_at", "balanceEventSerialId") SELECT "serial_id", "channel_id", "local_balance_sats", "remote_balance_sats", "created_at", "updated_at", "balanceEventSerialId" FROM "temporary_channel_balance_event"`);
|
||||||
await queryRunner.query(`DROP TABLE "temporary_channel_balance_event"`);
|
await queryRunner.query(`DROP TABLE "temporary_channel_balance_event"`);
|
||||||
await queryRunner.query(`DROP TABLE "routing_event"`);
|
await queryRunner.query(`DROP TABLE "routing_event"`);
|
||||||
await queryRunner.query(`DROP TABLE "channel_balance_event"`);
|
await queryRunner.query(`DROP TABLE "channel_balance_event"`);
|
||||||
await queryRunner.query(`DROP TABLE "balance_event"`);
|
await queryRunner.query(`DROP TABLE "balance_event"`);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,14 @@
|
||||||
import { MigrationInterface, QueryRunner } from "typeorm";
|
import { MigrationInterface, QueryRunner } from "typeorm";
|
||||||
|
|
||||||
export class ChannelRouting1709316653538 implements MigrationInterface {
|
export class ChannelRouting1709316653538 implements MigrationInterface {
|
||||||
name = 'ChannelRouting1709316653538'
|
name = 'ChannelRouting1709316653538'
|
||||||
|
|
||||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||||
await queryRunner.query(`CREATE TABLE "channel_routing" ("serial_id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "day_unix" integer NOT NULL, "channel_id" varchar NOT NULL, "send_errors" integer NOT NULL DEFAULT (0), "receive_errors" integer NOT NULL DEFAULT (0), "forward_errors_as_input" integer NOT NULL DEFAULT (0), "forward_errors_as_output" integer NOT NULL DEFAULT (0), "missed_forward_fee_as_input" integer NOT NULL DEFAULT (0), "missed_forward_fee_as_output" integer NOT NULL DEFAULT (0), "forward_fee_as_input" integer NOT NULL DEFAULT (0), "forward_fee_as_output" integer NOT NULL DEFAULT (0), "latest_index_offset" 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 TABLE "channel_routing" ("serial_id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "day_unix" integer NOT NULL, "channel_id" varchar NOT NULL, "send_errors" integer NOT NULL DEFAULT (0), "receive_errors" integer NOT NULL DEFAULT (0), "forward_errors_as_input" integer NOT NULL DEFAULT (0), "forward_errors_as_output" integer NOT NULL DEFAULT (0), "missed_forward_fee_as_input" integer NOT NULL DEFAULT (0), "missed_forward_fee_as_output" integer NOT NULL DEFAULT (0), "forward_fee_as_input" integer NOT NULL DEFAULT (0), "forward_fee_as_output" integer NOT NULL DEFAULT (0), "latest_index_offset" integer NOT NULL DEFAULT (0), "created_at" datetime NOT NULL DEFAULT (datetime('now')), "updated_at" datetime NOT NULL DEFAULT (datetime('now')))`);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||||
await queryRunner.query(`DROP TABLE "channel_routing"`);
|
await queryRunner.query(`DROP TABLE "channel_routing"`);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,26 +1,26 @@
|
||||||
import { DataSource, EntityManager } from "typeorm"
|
import { DataSource, EntityManager } from "typeorm"
|
||||||
import { Product } from "./entity/Product.js"
|
import { Product } from "./entity/Product.js"
|
||||||
import { User } from "./entity/User.js"
|
import { User } from "./entity/User.js"
|
||||||
import TransactionsQueue, { TX } from "./transactionsQueue.js";
|
import TransactionsQueue, { TX } from "./transactionsQueue.js";
|
||||||
export default class {
|
export default class {
|
||||||
DB: DataSource | EntityManager
|
DB: DataSource | EntityManager
|
||||||
txQueue: TransactionsQueue
|
txQueue: TransactionsQueue
|
||||||
constructor(DB: DataSource | EntityManager, txQueue: TransactionsQueue) {
|
constructor(DB: DataSource | EntityManager, txQueue: TransactionsQueue) {
|
||||||
this.DB = DB
|
this.DB = DB
|
||||||
this.txQueue = txQueue
|
this.txQueue = txQueue
|
||||||
}
|
}
|
||||||
async AddProduct(name: string, priceSats: number, user: User): Promise<Product> {
|
async AddProduct(name: string, priceSats: number, user: User): Promise<Product> {
|
||||||
const newProduct = this.DB.getRepository(Product).create({
|
const newProduct = this.DB.getRepository(Product).create({
|
||||||
name: name, price_sats: priceSats, owner: user
|
name: name, price_sats: priceSats, owner: user
|
||||||
})
|
})
|
||||||
return this.txQueue.PushToQueue<Product>({ exec: async db => db.getRepository(Product).save(newProduct), dbTx: false })
|
return this.txQueue.PushToQueue<Product>({ exec: async db => db.getRepository(Product).save(newProduct), dbTx: false })
|
||||||
}
|
}
|
||||||
|
|
||||||
async GetProduct(id: string, entityManager = this.DB): Promise<Product> {
|
async GetProduct(id: string, entityManager = this.DB): Promise<Product> {
|
||||||
const product = await entityManager.getRepository(Product).findOne({ where: { product_id: id } })
|
const product = await entityManager.getRepository(Product).findOne({ where: { product_id: id } })
|
||||||
if (!product) {
|
if (!product) {
|
||||||
throw new Error("product not found")
|
throw new Error("product not found")
|
||||||
}
|
}
|
||||||
return product
|
return product
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,81 +1,81 @@
|
||||||
import { DataSource, EntityManager, EntityTarget } from "typeorm"
|
import { DataSource, EntityManager, EntityTarget } from "typeorm"
|
||||||
import { PubLogger, getLogger } from "../helpers/logger.js"
|
import { PubLogger, getLogger } from "../helpers/logger.js"
|
||||||
|
|
||||||
export type TX<T> = (entityManager: EntityManager | DataSource) => Promise<T>
|
export type TX<T> = (entityManager: EntityManager | DataSource) => Promise<T>
|
||||||
export type TxOperation<T> = {
|
export type TxOperation<T> = {
|
||||||
exec: TX<T>
|
exec: TX<T>
|
||||||
dbTx: boolean
|
dbTx: boolean
|
||||||
description?: string
|
description?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class {
|
export default class {
|
||||||
DB: DataSource | EntityManager
|
DB: DataSource | EntityManager
|
||||||
pendingTx: boolean
|
pendingTx: boolean
|
||||||
transactionsQueue: { op: TxOperation<any>, res: (v: any) => void, rej: (message: string) => void }[] = []
|
transactionsQueue: { op: TxOperation<any>, res: (v: any) => void, rej: (message: string) => void }[] = []
|
||||||
log: PubLogger
|
log: PubLogger
|
||||||
constructor(name: string, DB: DataSource | EntityManager) {
|
constructor(name: string, DB: DataSource | EntityManager) {
|
||||||
this.DB = DB
|
this.DB = DB
|
||||||
this.log = getLogger({ component: name })
|
this.log = getLogger({ component: name })
|
||||||
}
|
}
|
||||||
|
|
||||||
PushToQueue<T>(op: TxOperation<T>) {
|
PushToQueue<T>(op: TxOperation<T>) {
|
||||||
if (!this.pendingTx) {
|
if (!this.pendingTx) {
|
||||||
return this.execQueueItem(op)
|
return this.execQueueItem(op)
|
||||||
}
|
}
|
||||||
return new Promise<T>((res, rej) => {
|
return new Promise<T>((res, rej) => {
|
||||||
this.transactionsQueue.push({ op, res, rej })
|
this.transactionsQueue.push({ op, res, rej })
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async execNextInQueue() {
|
async execNextInQueue() {
|
||||||
this.pendingTx = false
|
this.pendingTx = false
|
||||||
const next = this.transactionsQueue.pop()
|
const next = this.transactionsQueue.pop()
|
||||||
if (!next) {
|
if (!next) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const res = await this.execQueueItem(next.op)
|
const res = await this.execQueueItem(next.op)
|
||||||
if (next.op.description) this.log("done", next.op.description)
|
if (next.op.description) this.log("done", next.op.description)
|
||||||
next.res(res)
|
next.res(res)
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
next.rej(err.message)
|
next.rej(err.message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
execQueueItem<T>(op: TxOperation<T>) {
|
execQueueItem<T>(op: TxOperation<T>) {
|
||||||
if (this.pendingTx) {
|
if (this.pendingTx) {
|
||||||
throw new Error("cannot start DB transaction")
|
throw new Error("cannot start DB transaction")
|
||||||
}
|
}
|
||||||
this.pendingTx = true
|
this.pendingTx = true
|
||||||
if (op.dbTx) {
|
if (op.dbTx) {
|
||||||
return this.doTransaction(op.exec)
|
return this.doTransaction(op.exec)
|
||||||
}
|
}
|
||||||
return this.doOperation(op.exec)
|
return this.doOperation(op.exec)
|
||||||
}
|
}
|
||||||
|
|
||||||
async doOperation<T>(exec: TX<T>) {
|
async doOperation<T>(exec: TX<T>) {
|
||||||
try {
|
try {
|
||||||
const res = await exec(this.DB)
|
const res = await exec(this.DB)
|
||||||
this.execNextInQueue()
|
this.execNextInQueue()
|
||||||
return res
|
return res
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
this.execNextInQueue()
|
this.execNextInQueue()
|
||||||
throw err
|
throw err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
async doTransaction<T>(exec: TX<T>) {
|
async doTransaction<T>(exec: TX<T>) {
|
||||||
try {
|
try {
|
||||||
const res = await this.DB.transaction(async tx => {
|
const res = await this.DB.transaction(async tx => {
|
||||||
return exec(tx)
|
return exec(tx)
|
||||||
})
|
})
|
||||||
this.execNextInQueue()
|
this.execNextInQueue()
|
||||||
return res
|
return res
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
this.execNextInQueue()
|
this.execNextInQueue()
|
||||||
this.log("transaction failed", err.message)
|
this.log("transaction failed", err.message)
|
||||||
throw err
|
throw err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,137 +1,137 @@
|
||||||
import crypto from 'crypto';
|
import crypto from 'crypto';
|
||||||
import { DataSource, EntityManager } from "typeorm"
|
import { DataSource, EntityManager } from "typeorm"
|
||||||
import { User } from './entity/User.js';
|
import { User } from './entity/User.js';
|
||||||
import { UserBasicAuth } from './entity/UserBasicAuth.js';
|
import { UserBasicAuth } from './entity/UserBasicAuth.js';
|
||||||
import { getLogger } from '../helpers/logger.js';
|
import { getLogger } from '../helpers/logger.js';
|
||||||
import TransactionsQueue from "./transactionsQueue.js";
|
import TransactionsQueue from "./transactionsQueue.js";
|
||||||
import EventsLogManager from './eventsLog.js';
|
import EventsLogManager from './eventsLog.js';
|
||||||
export default class {
|
export default class {
|
||||||
DB: DataSource | EntityManager
|
DB: DataSource | EntityManager
|
||||||
txQueue: TransactionsQueue
|
txQueue: TransactionsQueue
|
||||||
eventsLog: EventsLogManager
|
eventsLog: EventsLogManager
|
||||||
constructor(DB: DataSource | EntityManager, txQueue: TransactionsQueue, eventsLog: EventsLogManager) {
|
constructor(DB: DataSource | EntityManager, txQueue: TransactionsQueue, eventsLog: EventsLogManager) {
|
||||||
this.DB = DB
|
this.DB = DB
|
||||||
this.txQueue = txQueue
|
this.txQueue = txQueue
|
||||||
this.eventsLog = eventsLog
|
this.eventsLog = eventsLog
|
||||||
}
|
}
|
||||||
|
|
||||||
async AddUser(balance: number, dbTx: DataSource | EntityManager): Promise<User> {
|
async AddUser(balance: number, dbTx: DataSource | EntityManager): Promise<User> {
|
||||||
if (balance && process.env.ALLOW_BALANCE_MIGRATION !== 'true') {
|
if (balance && process.env.ALLOW_BALANCE_MIGRATION !== 'true') {
|
||||||
throw new Error("balance migration is not allowed")
|
throw new Error("balance migration is not allowed")
|
||||||
}
|
}
|
||||||
getLogger({})("Adding user with balance", balance)
|
getLogger({})("Adding user with balance", balance)
|
||||||
const newUser = dbTx.getRepository(User).create({
|
const newUser = dbTx.getRepository(User).create({
|
||||||
user_id: crypto.randomBytes(32).toString('hex'),
|
user_id: crypto.randomBytes(32).toString('hex'),
|
||||||
balance_sats: balance
|
balance_sats: balance
|
||||||
})
|
})
|
||||||
return dbTx.getRepository(User).save(newUser)
|
return dbTx.getRepository(User).save(newUser)
|
||||||
}
|
}
|
||||||
|
|
||||||
async AddBasicUser(name: string, secret: string): Promise<UserBasicAuth> {
|
async AddBasicUser(name: string, secret: string): Promise<UserBasicAuth> {
|
||||||
return this.DB.transaction(async tx => {
|
return this.DB.transaction(async tx => {
|
||||||
const user = await this.AddUser(0, tx)
|
const user = await this.AddUser(0, tx)
|
||||||
const newUserAuth = tx.getRepository(UserBasicAuth).create({
|
const newUserAuth = tx.getRepository(UserBasicAuth).create({
|
||||||
user: user,
|
user: user,
|
||||||
name: name,
|
name: name,
|
||||||
secret_sha256: crypto.createHash('sha256').update(secret).digest('base64')
|
secret_sha256: crypto.createHash('sha256').update(secret).digest('base64')
|
||||||
})
|
})
|
||||||
return tx.getRepository(UserBasicAuth).save(newUserAuth)
|
return tx.getRepository(UserBasicAuth).save(newUserAuth)
|
||||||
})
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
FindUser(userId: string, entityManager = this.DB) {
|
FindUser(userId: string, entityManager = this.DB) {
|
||||||
return entityManager.getRepository(User).findOne({
|
return entityManager.getRepository(User).findOne({
|
||||||
where: {
|
where: {
|
||||||
user_id: userId
|
user_id: userId
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
async GetUser(userId: string, entityManager = this.DB): Promise<User> {
|
async GetUser(userId: string, entityManager = this.DB): Promise<User> {
|
||||||
const user = await this.FindUser(userId, entityManager)
|
const user = await this.FindUser(userId, entityManager)
|
||||||
if (!user) {
|
if (!user) {
|
||||||
throw new Error(`user ${userId} not found`) // TODO: fix logs doxing
|
throw new Error(`user ${userId} not found`) // TODO: fix logs doxing
|
||||||
}
|
}
|
||||||
return user
|
return user
|
||||||
}
|
}
|
||||||
|
|
||||||
async UnbanUser(userId: string, entityManager = this.DB) {
|
async UnbanUser(userId: string, entityManager = this.DB) {
|
||||||
const res = await entityManager.getRepository(User).update({
|
const res = await entityManager.getRepository(User).update({
|
||||||
user_id: userId
|
user_id: userId
|
||||||
}, { locked: false })
|
}, { locked: false })
|
||||||
if (!res.affected) {
|
if (!res.affected) {
|
||||||
throw new Error("unaffected user unlock for " + userId) // TODO: fix logs doxing
|
throw new Error("unaffected user unlock for " + userId) // TODO: fix logs doxing
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async BanUser(userId: string, entityManager = this.DB) {
|
async BanUser(userId: string, entityManager = this.DB) {
|
||||||
const user = await this.GetUser(userId, entityManager)
|
const user = await this.GetUser(userId, entityManager)
|
||||||
const res = await entityManager.getRepository(User).update({
|
const res = await entityManager.getRepository(User).update({
|
||||||
user_id: userId
|
user_id: userId
|
||||||
}, { balance_sats: 0, locked: true })
|
}, { balance_sats: 0, locked: true })
|
||||||
if (!res.affected) {
|
if (!res.affected) {
|
||||||
throw new Error("unaffected ban user for " + userId) // TODO: fix logs doxing
|
throw new Error("unaffected ban user for " + userId) // TODO: fix logs doxing
|
||||||
}
|
}
|
||||||
if (user.balance_sats > 0) {
|
if (user.balance_sats > 0) {
|
||||||
this.eventsLog.LogEvent({ type: 'balance_decrement', userId, appId: "", appUserId: "", balance: user.balance_sats, data: 'ban', amount: user.balance_sats })
|
this.eventsLog.LogEvent({ type: 'balance_decrement', userId, appId: "", appUserId: "", balance: user.balance_sats, data: 'ban', amount: user.balance_sats })
|
||||||
}
|
}
|
||||||
return user
|
return user
|
||||||
}
|
}
|
||||||
async IncrementUserBalance(userId: string, increment: number, reason: string, entityManager?: DataSource | EntityManager) {
|
async IncrementUserBalance(userId: string, increment: number, reason: string, entityManager?: DataSource | EntityManager) {
|
||||||
if (entityManager) {
|
if (entityManager) {
|
||||||
return this.IncrementUserBalanceInTx(userId, increment, reason, entityManager)
|
return this.IncrementUserBalanceInTx(userId, increment, reason, entityManager)
|
||||||
}
|
}
|
||||||
await this.txQueue.PushToQueue({
|
await this.txQueue.PushToQueue({
|
||||||
dbTx: true,
|
dbTx: true,
|
||||||
description: `incrementing user ${userId} balance by ${increment}`,
|
description: `incrementing user ${userId} balance by ${increment}`,
|
||||||
exec: async tx => {
|
exec: async tx => {
|
||||||
await this.IncrementUserBalanceInTx(userId, increment, reason, tx)
|
await this.IncrementUserBalanceInTx(userId, increment, reason, tx)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
async IncrementUserBalanceInTx(userId: string, increment: number, reason: string, dbTx: DataSource | EntityManager) {
|
async IncrementUserBalanceInTx(userId: string, increment: number, reason: string, dbTx: DataSource | EntityManager) {
|
||||||
const user = await this.GetUser(userId, dbTx)
|
const user = await this.GetUser(userId, dbTx)
|
||||||
const res = await dbTx.getRepository(User).increment({
|
const res = await dbTx.getRepository(User).increment({
|
||||||
user_id: userId,
|
user_id: userId,
|
||||||
}, "balance_sats", increment)
|
}, "balance_sats", increment)
|
||||||
if (!res.affected) {
|
if (!res.affected) {
|
||||||
getLogger({ userId: userId, component: "balanceUpdates" })("user unaffected by increment")
|
getLogger({ userId: userId, component: "balanceUpdates" })("user unaffected by increment")
|
||||||
throw new Error("unaffected balance increment for " + userId) // TODO: fix logs doxing
|
throw new Error("unaffected balance increment for " + userId) // TODO: fix logs doxing
|
||||||
}
|
}
|
||||||
getLogger({ userId: userId, component: "balanceUpdates" })("incremented balance from", user.balance_sats, "sats, by", increment, "sats")
|
getLogger({ userId: userId, component: "balanceUpdates" })("incremented balance from", user.balance_sats, "sats, by", increment, "sats")
|
||||||
this.eventsLog.LogEvent({ type: 'balance_increment', userId, appId: "", appUserId: "", balance: user.balance_sats, data: reason, amount: increment })
|
this.eventsLog.LogEvent({ type: 'balance_increment', userId, appId: "", appUserId: "", balance: user.balance_sats, data: reason, amount: increment })
|
||||||
}
|
}
|
||||||
async DecrementUserBalance(userId: string, decrement: number, reason: string, entityManager?: DataSource | EntityManager) {
|
async DecrementUserBalance(userId: string, decrement: number, reason: string, entityManager?: DataSource | EntityManager) {
|
||||||
if (entityManager) {
|
if (entityManager) {
|
||||||
return this.DecrementUserBalanceInTx(userId, decrement, reason, entityManager)
|
return this.DecrementUserBalanceInTx(userId, decrement, reason, entityManager)
|
||||||
}
|
}
|
||||||
await this.txQueue.PushToQueue({
|
await this.txQueue.PushToQueue({
|
||||||
dbTx: true,
|
dbTx: true,
|
||||||
description: `decrementing user ${userId} balance by ${decrement}`,
|
description: `decrementing user ${userId} balance by ${decrement}`,
|
||||||
exec: async tx => {
|
exec: async tx => {
|
||||||
await this.DecrementUserBalanceInTx(userId, decrement, reason, tx)
|
await this.DecrementUserBalanceInTx(userId, decrement, reason, tx)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async DecrementUserBalanceInTx(userId: string, decrement: number, reason: string, dbTx: DataSource | EntityManager) {
|
async DecrementUserBalanceInTx(userId: string, decrement: number, reason: string, dbTx: DataSource | EntityManager) {
|
||||||
const user = await this.GetUser(userId, dbTx)
|
const user = await this.GetUser(userId, dbTx)
|
||||||
if (!user || user.balance_sats < decrement) {
|
if (!user || user.balance_sats < decrement) {
|
||||||
getLogger({ userId: userId, component: "balanceUpdates" })("not enough balance to decrement")
|
getLogger({ userId: userId, component: "balanceUpdates" })("not enough balance to decrement")
|
||||||
throw new Error("not enough balance to decrement")
|
throw new Error("not enough balance to decrement")
|
||||||
}
|
}
|
||||||
const res = await dbTx.getRepository(User).decrement({
|
const res = await dbTx.getRepository(User).decrement({
|
||||||
user_id: userId,
|
user_id: userId,
|
||||||
}, "balance_sats", decrement)
|
}, "balance_sats", decrement)
|
||||||
if (!res.affected) {
|
if (!res.affected) {
|
||||||
getLogger({ userId: userId, component: "balanceUpdates" })("user unaffected by decrement")
|
getLogger({ userId: userId, component: "balanceUpdates" })("user unaffected by decrement")
|
||||||
throw new Error("unaffected balance decrement for " + userId) // TODO: fix logs doxing
|
throw new Error("unaffected balance decrement for " + userId) // TODO: fix logs doxing
|
||||||
}
|
}
|
||||||
getLogger({ userId: userId, component: "balanceUpdates" })("decremented balance from", user.balance_sats, "sats, by", decrement, "sats")
|
getLogger({ userId: userId, component: "balanceUpdates" })("decremented balance from", user.balance_sats, "sats, by", decrement, "sats")
|
||||||
this.eventsLog.LogEvent({ type: 'balance_decrement', userId, appId: "", appUserId: "", balance: user.balance_sats, data: reason, amount: decrement })
|
this.eventsLog.LogEvent({ type: 'balance_decrement', userId, appId: "", appUserId: "", balance: user.balance_sats, data: reason, amount: decrement })
|
||||||
}
|
}
|
||||||
|
|
||||||
async UpdateUser(userId: string, update: Partial<User>, entityManager = this.DB) {
|
async UpdateUser(userId: string, update: Partial<User>, entityManager = this.DB) {
|
||||||
const user = await this.GetUser(userId, entityManager)
|
const user = await this.GetUser(userId, entityManager)
|
||||||
await entityManager.getRepository(User).update(user.serial_id, update)
|
await entityManager.getRepository(User).update(user.serial_id, update)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,40 +1,40 @@
|
||||||
LND_ADDRESS=127.0.0.1:10001 #alice
|
LND_ADDRESS=127.0.0.1:10001 #alice
|
||||||
LND_CERT_PATH=alice-tls.cert #alice
|
LND_CERT_PATH=alice-tls.cert #alice
|
||||||
LND_MACAROON_PATH=alice-admin.macaroon
|
LND_MACAROON_PATH=alice-admin.macaroon
|
||||||
DATABASE_FILE=db.sqlite
|
DATABASE_FILE=db.sqlite
|
||||||
JWT_SECRET=bigsecrethere
|
JWT_SECRET=bigsecrethere
|
||||||
ALLOW_BALANCE_MIGRATION=true
|
ALLOW_BALANCE_MIGRATION=true
|
||||||
OUTBOUND_MAX_FEE_BPS=60
|
OUTBOUND_MAX_FEE_BPS=60
|
||||||
OUTBOUND_MAX_FEE_EXTRA_SATS=100
|
OUTBOUND_MAX_FEE_EXTRA_SATS=100
|
||||||
INCOMING_CHAIN_FEE_ROOT_BPS=0
|
INCOMING_CHAIN_FEE_ROOT_BPS=0
|
||||||
OUTGOING_CHAIN_FEE_ROOT_BPS=60 #this is applied only to withdrawls from application wallets
|
OUTGOING_CHAIN_FEE_ROOT_BPS=60 #this is applied only to withdrawls from application wallets
|
||||||
INCOMING_INVOICE_FEE_ROOT_BPS=0
|
INCOMING_INVOICE_FEE_ROOT_BPS=0
|
||||||
OUTGOING_INVOICE_FEE_ROOT_BPS=60 #this is applied only to withdrawals from application wallets
|
OUTGOING_INVOICE_FEE_ROOT_BPS=60 #this is applied only to withdrawals from application wallets
|
||||||
INCOMING_INVOICE_FEE_USER_BPS=0 #defined by app this is just default
|
INCOMING_INVOICE_FEE_USER_BPS=0 #defined by app this is just default
|
||||||
OUTGOING_INVOICE_FEE_USER_BPS=60 #defined by app this is just default
|
OUTGOING_INVOICE_FEE_USER_BPS=60 #defined by app this is just default
|
||||||
TX_FEE_INTERNAL_ROOT_BPS=60 #this is applied only to withdrawls from application wallets
|
TX_FEE_INTERNAL_ROOT_BPS=60 #this is applied only to withdrawls from application wallets
|
||||||
TX_FEE_INTERNAL_USER_BPS=60 #defined by app this is just default
|
TX_FEE_INTERNAL_USER_BPS=60 #defined by app this is just default
|
||||||
NOSTR_RELAYS=wss://strfry.shock.network
|
NOSTR_RELAYS=wss://strfry.shock.network
|
||||||
SERVICE_URL=http://localhost:8080
|
SERVICE_URL=http://localhost:8080
|
||||||
ADMIN_TOKEN=thisisadmin
|
ADMIN_TOKEN=thisisadmin
|
||||||
PORT=8080
|
PORT=8080
|
||||||
METRICS_DATABASE_FILE=metrics.sqlite
|
METRICS_DATABASE_FILE=metrics.sqlite
|
||||||
WATCHDOG_MAX_DIFF_BPS=100
|
WATCHDOG_MAX_DIFF_BPS=100
|
||||||
WATCHDOG_MAX_DIFF_SATS=10000
|
WATCHDOG_MAX_DIFF_SATS=10000
|
||||||
|
|
||||||
# dave <--> alice <--> carol <--> bob
|
# dave <--> alice <--> carol <--> bob
|
||||||
LND_OTHER_ADDR=127.0.0.1:10002
|
LND_OTHER_ADDR=127.0.0.1:10002
|
||||||
LND_OTHER_CERT_PATH=bob-tls.cert
|
LND_OTHER_CERT_PATH=bob-tls.cert
|
||||||
LND_OTHER_MACAROON_PATH=bob-admin.macaroon
|
LND_OTHER_MACAROON_PATH=bob-admin.macaroon
|
||||||
|
|
||||||
LND_THIRD_ADDR=127.0.0.1:10003
|
LND_THIRD_ADDR=127.0.0.1:10003
|
||||||
LND_THIRD_CERT_PATH=carol-tls.cert
|
LND_THIRD_CERT_PATH=carol-tls.cert
|
||||||
LND_THIRD_MACAROON_PATH=carol-admin.macaroon
|
LND_THIRD_MACAROON_PATH=carol-admin.macaroon
|
||||||
|
|
||||||
LND_FOURTH_ADDR=127.0.0.1:10004
|
LND_FOURTH_ADDR=127.0.0.1:10004
|
||||||
LND_FOURTH_CERT_PATH=dave-tls.cert
|
LND_FOURTH_CERT_PATH=dave-tls.cert
|
||||||
LND_FOURTH_MACAROON_PATH=dave-admin.macaroon
|
LND_FOURTH_MACAROON_PATH=dave-admin.macaroon
|
||||||
|
|
||||||
BITCOIN_CORE_PORT=18443
|
BITCOIN_CORE_PORT=18443
|
||||||
BITCOIN_CORE_USER=polaruser
|
BITCOIN_CORE_USER=polaruser
|
||||||
BITCOIN_CORE_PASS=polarpass
|
BITCOIN_CORE_PASS=polarpass
|
||||||
|
|
@ -1,17 +1,17 @@
|
||||||
FROM node:10-alpine
|
FROM node:10-alpine
|
||||||
|
|
||||||
RUN mkdir -p /home/node/app/node_modules && chown -R node:node /home/node/app
|
RUN mkdir -p /home/node/app/node_modules && chown -R node:node /home/node/app
|
||||||
|
|
||||||
WORKDIR /home/node/app
|
WORKDIR /home/node/app
|
||||||
|
|
||||||
COPY package*.json ./
|
COPY package*.json ./
|
||||||
|
|
||||||
USER node
|
USER node
|
||||||
|
|
||||||
RUN npm install
|
RUN npm install
|
||||||
|
|
||||||
COPY env.example .env
|
COPY env.example .env
|
||||||
|
|
||||||
COPY --chown=node:node . .
|
COPY --chown=node:node . .
|
||||||
|
|
||||||
CMD [ "npm", "test" ]
|
CMD [ "npm", "test" ]
|
||||||
|
|
@ -1,39 +1,39 @@
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import BitcoinCore from 'bitcoin-core';
|
import BitcoinCore from 'bitcoin-core';
|
||||||
import { TestSettings } from '../services/main/settings';
|
import { TestSettings } from '../services/main/settings';
|
||||||
export class BitcoinCoreWrapper {
|
export class BitcoinCoreWrapper {
|
||||||
core: BitcoinCore
|
core: BitcoinCore
|
||||||
addr: { address: string }
|
addr: { address: string }
|
||||||
constructor(settings: TestSettings) {
|
constructor(settings: TestSettings) {
|
||||||
this.core = new BitcoinCore({
|
this.core = new BitcoinCore({
|
||||||
//network: 'regtest',
|
//network: 'regtest',
|
||||||
host: '127.0.0.1',
|
host: '127.0.0.1',
|
||||||
port: `${settings.bitcoinCoreSettings.port}`,
|
port: `${settings.bitcoinCoreSettings.port}`,
|
||||||
username: settings.bitcoinCoreSettings.user,
|
username: settings.bitcoinCoreSettings.user,
|
||||||
password: settings.bitcoinCoreSettings.pass,
|
password: settings.bitcoinCoreSettings.pass,
|
||||||
// use a long timeout due to the time it takes to mine a lot of blocks
|
// use a long timeout due to the time it takes to mine a lot of blocks
|
||||||
timeout: 5 * 60 * 1000,
|
timeout: 5 * 60 * 1000,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
InitAddress = async () => {
|
InitAddress = async () => {
|
||||||
this.addr = await this.core.getNewAddress()
|
this.addr = await this.core.getNewAddress()
|
||||||
}
|
}
|
||||||
Init = async () => {
|
Init = async () => {
|
||||||
const wallet = await this.core.createWallet('');
|
const wallet = await this.core.createWallet('');
|
||||||
console.log({ wallet })
|
console.log({ wallet })
|
||||||
await this.InitAddress()
|
await this.InitAddress()
|
||||||
console.log({ addr: this.addr })
|
console.log({ addr: this.addr })
|
||||||
await this.Mine(101)
|
await this.Mine(101)
|
||||||
const info = await this.core.getWalletInfo();
|
const info = await this.core.getWalletInfo();
|
||||||
console.log({ info })
|
console.log({ info })
|
||||||
}
|
}
|
||||||
|
|
||||||
Mine = async (blocks: number) => {
|
Mine = async (blocks: number) => {
|
||||||
await this.core.generateToAddress(blocks, this.addr)
|
await this.core.generateToAddress(blocks, this.addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
SendToAddress = async (address: string, amount: number) => {
|
SendToAddress = async (address: string, amount: number) => {
|
||||||
const tx = await this.core.sendToAddress(address, amount)
|
const tx = await this.core.sendToAddress(address, amount)
|
||||||
console.log({ tx })
|
console.log({ tx })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,47 +1,47 @@
|
||||||
import { defaultInvoiceExpiry } from '../services/storage/paymentStorage.js'
|
import { defaultInvoiceExpiry } from '../services/storage/paymentStorage.js'
|
||||||
import { Describe, expect, expectThrowsAsync, runSanityCheck, safelySetUserBalance, SetupTest, TestBase } from './testBase.js'
|
import { Describe, expect, expectThrowsAsync, runSanityCheck, safelySetUserBalance, SetupTest, TestBase } from './testBase.js'
|
||||||
export const ignore = false
|
export const ignore = false
|
||||||
export const dev = false
|
export const dev = false
|
||||||
export default async (T: TestBase) => {
|
export default async (T: TestBase) => {
|
||||||
await safelySetUserBalance(T, T.user1, 2000)
|
await safelySetUserBalance(T, T.user1, 2000)
|
||||||
await testSuccessfulExternalPayment(T)
|
await testSuccessfulExternalPayment(T)
|
||||||
await testFailedExternalPayment(T)
|
await testFailedExternalPayment(T)
|
||||||
await runSanityCheck(T)
|
await runSanityCheck(T)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const testSuccessfulExternalPayment = async (T: TestBase) => {
|
const testSuccessfulExternalPayment = async (T: TestBase) => {
|
||||||
T.d("starting testSuccessfulExternalPayment")
|
T.d("starting testSuccessfulExternalPayment")
|
||||||
const application = await T.main.storage.applicationStorage.GetApplication(T.app.appId)
|
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)
|
||||||
expect(invoice.payRequest).to.startWith("lnbcrt5u")
|
expect(invoice.payRequest).to.startWith("lnbcrt5u")
|
||||||
T.d("generated 500 sats invoice for external node")
|
T.d("generated 500 sats invoice for external node")
|
||||||
|
|
||||||
const pay = await T.main.paymentManager.PayInvoice(T.user1.userId, { invoice: invoice.payRequest, amount: 0 }, application)
|
const pay = await T.main.paymentManager.PayInvoice(T.user1.userId, { invoice: invoice.payRequest, amount: 0 }, application)
|
||||||
expect(pay.amount_paid).to.be.equal(500)
|
expect(pay.amount_paid).to.be.equal(500)
|
||||||
T.d("paid 500 sats invoice from user1")
|
T.d("paid 500 sats invoice from user1")
|
||||||
const u1 = await T.main.storage.userStorage.GetUser(T.user1.userId)
|
const u1 = await T.main.storage.userStorage.GetUser(T.user1.userId)
|
||||||
const owner = await T.main.storage.userStorage.GetUser(application.owner.user_id)
|
const owner = await T.main.storage.userStorage.GetUser(application.owner.user_id)
|
||||||
expect(u1.balance_sats).to.be.equal(1496)
|
expect(u1.balance_sats).to.be.equal(1496)
|
||||||
T.d("user1 balance is now 1496 (2000 - (500 + 3 fee + 1 routing))")
|
T.d("user1 balance is now 1496 (2000 - (500 + 3 fee + 1 routing))")
|
||||||
expect(owner.balance_sats).to.be.equal(3)
|
expect(owner.balance_sats).to.be.equal(3)
|
||||||
T.d("app balance is 3 sats")
|
T.d("app balance is 3 sats")
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const testFailedExternalPayment = async (T: TestBase) => {
|
const testFailedExternalPayment = async (T: TestBase) => {
|
||||||
T.d("starting testFailedExternalPayment")
|
T.d("starting testFailedExternalPayment")
|
||||||
const application = await T.main.storage.applicationStorage.GetApplication(T.app.appId)
|
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)
|
||||||
expect(invoice.payRequest).to.startWith("lnbcrt15u")
|
expect(invoice.payRequest).to.startWith("lnbcrt15u")
|
||||||
T.d("generated 1500 sats invoice for external node")
|
T.d("generated 1500 sats invoice for external node")
|
||||||
|
|
||||||
await expectThrowsAsync(T.main.paymentManager.PayInvoice(T.user1.userId, { invoice: invoice.payRequest, amount: 0 }, application), "not enough balance to decrement")
|
await expectThrowsAsync(T.main.paymentManager.PayInvoice(T.user1.userId, { invoice: invoice.payRequest, amount: 0 }, application), "not enough balance to decrement")
|
||||||
T.d("payment failed as expected, with the expected error message")
|
T.d("payment failed as expected, with the expected error message")
|
||||||
const u1 = await T.main.storage.userStorage.GetUser(T.user1.userId)
|
const u1 = await T.main.storage.userStorage.GetUser(T.user1.userId)
|
||||||
expect(u1.balance_sats).to.be.equal(1496)
|
expect(u1.balance_sats).to.be.equal(1496)
|
||||||
T.d("user1 balance is still 1496")
|
T.d("user1 balance is still 1496")
|
||||||
const owner = await T.main.storage.userStorage.GetUser(application.owner.user_id)
|
const owner = await T.main.storage.userStorage.GetUser(application.owner.user_id)
|
||||||
expect(owner.balance_sats).to.be.equal(3)
|
expect(owner.balance_sats).to.be.equal(3)
|
||||||
T.d("app balance is still 3 sats")
|
T.d("app balance is still 3 sats")
|
||||||
}
|
}
|
||||||
|
|
@ -1,41 +1,41 @@
|
||||||
import { defaultInvoiceExpiry } from '../services/storage/paymentStorage.js'
|
import { defaultInvoiceExpiry } from '../services/storage/paymentStorage.js'
|
||||||
import { Describe, expect, expectThrowsAsync, runSanityCheck, safelySetUserBalance, SetupTest, TestBase } from './testBase.js'
|
import { Describe, expect, expectThrowsAsync, runSanityCheck, safelySetUserBalance, SetupTest, TestBase } from './testBase.js'
|
||||||
export const ignore = false
|
export const ignore = false
|
||||||
|
|
||||||
export default async (T: TestBase) => {
|
export default async (T: TestBase) => {
|
||||||
await safelySetUserBalance(T, T.user1, 2000)
|
await safelySetUserBalance(T, T.user1, 2000)
|
||||||
await testSuccessfulInternalPayment(T)
|
await testSuccessfulInternalPayment(T)
|
||||||
await testFailedInternalPayment(T)
|
await testFailedInternalPayment(T)
|
||||||
await runSanityCheck(T)
|
await runSanityCheck(T)
|
||||||
}
|
}
|
||||||
|
|
||||||
const testSuccessfulInternalPayment = async (T: TestBase) => {
|
const testSuccessfulInternalPayment = async (T: TestBase) => {
|
||||||
T.d("starting testSuccessfulInternalPayment")
|
T.d("starting testSuccessfulInternalPayment")
|
||||||
const application = await T.main.storage.applicationStorage.GetApplication(T.app.appId)
|
const application = await T.main.storage.applicationStorage.GetApplication(T.app.appId)
|
||||||
const invoice = await T.main.paymentManager.NewInvoice(T.user2.userId, { amountSats: 1000, memo: "test" }, { linkedApplication: application, expiry: defaultInvoiceExpiry })
|
const invoice = await T.main.paymentManager.NewInvoice(T.user2.userId, { amountSats: 1000, memo: "test" }, { linkedApplication: application, expiry: defaultInvoiceExpiry })
|
||||||
expect(invoice.invoice).to.startWith("lnbcrt10u")
|
expect(invoice.invoice).to.startWith("lnbcrt10u")
|
||||||
T.d("generated 1000 sats invoice for user2")
|
T.d("generated 1000 sats invoice for user2")
|
||||||
const pay = await T.main.paymentManager.PayInvoice(T.user1.userId, { invoice: invoice.invoice, amount: 0 }, application)
|
const pay = await T.main.paymentManager.PayInvoice(T.user1.userId, { invoice: invoice.invoice, amount: 0 }, application)
|
||||||
expect(pay.amount_paid).to.be.equal(1000)
|
expect(pay.amount_paid).to.be.equal(1000)
|
||||||
T.d("paid 1000 sats invoice from user1")
|
T.d("paid 1000 sats invoice from user1")
|
||||||
const u1 = await T.main.storage.userStorage.GetUser(T.user1.userId)
|
const u1 = await T.main.storage.userStorage.GetUser(T.user1.userId)
|
||||||
const u2 = await T.main.storage.userStorage.GetUser(T.user2.userId)
|
const u2 = await T.main.storage.userStorage.GetUser(T.user2.userId)
|
||||||
const owner = await T.main.storage.userStorage.GetUser(application.owner.user_id)
|
const owner = await T.main.storage.userStorage.GetUser(application.owner.user_id)
|
||||||
expect(u2.balance_sats).to.be.equal(1000)
|
expect(u2.balance_sats).to.be.equal(1000)
|
||||||
T.d("user2 balance is 1000")
|
T.d("user2 balance is 1000")
|
||||||
expect(u1.balance_sats).to.be.equal(994)
|
expect(u1.balance_sats).to.be.equal(994)
|
||||||
T.d("user1 balance is 994 cuz he paid 6 sats fee")
|
T.d("user1 balance is 994 cuz he paid 6 sats fee")
|
||||||
expect(owner.balance_sats).to.be.equal(6)
|
expect(owner.balance_sats).to.be.equal(6)
|
||||||
T.d("app balance is 6 sats")
|
T.d("app balance is 6 sats")
|
||||||
}
|
}
|
||||||
|
|
||||||
const testFailedInternalPayment = async (T: TestBase) => {
|
const testFailedInternalPayment = async (T: TestBase) => {
|
||||||
T.d("starting testFailedInternalPayment")
|
T.d("starting testFailedInternalPayment")
|
||||||
const application = await T.main.storage.applicationStorage.GetApplication(T.app.appId)
|
const application = await T.main.storage.applicationStorage.GetApplication(T.app.appId)
|
||||||
const invoice = await T.main.paymentManager.NewInvoice(T.user2.userId, { amountSats: 1000, memo: "test" }, { linkedApplication: application, expiry: defaultInvoiceExpiry })
|
const invoice = await T.main.paymentManager.NewInvoice(T.user2.userId, { amountSats: 1000, memo: "test" }, { linkedApplication: application, expiry: defaultInvoiceExpiry })
|
||||||
expect(invoice.invoice).to.startWith("lnbcrt10u")
|
expect(invoice.invoice).to.startWith("lnbcrt10u")
|
||||||
T.d("generated 1000 sats invoice for user2")
|
T.d("generated 1000 sats invoice for user2")
|
||||||
await expectThrowsAsync(T.main.paymentManager.PayInvoice(T.user1.userId, { invoice: invoice.invoice, amount: 0 }, application), "not enough balance to decrement")
|
await expectThrowsAsync(T.main.paymentManager.PayInvoice(T.user1.userId, { invoice: invoice.invoice, amount: 0 }, application), "not enough balance to decrement")
|
||||||
T.d("payment failed as expected, with the expected error message")
|
T.d("payment failed as expected, with the expected error message")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,43 +1,43 @@
|
||||||
import { disableLoggers } from '../services/helpers/logger.js'
|
import { disableLoggers } from '../services/helpers/logger.js'
|
||||||
import { defaultInvoiceExpiry } from '../services/storage/paymentStorage.js'
|
import { defaultInvoiceExpiry } from '../services/storage/paymentStorage.js'
|
||||||
import { Describe, expect, expectThrowsAsync, runSanityCheck, safelySetUserBalance, SetupTest, TestBase } from './testBase.js'
|
import { Describe, expect, expectThrowsAsync, runSanityCheck, safelySetUserBalance, SetupTest, TestBase } from './testBase.js'
|
||||||
export const ignore = false
|
export const ignore = false
|
||||||
|
|
||||||
export default async (T: TestBase) => {
|
export default async (T: TestBase) => {
|
||||||
disableLoggers([], ["EventsLogManager", "htlcTracker", "watchdog"])
|
disableLoggers([], ["EventsLogManager", "htlcTracker", "watchdog"])
|
||||||
await safelySetUserBalance(T, T.user1, 2000)
|
await safelySetUserBalance(T, T.user1, 2000)
|
||||||
await testSpamExternalPayment(T)
|
await testSpamExternalPayment(T)
|
||||||
await runSanityCheck(T)
|
await runSanityCheck(T)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const testSpamExternalPayment = async (T: TestBase) => {
|
const testSpamExternalPayment = async (T: TestBase) => {
|
||||||
T.d("starting testSpamExternalPayment")
|
T.d("starting testSpamExternalPayment")
|
||||||
const application = await T.main.storage.applicationStorage.GetApplication(T.app.appId)
|
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)))
|
||||||
T.d("generated 10 500 sats invoices for external node")
|
T.d("generated 10 500 sats invoices for external node")
|
||||||
const res = await Promise.all(invoices.map(async (invoice, i) => {
|
const res = await Promise.all(invoices.map(async (invoice, i) => {
|
||||||
try {
|
try {
|
||||||
const result = await T.main.paymentManager.PayInvoice(T.user1.userId, { invoice: invoice.payRequest, amount: 0 }, application)
|
const result = await T.main.paymentManager.PayInvoice(T.user1.userId, { invoice: invoice.payRequest, amount: 0 }, application)
|
||||||
return { success: true, result }
|
return { success: true, result }
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
return { success: false, err: e }
|
return { success: false, err: e }
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
|
|
||||||
const successfulPayments = res.filter(r => r.success)
|
const successfulPayments = res.filter(r => r.success)
|
||||||
const failedPayments = res.filter(r => !r.success)
|
const failedPayments = res.filter(r => !r.success)
|
||||||
failedPayments.forEach(f => expect(f.err).to.be.equal("not enough balance to decrement"))
|
failedPayments.forEach(f => expect(f.err).to.be.equal("not enough balance to decrement"))
|
||||||
successfulPayments.forEach(s => expect(s.result).to.contain({ amount_paid: 500, network_fee: 1, service_fee: 3 }))
|
successfulPayments.forEach(s => expect(s.result).to.contain({ amount_paid: 500, network_fee: 1, service_fee: 3 }))
|
||||||
expect(successfulPayments.length).to.be.equal(3)
|
expect(successfulPayments.length).to.be.equal(3)
|
||||||
expect(failedPayments.length).to.be.equal(7)
|
expect(failedPayments.length).to.be.equal(7)
|
||||||
T.d("3 payments succeeded, 7 failed as expected")
|
T.d("3 payments succeeded, 7 failed as expected")
|
||||||
const u = await T.main.storage.userStorage.GetUser(T.user1.userId)
|
const u = await T.main.storage.userStorage.GetUser(T.user1.userId)
|
||||||
const owner = await T.main.storage.userStorage.GetUser(application.owner.user_id)
|
const owner = await T.main.storage.userStorage.GetUser(application.owner.user_id)
|
||||||
expect(u.balance_sats).to.be.equal(488)
|
expect(u.balance_sats).to.be.equal(488)
|
||||||
T.d("user1 balance is now 488 (2000 - (500 + 3 fee + 1 routing) * 3)")
|
T.d("user1 balance is now 488 (2000 - (500 + 3 fee + 1 routing) * 3)")
|
||||||
expect(owner.balance_sats).to.be.equal(9)
|
expect(owner.balance_sats).to.be.equal(9)
|
||||||
T.d("app balance is 9 sats")
|
T.d("app balance is 9 sats")
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,51 +1,51 @@
|
||||||
import { disableLoggers } from '../services/helpers/logger.js'
|
import { disableLoggers } from '../services/helpers/logger.js'
|
||||||
import { defaultInvoiceExpiry } from '../services/storage/paymentStorage.js'
|
import { defaultInvoiceExpiry } from '../services/storage/paymentStorage.js'
|
||||||
import { Describe, expect, expectThrowsAsync, runSanityCheck, safelySetUserBalance, SetupTest, TestBase } from './testBase.js'
|
import { Describe, expect, expectThrowsAsync, runSanityCheck, safelySetUserBalance, SetupTest, TestBase } from './testBase.js'
|
||||||
import * as Types from '../../proto/autogenerated/ts/types.js'
|
import * as Types from '../../proto/autogenerated/ts/types.js'
|
||||||
export const ignore = false
|
export const ignore = false
|
||||||
|
|
||||||
export default async (T: TestBase) => {
|
export default async (T: TestBase) => {
|
||||||
disableLoggers([], ["EventsLogManager", "htlcTracker", "watchdog"])
|
disableLoggers([], ["EventsLogManager", "htlcTracker", "watchdog"])
|
||||||
await safelySetUserBalance(T, T.user1, 2000)
|
await safelySetUserBalance(T, T.user1, 2000)
|
||||||
await testSpamExternalPayment(T)
|
await testSpamExternalPayment(T)
|
||||||
await runSanityCheck(T)
|
await runSanityCheck(T)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const testSpamExternalPayment = async (T: TestBase) => {
|
const testSpamExternalPayment = async (T: TestBase) => {
|
||||||
T.d("starting testSpamExternalPayment")
|
T.d("starting testSpamExternalPayment")
|
||||||
const application = await T.main.storage.applicationStorage.GetApplication(T.app.appId)
|
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)))
|
||||||
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 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))
|
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")
|
T.d("generated 10 500 sats mixed invoices between external node and user 2")
|
||||||
const res = await Promise.all(invoices.map(async (invoice, i) => {
|
const res = await Promise.all(invoices.map(async (invoice, i) => {
|
||||||
try {
|
try {
|
||||||
const result = await T.main.paymentManager.PayInvoice(T.user1.userId, { invoice: invoice, amount: 0 }, application)
|
const result = await T.main.paymentManager.PayInvoice(T.user1.userId, { invoice: invoice, amount: 0 }, application)
|
||||||
return { success: true, result }
|
return { success: true, result }
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
return { success: false, err: e }
|
return { success: false, err: e }
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
|
|
||||||
const successfulPayments = res.filter(r => r.success) as { success: true, result: Types.PayInvoiceResponse }[]
|
const successfulPayments = res.filter(r => r.success) as { success: true, result: Types.PayInvoiceResponse }[]
|
||||||
const failedPayments = res.filter(r => !r.success)
|
const failedPayments = res.filter(r => !r.success)
|
||||||
failedPayments.forEach(f => expect(f.err).to.be.equal("not enough balance to decrement"))
|
failedPayments.forEach(f => expect(f.err).to.be.equal("not enough balance to decrement"))
|
||||||
expect(successfulPayments.length).to.be.equal(3)
|
expect(successfulPayments.length).to.be.equal(3)
|
||||||
expect(failedPayments.length).to.be.equal(7)
|
expect(failedPayments.length).to.be.equal(7)
|
||||||
T.d("3 payments succeeded, 7 failed as expected")
|
T.d("3 payments succeeded, 7 failed as expected")
|
||||||
const networkPayments = successfulPayments.filter(s => s.result.network_fee > 0)
|
const networkPayments = successfulPayments.filter(s => s.result.network_fee > 0)
|
||||||
const internalPayments = successfulPayments.filter(s => s.result.network_fee === 0)
|
const internalPayments = successfulPayments.filter(s => s.result.network_fee === 0)
|
||||||
expect(networkPayments.length).to.be.equal(1)
|
expect(networkPayments.length).to.be.equal(1)
|
||||||
expect(internalPayments.length).to.be.equal(2)
|
expect(internalPayments.length).to.be.equal(2)
|
||||||
networkPayments.forEach(s => expect(s.result).to.contain({ amount_paid: 500, service_fee: 3, network_fee: 1 }))
|
networkPayments.forEach(s => expect(s.result).to.contain({ amount_paid: 500, service_fee: 3, network_fee: 1 }))
|
||||||
internalPayments.forEach(s => expect(s.result).to.contain({ amount_paid: 500, service_fee: 3 }))
|
internalPayments.forEach(s => expect(s.result).to.contain({ amount_paid: 500, service_fee: 3 }))
|
||||||
const u = await T.main.storage.userStorage.GetUser(T.user1.userId)
|
const u = await T.main.storage.userStorage.GetUser(T.user1.userId)
|
||||||
const owner = await T.main.storage.userStorage.GetUser(application.owner.user_id)
|
const owner = await T.main.storage.userStorage.GetUser(application.owner.user_id)
|
||||||
expect(u.balance_sats).to.be.equal(490)
|
expect(u.balance_sats).to.be.equal(490)
|
||||||
T.d("user1 balance is now 490 (2000 - (500 + 3 fee + 1 routing + (500 + 3fee) * 2))")
|
T.d("user1 balance is now 490 (2000 - (500 + 3 fee + 1 routing + (500 + 3fee) * 2))")
|
||||||
expect(owner.balance_sats).to.be.equal(9)
|
expect(owner.balance_sats).to.be.equal(9)
|
||||||
T.d("app balance is 9 sats")
|
T.d("app balance is 9 sats")
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,85 +1,85 @@
|
||||||
|
|
||||||
import { globby } from 'globby'
|
import { globby } from 'globby'
|
||||||
import { setupNetwork } from './networkSetup.js'
|
import { setupNetwork } from './networkSetup.js'
|
||||||
import { Describe, SetupTest, teardown, TestBase } from './testBase.js'
|
import { Describe, SetupTest, teardown, TestBase } from './testBase.js'
|
||||||
type TestModule = {
|
type TestModule = {
|
||||||
ignore?: boolean
|
ignore?: boolean
|
||||||
dev?: boolean
|
dev?: boolean
|
||||||
default: (T: TestBase) => Promise<void>
|
default: (T: TestBase) => Promise<void>
|
||||||
}
|
}
|
||||||
let failures = 0
|
let failures = 0
|
||||||
const getDescribe = (fileName: string): Describe => {
|
const getDescribe = (fileName: string): Describe => {
|
||||||
return (message, failure) => {
|
return (message, failure) => {
|
||||||
if (failure) {
|
if (failure) {
|
||||||
failures++
|
failures++
|
||||||
console.error(redConsole, fileName, ": FAILURE ", message, resetConsole)
|
console.error(redConsole, fileName, ": FAILURE ", message, resetConsole)
|
||||||
} else {
|
} else {
|
||||||
console.log(greenConsole, fileName, ":", message, resetConsole)
|
console.log(greenConsole, fileName, ":", message, resetConsole)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const start = async () => {
|
const start = async () => {
|
||||||
await setupNetwork()
|
await setupNetwork()
|
||||||
const files = await globby(["**/*.spec.js", "!**/node_modules/**"])
|
const files = await globby(["**/*.spec.js", "!**/node_modules/**"])
|
||||||
const modules: { file: string, module: TestModule }[] = []
|
const modules: { file: string, module: TestModule }[] = []
|
||||||
let devModule = -1
|
let devModule = -1
|
||||||
for (const file of files) {
|
for (const file of files) {
|
||||||
const module = await import(`./${file.slice("build/src/tests/".length)}`) as TestModule
|
const module = await import(`./${file.slice("build/src/tests/".length)}`) as TestModule
|
||||||
modules.push({ module, file })
|
modules.push({ module, file })
|
||||||
if (module.dev) {
|
if (module.dev) {
|
||||||
console.log("dev module found", file)
|
console.log("dev module found", file)
|
||||||
if (devModule !== -1) {
|
if (devModule !== -1) {
|
||||||
throw new Error("there are multiple dev modules")
|
throw new Error("there are multiple dev modules")
|
||||||
}
|
}
|
||||||
devModule = modules.length - 1
|
devModule = modules.length - 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (devModule !== -1) {
|
if (devModule !== -1) {
|
||||||
console.log("running dev module")
|
console.log("running dev module")
|
||||||
await runTestFile(modules[devModule].file, modules[devModule].module)
|
await runTestFile(modules[devModule].file, modules[devModule].module)
|
||||||
} else {
|
} else {
|
||||||
console.log("running all tests")
|
console.log("running all tests")
|
||||||
for (const { file, module } of modules) {
|
for (const { file, module } of modules) {
|
||||||
await runTestFile(file, module)
|
await runTestFile(file, module)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
console.log(failures)
|
console.log(failures)
|
||||||
if (failures) {
|
if (failures) {
|
||||||
throw new Error("there have been " + failures + " failures in all tests")
|
throw new Error("there have been " + failures + " failures in all tests")
|
||||||
} else {
|
} else {
|
||||||
console.log(greenConsole, "there have been 0 failures in all tests", resetConsole)
|
console.log(greenConsole, "there have been 0 failures in all tests", resetConsole)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const runTestFile = async (fileName: string, mod: TestModule) => {
|
const runTestFile = async (fileName: string, mod: TestModule) => {
|
||||||
console.log(fileName)
|
console.log(fileName)
|
||||||
const d = getDescribe(fileName)
|
const d = getDescribe(fileName)
|
||||||
if (mod.ignore) {
|
if (mod.ignore) {
|
||||||
d("-----ignoring this file-----")
|
d("-----ignoring this file-----")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (mod.dev) {
|
if (mod.dev) {
|
||||||
d("-----running only this file-----")
|
d("-----running only this file-----")
|
||||||
}
|
}
|
||||||
const T = await SetupTest(d)
|
const T = await SetupTest(d)
|
||||||
try {
|
try {
|
||||||
d("test starting")
|
d("test starting")
|
||||||
await mod.default(T)
|
await mod.default(T)
|
||||||
d("test finished")
|
d("test finished")
|
||||||
await teardown(T)
|
await teardown(T)
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
d(e, true)
|
d(e, true)
|
||||||
await teardown(T)
|
await teardown(T)
|
||||||
}
|
}
|
||||||
if (mod.dev) {
|
if (mod.dev) {
|
||||||
d("dev mod is not allowed to in CI, failing for precaution", true)
|
d("dev mod is not allowed to in CI, failing for precaution", true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const greenConsole = "\x1b[32m"
|
const greenConsole = "\x1b[32m"
|
||||||
const redConsole = "\x1b[31m"
|
const redConsole = "\x1b[31m"
|
||||||
const resetConsole = "\x1b[0m"
|
const resetConsole = "\x1b[0m"
|
||||||
start()
|
start()
|
||||||
|
|
@ -1,18 +1,18 @@
|
||||||
import { defaultInvoiceExpiry } from '../services/storage/paymentStorage.js'
|
import { defaultInvoiceExpiry } from '../services/storage/paymentStorage.js'
|
||||||
import { runSanityCheck, safelySetUserBalance, TestBase } from './testBase.js'
|
import { runSanityCheck, safelySetUserBalance, TestBase } from './testBase.js'
|
||||||
export const ignore = false
|
export const ignore = false
|
||||||
export const dev = false
|
export const dev = false
|
||||||
|
|
||||||
export default async (T: TestBase) => {
|
export default async (T: TestBase) => {
|
||||||
await safelySetUserBalance(T, T.user1, 2000)
|
await safelySetUserBalance(T, T.user1, 2000)
|
||||||
await testSuccessfulUserPaymentToExternalNode(T)
|
await testSuccessfulUserPaymentToExternalNode(T)
|
||||||
await testSuccessfulUserPaymentToExternalNode(T)
|
await testSuccessfulUserPaymentToExternalNode(T)
|
||||||
await runSanityCheck(T)
|
await runSanityCheck(T)
|
||||||
}
|
}
|
||||||
|
|
||||||
const testSuccessfulUserPaymentToExternalNode = async (T: TestBase) => {
|
const testSuccessfulUserPaymentToExternalNode = async (T: TestBase) => {
|
||||||
T.d("starting testSuccessfulUserPaymentToExternalNode")
|
T.d("starting testSuccessfulUserPaymentToExternalNode")
|
||||||
const invoice = await T.externalAccessToOtherLnd.NewInvoice(500, "test", defaultInvoiceExpiry)
|
const invoice = await T.externalAccessToOtherLnd.NewInvoice(500, "test", defaultInvoiceExpiry)
|
||||||
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 })
|
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")
|
T.d("paid 500 sats invoice from user1 to external node")
|
||||||
}
|
}
|
||||||
|
|
@ -1,35 +1,35 @@
|
||||||
import { defaultInvoiceExpiry } from '../services/storage/paymentStorage.js'
|
import { defaultInvoiceExpiry } from '../services/storage/paymentStorage.js'
|
||||||
import { Describe, expect, expectThrowsAsync, runSanityCheck, safelySetUserBalance, SetupTest, TestBase } from './testBase.js'
|
import { Describe, expect, expectThrowsAsync, runSanityCheck, safelySetUserBalance, SetupTest, TestBase } from './testBase.js'
|
||||||
export const ignore = false
|
export const ignore = false
|
||||||
export const dev = false
|
export const dev = false
|
||||||
export default async (T: TestBase) => {
|
export default async (T: TestBase) => {
|
||||||
await safelySetUserBalance(T, T.user1, 2000)
|
await safelySetUserBalance(T, T.user1, 2000)
|
||||||
await testSuccessfulU2UPayment(T)
|
await testSuccessfulU2UPayment(T)
|
||||||
await testFailedInternalPayment(T)
|
await testFailedInternalPayment(T)
|
||||||
await runSanityCheck(T)
|
await runSanityCheck(T)
|
||||||
}
|
}
|
||||||
|
|
||||||
const testSuccessfulU2UPayment = async (T: TestBase) => {
|
const testSuccessfulU2UPayment = async (T: TestBase) => {
|
||||||
T.d("starting testSuccessfulU2UPayment")
|
T.d("starting testSuccessfulU2UPayment")
|
||||||
const application = await T.main.storage.applicationStorage.GetApplication(T.app.appId)
|
const application = await T.main.storage.applicationStorage.GetApplication(T.app.appId)
|
||||||
const sentAmt = await T.main.paymentManager.SendUserToUserPayment(T.user1.userId, T.user2.userId, 1000, application)
|
const sentAmt = await T.main.paymentManager.SendUserToUserPayment(T.user1.userId, T.user2.userId, 1000, application)
|
||||||
expect(sentAmt.amount).to.be.equal(1000)
|
expect(sentAmt.amount).to.be.equal(1000)
|
||||||
T.d("paid 1000 sats u2u from user1 to user2")
|
T.d("paid 1000 sats u2u from user1 to user2")
|
||||||
const u1 = await T.main.storage.userStorage.GetUser(T.user1.userId)
|
const u1 = await T.main.storage.userStorage.GetUser(T.user1.userId)
|
||||||
const u2 = await T.main.storage.userStorage.GetUser(T.user2.userId)
|
const u2 = await T.main.storage.userStorage.GetUser(T.user2.userId)
|
||||||
const owner = await T.main.storage.userStorage.GetUser(application.owner.user_id)
|
const owner = await T.main.storage.userStorage.GetUser(application.owner.user_id)
|
||||||
expect(u2.balance_sats).to.be.equal(1000)
|
expect(u2.balance_sats).to.be.equal(1000)
|
||||||
T.d("user2 balance is 1000")
|
T.d("user2 balance is 1000")
|
||||||
expect(u1.balance_sats).to.be.equal(994)
|
expect(u1.balance_sats).to.be.equal(994)
|
||||||
T.d("user1 balance is 994 cuz he paid 6 sats fee")
|
T.d("user1 balance is 994 cuz he paid 6 sats fee")
|
||||||
expect(owner.balance_sats).to.be.equal(6)
|
expect(owner.balance_sats).to.be.equal(6)
|
||||||
T.d("app balance is 6 sats")
|
T.d("app balance is 6 sats")
|
||||||
}
|
}
|
||||||
|
|
||||||
const testFailedInternalPayment = async (T: TestBase) => {
|
const testFailedInternalPayment = async (T: TestBase) => {
|
||||||
T.d("starting testFailedInternalPayment")
|
T.d("starting testFailedInternalPayment")
|
||||||
const application = await T.main.storage.applicationStorage.GetApplication(T.app.appId)
|
const application = await T.main.storage.applicationStorage.GetApplication(T.app.appId)
|
||||||
await expectThrowsAsync(T.main.paymentManager.SendUserToUserPayment(T.user1.userId, T.user2.userId, 1000, application), "not enough balance to send payment")
|
await expectThrowsAsync(T.main.paymentManager.SendUserToUserPayment(T.user1.userId, T.user2.userId, 1000, application), "not enough balance to send payment")
|
||||||
T.d("payment failed as expected, with the expected error message")
|
T.d("payment failed as expected, with the expected error message")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
102
static/backup.html
Normal file
102
static/backup.html
Normal file
|
|
@ -0,0 +1,102 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<title></title>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<link
|
||||||
|
rel="stylesheet"
|
||||||
|
href="https://fonts.googleapis.com/css?family=Montserrat"
|
||||||
|
/>
|
||||||
|
<link rel="stylesheet" href="css/styles.css" />
|
||||||
|
<link rel="stylesheet" href="css/backup.css" />
|
||||||
|
<!-- HTML Meta Tags -->
|
||||||
|
<title>Lightning.Pub</title>
|
||||||
|
<meta name="description" content="Lightning for Everyone" />
|
||||||
|
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<header>
|
||||||
|
<img
|
||||||
|
src="img/pub_logo.png"
|
||||||
|
width="38px"
|
||||||
|
height="auto"
|
||||||
|
alt="Lightning Pub logo"
|
||||||
|
/>
|
||||||
|
<img src="img/LightningPub.png" height="33px" alt="Lightning Pub logo" />
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<main>
|
||||||
|
<section class="setup-header">
|
||||||
|
<button class="icon-button back-button" onclick="history.back()">
|
||||||
|
<img src="img/back.svg" alt="" />
|
||||||
|
</button>
|
||||||
|
<h2>Choose a Recovery Method</h2>
|
||||||
|
<p class="header-title">
|
||||||
|
<span style="font-weight: bold">New Node! 🎉</span> It's important
|
||||||
|
to backup your keys.
|
||||||
|
</p>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<div class="line"></div>
|
||||||
|
|
||||||
|
<section class="setup-content">
|
||||||
|
<div class="description-box">
|
||||||
|
<div class="description">
|
||||||
|
In addition to your seed phrase, you also need channel details to recover funds should your node experience a hardware failure.
|
||||||
|
</div>
|
||||||
|
<br />
|
||||||
|
<div class="description">
|
||||||
|
It's important always to have the latest version of this file. Fortunately, it's small enough to automatically store on the Nostr relay.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="warning-text">
|
||||||
|
If you did not choose the developers relay, be sure your relay has
|
||||||
|
adequate storage policies to hold NIP78 events.
|
||||||
|
</div>
|
||||||
|
<div class="checkbox-container">
|
||||||
|
<div class="checkbox" style="margin-top: 12px">
|
||||||
|
<input type="checkbox" id="backup" />
|
||||||
|
<div class="checkbox-shape"></div>
|
||||||
|
<label for="backup">
|
||||||
|
Encrypted Backup to Nostr Relay
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="checkbox-container">
|
||||||
|
<div class="checkbox manual-checkbox" style="margin-top: 12px">
|
||||||
|
<input type="checkbox" id="manual-backup" />
|
||||||
|
<div class="checkbox-shape"></div>
|
||||||
|
<label for="manual-backup" >
|
||||||
|
DO NOT store on relay (Manual Backups)
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
class="push-button hidden-button"
|
||||||
|
onclick="location.href='seed.html'"
|
||||||
|
style="margin-top: 60px;"
|
||||||
|
id="next-button"
|
||||||
|
>
|
||||||
|
Next
|
||||||
|
</button>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<footer>
|
||||||
|
<div class="footer-text">
|
||||||
|
<div>By proceeding you acknowledge that this is</div>
|
||||||
|
<div>bleeding-edge software, and agree to the providers</div>
|
||||||
|
<div>
|
||||||
|
<span style="color: #c434e0">terms</span> regarding any services
|
||||||
|
herein.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="line"></div>
|
||||||
|
<a href="https://docs.shock.network" class="marked need-help">Need Help?</a>
|
||||||
|
</footer>
|
||||||
|
|
||||||
|
<script src="js/backup.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
80
static/connect.html
Normal file
80
static/connect.html
Normal file
|
|
@ -0,0 +1,80 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<title></title>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<link
|
||||||
|
rel="stylesheet"
|
||||||
|
href="https://fonts.googleapis.com/css?family=Montserrat"
|
||||||
|
/>
|
||||||
|
<link rel="stylesheet" href="css/styles.css" />
|
||||||
|
<link rel="stylesheet" href="css/connect.css" />
|
||||||
|
<!-- HTML Meta Tags -->
|
||||||
|
<title>Lightning.Pub</title>
|
||||||
|
<meta name="description" content="Lightning for Everyone" />
|
||||||
|
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<header>
|
||||||
|
<img
|
||||||
|
src="img/pub_logo.png"
|
||||||
|
width="38px"
|
||||||
|
height="auto"
|
||||||
|
alt="Lightning Pub logo"
|
||||||
|
/>
|
||||||
|
<img src="img/LightningPub.png" height="33px" alt="Lightning Pub logo" />
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<main>
|
||||||
|
<section class="setup-header">
|
||||||
|
<button class="icon-button back-button" onclick="history.back()">
|
||||||
|
<img src="img/back.svg" alt="" />
|
||||||
|
</button>
|
||||||
|
<h2>Connect</h2>
|
||||||
|
<p class="header-title">
|
||||||
|
You can now manage your node remotely
|
||||||
|
</p>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<div class="line"></div>
|
||||||
|
|
||||||
|
<section class="setup-content">
|
||||||
|
<div>For dashboard access, use <a href="https://preview.uxpin.com/ae6e6372ab26cd13438d486d4d1ac9d184ec8e82#/pages/164889267" style="color: #2aabe9;" target="_blank">ShockWallet</a> and tap the logo 3 times.</div>
|
||||||
|
<div style="font-size: 13px; margin-top: 5px;">Scan the QR or Copy-Paste the string to establish the connection.</div>
|
||||||
|
<div style="display: flex; justify-content: center;">
|
||||||
|
<div class="qrcode-box" id="codebox">
|
||||||
|
<div style="font-size: 11px;">
|
||||||
|
<div style="text-align: center; color: #a3a3a3;">Code contains a one-time pairing secret</div>
|
||||||
|
<div style="text-align: center; color: #c434e0;" id="click-text">Click to reveal</div>
|
||||||
|
</div>
|
||||||
|
<div id="qrcode"></div>
|
||||||
|
<div style="color: #a3a3a3; font-size: 11px;">
|
||||||
|
<div>npub123abcdefghhhhhhhhhhhhhhh</div>
|
||||||
|
<div>relay.lightning.pub</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<footer>
|
||||||
|
<div class="footer-text">
|
||||||
|
<div>By proceeding you acknowledge that this is</div>
|
||||||
|
<div>bleeding-edge software, and agree to the providers</div>
|
||||||
|
<div>
|
||||||
|
<span style="color: #c434e0">terms</span> regarding any services
|
||||||
|
herein.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="line"></div>
|
||||||
|
<a href="https://docs.shock.network" class="marked need-help">Need Help?</a>
|
||||||
|
</footer>
|
||||||
|
|
||||||
|
<script src="https://cdn.rawgit.com/davidshimjs/qrcodejs/gh-pages/qrcode.min.js"></script>
|
||||||
|
|
||||||
|
<script src="js/script.js"></script>
|
||||||
|
<script src="js/connect.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
28
static/css/backup.css
Normal file
28
static/css/backup.css
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
.description {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #a3a3a3;
|
||||||
|
text-decoration: none solid rgb(163, 163, 163);
|
||||||
|
text-align: center;
|
||||||
|
text-shadow: 0px 0px 2px rgba(0, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.warning-text {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #c434e0;
|
||||||
|
font-style: italic;
|
||||||
|
text-decoration: none solid rgb(196, 52, 224);
|
||||||
|
text-align: center;
|
||||||
|
text-shadow: 0px 0px 2px rgba(0, 0, 0, 1);
|
||||||
|
margin-top: 16px;
|
||||||
|
}
|
||||||
|
.checkbox .manual_backup {
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
.manual-checkbox {
|
||||||
|
margin-left: 9%;
|
||||||
|
}
|
||||||
|
@media screen and (max-width: 425px) {
|
||||||
|
.manual-checkbox {
|
||||||
|
margin-left: 4%;
|
||||||
|
}
|
||||||
|
}
|
||||||
49
static/css/connect.css
Normal file
49
static/css/connect.css
Normal file
|
|
@ -0,0 +1,49 @@
|
||||||
|
.qrcode-box::before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
border-radius: 15px;
|
||||||
|
border: 1px solid transparent;
|
||||||
|
background: linear-gradient(60deg, #ff7700 0%, #c740c7 100% ) border-box;
|
||||||
|
mask: linear-gradient(#fff 0 0) padding-box, linear-gradient(#fff 0 0);
|
||||||
|
-webkit-mask-composite: destination-out;
|
||||||
|
mask-composite: exclude;
|
||||||
|
}
|
||||||
|
.qrcode-box {
|
||||||
|
display: block;
|
||||||
|
position: relative;
|
||||||
|
width: 253px;
|
||||||
|
height: 241px;
|
||||||
|
-webkit-backdrop-filter: blur(10px);
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
margin-top: 10px;
|
||||||
|
padding: 10px;
|
||||||
|
transition: background-color 0.5s;
|
||||||
|
border-radius: 15px;
|
||||||
|
}
|
||||||
|
.qrcode-box:hover {
|
||||||
|
background-color: #80808062;
|
||||||
|
transition: background-color 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.qrcode-box-clicked::before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
border-radius: 15px;
|
||||||
|
border: 1px solid transparent;
|
||||||
|
background: linear-gradient(60deg, #ff7700 0%, #c740c7 100% ) border-box;
|
||||||
|
mask: linear-gradient(#fff 0 0) padding-box, linear-gradient(#fff 0 0);
|
||||||
|
-webkit-mask-composite: destination-out;
|
||||||
|
mask-composite: exclude;
|
||||||
|
}
|
||||||
|
.qrcode-box-clicked {
|
||||||
|
display: block;
|
||||||
|
position: relative;
|
||||||
|
width: 253px;
|
||||||
|
height: 241px;
|
||||||
|
margin-top: 10px;
|
||||||
|
padding: 10px;
|
||||||
|
transition: background-color 0.5s;
|
||||||
|
border-radius: 15px;
|
||||||
|
}
|
||||||
43
static/css/liquidity.css
Normal file
43
static/css/liquidity.css
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
.question-box {
|
||||||
|
cursor: pointer;
|
||||||
|
display: inline-block;
|
||||||
|
position: relative;
|
||||||
|
top: -8px;
|
||||||
|
left: -4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.automate .question-content {
|
||||||
|
display: none;
|
||||||
|
position: absolute;
|
||||||
|
min-width: 280px;
|
||||||
|
background-color: var(--background-color);
|
||||||
|
color: #a3a3a3;
|
||||||
|
padding: 12px;
|
||||||
|
border: 2px solid #c423e0;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 14px;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
padding-top: 28px;
|
||||||
|
z-index: 200;
|
||||||
|
left: 65%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.question-content .close-button {
|
||||||
|
position: absolute;
|
||||||
|
top: 4px;
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
|
.question-content .question-more {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 4px;
|
||||||
|
right: 6px;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
.automate {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
@media screen and (max-width: 450px) {
|
||||||
|
.automate > .question-content {
|
||||||
|
left: 50%;
|
||||||
|
}
|
||||||
|
}
|
||||||
35
static/css/seed.css
Normal file
35
static/css/seed.css
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
.seed-box-container {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: auto auto auto auto auto auto;
|
||||||
|
justify-content: center;
|
||||||
|
row-gap: 4px;
|
||||||
|
column-gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 680px) {
|
||||||
|
.seed-box-container {
|
||||||
|
grid-template-columns: auto auto auto auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.blur-filter {
|
||||||
|
filter: blur(5px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.seed-box {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.reveal-button {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #c434e0;
|
||||||
|
font-style: italic;
|
||||||
|
text-decoration: none solid rgb(196, 52, 224);
|
||||||
|
text-align: center;
|
||||||
|
text-shadow: 0px 0px 2px rgba(0, 0, 0, 1);
|
||||||
|
background-color: transparent;
|
||||||
|
border: none;
|
||||||
|
margin-top: 16px;
|
||||||
|
}
|
||||||
141
static/css/status.css
Normal file
141
static/css/status.css
Normal file
|
|
@ -0,0 +1,141 @@
|
||||||
|
.status-element {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 100px;
|
||||||
|
margin-top: 10px;
|
||||||
|
font-size: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.green-dot {
|
||||||
|
font-size: 15px;
|
||||||
|
color: #32a852;
|
||||||
|
}
|
||||||
|
|
||||||
|
.yellow-dot {
|
||||||
|
font-size: 15px;
|
||||||
|
color: #ccc731;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editable-content {
|
||||||
|
font-size: 12px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: end;
|
||||||
|
align-items: flex-start;
|
||||||
|
color: #999999;
|
||||||
|
max-width: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.show-nodey>input {
|
||||||
|
/* border: none; */
|
||||||
|
/* box-shadow: none; */
|
||||||
|
padding: 5px;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.invite-link {
|
||||||
|
margin-top: 5px;
|
||||||
|
font-size: 12px;
|
||||||
|
color: #c434e0;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: 450px) {
|
||||||
|
.status-element {
|
||||||
|
gap: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
main {
|
||||||
|
zoom: 1.1;
|
||||||
|
}
|
||||||
|
#reset-box {
|
||||||
|
top: 30%!important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.watchdog-status {
|
||||||
|
position: absolute;
|
||||||
|
right: -22px;
|
||||||
|
top: -3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#reset-box {
|
||||||
|
width: 296px;
|
||||||
|
height: auto;
|
||||||
|
border: 1px solid #c434e0;
|
||||||
|
border-radius: 5px;
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
background-color: rgb(0, 0, 0);
|
||||||
|
z-index: 1;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#reset-box .close-button {
|
||||||
|
position: absolute;
|
||||||
|
top: 4px;
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.reset-box-content {
|
||||||
|
padding: 28px 10px 5px 10px;
|
||||||
|
color: #a3a3a3;
|
||||||
|
font-size: 10px;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.continue-button-container {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.continue-button {
|
||||||
|
display: block;
|
||||||
|
position: relative;
|
||||||
|
border-radius: 100px;
|
||||||
|
text-align: center;
|
||||||
|
width: 134px;
|
||||||
|
height: 30px;
|
||||||
|
margin-top: 10px;
|
||||||
|
padding: 10px;
|
||||||
|
transition: background-color 0.5s;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.continue-button::before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
border-radius: 15px;
|
||||||
|
border: 1px solid transparent;
|
||||||
|
background: linear-gradient(60deg, #ff7700 0%, #c740c7 100% ) border-box;
|
||||||
|
mask: linear-gradient(#fff 0 0) padding-box, linear-gradient(#fff 0 0);
|
||||||
|
-webkit-mask-composite: destination-out;
|
||||||
|
mask-composite: exclude;
|
||||||
|
}
|
||||||
|
.continue-button:hover {
|
||||||
|
background-color: #373a3d;
|
||||||
|
transition: background-color 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.small-btn {
|
||||||
|
margin-block-start: 1px;
|
||||||
|
width: 50px;
|
||||||
|
height: 25px;
|
||||||
|
color: white;
|
||||||
|
text-align: center;
|
||||||
|
background-color: transparent;
|
||||||
|
font-size: 12px;
|
||||||
|
text-align: center;
|
||||||
|
box-shadow: 0px 0px 2px rgba(0, 0, 0, 1);
|
||||||
|
background: linear-gradient(var(--background-color), var(--background-color)) padding-box,
|
||||||
|
var(--gradient) border-box;
|
||||||
|
border-radius: 2rem;
|
||||||
|
border: 1px solid transparent;
|
||||||
|
}
|
||||||
286
static/css/styles.css
Normal file
286
static/css/styles.css
Normal file
|
|
@ -0,0 +1,286 @@
|
||||||
|
:root {
|
||||||
|
--background-color: #16191c;
|
||||||
|
--color: #ffffff;
|
||||||
|
--color-marked: #ff7700;
|
||||||
|
--color-linked: #2aabe9;
|
||||||
|
--gradient: linear-gradient(60deg, #ff7700 0%, #c740c7 100%);
|
||||||
|
--font-size-h2: 36px;
|
||||||
|
--font-size-p: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: Montserrat;
|
||||||
|
background-color: var(--background-color);
|
||||||
|
color: var(--color);
|
||||||
|
text-align: center;
|
||||||
|
overflow-y: scroll;
|
||||||
|
overflow-x: hidden;
|
||||||
|
margin: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: space-between;
|
||||||
|
min-height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
header {
|
||||||
|
background-color: var(--background-color);
|
||||||
|
padding-inline: 2%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
gap: 1rem;
|
||||||
|
height: 4rem;
|
||||||
|
padding: 0.5rem 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
main {
|
||||||
|
max-width: 600px;
|
||||||
|
margin-inline: auto;
|
||||||
|
padding: 1rem;
|
||||||
|
margin-bottom: auto;
|
||||||
|
zoom: 1.3;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-height: 740px) {
|
||||||
|
main {
|
||||||
|
zoom: unset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
* {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 768px) {
|
||||||
|
body > * {
|
||||||
|
zoom: 1.4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 2000px) {
|
||||||
|
body > * {
|
||||||
|
zoom: 1.6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: 425px) {
|
||||||
|
header > img:nth-child(1) {
|
||||||
|
width: 30px;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
header > img:nth-child(2) {
|
||||||
|
width: auto;
|
||||||
|
height: 26px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="text"] {
|
||||||
|
background-color: transparent;
|
||||||
|
padding: 7px 10px;
|
||||||
|
border: 1px solid #c740c7;
|
||||||
|
border-radius: 5px;
|
||||||
|
font-size: 14px;
|
||||||
|
outline: none;
|
||||||
|
color: #999999;
|
||||||
|
box-shadow: 0px 0px 2px rgba(0, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-button {
|
||||||
|
background-color: transparent;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.push-button {
|
||||||
|
background-color: transparent;
|
||||||
|
padding: 10px 55px;
|
||||||
|
font-size: 20px;
|
||||||
|
color: var(--color);
|
||||||
|
text-align: center;
|
||||||
|
box-shadow: 0px 0px 2px rgba(0, 0, 0, 1);
|
||||||
|
background: linear-gradient(var(--background-color), var(--background-color))
|
||||||
|
padding-box,
|
||||||
|
var(--gradient) border-box;
|
||||||
|
border-radius: 5px;
|
||||||
|
border: 2px solid transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
font-size: var(--font-size-h2);
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
font-size: var(--font-size-p);
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: var(--color);
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-gray {
|
||||||
|
color: #a3a3a3;
|
||||||
|
margin-block-end: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.checkbox {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hide the default checkbox */
|
||||||
|
.checkbox input[type="checkbox"] {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create a new box */
|
||||||
|
.checkbox label {
|
||||||
|
padding-left: 32px;
|
||||||
|
display: inline-block;
|
||||||
|
width: 100%;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #a3a3a3;
|
||||||
|
text-decoration: none solid rgb(163, 163, 163);
|
||||||
|
text-shadow: 0px 0px 2px rgba(0, 0, 0, 1);
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.checkbox .checkbox-shape {
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
background-color: transparent;
|
||||||
|
border: 1px solid #a3a3a3;
|
||||||
|
border-radius: 5px;
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
transform: translate(0, -50%);
|
||||||
|
z-index: -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Display a checkmark when the checkbox is checked */
|
||||||
|
.checkbox input[type="checkbox"]:checked + .checkbox-shape::before {
|
||||||
|
content: "✓";
|
||||||
|
color: #a012c7;
|
||||||
|
font-size: 20px;
|
||||||
|
text-align: center;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.line {
|
||||||
|
margin-block: 24px;
|
||||||
|
background: var(--gradient);
|
||||||
|
width: 100%;
|
||||||
|
height: 1px;
|
||||||
|
margin-inline: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.marked {
|
||||||
|
color: var(--color-marked);
|
||||||
|
}
|
||||||
|
|
||||||
|
.linked {
|
||||||
|
color: var(--color-linked);
|
||||||
|
}
|
||||||
|
|
||||||
|
.setup-footer > p {
|
||||||
|
line-height: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.setup-header {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.setup-header > .back-button {
|
||||||
|
position: absolute;
|
||||||
|
top: 2px;
|
||||||
|
left: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 640px) {
|
||||||
|
.setup-header > .back-button {
|
||||||
|
top: 10px;
|
||||||
|
left: -20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.setup-header > h2 {
|
||||||
|
margin-block-start: 20px;
|
||||||
|
padding: 0 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.setup-header > h2 {
|
||||||
|
font-size: 24px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.setup-header .header-title {
|
||||||
|
font-size: 16px;
|
||||||
|
text-align: center;
|
||||||
|
text-shadow: 0px 0px 2px rgba(0, 0, 0, 1);
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
|
|
||||||
|
#qrcode {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
margin: 5px;
|
||||||
|
filter: blur(5px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-group {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-group span {
|
||||||
|
font-size: 16px;
|
||||||
|
color: #ffffff;
|
||||||
|
font-weight: bold;
|
||||||
|
text-decoration: none solid rgb(255, 255, 255);
|
||||||
|
text-shadow: 0px 0px 2px rgba(0, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-group > input {
|
||||||
|
align-self: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
footer {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
max-width: 500px;
|
||||||
|
width: 100%;
|
||||||
|
margin-inline: auto;
|
||||||
|
padding-top: 18px;
|
||||||
|
padding-left: 1rem;
|
||||||
|
padding-right: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
footer .footer-text {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #999999;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.checkbox-container {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
margin-top: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hidden-button {
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
.need-help{
|
||||||
|
transition-duration: 0.3s;
|
||||||
|
text-decoration-color: #c434e0;
|
||||||
|
|
||||||
|
}
|
||||||
|
.need-help:hover{
|
||||||
|
text-decoration: underline;
|
||||||
|
text-decoration-color: #c434e0;
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue