commit
fb17b05441
49 changed files with 10182 additions and 7105 deletions
|
|
@ -15,6 +15,7 @@ import { LspOrder } from "./build/src/services/storage/entity/LspOrder.js"
|
||||||
import { LndNodeInfo } from "./build/src/services/storage/entity/LndNodeInfo.js"
|
import { LndNodeInfo } from "./build/src/services/storage/entity/LndNodeInfo.js"
|
||||||
import { TrackedProvider } from "./build/src/services/storage/entity/TrackedProvider.js"
|
import { TrackedProvider } from "./build/src/services/storage/entity/TrackedProvider.js"
|
||||||
import { InviteToken } from "./build/src/services/storage/entity/InviteToken.js"
|
import { InviteToken } from "./build/src/services/storage/entity/InviteToken.js"
|
||||||
|
import { DebitAccess } from "./build/src/services/storage/entity/DebitAccess.js"
|
||||||
|
|
||||||
import { Initial1703170309875 } from './build/src/services/storage/migrations/1703170309875-initial.js'
|
import { Initial1703170309875 } from './build/src/services/storage/migrations/1703170309875-initial.js'
|
||||||
import { LspOrder1718387847693 } from './build/src/services/storage/migrations/1718387847693-lsp_order.js'
|
import { LspOrder1718387847693 } from './build/src/services/storage/migrations/1718387847693-lsp_order.js'
|
||||||
|
|
@ -22,13 +23,17 @@ import { LndNodeInfo1720187506189 } from './build/src/services/storage/migration
|
||||||
import { LiquidityProvider1719335699480 } from './build/src/services/storage/migrations/1719335699480-liquidity_provider.js'
|
import { LiquidityProvider1719335699480 } from './build/src/services/storage/migrations/1719335699480-liquidity_provider.js'
|
||||||
import { CreateInviteTokenTable1721751414878 } from './build/src/services/storage/migrations/1721751414878-create_invite_token_table.js'
|
import { CreateInviteTokenTable1721751414878 } from './build/src/services/storage/migrations/1721751414878-create_invite_token_table.js'
|
||||||
import { PaymentIndex1721760297610 } from './build/src/services/storage/migrations/1721760297610-payment_index.js'
|
import { PaymentIndex1721760297610 } from './build/src/services/storage/migrations/1721760297610-payment_index.js'
|
||||||
|
import { DebitAccess1726496225078 } from './build/src/services/storage/migrations/1726496225078-debit_access.js'
|
||||||
|
import { DebitAccessFixes1726685229264 } from './build/src/services/storage/migrations/1726685229264-debit_access_fixes.js'
|
||||||
|
import { DebitToPub1727105758354 } from './build/src/services/storage/migrations/1727105758354-debit_to_pub.js'
|
||||||
|
import { UserCbUrl1727112281043 } from './build/src/services/storage/migrations/1727112281043-user_cb_url.js'
|
||||||
export default new DataSource({
|
export default new DataSource({
|
||||||
type: "sqlite",
|
type: "sqlite",
|
||||||
database: "db.sqlite",
|
database: "db.sqlite",
|
||||||
// logging: true,
|
// logging: true,
|
||||||
migrations: [Initial1703170309875, LspOrder1718387847693, LiquidityProvider1719335699480, LndNodeInfo1720187506189, CreateInviteTokenTable1721751414878, PaymentIndex1721760297610],
|
migrations: [Initial1703170309875, LspOrder1718387847693, LiquidityProvider1719335699480, LndNodeInfo1720187506189, CreateInviteTokenTable1721751414878, PaymentIndex1721760297610, DebitAccess1726496225078, DebitAccessFixes1726685229264, DebitToPub1727105758354, UserCbUrl1727112281043],
|
||||||
entities: [User, UserReceivingInvoice, UserReceivingAddress, AddressReceivingTransaction, UserInvoicePayment, UserTransactionPayment,
|
entities: [User, UserReceivingInvoice, UserReceivingAddress, AddressReceivingTransaction, UserInvoicePayment, UserTransactionPayment,
|
||||||
UserBasicAuth, UserEphemeralKey, Product, UserToUserPayment, Application, ApplicationUser, UserToUserPayment, LspOrder, LndNodeInfo, TrackedProvider, InviteToken],
|
UserBasicAuth, UserEphemeralKey, Product, UserToUserPayment, Application, ApplicationUser, UserToUserPayment, LspOrder, LndNodeInfo, TrackedProvider, InviteToken, DebitAccess],
|
||||||
// synchronize: true,
|
// synchronize: true,
|
||||||
})
|
})
|
||||||
//npx typeorm migration:generate ./src/services/storage/migrations/lnd_node_info -d ./datasource.js
|
//npx typeorm migration:generate ./src/services/storage/migrations/usert_cb_url -d ./datasource.js
|
||||||
11629
package-lock.json
generated
11629
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -8,6 +8,7 @@
|
||||||
"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",
|
||||||
|
"gen": "cd proto && rimraf autogenerated && export PATH=$PATH:~/Lightning.Pub/proto && protoc -I ./service --pub_out=. service/*",
|
||||||
"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/* ",
|
||||||
|
|
@ -48,7 +49,7 @@
|
||||||
"grpc-tools": "^1.12.4",
|
"grpc-tools": "^1.12.4",
|
||||||
"jsonwebtoken": "^9.0.2",
|
"jsonwebtoken": "^9.0.2",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"nostr-tools": "^1.9.0",
|
"nostr-tools": "github:shocknet/nostr-tools#19271c4bcc9ff9bf18f9208e2d9fd6870e5f350c",
|
||||||
"pg": "^8.4.0",
|
"pg": "^8.4.0",
|
||||||
"reflect-metadata": "^0.2.2",
|
"reflect-metadata": "^0.2.2",
|
||||||
"rimraf": "^3.0.2",
|
"rimraf": "^3.0.2",
|
||||||
|
|
@ -62,7 +63,8 @@
|
||||||
"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",
|
||||||
"why-is-node-running": "^3.2.0"
|
"why-is-node-running": "^3.2.0",
|
||||||
|
"ws": "^8.18.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/chai": "^4.3.4",
|
"@types/chai": "^4.3.4",
|
||||||
|
|
@ -75,8 +77,9 @@
|
||||||
"@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",
|
||||||
|
"@types/ws": "^8.5.12",
|
||||||
"nodemon": "^2.0.20",
|
"nodemon": "^2.0.20",
|
||||||
"ts-node": "10.7.0",
|
"ts-node": "10.7.0",
|
||||||
"typescript": "5.5.4"
|
"typescript": "5.5.4"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -28,6 +28,16 @@ The nostr server will send back a message response, and inside the body there wi
|
||||||
- input: [AuthAppRequest](#AuthAppRequest)
|
- input: [AuthAppRequest](#AuthAppRequest)
|
||||||
- output: [AuthApp](#AuthApp)
|
- output: [AuthApp](#AuthApp)
|
||||||
|
|
||||||
|
- AuthorizeDebit
|
||||||
|
- auth type: __User__
|
||||||
|
- input: [DebitAuthorizationRequest](#DebitAuthorizationRequest)
|
||||||
|
- output: [DebitAuthorization](#DebitAuthorization)
|
||||||
|
|
||||||
|
- BanDebit
|
||||||
|
- auth type: __User__
|
||||||
|
- input: [DebitOperation](#DebitOperation)
|
||||||
|
- This methods has an __empty__ __response__ body
|
||||||
|
|
||||||
- BanUser
|
- BanUser
|
||||||
- auth type: __Admin__
|
- auth type: __Admin__
|
||||||
- input: [BanUserRequest](#BanUserRequest)
|
- input: [BanUserRequest](#BanUserRequest)
|
||||||
|
|
@ -48,6 +58,11 @@ The nostr server will send back a message response, and inside the body there wi
|
||||||
- input: [DecodeInvoiceRequest](#DecodeInvoiceRequest)
|
- input: [DecodeInvoiceRequest](#DecodeInvoiceRequest)
|
||||||
- output: [DecodeInvoiceResponse](#DecodeInvoiceResponse)
|
- output: [DecodeInvoiceResponse](#DecodeInvoiceResponse)
|
||||||
|
|
||||||
|
- EditDebit
|
||||||
|
- auth type: __User__
|
||||||
|
- input: [DebitAuthorizationRequest](#DebitAuthorizationRequest)
|
||||||
|
- This methods has an __empty__ __response__ body
|
||||||
|
|
||||||
- EnrollAdminToken
|
- EnrollAdminToken
|
||||||
- auth type: __User__
|
- auth type: __User__
|
||||||
- input: [EnrollAdminTokenRequest](#EnrollAdminTokenRequest)
|
- input: [EnrollAdminTokenRequest](#EnrollAdminTokenRequest)
|
||||||
|
|
@ -58,6 +73,11 @@ The nostr server will send back a message response, and inside the body there wi
|
||||||
- input: [AppsMetricsRequest](#AppsMetricsRequest)
|
- input: [AppsMetricsRequest](#AppsMetricsRequest)
|
||||||
- output: [AppsMetrics](#AppsMetrics)
|
- output: [AppsMetrics](#AppsMetrics)
|
||||||
|
|
||||||
|
- GetDebitAuthorizations
|
||||||
|
- auth type: __User__
|
||||||
|
- This methods has an __empty__ __request__ body
|
||||||
|
- output: [DebitAuthorizations](#DebitAuthorizations)
|
||||||
|
|
||||||
- GetHttpCreds
|
- GetHttpCreds
|
||||||
- auth type: __User__
|
- auth type: __User__
|
||||||
- This methods has an __empty__ __request__ body
|
- This methods has an __empty__ __request__ body
|
||||||
|
|
@ -73,6 +93,11 @@ The nostr server will send back a message response, and inside the body there wi
|
||||||
- This methods has an __empty__ __request__ body
|
- This methods has an __empty__ __request__ body
|
||||||
- output: [LnurlLinkResponse](#LnurlLinkResponse)
|
- output: [LnurlLinkResponse](#LnurlLinkResponse)
|
||||||
|
|
||||||
|
- GetLiveDebitRequests
|
||||||
|
- auth type: __User__
|
||||||
|
- This methods has an __empty__ __request__ body
|
||||||
|
- output: [LiveDebitRequest](#LiveDebitRequest)
|
||||||
|
|
||||||
- GetLiveUserOperations
|
- GetLiveUserOperations
|
||||||
- auth type: __User__
|
- auth type: __User__
|
||||||
- This methods has an __empty__ __request__ body
|
- This methods has an __empty__ __request__ body
|
||||||
|
|
@ -170,6 +195,21 @@ The nostr server will send back a message response, and inside the body there wi
|
||||||
- input: [PayInvoiceRequest](#PayInvoiceRequest)
|
- input: [PayInvoiceRequest](#PayInvoiceRequest)
|
||||||
- output: [PayInvoiceResponse](#PayInvoiceResponse)
|
- output: [PayInvoiceResponse](#PayInvoiceResponse)
|
||||||
|
|
||||||
|
- ResetDebit
|
||||||
|
- auth type: __User__
|
||||||
|
- input: [DebitOperation](#DebitOperation)
|
||||||
|
- This methods has an __empty__ __response__ body
|
||||||
|
|
||||||
|
- RespondToDebit
|
||||||
|
- auth type: __User__
|
||||||
|
- input: [DebitResponse](#DebitResponse)
|
||||||
|
- This methods has an __empty__ __response__ body
|
||||||
|
|
||||||
|
- UpdateCallbackUrl
|
||||||
|
- auth type: __User__
|
||||||
|
- input: [CallbackUrl](#CallbackUrl)
|
||||||
|
- output: [CallbackUrl](#CallbackUrl)
|
||||||
|
|
||||||
- UseInviteLink
|
- UseInviteLink
|
||||||
- auth type: __GuestWithPub__
|
- auth type: __GuestWithPub__
|
||||||
- input: [UseInviteLinkRequest](#UseInviteLinkRequest)
|
- input: [UseInviteLinkRequest](#UseInviteLinkRequest)
|
||||||
|
|
@ -256,6 +296,20 @@ The nostr server will send back a message response, and inside the body there wi
|
||||||
- input: [AuthAppRequest](#AuthAppRequest)
|
- input: [AuthAppRequest](#AuthAppRequest)
|
||||||
- output: [AuthApp](#AuthApp)
|
- output: [AuthApp](#AuthApp)
|
||||||
|
|
||||||
|
- AuthorizeDebit
|
||||||
|
- auth type: __User__
|
||||||
|
- http method: __post__
|
||||||
|
- http route: __/api/user/debit/authorize__
|
||||||
|
- input: [DebitAuthorizationRequest](#DebitAuthorizationRequest)
|
||||||
|
- output: [DebitAuthorization](#DebitAuthorization)
|
||||||
|
|
||||||
|
- BanDebit
|
||||||
|
- auth type: __User__
|
||||||
|
- http method: __post__
|
||||||
|
- http route: __/api/user/debit/ban__
|
||||||
|
- input: [DebitOperation](#DebitOperation)
|
||||||
|
- This methods has an __empty__ __response__ body
|
||||||
|
|
||||||
- BanUser
|
- BanUser
|
||||||
- auth type: __Admin__
|
- auth type: __Admin__
|
||||||
- http method: __post__
|
- http method: __post__
|
||||||
|
|
@ -284,6 +338,13 @@ The nostr server will send back a message response, and inside the body there wi
|
||||||
- input: [DecodeInvoiceRequest](#DecodeInvoiceRequest)
|
- input: [DecodeInvoiceRequest](#DecodeInvoiceRequest)
|
||||||
- output: [DecodeInvoiceResponse](#DecodeInvoiceResponse)
|
- output: [DecodeInvoiceResponse](#DecodeInvoiceResponse)
|
||||||
|
|
||||||
|
- EditDebit
|
||||||
|
- auth type: __User__
|
||||||
|
- http method: __post__
|
||||||
|
- http route: __/api/user/debit/edit__
|
||||||
|
- input: [DebitAuthorizationRequest](#DebitAuthorizationRequest)
|
||||||
|
- This methods has an __empty__ __response__ body
|
||||||
|
|
||||||
- EncryptionExchange
|
- EncryptionExchange
|
||||||
- auth type: __Guest__
|
- auth type: __Guest__
|
||||||
- http method: __post__
|
- http method: __post__
|
||||||
|
|
@ -326,6 +387,13 @@ The nostr server will send back a message response, and inside the body there wi
|
||||||
- input: [AppsMetricsRequest](#AppsMetricsRequest)
|
- input: [AppsMetricsRequest](#AppsMetricsRequest)
|
||||||
- output: [AppsMetrics](#AppsMetrics)
|
- output: [AppsMetrics](#AppsMetrics)
|
||||||
|
|
||||||
|
- GetDebitAuthorizations
|
||||||
|
- auth type: __User__
|
||||||
|
- http method: __get__
|
||||||
|
- http route: __/api/user/debit/get__
|
||||||
|
- This methods has an __empty__ __request__ body
|
||||||
|
- output: [DebitAuthorizations](#DebitAuthorizations)
|
||||||
|
|
||||||
- GetHttpCreds
|
- GetHttpCreds
|
||||||
- auth type: __User__
|
- auth type: __User__
|
||||||
- http method: __post__
|
- http method: __post__
|
||||||
|
|
@ -347,6 +415,13 @@ The nostr server will send back a message response, and inside the body there wi
|
||||||
- This methods has an __empty__ __request__ body
|
- This methods has an __empty__ __request__ body
|
||||||
- output: [LnurlLinkResponse](#LnurlLinkResponse)
|
- output: [LnurlLinkResponse](#LnurlLinkResponse)
|
||||||
|
|
||||||
|
- GetLiveDebitRequests
|
||||||
|
- auth type: __User__
|
||||||
|
- http method: __post__
|
||||||
|
- http route: __/api/user/debit/sub__
|
||||||
|
- This methods has an __empty__ __request__ body
|
||||||
|
- output: [LiveDebitRequest](#LiveDebitRequest)
|
||||||
|
|
||||||
- GetLiveUserOperations
|
- GetLiveUserOperations
|
||||||
- auth type: __User__
|
- auth type: __User__
|
||||||
- http method: __post__
|
- http method: __post__
|
||||||
|
|
@ -552,6 +627,13 @@ The nostr server will send back a message response, and inside the body there wi
|
||||||
- input: [RequestNPubLinkingTokenRequest](#RequestNPubLinkingTokenRequest)
|
- input: [RequestNPubLinkingTokenRequest](#RequestNPubLinkingTokenRequest)
|
||||||
- output: [RequestNPubLinkingTokenResponse](#RequestNPubLinkingTokenResponse)
|
- output: [RequestNPubLinkingTokenResponse](#RequestNPubLinkingTokenResponse)
|
||||||
|
|
||||||
|
- ResetDebit
|
||||||
|
- auth type: __User__
|
||||||
|
- http method: __post__
|
||||||
|
- http route: __/api/user/debit/reset__
|
||||||
|
- input: [DebitOperation](#DebitOperation)
|
||||||
|
- This methods has an __empty__ __response__ body
|
||||||
|
|
||||||
- ResetNPubLinkingToken
|
- ResetNPubLinkingToken
|
||||||
- auth type: __App__
|
- auth type: __App__
|
||||||
- http method: __post__
|
- http method: __post__
|
||||||
|
|
@ -559,6 +641,13 @@ The nostr server will send back a message response, and inside the body there wi
|
||||||
- input: [RequestNPubLinkingTokenRequest](#RequestNPubLinkingTokenRequest)
|
- input: [RequestNPubLinkingTokenRequest](#RequestNPubLinkingTokenRequest)
|
||||||
- output: [RequestNPubLinkingTokenResponse](#RequestNPubLinkingTokenResponse)
|
- output: [RequestNPubLinkingTokenResponse](#RequestNPubLinkingTokenResponse)
|
||||||
|
|
||||||
|
- RespondToDebit
|
||||||
|
- auth type: __User__
|
||||||
|
- http method: __post__
|
||||||
|
- http route: __/api/user/debit/finish__
|
||||||
|
- input: [DebitResponse](#DebitResponse)
|
||||||
|
- This methods has an __empty__ __response__ body
|
||||||
|
|
||||||
- SendAppUserToAppPayment
|
- SendAppUserToAppPayment
|
||||||
- auth type: __App__
|
- auth type: __App__
|
||||||
- http method: __post__
|
- http method: __post__
|
||||||
|
|
@ -594,6 +683,13 @@ The nostr server will send back a message response, and inside the body there wi
|
||||||
- input: [SetMockInvoiceAsPaidRequest](#SetMockInvoiceAsPaidRequest)
|
- input: [SetMockInvoiceAsPaidRequest](#SetMockInvoiceAsPaidRequest)
|
||||||
- This methods has an __empty__ __response__ body
|
- This methods has an __empty__ __response__ body
|
||||||
|
|
||||||
|
- UpdateCallbackUrl
|
||||||
|
- auth type: __User__
|
||||||
|
- http method: __post__
|
||||||
|
- http route: __/api/user/cb/update__
|
||||||
|
- input: [CallbackUrl](#CallbackUrl)
|
||||||
|
- output: [CallbackUrl](#CallbackUrl)
|
||||||
|
|
||||||
- UseInviteLink
|
- UseInviteLink
|
||||||
- auth type: __GuestWithPub__
|
- auth type: __GuestWithPub__
|
||||||
- http method: __post__
|
- http method: __post__
|
||||||
|
|
@ -688,6 +784,9 @@ The nostr server will send back a message response, and inside the body there wi
|
||||||
- __nostr_pub__: _string_
|
- __nostr_pub__: _string_
|
||||||
- __user_identifier__: _string_
|
- __user_identifier__: _string_
|
||||||
|
|
||||||
|
### CallbackUrl
|
||||||
|
- __url__: _string_
|
||||||
|
|
||||||
### ClosedChannel
|
### ClosedChannel
|
||||||
- __capacity__: _number_
|
- __capacity__: _number_
|
||||||
- __channel_id__: _string_
|
- __channel_id__: _string_
|
||||||
|
|
@ -702,6 +801,34 @@ The nostr server will send back a message response, and inside the body there wi
|
||||||
### CreateOneTimeInviteLinkResponse
|
### CreateOneTimeInviteLinkResponse
|
||||||
- __invitation_link__: _string_
|
- __invitation_link__: _string_
|
||||||
|
|
||||||
|
### DebitAuthorization
|
||||||
|
- __authorized__: _boolean_
|
||||||
|
- __debit_id__: _string_
|
||||||
|
- __npub__: _string_
|
||||||
|
- __rules__: ARRAY of: _[DebitRule](#DebitRule)_
|
||||||
|
|
||||||
|
### DebitAuthorizationRequest
|
||||||
|
- __authorize_npub__: _string_
|
||||||
|
- __request_id__: _string_ *this field is optional
|
||||||
|
- __rules__: ARRAY of: _[DebitRule](#DebitRule)_
|
||||||
|
|
||||||
|
### DebitAuthorizations
|
||||||
|
- __debits__: ARRAY of: _[DebitAuthorization](#DebitAuthorization)_
|
||||||
|
|
||||||
|
### DebitExpirationRule
|
||||||
|
- __expires_at_unix__: _number_
|
||||||
|
|
||||||
|
### DebitOperation
|
||||||
|
- __npub__: _string_
|
||||||
|
|
||||||
|
### DebitResponse
|
||||||
|
- __npub__: _string_
|
||||||
|
- __request_id__: _string_
|
||||||
|
- __response__: _[DebitResponse_response](#DebitResponse_response)_
|
||||||
|
|
||||||
|
### DebitRule
|
||||||
|
- __rule__: _[DebitRule_rule](#DebitRule_rule)_
|
||||||
|
|
||||||
### DecodeInvoiceRequest
|
### DecodeInvoiceRequest
|
||||||
- __invoice__: _string_
|
- __invoice__: _string_
|
||||||
|
|
||||||
|
|
@ -717,6 +844,11 @@ The nostr server will send back a message response, and inside the body there wi
|
||||||
### EnrollAdminTokenRequest
|
### EnrollAdminTokenRequest
|
||||||
- __admin_token__: _string_
|
- __admin_token__: _string_
|
||||||
|
|
||||||
|
### FrequencyRule
|
||||||
|
- __amount__: _number_
|
||||||
|
- __interval__: _[IntervalType](#IntervalType)_
|
||||||
|
- __number_of_intervals__: _number_
|
||||||
|
|
||||||
### GetAppUserLNURLInfoRequest
|
### GetAppUserLNURLInfoRequest
|
||||||
- __base_url_override__: _string_
|
- __base_url_override__: _string_
|
||||||
- __user_identifier__: _string_
|
- __user_identifier__: _string_
|
||||||
|
|
@ -768,6 +900,11 @@ The nostr server will send back a message response, and inside the body there wi
|
||||||
### LinkNPubThroughTokenRequest
|
### LinkNPubThroughTokenRequest
|
||||||
- __token__: _string_
|
- __token__: _string_
|
||||||
|
|
||||||
|
### LiveDebitRequest
|
||||||
|
- __debit__: _[LiveDebitRequest_debit](#LiveDebitRequest_debit)_
|
||||||
|
- __npub__: _string_
|
||||||
|
- __request_id__: _string_
|
||||||
|
|
||||||
### LiveUserOperation
|
### LiveUserOperation
|
||||||
- __operation__: _[UserOperation](#UserOperation)_
|
- __operation__: _[UserOperation](#UserOperation)_
|
||||||
|
|
||||||
|
|
@ -874,11 +1011,13 @@ The nostr server will send back a message response, and inside the body there wi
|
||||||
|
|
||||||
### PayAppUserInvoiceRequest
|
### PayAppUserInvoiceRequest
|
||||||
- __amount__: _number_
|
- __amount__: _number_
|
||||||
|
- __debit_npub__: _string_ *this field is optional
|
||||||
- __invoice__: _string_
|
- __invoice__: _string_
|
||||||
- __user_identifier__: _string_
|
- __user_identifier__: _string_
|
||||||
|
|
||||||
### PayInvoiceRequest
|
### PayInvoiceRequest
|
||||||
- __amount__: _number_
|
- __amount__: _number_
|
||||||
|
- __debit_npub__: _string_ *this field is optional
|
||||||
- __invoice__: _string_
|
- __invoice__: _string_
|
||||||
|
|
||||||
### PayInvoiceResponse
|
### PayInvoiceResponse
|
||||||
|
|
@ -963,7 +1102,9 @@ The nostr server will send back a message response, and inside the body there wi
|
||||||
### UserInfo
|
### UserInfo
|
||||||
- __balance__: _number_
|
- __balance__: _number_
|
||||||
- __bridge_url__: _string_
|
- __bridge_url__: _string_
|
||||||
|
- __callback_url__: _string_
|
||||||
- __max_withdrawable__: _number_
|
- __max_withdrawable__: _number_
|
||||||
|
- __ndebit__: _string_
|
||||||
- __network_max_fee_bps__: _number_
|
- __network_max_fee_bps__: _number_
|
||||||
- __network_max_fee_fixed__: _number_
|
- __network_max_fee_fixed__: _number_
|
||||||
- __noffer__: _string_
|
- __noffer__: _string_
|
||||||
|
|
@ -1004,6 +1145,11 @@ The nostr server will send back a message response, and inside the body there wi
|
||||||
- __TAPROOT_PUBKEY__
|
- __TAPROOT_PUBKEY__
|
||||||
- __WITNESS_PUBKEY_HASH__
|
- __WITNESS_PUBKEY_HASH__
|
||||||
|
|
||||||
|
### IntervalType
|
||||||
|
- __DAY__
|
||||||
|
- __MONTH__
|
||||||
|
- __WEEK__
|
||||||
|
|
||||||
### UserOperationType
|
### UserOperationType
|
||||||
- __INCOMING_INVOICE__
|
- __INCOMING_INVOICE__
|
||||||
- __INCOMING_TX__
|
- __INCOMING_TX__
|
||||||
|
|
|
||||||
1656
proto/autogenerated/go/http_client.go
Normal file
1656
proto/autogenerated/go/http_client.go
Normal file
File diff suppressed because it is too large
Load diff
544
proto/autogenerated/go/types.go
Normal file
544
proto/autogenerated/go/types.go
Normal file
|
|
@ -0,0 +1,544 @@
|
||||||
|
// This file was autogenerated from a .proto file, DO NOT EDIT!
|
||||||
|
|
||||||
|
package lightning_pub
|
||||||
|
|
||||||
|
type ResultError struct {
|
||||||
|
Status string `json:"status"`
|
||||||
|
Reason string `json:"reason"`
|
||||||
|
}
|
||||||
|
type AdminContext struct {
|
||||||
|
Admin_id string `json:"admin_id"`
|
||||||
|
}
|
||||||
|
type AppContext struct {
|
||||||
|
App_id string `json:"app_id"`
|
||||||
|
}
|
||||||
|
type GuestContext struct {
|
||||||
|
}
|
||||||
|
type GuestWithPubContext struct {
|
||||||
|
App_id string `json:"app_id"`
|
||||||
|
Pub string `json:"pub"`
|
||||||
|
}
|
||||||
|
type MetricsContext struct {
|
||||||
|
Operator_id string `json:"operator_id"`
|
||||||
|
}
|
||||||
|
type UserContext struct {
|
||||||
|
App_id string `json:"app_id"`
|
||||||
|
App_user_id string `json:"app_user_id"`
|
||||||
|
User_id string `json:"user_id"`
|
||||||
|
}
|
||||||
|
type GetLnurlPayInfo_Query struct {
|
||||||
|
K1 *string `json:"k1,omitempty"`
|
||||||
|
}
|
||||||
|
type GetLnurlWithdrawInfo_Query struct {
|
||||||
|
K1 *string `json:"k1,omitempty"`
|
||||||
|
}
|
||||||
|
type HandleLnurlAddress_RouteParams struct {
|
||||||
|
Address_name string `json:"address_name"`
|
||||||
|
}
|
||||||
|
type HandleLnurlPay_Query struct {
|
||||||
|
Amount *string `json:"amount,omitempty"`
|
||||||
|
K1 *string `json:"k1,omitempty"`
|
||||||
|
Lnurl *string `json:"lnurl,omitempty"`
|
||||||
|
Nostr *string `json:"nostr,omitempty"`
|
||||||
|
}
|
||||||
|
type HandleLnurlWithdraw_Query struct {
|
||||||
|
K1 *string `json:"k1,omitempty"`
|
||||||
|
Pr *string `json:"pr,omitempty"`
|
||||||
|
}
|
||||||
|
type NewProductInvoice_Query struct {
|
||||||
|
Id *string `json:"id,omitempty"`
|
||||||
|
}
|
||||||
|
type AddressType string
|
||||||
|
|
||||||
|
const (
|
||||||
|
NESTED_PUBKEY_HASH AddressType = "NESTED_PUBKEY_HASH"
|
||||||
|
TAPROOT_PUBKEY AddressType = "TAPROOT_PUBKEY"
|
||||||
|
WITNESS_PUBKEY_HASH AddressType = "WITNESS_PUBKEY_HASH"
|
||||||
|
)
|
||||||
|
|
||||||
|
type IntervalType string
|
||||||
|
|
||||||
|
const (
|
||||||
|
DAY IntervalType = "DAY"
|
||||||
|
MONTH IntervalType = "MONTH"
|
||||||
|
WEEK IntervalType = "WEEK"
|
||||||
|
)
|
||||||
|
|
||||||
|
type UserOperationType string
|
||||||
|
|
||||||
|
const (
|
||||||
|
INCOMING_INVOICE UserOperationType = "INCOMING_INVOICE"
|
||||||
|
INCOMING_TX UserOperationType = "INCOMING_TX"
|
||||||
|
INCOMING_USER_TO_USER UserOperationType = "INCOMING_USER_TO_USER"
|
||||||
|
OUTGOING_INVOICE UserOperationType = "OUTGOING_INVOICE"
|
||||||
|
OUTGOING_TX UserOperationType = "OUTGOING_TX"
|
||||||
|
OUTGOING_USER_TO_USER UserOperationType = "OUTGOING_USER_TO_USER"
|
||||||
|
)
|
||||||
|
|
||||||
|
type AddAppInvoiceRequest struct {
|
||||||
|
Http_callback_url string `json:"http_callback_url"`
|
||||||
|
Invoice_req *NewInvoiceRequest `json:"invoice_req"`
|
||||||
|
Payer_identifier string `json:"payer_identifier"`
|
||||||
|
}
|
||||||
|
type AddAppRequest struct {
|
||||||
|
Allow_user_creation bool `json:"allow_user_creation"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
}
|
||||||
|
type AddAppUserInvoiceRequest struct {
|
||||||
|
Http_callback_url string `json:"http_callback_url"`
|
||||||
|
Invoice_req *NewInvoiceRequest `json:"invoice_req"`
|
||||||
|
Payer_identifier string `json:"payer_identifier"`
|
||||||
|
Receiver_identifier string `json:"receiver_identifier"`
|
||||||
|
}
|
||||||
|
type AddAppUserRequest struct {
|
||||||
|
Balance int64 `json:"balance"`
|
||||||
|
Fail_if_exists bool `json:"fail_if_exists"`
|
||||||
|
Identifier string `json:"identifier"`
|
||||||
|
}
|
||||||
|
type AddProductRequest struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Price_sats int64 `json:"price_sats"`
|
||||||
|
}
|
||||||
|
type AppMetrics struct {
|
||||||
|
App *Application `json:"app"`
|
||||||
|
Available int64 `json:"available"`
|
||||||
|
Fees int64 `json:"fees"`
|
||||||
|
Invoices int64 `json:"invoices"`
|
||||||
|
Operations []UserOperation `json:"operations"`
|
||||||
|
Received int64 `json:"received"`
|
||||||
|
Spent int64 `json:"spent"`
|
||||||
|
Total_fees int64 `json:"total_fees"`
|
||||||
|
Users *UsersInfo `json:"users"`
|
||||||
|
}
|
||||||
|
type AppUser struct {
|
||||||
|
Identifier string `json:"identifier"`
|
||||||
|
Info *UserInfo `json:"info"`
|
||||||
|
Max_withdrawable int64 `json:"max_withdrawable"`
|
||||||
|
}
|
||||||
|
type Application struct {
|
||||||
|
Balance int64 `json:"balance"`
|
||||||
|
Id string `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Npub string `json:"npub"`
|
||||||
|
}
|
||||||
|
type AppsMetrics struct {
|
||||||
|
Apps []AppMetrics `json:"apps"`
|
||||||
|
}
|
||||||
|
type AppsMetricsRequest struct {
|
||||||
|
From_unix int64 `json:"from_unix"`
|
||||||
|
Include_operations bool `json:"include_operations"`
|
||||||
|
To_unix int64 `json:"to_unix"`
|
||||||
|
}
|
||||||
|
type AuthApp struct {
|
||||||
|
App *Application `json:"app"`
|
||||||
|
Auth_token string `json:"auth_token"`
|
||||||
|
}
|
||||||
|
type AuthAppRequest struct {
|
||||||
|
Allow_user_creation bool `json:"allow_user_creation"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
}
|
||||||
|
type BanUserRequest struct {
|
||||||
|
User_id string `json:"user_id"`
|
||||||
|
}
|
||||||
|
type BanUserResponse struct {
|
||||||
|
Balance_sats int64 `json:"balance_sats"`
|
||||||
|
Banned_app_users []BannedAppUser `json:"banned_app_users"`
|
||||||
|
}
|
||||||
|
type BannedAppUser struct {
|
||||||
|
App_id string `json:"app_id"`
|
||||||
|
App_name string `json:"app_name"`
|
||||||
|
Nostr_pub string `json:"nostr_pub"`
|
||||||
|
User_identifier string `json:"user_identifier"`
|
||||||
|
}
|
||||||
|
type CallbackUrl struct {
|
||||||
|
Url string `json:"url"`
|
||||||
|
}
|
||||||
|
type ClosedChannel struct {
|
||||||
|
Capacity int64 `json:"capacity"`
|
||||||
|
Channel_id string `json:"channel_id"`
|
||||||
|
Closed_height int64 `json:"closed_height"`
|
||||||
|
}
|
||||||
|
type ClosureMigration struct {
|
||||||
|
Closes_at_unix int64 `json:"closes_at_unix"`
|
||||||
|
}
|
||||||
|
type CreateOneTimeInviteLinkRequest struct {
|
||||||
|
Sats int64 `json:"sats"`
|
||||||
|
}
|
||||||
|
type CreateOneTimeInviteLinkResponse struct {
|
||||||
|
Invitation_link string `json:"invitation_link"`
|
||||||
|
}
|
||||||
|
type DebitAuthorization struct {
|
||||||
|
Authorized bool `json:"authorized"`
|
||||||
|
Debit_id string `json:"debit_id"`
|
||||||
|
Npub string `json:"npub"`
|
||||||
|
Rules []DebitRule `json:"rules"`
|
||||||
|
}
|
||||||
|
type DebitAuthorizationRequest struct {
|
||||||
|
Authorize_npub string `json:"authorize_npub"`
|
||||||
|
Request_id string `json:"request_id"`
|
||||||
|
Rules []DebitRule `json:"rules"`
|
||||||
|
}
|
||||||
|
type DebitAuthorizations struct {
|
||||||
|
Debits []DebitAuthorization `json:"debits"`
|
||||||
|
}
|
||||||
|
type DebitExpirationRule struct {
|
||||||
|
Expires_at_unix int64 `json:"expires_at_unix"`
|
||||||
|
}
|
||||||
|
type DebitOperation struct {
|
||||||
|
Npub string `json:"npub"`
|
||||||
|
}
|
||||||
|
type DebitResponse struct {
|
||||||
|
Npub string `json:"npub"`
|
||||||
|
Request_id string `json:"request_id"`
|
||||||
|
Response *DebitResponse_response `json:"response"`
|
||||||
|
}
|
||||||
|
type DebitRule struct {
|
||||||
|
Rule *DebitRule_rule `json:"rule"`
|
||||||
|
}
|
||||||
|
type DecodeInvoiceRequest struct {
|
||||||
|
Invoice string `json:"invoice"`
|
||||||
|
}
|
||||||
|
type DecodeInvoiceResponse struct {
|
||||||
|
Amount int64 `json:"amount"`
|
||||||
|
}
|
||||||
|
type Empty struct {
|
||||||
|
}
|
||||||
|
type EncryptionExchangeRequest struct {
|
||||||
|
Deviceid string `json:"deviceId"`
|
||||||
|
Publickey string `json:"publicKey"`
|
||||||
|
}
|
||||||
|
type EnrollAdminTokenRequest struct {
|
||||||
|
Admin_token string `json:"admin_token"`
|
||||||
|
}
|
||||||
|
type FrequencyRule struct {
|
||||||
|
Amount int64 `json:"amount"`
|
||||||
|
Interval IntervalType `json:"interval"`
|
||||||
|
Number_of_intervals int64 `json:"number_of_intervals"`
|
||||||
|
}
|
||||||
|
type GetAppUserLNURLInfoRequest struct {
|
||||||
|
Base_url_override string `json:"base_url_override"`
|
||||||
|
User_identifier string `json:"user_identifier"`
|
||||||
|
}
|
||||||
|
type GetAppUserRequest struct {
|
||||||
|
User_identifier string `json:"user_identifier"`
|
||||||
|
}
|
||||||
|
type GetInviteTokenStateRequest struct {
|
||||||
|
Invite_token string `json:"invite_token"`
|
||||||
|
}
|
||||||
|
type GetInviteTokenStateResponse struct {
|
||||||
|
Used bool `json:"used"`
|
||||||
|
}
|
||||||
|
type GetPaymentStateRequest struct {
|
||||||
|
Invoice string `json:"invoice"`
|
||||||
|
}
|
||||||
|
type GetProductBuyLinkResponse struct {
|
||||||
|
Link string `json:"link"`
|
||||||
|
}
|
||||||
|
type GetUserOperationsRequest struct {
|
||||||
|
Latestincominginvoice int64 `json:"latestIncomingInvoice"`
|
||||||
|
Latestincomingtx int64 `json:"latestIncomingTx"`
|
||||||
|
Latestincomingusertouserpayment int64 `json:"latestIncomingUserToUserPayment"`
|
||||||
|
Latestoutgoinginvoice int64 `json:"latestOutgoingInvoice"`
|
||||||
|
Latestoutgoingtx int64 `json:"latestOutgoingTx"`
|
||||||
|
Latestoutgoingusertouserpayment int64 `json:"latestOutgoingUserToUserPayment"`
|
||||||
|
Max_size int64 `json:"max_size"`
|
||||||
|
}
|
||||||
|
type GetUserOperationsResponse struct {
|
||||||
|
Latestincominginvoiceoperations *UserOperations `json:"latestIncomingInvoiceOperations"`
|
||||||
|
Latestincomingtxoperations *UserOperations `json:"latestIncomingTxOperations"`
|
||||||
|
Latestincomingusertouserpayemnts *UserOperations `json:"latestIncomingUserToUserPayemnts"`
|
||||||
|
Latestoutgoinginvoiceoperations *UserOperations `json:"latestOutgoingInvoiceOperations"`
|
||||||
|
Latestoutgoingtxoperations *UserOperations `json:"latestOutgoingTxOperations"`
|
||||||
|
Latestoutgoingusertouserpayemnts *UserOperations `json:"latestOutgoingUserToUserPayemnts"`
|
||||||
|
}
|
||||||
|
type GraphPoint struct {
|
||||||
|
X int64 `json:"x"`
|
||||||
|
Y int64 `json:"y"`
|
||||||
|
}
|
||||||
|
type HandleLnurlPayResponse struct {
|
||||||
|
Pr string `json:"pr"`
|
||||||
|
Routes []Empty `json:"routes"`
|
||||||
|
}
|
||||||
|
type HttpCreds struct {
|
||||||
|
Token string `json:"token"`
|
||||||
|
Url string `json:"url"`
|
||||||
|
}
|
||||||
|
type LinkNPubThroughTokenRequest struct {
|
||||||
|
Token string `json:"token"`
|
||||||
|
}
|
||||||
|
type LiveDebitRequest struct {
|
||||||
|
Debit *LiveDebitRequest_debit `json:"debit"`
|
||||||
|
Npub string `json:"npub"`
|
||||||
|
Request_id string `json:"request_id"`
|
||||||
|
}
|
||||||
|
type LiveUserOperation struct {
|
||||||
|
Operation *UserOperation `json:"operation"`
|
||||||
|
}
|
||||||
|
type LndChannels struct {
|
||||||
|
Open_channels []OpenChannel `json:"open_channels"`
|
||||||
|
}
|
||||||
|
type LndGetInfoRequest struct {
|
||||||
|
Nodeid int64 `json:"nodeId"`
|
||||||
|
}
|
||||||
|
type LndGetInfoResponse struct {
|
||||||
|
Alias string `json:"alias"`
|
||||||
|
}
|
||||||
|
type LndMetrics struct {
|
||||||
|
Nodes []LndNodeMetrics `json:"nodes"`
|
||||||
|
}
|
||||||
|
type LndMetricsRequest struct {
|
||||||
|
From_unix int64 `json:"from_unix"`
|
||||||
|
To_unix int64 `json:"to_unix"`
|
||||||
|
}
|
||||||
|
type LndNodeMetrics struct {
|
||||||
|
Chain_balance []GraphPoint `json:"chain_balance"`
|
||||||
|
Channel_balance []GraphPoint `json:"channel_balance"`
|
||||||
|
Closed_channels []ClosedChannel `json:"closed_channels"`
|
||||||
|
Closing_channels int64 `json:"closing_channels"`
|
||||||
|
External_balance []GraphPoint `json:"external_balance"`
|
||||||
|
Forwarding_events int64 `json:"forwarding_events"`
|
||||||
|
Forwarding_fees int64 `json:"forwarding_fees"`
|
||||||
|
Offline_channels int64 `json:"offline_channels"`
|
||||||
|
Online_channels int64 `json:"online_channels"`
|
||||||
|
Open_channels []OpenChannel `json:"open_channels"`
|
||||||
|
Pending_channels int64 `json:"pending_channels"`
|
||||||
|
}
|
||||||
|
type LndSeed struct {
|
||||||
|
Seed []string `json:"seed"`
|
||||||
|
}
|
||||||
|
type LnurlLinkResponse struct {
|
||||||
|
K1 string `json:"k1"`
|
||||||
|
Lnurl string `json:"lnurl"`
|
||||||
|
}
|
||||||
|
type LnurlPayInfoResponse struct {
|
||||||
|
Allowsnostr bool `json:"allowsNostr"`
|
||||||
|
Callback string `json:"callback"`
|
||||||
|
Maxsendable int64 `json:"maxSendable"`
|
||||||
|
Metadata string `json:"metadata"`
|
||||||
|
Minsendable int64 `json:"minSendable"`
|
||||||
|
Nostrpubkey string `json:"nostrPubkey"`
|
||||||
|
Tag string `json:"tag"`
|
||||||
|
}
|
||||||
|
type LnurlWithdrawInfoResponse struct {
|
||||||
|
Balancecheck string `json:"balanceCheck"`
|
||||||
|
Callback string `json:"callback"`
|
||||||
|
Defaultdescription string `json:"defaultDescription"`
|
||||||
|
K1 string `json:"k1"`
|
||||||
|
Maxwithdrawable int64 `json:"maxWithdrawable"`
|
||||||
|
Minwithdrawable int64 `json:"minWithdrawable"`
|
||||||
|
Paylink string `json:"payLink"`
|
||||||
|
Tag string `json:"tag"`
|
||||||
|
}
|
||||||
|
type MigrationUpdate struct {
|
||||||
|
Closure *ClosureMigration `json:"closure"`
|
||||||
|
Relays *RelaysMigration `json:"relays"`
|
||||||
|
}
|
||||||
|
type NewAddressRequest struct {
|
||||||
|
Addresstype AddressType `json:"addressType"`
|
||||||
|
}
|
||||||
|
type NewAddressResponse struct {
|
||||||
|
Address string `json:"address"`
|
||||||
|
}
|
||||||
|
type NewInvoiceRequest struct {
|
||||||
|
Amountsats int64 `json:"amountSats"`
|
||||||
|
Memo string `json:"memo"`
|
||||||
|
}
|
||||||
|
type NewInvoiceResponse struct {
|
||||||
|
Invoice string `json:"invoice"`
|
||||||
|
}
|
||||||
|
type OpenChannel struct {
|
||||||
|
Active bool `json:"active"`
|
||||||
|
Capacity int64 `json:"capacity"`
|
||||||
|
Channel_id string `json:"channel_id"`
|
||||||
|
Label string `json:"label"`
|
||||||
|
Lifetime int64 `json:"lifetime"`
|
||||||
|
Local_balance int64 `json:"local_balance"`
|
||||||
|
Remote_balance int64 `json:"remote_balance"`
|
||||||
|
}
|
||||||
|
type OpenChannelRequest struct {
|
||||||
|
Closeaddress string `json:"closeAddress"`
|
||||||
|
Destination string `json:"destination"`
|
||||||
|
Fundingamount int64 `json:"fundingAmount"`
|
||||||
|
Pushamount int64 `json:"pushAmount"`
|
||||||
|
}
|
||||||
|
type OpenChannelResponse struct {
|
||||||
|
Channelid string `json:"channelId"`
|
||||||
|
}
|
||||||
|
type PayAddressRequest struct {
|
||||||
|
Address string `json:"address"`
|
||||||
|
Amoutsats int64 `json:"amoutSats"`
|
||||||
|
Satspervbyte int64 `json:"satsPerVByte"`
|
||||||
|
}
|
||||||
|
type PayAddressResponse struct {
|
||||||
|
Network_fee int64 `json:"network_fee"`
|
||||||
|
Operation_id string `json:"operation_id"`
|
||||||
|
Service_fee int64 `json:"service_fee"`
|
||||||
|
Txid string `json:"txId"`
|
||||||
|
}
|
||||||
|
type PayAppUserInvoiceRequest struct {
|
||||||
|
Amount int64 `json:"amount"`
|
||||||
|
Debit_npub string `json:"debit_npub"`
|
||||||
|
Invoice string `json:"invoice"`
|
||||||
|
User_identifier string `json:"user_identifier"`
|
||||||
|
}
|
||||||
|
type PayInvoiceRequest struct {
|
||||||
|
Amount int64 `json:"amount"`
|
||||||
|
Debit_npub string `json:"debit_npub"`
|
||||||
|
Invoice string `json:"invoice"`
|
||||||
|
}
|
||||||
|
type PayInvoiceResponse struct {
|
||||||
|
Amount_paid int64 `json:"amount_paid"`
|
||||||
|
Network_fee int64 `json:"network_fee"`
|
||||||
|
Operation_id string `json:"operation_id"`
|
||||||
|
Preimage string `json:"preimage"`
|
||||||
|
Service_fee int64 `json:"service_fee"`
|
||||||
|
}
|
||||||
|
type PaymentState struct {
|
||||||
|
Amount int64 `json:"amount"`
|
||||||
|
Network_fee int64 `json:"network_fee"`
|
||||||
|
Paid_at_unix int64 `json:"paid_at_unix"`
|
||||||
|
Service_fee int64 `json:"service_fee"`
|
||||||
|
}
|
||||||
|
type Product struct {
|
||||||
|
Id string `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Noffer string `json:"noffer"`
|
||||||
|
Price_sats int64 `json:"price_sats"`
|
||||||
|
}
|
||||||
|
type RelaysMigration struct {
|
||||||
|
Relays []string `json:"relays"`
|
||||||
|
}
|
||||||
|
type RequestNPubLinkingTokenRequest struct {
|
||||||
|
User_identifier string `json:"user_identifier"`
|
||||||
|
}
|
||||||
|
type RequestNPubLinkingTokenResponse struct {
|
||||||
|
Token string `json:"token"`
|
||||||
|
}
|
||||||
|
type RoutingEvent struct {
|
||||||
|
Event_type string `json:"event_type"`
|
||||||
|
Failure_string string `json:"failure_string"`
|
||||||
|
Forward_fail_event bool `json:"forward_fail_event"`
|
||||||
|
Incoming_amt_msat int64 `json:"incoming_amt_msat"`
|
||||||
|
Incoming_channel_id int64 `json:"incoming_channel_id"`
|
||||||
|
Incoming_htlc_id int64 `json:"incoming_htlc_id"`
|
||||||
|
Offchain bool `json:"offchain"`
|
||||||
|
Outgoing_amt_msat int64 `json:"outgoing_amt_msat"`
|
||||||
|
Outgoing_channel_id int64 `json:"outgoing_channel_id"`
|
||||||
|
Outgoing_htlc_id int64 `json:"outgoing_htlc_id"`
|
||||||
|
Settled bool `json:"settled"`
|
||||||
|
Timestamp_ns int64 `json:"timestamp_ns"`
|
||||||
|
}
|
||||||
|
type SendAppUserToAppPaymentRequest struct {
|
||||||
|
Amount int64 `json:"amount"`
|
||||||
|
From_user_identifier string `json:"from_user_identifier"`
|
||||||
|
}
|
||||||
|
type SendAppUserToAppUserPaymentRequest struct {
|
||||||
|
Amount int64 `json:"amount"`
|
||||||
|
From_user_identifier string `json:"from_user_identifier"`
|
||||||
|
To_user_identifier string `json:"to_user_identifier"`
|
||||||
|
}
|
||||||
|
type SetMockAppBalanceRequest struct {
|
||||||
|
Amount int64 `json:"amount"`
|
||||||
|
}
|
||||||
|
type SetMockAppUserBalanceRequest struct {
|
||||||
|
Amount int64 `json:"amount"`
|
||||||
|
User_identifier string `json:"user_identifier"`
|
||||||
|
}
|
||||||
|
type SetMockInvoiceAsPaidRequest struct {
|
||||||
|
Amount int64 `json:"amount"`
|
||||||
|
Invoice string `json:"invoice"`
|
||||||
|
}
|
||||||
|
type UsageMetric struct {
|
||||||
|
Auth_in_nano int64 `json:"auth_in_nano"`
|
||||||
|
Batch bool `json:"batch"`
|
||||||
|
Batch_size int64 `json:"batch_size"`
|
||||||
|
Handle_in_nano int64 `json:"handle_in_nano"`
|
||||||
|
Nostr bool `json:"nostr"`
|
||||||
|
Parsed_in_nano int64 `json:"parsed_in_nano"`
|
||||||
|
Processed_at_ms int64 `json:"processed_at_ms"`
|
||||||
|
Rpc_name string `json:"rpc_name"`
|
||||||
|
Validate_in_nano int64 `json:"validate_in_nano"`
|
||||||
|
}
|
||||||
|
type UsageMetrics struct {
|
||||||
|
Metrics []UsageMetric `json:"metrics"`
|
||||||
|
}
|
||||||
|
type UseInviteLinkRequest struct {
|
||||||
|
Invite_token string `json:"invite_token"`
|
||||||
|
}
|
||||||
|
type UserInfo struct {
|
||||||
|
Balance int64 `json:"balance"`
|
||||||
|
Bridge_url string `json:"bridge_url"`
|
||||||
|
Callback_url string `json:"callback_url"`
|
||||||
|
Max_withdrawable int64 `json:"max_withdrawable"`
|
||||||
|
Ndebit string `json:"ndebit"`
|
||||||
|
Network_max_fee_bps int64 `json:"network_max_fee_bps"`
|
||||||
|
Network_max_fee_fixed int64 `json:"network_max_fee_fixed"`
|
||||||
|
Noffer string `json:"noffer"`
|
||||||
|
Service_fee_bps int64 `json:"service_fee_bps"`
|
||||||
|
Userid string `json:"userId"`
|
||||||
|
User_identifier string `json:"user_identifier"`
|
||||||
|
}
|
||||||
|
type UserOperation struct {
|
||||||
|
Amount int64 `json:"amount"`
|
||||||
|
Confirmed bool `json:"confirmed"`
|
||||||
|
Identifier string `json:"identifier"`
|
||||||
|
Inbound bool `json:"inbound"`
|
||||||
|
Internal bool `json:"internal"`
|
||||||
|
Network_fee int64 `json:"network_fee"`
|
||||||
|
Operationid string `json:"operationId"`
|
||||||
|
Paidatunix int64 `json:"paidAtUnix"`
|
||||||
|
Service_fee int64 `json:"service_fee"`
|
||||||
|
Tx_hash string `json:"tx_hash"`
|
||||||
|
Type UserOperationType `json:"type"`
|
||||||
|
}
|
||||||
|
type UserOperations struct {
|
||||||
|
Fromindex int64 `json:"fromIndex"`
|
||||||
|
Operations []UserOperation `json:"operations"`
|
||||||
|
Toindex int64 `json:"toIndex"`
|
||||||
|
}
|
||||||
|
type UsersInfo struct {
|
||||||
|
Always_been_inactive int64 `json:"always_been_inactive"`
|
||||||
|
Balance_avg int64 `json:"balance_avg"`
|
||||||
|
Balance_median int64 `json:"balance_median"`
|
||||||
|
Negative_balance int64 `json:"negative_balance"`
|
||||||
|
No_balance int64 `json:"no_balance"`
|
||||||
|
Total int64 `json:"total"`
|
||||||
|
}
|
||||||
|
type DebitResponse_response_type string
|
||||||
|
|
||||||
|
const (
|
||||||
|
DENIED DebitResponse_response_type = "denied"
|
||||||
|
INVOICE DebitResponse_response_type = "invoice"
|
||||||
|
)
|
||||||
|
|
||||||
|
type DebitResponse_response struct {
|
||||||
|
Type DebitResponse_response_type `json:"type"`
|
||||||
|
Denied *Empty `json:"denied"`
|
||||||
|
Invoice *string `json:"invoice"`
|
||||||
|
}
|
||||||
|
type DebitRule_rule_type string
|
||||||
|
|
||||||
|
const (
|
||||||
|
EXPIRATION_RULE DebitRule_rule_type = "expiration_rule"
|
||||||
|
FREQUENCY_RULE DebitRule_rule_type = "frequency_rule"
|
||||||
|
)
|
||||||
|
|
||||||
|
type DebitRule_rule struct {
|
||||||
|
Type DebitRule_rule_type `json:"type"`
|
||||||
|
Expiration_rule *DebitExpirationRule `json:"expiration_rule"`
|
||||||
|
Frequency_rule *FrequencyRule `json:"frequency_rule"`
|
||||||
|
}
|
||||||
|
type LiveDebitRequest_debit_type string
|
||||||
|
|
||||||
|
const (
|
||||||
|
FREQUENCY LiveDebitRequest_debit_type = "frequency"
|
||||||
|
FULL_ACCESS LiveDebitRequest_debit_type = "full_access"
|
||||||
|
INVOICE LiveDebitRequest_debit_type = "invoice"
|
||||||
|
)
|
||||||
|
|
||||||
|
type LiveDebitRequest_debit struct {
|
||||||
|
Type LiveDebitRequest_debit_type `json:"type"`
|
||||||
|
Frequency *FrequencyRule `json:"frequency"`
|
||||||
|
Full_access *Empty `json:"full_access"`
|
||||||
|
Invoice *string `json:"invoice"`
|
||||||
|
}
|
||||||
|
|
@ -166,6 +166,50 @@ export default (methods: Types.ServerMethods, opts: ServerOptions) => {
|
||||||
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 }
|
||||||
})
|
})
|
||||||
|
if (!opts.allowNotImplementedMethods && !methods.AuthorizeDebit) throw new Error('method: AuthorizeDebit is not implemented')
|
||||||
|
app.post('/api/user/debit/authorize', async (req, res) => {
|
||||||
|
const info: Types.RequestInfo = { rpcName: 'AuthorizeDebit', batch: false, nostr: false, batchSize: 0}
|
||||||
|
const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n }
|
||||||
|
let authCtx: Types.AuthContext = {}
|
||||||
|
try {
|
||||||
|
if (!methods.AuthorizeDebit) throw new Error('method: AuthorizeDebit is not implemented')
|
||||||
|
const authContext = await opts.UserAuthGuard(req.headers['authorization'])
|
||||||
|
authCtx = authContext
|
||||||
|
stats.guard = process.hrtime.bigint()
|
||||||
|
const request = req.body
|
||||||
|
const error = Types.DebitAuthorizationRequestValidate(request)
|
||||||
|
stats.validate = process.hrtime.bigint()
|
||||||
|
if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authContext }, opts.metricsCallback)
|
||||||
|
const query = req.query
|
||||||
|
const params = req.params
|
||||||
|
const response = await methods.AuthorizeDebit({rpcName:'AuthorizeDebit', ctx:authContext , req: request})
|
||||||
|
stats.handle = process.hrtime.bigint()
|
||||||
|
res.json({status: 'OK', ...response})
|
||||||
|
opts.metricsCallback([{ ...info, ...stats, ...authContext }])
|
||||||
|
} catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e }
|
||||||
|
})
|
||||||
|
if (!opts.allowNotImplementedMethods && !methods.BanDebit) throw new Error('method: BanDebit is not implemented')
|
||||||
|
app.post('/api/user/debit/ban', async (req, res) => {
|
||||||
|
const info: Types.RequestInfo = { rpcName: 'BanDebit', batch: false, nostr: false, batchSize: 0}
|
||||||
|
const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n }
|
||||||
|
let authCtx: Types.AuthContext = {}
|
||||||
|
try {
|
||||||
|
if (!methods.BanDebit) throw new Error('method: BanDebit is not implemented')
|
||||||
|
const authContext = await opts.UserAuthGuard(req.headers['authorization'])
|
||||||
|
authCtx = authContext
|
||||||
|
stats.guard = process.hrtime.bigint()
|
||||||
|
const request = req.body
|
||||||
|
const error = Types.DebitOperationValidate(request)
|
||||||
|
stats.validate = process.hrtime.bigint()
|
||||||
|
if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authContext }, opts.metricsCallback)
|
||||||
|
const query = req.query
|
||||||
|
const params = req.params
|
||||||
|
await methods.BanDebit({rpcName:'BanDebit', ctx:authContext , req: request})
|
||||||
|
stats.handle = process.hrtime.bigint()
|
||||||
|
res.json({status: 'OK'})
|
||||||
|
opts.metricsCallback([{ ...info, ...stats, ...authContext }])
|
||||||
|
} catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e }
|
||||||
|
})
|
||||||
if (!opts.allowNotImplementedMethods && !methods.BanUser) throw new Error('method: BanUser is not implemented')
|
if (!opts.allowNotImplementedMethods && !methods.BanUser) throw new Error('method: BanUser is not implemented')
|
||||||
app.post('/api/admin/user/ban', async (req, res) => {
|
app.post('/api/admin/user/ban', async (req, res) => {
|
||||||
const info: Types.RequestInfo = { rpcName: 'BanUser', batch: false, nostr: false, batchSize: 0}
|
const info: Types.RequestInfo = { rpcName: 'BanUser', batch: false, nostr: false, batchSize: 0}
|
||||||
|
|
@ -221,6 +265,30 @@ export default (methods: Types.ServerMethods, opts: ServerOptions) => {
|
||||||
callsMetrics.push({ ...opInfo, ...opStats, ...ctx })
|
callsMetrics.push({ ...opInfo, ...opStats, ...ctx })
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
|
case 'AuthorizeDebit':
|
||||||
|
if (!methods.AuthorizeDebit) {
|
||||||
|
throw new Error('method AuthorizeDebit not found' )
|
||||||
|
} else {
|
||||||
|
const error = Types.DebitAuthorizationRequestValidate(operation.req)
|
||||||
|
opStats.validate = process.hrtime.bigint()
|
||||||
|
if (error !== null) throw error
|
||||||
|
const res = await methods.AuthorizeDebit({...operation, ctx}); responses.push({ status: 'OK', ...res })
|
||||||
|
opStats.handle = process.hrtime.bigint()
|
||||||
|
callsMetrics.push({ ...opInfo, ...opStats, ...ctx })
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case 'BanDebit':
|
||||||
|
if (!methods.BanDebit) {
|
||||||
|
throw new Error('method BanDebit not found' )
|
||||||
|
} else {
|
||||||
|
const error = Types.DebitOperationValidate(operation.req)
|
||||||
|
opStats.validate = process.hrtime.bigint()
|
||||||
|
if (error !== null) throw error
|
||||||
|
await methods.BanDebit({...operation, ctx}); responses.push({ status: 'OK' })
|
||||||
|
opStats.handle = process.hrtime.bigint()
|
||||||
|
callsMetrics.push({ ...opInfo, ...opStats, ...ctx })
|
||||||
|
}
|
||||||
|
break
|
||||||
case 'DecodeInvoice':
|
case 'DecodeInvoice':
|
||||||
if (!methods.DecodeInvoice) {
|
if (!methods.DecodeInvoice) {
|
||||||
throw new Error('method DecodeInvoice not found' )
|
throw new Error('method DecodeInvoice not found' )
|
||||||
|
|
@ -233,6 +301,18 @@ export default (methods: Types.ServerMethods, opts: ServerOptions) => {
|
||||||
callsMetrics.push({ ...opInfo, ...opStats, ...ctx })
|
callsMetrics.push({ ...opInfo, ...opStats, ...ctx })
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
|
case 'EditDebit':
|
||||||
|
if (!methods.EditDebit) {
|
||||||
|
throw new Error('method EditDebit not found' )
|
||||||
|
} else {
|
||||||
|
const error = Types.DebitAuthorizationRequestValidate(operation.req)
|
||||||
|
opStats.validate = process.hrtime.bigint()
|
||||||
|
if (error !== null) throw error
|
||||||
|
await methods.EditDebit({...operation, ctx}); responses.push({ status: 'OK' })
|
||||||
|
opStats.handle = process.hrtime.bigint()
|
||||||
|
callsMetrics.push({ ...opInfo, ...opStats, ...ctx })
|
||||||
|
}
|
||||||
|
break
|
||||||
case 'EnrollAdminToken':
|
case 'EnrollAdminToken':
|
||||||
if (!methods.EnrollAdminToken) {
|
if (!methods.EnrollAdminToken) {
|
||||||
throw new Error('method EnrollAdminToken not found' )
|
throw new Error('method EnrollAdminToken not found' )
|
||||||
|
|
@ -245,6 +325,16 @@ export default (methods: Types.ServerMethods, opts: ServerOptions) => {
|
||||||
callsMetrics.push({ ...opInfo, ...opStats, ...ctx })
|
callsMetrics.push({ ...opInfo, ...opStats, ...ctx })
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
|
case 'GetDebitAuthorizations':
|
||||||
|
if (!methods.GetDebitAuthorizations) {
|
||||||
|
throw new Error('method GetDebitAuthorizations not found' )
|
||||||
|
} else {
|
||||||
|
opStats.validate = opStats.guard
|
||||||
|
const res = await methods.GetDebitAuthorizations({...operation, ctx}); responses.push({ status: 'OK', ...res })
|
||||||
|
opStats.handle = process.hrtime.bigint()
|
||||||
|
callsMetrics.push({ ...opInfo, ...opStats, ...ctx })
|
||||||
|
}
|
||||||
|
break
|
||||||
case 'GetLNURLChannelLink':
|
case 'GetLNURLChannelLink':
|
||||||
if (!methods.GetLNURLChannelLink) {
|
if (!methods.GetLNURLChannelLink) {
|
||||||
throw new Error('method GetLNURLChannelLink not found' )
|
throw new Error('method GetLNURLChannelLink not found' )
|
||||||
|
|
@ -379,6 +469,42 @@ export default (methods: Types.ServerMethods, opts: ServerOptions) => {
|
||||||
callsMetrics.push({ ...opInfo, ...opStats, ...ctx })
|
callsMetrics.push({ ...opInfo, ...opStats, ...ctx })
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
|
case 'ResetDebit':
|
||||||
|
if (!methods.ResetDebit) {
|
||||||
|
throw new Error('method ResetDebit not found' )
|
||||||
|
} else {
|
||||||
|
const error = Types.DebitOperationValidate(operation.req)
|
||||||
|
opStats.validate = process.hrtime.bigint()
|
||||||
|
if (error !== null) throw error
|
||||||
|
await methods.ResetDebit({...operation, ctx}); responses.push({ status: 'OK' })
|
||||||
|
opStats.handle = process.hrtime.bigint()
|
||||||
|
callsMetrics.push({ ...opInfo, ...opStats, ...ctx })
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case 'RespondToDebit':
|
||||||
|
if (!methods.RespondToDebit) {
|
||||||
|
throw new Error('method RespondToDebit not found' )
|
||||||
|
} else {
|
||||||
|
const error = Types.DebitResponseValidate(operation.req)
|
||||||
|
opStats.validate = process.hrtime.bigint()
|
||||||
|
if (error !== null) throw error
|
||||||
|
await methods.RespondToDebit({...operation, ctx}); responses.push({ status: 'OK' })
|
||||||
|
opStats.handle = process.hrtime.bigint()
|
||||||
|
callsMetrics.push({ ...opInfo, ...opStats, ...ctx })
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case 'UpdateCallbackUrl':
|
||||||
|
if (!methods.UpdateCallbackUrl) {
|
||||||
|
throw new Error('method UpdateCallbackUrl not found' )
|
||||||
|
} else {
|
||||||
|
const error = Types.CallbackUrlValidate(operation.req)
|
||||||
|
opStats.validate = process.hrtime.bigint()
|
||||||
|
if (error !== null) throw error
|
||||||
|
const res = await methods.UpdateCallbackUrl({...operation, ctx}); responses.push({ status: 'OK', ...res })
|
||||||
|
opStats.handle = process.hrtime.bigint()
|
||||||
|
callsMetrics.push({ ...opInfo, ...opStats, ...ctx })
|
||||||
|
}
|
||||||
|
break
|
||||||
case 'UserHealth':
|
case 'UserHealth':
|
||||||
if (!methods.UserHealth) {
|
if (!methods.UserHealth) {
|
||||||
throw new Error('method UserHealth not found' )
|
throw new Error('method UserHealth not found' )
|
||||||
|
|
@ -443,6 +569,28 @@ export default (methods: Types.ServerMethods, opts: ServerOptions) => {
|
||||||
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 }
|
||||||
})
|
})
|
||||||
|
if (!opts.allowNotImplementedMethods && !methods.EditDebit) throw new Error('method: EditDebit is not implemented')
|
||||||
|
app.post('/api/user/debit/edit', async (req, res) => {
|
||||||
|
const info: Types.RequestInfo = { rpcName: 'EditDebit', batch: false, nostr: false, batchSize: 0}
|
||||||
|
const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n }
|
||||||
|
let authCtx: Types.AuthContext = {}
|
||||||
|
try {
|
||||||
|
if (!methods.EditDebit) throw new Error('method: EditDebit is not implemented')
|
||||||
|
const authContext = await opts.UserAuthGuard(req.headers['authorization'])
|
||||||
|
authCtx = authContext
|
||||||
|
stats.guard = process.hrtime.bigint()
|
||||||
|
const request = req.body
|
||||||
|
const error = Types.DebitAuthorizationRequestValidate(request)
|
||||||
|
stats.validate = process.hrtime.bigint()
|
||||||
|
if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authContext }, opts.metricsCallback)
|
||||||
|
const query = req.query
|
||||||
|
const params = req.params
|
||||||
|
await methods.EditDebit({rpcName:'EditDebit', ctx:authContext , req: request})
|
||||||
|
stats.handle = process.hrtime.bigint()
|
||||||
|
res.json({status: 'OK'})
|
||||||
|
opts.metricsCallback([{ ...info, ...stats, ...authContext }])
|
||||||
|
} catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e }
|
||||||
|
})
|
||||||
if (!opts.allowNotImplementedMethods && !methods.EncryptionExchange) throw new Error('method: EncryptionExchange is not implemented')
|
if (!opts.allowNotImplementedMethods && !methods.EncryptionExchange) throw new Error('method: EncryptionExchange is not implemented')
|
||||||
app.post('/api/encryption/exchange', async (req, res) => {
|
app.post('/api/encryption/exchange', async (req, res) => {
|
||||||
const info: Types.RequestInfo = { rpcName: 'EncryptionExchange', batch: false, nostr: false, batchSize: 0}
|
const info: Types.RequestInfo = { rpcName: 'EncryptionExchange', batch: false, nostr: false, batchSize: 0}
|
||||||
|
|
@ -572,6 +720,25 @@ export default (methods: Types.ServerMethods, opts: ServerOptions) => {
|
||||||
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 }
|
||||||
})
|
})
|
||||||
|
if (!opts.allowNotImplementedMethods && !methods.GetDebitAuthorizations) throw new Error('method: GetDebitAuthorizations is not implemented')
|
||||||
|
app.get('/api/user/debit/get', async (req, res) => {
|
||||||
|
const info: Types.RequestInfo = { rpcName: 'GetDebitAuthorizations', batch: false, nostr: false, batchSize: 0}
|
||||||
|
const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n }
|
||||||
|
let authCtx: Types.AuthContext = {}
|
||||||
|
try {
|
||||||
|
if (!methods.GetDebitAuthorizations) throw new Error('method: GetDebitAuthorizations is not implemented')
|
||||||
|
const authContext = await opts.UserAuthGuard(req.headers['authorization'])
|
||||||
|
authCtx = authContext
|
||||||
|
stats.guard = process.hrtime.bigint()
|
||||||
|
stats.validate = stats.guard
|
||||||
|
const query = req.query
|
||||||
|
const params = req.params
|
||||||
|
const response = await methods.GetDebitAuthorizations({rpcName:'GetDebitAuthorizations', ctx:authContext })
|
||||||
|
stats.handle = process.hrtime.bigint()
|
||||||
|
res.json({status: 'OK', ...response})
|
||||||
|
opts.metricsCallback([{ ...info, ...stats, ...authContext }])
|
||||||
|
} catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e }
|
||||||
|
})
|
||||||
if (!opts.allowNotImplementedMethods && !methods.GetInviteLinkState) throw new Error('method: GetInviteLinkState is not implemented')
|
if (!opts.allowNotImplementedMethods && !methods.GetInviteLinkState) throw new Error('method: GetInviteLinkState is not implemented')
|
||||||
app.post('/api/admin/app/invite/get', async (req, res) => {
|
app.post('/api/admin/app/invite/get', async (req, res) => {
|
||||||
const info: Types.RequestInfo = { rpcName: 'GetInviteLinkState', batch: false, nostr: false, batchSize: 0}
|
const info: Types.RequestInfo = { rpcName: 'GetInviteLinkState', batch: false, nostr: false, batchSize: 0}
|
||||||
|
|
@ -1124,6 +1291,28 @@ export default (methods: Types.ServerMethods, opts: ServerOptions) => {
|
||||||
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 }
|
||||||
})
|
})
|
||||||
|
if (!opts.allowNotImplementedMethods && !methods.ResetDebit) throw new Error('method: ResetDebit is not implemented')
|
||||||
|
app.post('/api/user/debit/reset', async (req, res) => {
|
||||||
|
const info: Types.RequestInfo = { rpcName: 'ResetDebit', batch: false, nostr: false, batchSize: 0}
|
||||||
|
const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n }
|
||||||
|
let authCtx: Types.AuthContext = {}
|
||||||
|
try {
|
||||||
|
if (!methods.ResetDebit) throw new Error('method: ResetDebit is not implemented')
|
||||||
|
const authContext = await opts.UserAuthGuard(req.headers['authorization'])
|
||||||
|
authCtx = authContext
|
||||||
|
stats.guard = process.hrtime.bigint()
|
||||||
|
const request = req.body
|
||||||
|
const error = Types.DebitOperationValidate(request)
|
||||||
|
stats.validate = process.hrtime.bigint()
|
||||||
|
if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authContext }, opts.metricsCallback)
|
||||||
|
const query = req.query
|
||||||
|
const params = req.params
|
||||||
|
await methods.ResetDebit({rpcName:'ResetDebit', ctx:authContext , req: request})
|
||||||
|
stats.handle = process.hrtime.bigint()
|
||||||
|
res.json({status: 'OK'})
|
||||||
|
opts.metricsCallback([{ ...info, ...stats, ...authContext }])
|
||||||
|
} catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e }
|
||||||
|
})
|
||||||
if (!opts.allowNotImplementedMethods && !methods.ResetNPubLinkingToken) throw new Error('method: ResetNPubLinkingToken is not implemented')
|
if (!opts.allowNotImplementedMethods && !methods.ResetNPubLinkingToken) throw new Error('method: ResetNPubLinkingToken is not implemented')
|
||||||
app.post('/api/app/user/npub/token/reset', async (req, res) => {
|
app.post('/api/app/user/npub/token/reset', async (req, res) => {
|
||||||
const info: Types.RequestInfo = { rpcName: 'ResetNPubLinkingToken', batch: false, nostr: false, batchSize: 0}
|
const info: Types.RequestInfo = { rpcName: 'ResetNPubLinkingToken', batch: false, nostr: false, batchSize: 0}
|
||||||
|
|
@ -1146,6 +1335,28 @@ export default (methods: Types.ServerMethods, opts: ServerOptions) => {
|
||||||
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 }
|
||||||
})
|
})
|
||||||
|
if (!opts.allowNotImplementedMethods && !methods.RespondToDebit) throw new Error('method: RespondToDebit is not implemented')
|
||||||
|
app.post('/api/user/debit/finish', async (req, res) => {
|
||||||
|
const info: Types.RequestInfo = { rpcName: 'RespondToDebit', batch: false, nostr: false, batchSize: 0}
|
||||||
|
const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n }
|
||||||
|
let authCtx: Types.AuthContext = {}
|
||||||
|
try {
|
||||||
|
if (!methods.RespondToDebit) throw new Error('method: RespondToDebit is not implemented')
|
||||||
|
const authContext = await opts.UserAuthGuard(req.headers['authorization'])
|
||||||
|
authCtx = authContext
|
||||||
|
stats.guard = process.hrtime.bigint()
|
||||||
|
const request = req.body
|
||||||
|
const error = Types.DebitResponseValidate(request)
|
||||||
|
stats.validate = process.hrtime.bigint()
|
||||||
|
if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authContext }, opts.metricsCallback)
|
||||||
|
const query = req.query
|
||||||
|
const params = req.params
|
||||||
|
await methods.RespondToDebit({rpcName:'RespondToDebit', ctx:authContext , req: request})
|
||||||
|
stats.handle = process.hrtime.bigint()
|
||||||
|
res.json({status: 'OK'})
|
||||||
|
opts.metricsCallback([{ ...info, ...stats, ...authContext }])
|
||||||
|
} catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e }
|
||||||
|
})
|
||||||
if (!opts.allowNotImplementedMethods && !methods.SendAppUserToAppPayment) throw new Error('method: SendAppUserToAppPayment is not implemented')
|
if (!opts.allowNotImplementedMethods && !methods.SendAppUserToAppPayment) throw new Error('method: SendAppUserToAppPayment is not implemented')
|
||||||
app.post('/api/app/internal/pay', async (req, res) => {
|
app.post('/api/app/internal/pay', async (req, res) => {
|
||||||
const info: Types.RequestInfo = { rpcName: 'SendAppUserToAppPayment', batch: false, nostr: false, batchSize: 0}
|
const info: Types.RequestInfo = { rpcName: 'SendAppUserToAppPayment', batch: false, nostr: false, batchSize: 0}
|
||||||
|
|
@ -1256,6 +1467,28 @@ export default (methods: Types.ServerMethods, opts: ServerOptions) => {
|
||||||
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 }
|
||||||
})
|
})
|
||||||
|
if (!opts.allowNotImplementedMethods && !methods.UpdateCallbackUrl) throw new Error('method: UpdateCallbackUrl is not implemented')
|
||||||
|
app.post('/api/user/cb/update', async (req, res) => {
|
||||||
|
const info: Types.RequestInfo = { rpcName: 'UpdateCallbackUrl', batch: false, nostr: false, batchSize: 0}
|
||||||
|
const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n }
|
||||||
|
let authCtx: Types.AuthContext = {}
|
||||||
|
try {
|
||||||
|
if (!methods.UpdateCallbackUrl) throw new Error('method: UpdateCallbackUrl is not implemented')
|
||||||
|
const authContext = await opts.UserAuthGuard(req.headers['authorization'])
|
||||||
|
authCtx = authContext
|
||||||
|
stats.guard = process.hrtime.bigint()
|
||||||
|
const request = req.body
|
||||||
|
const error = Types.CallbackUrlValidate(request)
|
||||||
|
stats.validate = process.hrtime.bigint()
|
||||||
|
if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authContext }, opts.metricsCallback)
|
||||||
|
const query = req.query
|
||||||
|
const params = req.params
|
||||||
|
const response = await methods.UpdateCallbackUrl({rpcName:'UpdateCallbackUrl', ctx:authContext , req: request})
|
||||||
|
stats.handle = process.hrtime.bigint()
|
||||||
|
res.json({status: 'OK', ...response})
|
||||||
|
opts.metricsCallback([{ ...info, ...stats, ...authContext }])
|
||||||
|
} catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e }
|
||||||
|
})
|
||||||
if (!opts.allowNotImplementedMethods && !methods.UseInviteLink) throw new Error('method: UseInviteLink is not implemented')
|
if (!opts.allowNotImplementedMethods && !methods.UseInviteLink) throw new Error('method: UseInviteLink is not implemented')
|
||||||
app.post('/api/guest/invite', async (req, res) => {
|
app.post('/api/guest/invite', async (req, res) => {
|
||||||
const info: Types.RequestInfo = { rpcName: 'UseInviteLink', batch: false, nostr: false, batchSize: 0}
|
const info: Types.RequestInfo = { rpcName: 'UseInviteLink', batch: false, nostr: false, batchSize: 0}
|
||||||
|
|
|
||||||
|
|
@ -101,6 +101,31 @@ export default (params: ClientParams) => ({
|
||||||
}
|
}
|
||||||
return { status: 'ERROR', reason: 'invalid response' }
|
return { status: 'ERROR', reason: 'invalid response' }
|
||||||
},
|
},
|
||||||
|
AuthorizeDebit: async (request: Types.DebitAuthorizationRequest): Promise<ResultError | ({ status: 'OK' }& Types.DebitAuthorization)> => {
|
||||||
|
const auth = await params.retrieveUserAuth()
|
||||||
|
if (auth === null) throw new Error('retrieveUserAuth() returned null')
|
||||||
|
let finalRoute = '/api/user/debit/authorize'
|
||||||
|
const { data } = await axios.post(params.baseUrl + finalRoute, request, { headers: { 'authorization': auth } })
|
||||||
|
if (data.status === 'ERROR' && typeof data.reason === 'string') return data
|
||||||
|
if (data.status === 'OK') {
|
||||||
|
const result = data
|
||||||
|
if(!params.checkResult) return { status: 'OK', ...result }
|
||||||
|
const error = Types.DebitAuthorizationValidate(result)
|
||||||
|
if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message }
|
||||||
|
}
|
||||||
|
return { status: 'ERROR', reason: 'invalid response' }
|
||||||
|
},
|
||||||
|
BanDebit: async (request: Types.DebitOperation): Promise<ResultError | ({ status: 'OK' })> => {
|
||||||
|
const auth = await params.retrieveUserAuth()
|
||||||
|
if (auth === null) throw new Error('retrieveUserAuth() returned null')
|
||||||
|
let finalRoute = '/api/user/debit/ban'
|
||||||
|
const { data } = await axios.post(params.baseUrl + finalRoute, request, { headers: { 'authorization': auth } })
|
||||||
|
if (data.status === 'ERROR' && typeof data.reason === 'string') return data
|
||||||
|
if (data.status === 'OK') {
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
return { status: 'ERROR', reason: 'invalid response' }
|
||||||
|
},
|
||||||
BanUser: async (request: Types.BanUserRequest): Promise<ResultError | ({ status: 'OK' }& Types.BanUserResponse)> => {
|
BanUser: async (request: Types.BanUserRequest): Promise<ResultError | ({ status: 'OK' }& Types.BanUserResponse)> => {
|
||||||
const auth = await params.retrieveAdminAuth()
|
const auth = await params.retrieveAdminAuth()
|
||||||
if (auth === null) throw new Error('retrieveAdminAuth() returned null')
|
if (auth === null) throw new Error('retrieveAdminAuth() returned null')
|
||||||
|
|
@ -154,6 +179,17 @@ export default (params: ClientParams) => ({
|
||||||
}
|
}
|
||||||
return { status: 'ERROR', reason: 'invalid response' }
|
return { status: 'ERROR', reason: 'invalid response' }
|
||||||
},
|
},
|
||||||
|
EditDebit: async (request: Types.DebitAuthorizationRequest): Promise<ResultError | ({ status: 'OK' })> => {
|
||||||
|
const auth = await params.retrieveUserAuth()
|
||||||
|
if (auth === null) throw new Error('retrieveUserAuth() returned null')
|
||||||
|
let finalRoute = '/api/user/debit/edit'
|
||||||
|
const { data } = await axios.post(params.baseUrl + finalRoute, request, { headers: { 'authorization': auth } })
|
||||||
|
if (data.status === 'ERROR' && typeof data.reason === 'string') return data
|
||||||
|
if (data.status === 'OK') {
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
return { status: 'ERROR', reason: 'invalid response' }
|
||||||
|
},
|
||||||
EncryptionExchange: async (request: Types.EncryptionExchangeRequest): Promise<ResultError | ({ status: 'OK' })> => {
|
EncryptionExchange: async (request: Types.EncryptionExchangeRequest): Promise<ResultError | ({ status: 'OK' })> => {
|
||||||
const auth = await params.retrieveGuestAuth()
|
const auth = await params.retrieveGuestAuth()
|
||||||
if (auth === null) throw new Error('retrieveGuestAuth() returned null')
|
if (auth === null) throw new Error('retrieveGuestAuth() returned null')
|
||||||
|
|
@ -232,6 +268,20 @@ export default (params: ClientParams) => ({
|
||||||
}
|
}
|
||||||
return { status: 'ERROR', reason: 'invalid response' }
|
return { status: 'ERROR', reason: 'invalid response' }
|
||||||
},
|
},
|
||||||
|
GetDebitAuthorizations: async (): Promise<ResultError | ({ status: 'OK' }& Types.DebitAuthorizations)> => {
|
||||||
|
const auth = await params.retrieveUserAuth()
|
||||||
|
if (auth === null) throw new Error('retrieveUserAuth() returned null')
|
||||||
|
let finalRoute = '/api/user/debit/get'
|
||||||
|
const { data } = await axios.get(params.baseUrl + finalRoute, { headers: { 'authorization': auth } })
|
||||||
|
if (data.status === 'ERROR' && typeof data.reason === 'string') return data
|
||||||
|
if (data.status === 'OK') {
|
||||||
|
const result = data
|
||||||
|
if(!params.checkResult) return { status: 'OK', ...result }
|
||||||
|
const error = Types.DebitAuthorizationsValidate(result)
|
||||||
|
if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message }
|
||||||
|
}
|
||||||
|
return { status: 'ERROR', reason: 'invalid response' }
|
||||||
|
},
|
||||||
GetHttpCreds: async (cb: (v:ResultError | ({ status: 'OK' }& Types.HttpCreds)) => void): Promise<void> => { throw new Error('http streams are not supported')},
|
GetHttpCreds: async (cb: (v:ResultError | ({ status: 'OK' }& Types.HttpCreds)) => void): Promise<void> => { throw new Error('http streams are not supported')},
|
||||||
GetInviteLinkState: async (request: Types.GetInviteTokenStateRequest): Promise<ResultError | ({ status: 'OK' }& Types.GetInviteTokenStateResponse)> => {
|
GetInviteLinkState: async (request: Types.GetInviteTokenStateRequest): Promise<ResultError | ({ status: 'OK' }& Types.GetInviteTokenStateResponse)> => {
|
||||||
const auth = await params.retrieveAdminAuth()
|
const auth = await params.retrieveAdminAuth()
|
||||||
|
|
@ -261,6 +311,7 @@ export default (params: ClientParams) => ({
|
||||||
}
|
}
|
||||||
return { status: 'ERROR', reason: 'invalid response' }
|
return { status: 'ERROR', reason: 'invalid response' }
|
||||||
},
|
},
|
||||||
|
GetLiveDebitRequests: async (cb: (v:ResultError | ({ status: 'OK' }& Types.LiveDebitRequest)) => void): Promise<void> => { throw new Error('http streams are not supported')},
|
||||||
GetLiveUserOperations: async (cb: (v:ResultError | ({ status: 'OK' }& Types.LiveUserOperation)) => void): Promise<void> => { throw new Error('http streams are not supported')},
|
GetLiveUserOperations: async (cb: (v:ResultError | ({ status: 'OK' }& Types.LiveUserOperation)) => void): Promise<void> => { throw new Error('http streams are not supported')},
|
||||||
GetLndMetrics: async (request: Types.LndMetricsRequest): Promise<ResultError | ({ status: 'OK' }& Types.LndMetrics)> => {
|
GetLndMetrics: async (request: Types.LndMetricsRequest): Promise<ResultError | ({ status: 'OK' }& Types.LndMetrics)> => {
|
||||||
const auth = await params.retrieveMetricsAuth()
|
const auth = await params.retrieveMetricsAuth()
|
||||||
|
|
@ -615,6 +666,17 @@ export default (params: ClientParams) => ({
|
||||||
}
|
}
|
||||||
return { status: 'ERROR', reason: 'invalid response' }
|
return { status: 'ERROR', reason: 'invalid response' }
|
||||||
},
|
},
|
||||||
|
ResetDebit: async (request: Types.DebitOperation): Promise<ResultError | ({ status: 'OK' })> => {
|
||||||
|
const auth = await params.retrieveUserAuth()
|
||||||
|
if (auth === null) throw new Error('retrieveUserAuth() returned null')
|
||||||
|
let finalRoute = '/api/user/debit/reset'
|
||||||
|
const { data } = await axios.post(params.baseUrl + finalRoute, request, { headers: { 'authorization': auth } })
|
||||||
|
if (data.status === 'ERROR' && typeof data.reason === 'string') return data
|
||||||
|
if (data.status === 'OK') {
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
return { status: 'ERROR', reason: 'invalid response' }
|
||||||
|
},
|
||||||
ResetNPubLinkingToken: async (request: Types.RequestNPubLinkingTokenRequest): Promise<ResultError | ({ status: 'OK' }& Types.RequestNPubLinkingTokenResponse)> => {
|
ResetNPubLinkingToken: async (request: Types.RequestNPubLinkingTokenRequest): Promise<ResultError | ({ status: 'OK' }& Types.RequestNPubLinkingTokenResponse)> => {
|
||||||
const auth = await params.retrieveAppAuth()
|
const auth = await params.retrieveAppAuth()
|
||||||
if (auth === null) throw new Error('retrieveAppAuth() returned null')
|
if (auth === null) throw new Error('retrieveAppAuth() returned null')
|
||||||
|
|
@ -629,6 +691,17 @@ export default (params: ClientParams) => ({
|
||||||
}
|
}
|
||||||
return { status: 'ERROR', reason: 'invalid response' }
|
return { status: 'ERROR', reason: 'invalid response' }
|
||||||
},
|
},
|
||||||
|
RespondToDebit: async (request: Types.DebitResponse): Promise<ResultError | ({ status: 'OK' })> => {
|
||||||
|
const auth = await params.retrieveUserAuth()
|
||||||
|
if (auth === null) throw new Error('retrieveUserAuth() returned null')
|
||||||
|
let finalRoute = '/api/user/debit/finish'
|
||||||
|
const { data } = await axios.post(params.baseUrl + finalRoute, request, { headers: { 'authorization': auth } })
|
||||||
|
if (data.status === 'ERROR' && typeof data.reason === 'string') return data
|
||||||
|
if (data.status === 'OK') {
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
return { status: 'ERROR', reason: 'invalid response' }
|
||||||
|
},
|
||||||
SendAppUserToAppPayment: async (request: Types.SendAppUserToAppPaymentRequest): Promise<ResultError | ({ status: 'OK' })> => {
|
SendAppUserToAppPayment: async (request: Types.SendAppUserToAppPaymentRequest): Promise<ResultError | ({ status: 'OK' })> => {
|
||||||
const auth = await params.retrieveAppAuth()
|
const auth = await params.retrieveAppAuth()
|
||||||
if (auth === null) throw new Error('retrieveAppAuth() returned null')
|
if (auth === null) throw new Error('retrieveAppAuth() returned null')
|
||||||
|
|
@ -684,6 +757,20 @@ export default (params: ClientParams) => ({
|
||||||
}
|
}
|
||||||
return { status: 'ERROR', reason: 'invalid response' }
|
return { status: 'ERROR', reason: 'invalid response' }
|
||||||
},
|
},
|
||||||
|
UpdateCallbackUrl: async (request: Types.CallbackUrl): Promise<ResultError | ({ status: 'OK' }& Types.CallbackUrl)> => {
|
||||||
|
const auth = await params.retrieveUserAuth()
|
||||||
|
if (auth === null) throw new Error('retrieveUserAuth() returned null')
|
||||||
|
let finalRoute = '/api/user/cb/update'
|
||||||
|
const { data } = await axios.post(params.baseUrl + finalRoute, request, { headers: { 'authorization': auth } })
|
||||||
|
if (data.status === 'ERROR' && typeof data.reason === 'string') return data
|
||||||
|
if (data.status === 'OK') {
|
||||||
|
const result = data
|
||||||
|
if(!params.checkResult) return { status: 'OK', ...result }
|
||||||
|
const error = Types.CallbackUrlValidate(result)
|
||||||
|
if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message }
|
||||||
|
}
|
||||||
|
return { status: 'ERROR', reason: 'invalid response' }
|
||||||
|
},
|
||||||
UseInviteLink: async (request: Types.UseInviteLinkRequest): Promise<ResultError | ({ status: 'OK' })> => {
|
UseInviteLink: async (request: Types.UseInviteLinkRequest): Promise<ResultError | ({ status: 'OK' })> => {
|
||||||
const auth = await params.retrieveGuestWithPubAuth()
|
const auth = await params.retrieveGuestWithPubAuth()
|
||||||
if (auth === null) throw new Error('retrieveGuestWithPubAuth() returned null')
|
if (auth === null) throw new Error('retrieveGuestWithPubAuth() returned null')
|
||||||
|
|
|
||||||
|
|
@ -57,6 +57,33 @@ export default (params: NostrClientParams, send: (to:string, message: NostrRequ
|
||||||
}
|
}
|
||||||
return { status: 'ERROR', reason: 'invalid response' }
|
return { status: 'ERROR', reason: 'invalid response' }
|
||||||
},
|
},
|
||||||
|
AuthorizeDebit: async (request: Types.DebitAuthorizationRequest): Promise<ResultError | ({ status: 'OK' }& Types.DebitAuthorization)> => {
|
||||||
|
const auth = await params.retrieveNostrUserAuth()
|
||||||
|
if (auth === null) throw new Error('retrieveNostrUserAuth() returned null')
|
||||||
|
const nostrRequest: NostrRequest = {}
|
||||||
|
nostrRequest.body = request
|
||||||
|
const data = await send(params.pubDestination, {rpcName:'AuthorizeDebit',authIdentifier:auth, ...nostrRequest })
|
||||||
|
if (data.status === 'ERROR' && typeof data.reason === 'string') return data
|
||||||
|
if (data.status === 'OK') {
|
||||||
|
const result = data
|
||||||
|
if(!params.checkResult) return { status: 'OK', ...result }
|
||||||
|
const error = Types.DebitAuthorizationValidate(result)
|
||||||
|
if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message }
|
||||||
|
}
|
||||||
|
return { status: 'ERROR', reason: 'invalid response' }
|
||||||
|
},
|
||||||
|
BanDebit: async (request: Types.DebitOperation): Promise<ResultError | ({ status: 'OK' })> => {
|
||||||
|
const auth = await params.retrieveNostrUserAuth()
|
||||||
|
if (auth === null) throw new Error('retrieveNostrUserAuth() returned null')
|
||||||
|
const nostrRequest: NostrRequest = {}
|
||||||
|
nostrRequest.body = request
|
||||||
|
const data = await send(params.pubDestination, {rpcName:'BanDebit',authIdentifier:auth, ...nostrRequest })
|
||||||
|
if (data.status === 'ERROR' && typeof data.reason === 'string') return data
|
||||||
|
if (data.status === 'OK') {
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
return { status: 'ERROR', reason: 'invalid response' }
|
||||||
|
},
|
||||||
BanUser: async (request: Types.BanUserRequest): Promise<ResultError | ({ status: 'OK' }& Types.BanUserResponse)> => {
|
BanUser: async (request: Types.BanUserRequest): Promise<ResultError | ({ status: 'OK' }& Types.BanUserResponse)> => {
|
||||||
const auth = await params.retrieveNostrAdminAuth()
|
const auth = await params.retrieveNostrAdminAuth()
|
||||||
if (auth === null) throw new Error('retrieveNostrAdminAuth() returned null')
|
if (auth === null) throw new Error('retrieveNostrAdminAuth() returned null')
|
||||||
|
|
@ -113,6 +140,18 @@ export default (params: NostrClientParams, send: (to:string, message: NostrRequ
|
||||||
}
|
}
|
||||||
return { status: 'ERROR', reason: 'invalid response' }
|
return { status: 'ERROR', reason: 'invalid response' }
|
||||||
},
|
},
|
||||||
|
EditDebit: async (request: Types.DebitAuthorizationRequest): Promise<ResultError | ({ status: 'OK' })> => {
|
||||||
|
const auth = await params.retrieveNostrUserAuth()
|
||||||
|
if (auth === null) throw new Error('retrieveNostrUserAuth() returned null')
|
||||||
|
const nostrRequest: NostrRequest = {}
|
||||||
|
nostrRequest.body = request
|
||||||
|
const data = await send(params.pubDestination, {rpcName:'EditDebit',authIdentifier:auth, ...nostrRequest })
|
||||||
|
if (data.status === 'ERROR' && typeof data.reason === 'string') return data
|
||||||
|
if (data.status === 'OK') {
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
return { status: 'ERROR', reason: 'invalid response' }
|
||||||
|
},
|
||||||
EnrollAdminToken: async (request: Types.EnrollAdminTokenRequest): Promise<ResultError | ({ status: 'OK' })> => {
|
EnrollAdminToken: async (request: Types.EnrollAdminTokenRequest): 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')
|
||||||
|
|
@ -140,6 +179,20 @@ export default (params: NostrClientParams, send: (to:string, message: NostrRequ
|
||||||
}
|
}
|
||||||
return { status: 'ERROR', reason: 'invalid response' }
|
return { status: 'ERROR', reason: 'invalid response' }
|
||||||
},
|
},
|
||||||
|
GetDebitAuthorizations: async (): Promise<ResultError | ({ status: 'OK' }& Types.DebitAuthorizations)> => {
|
||||||
|
const auth = await params.retrieveNostrUserAuth()
|
||||||
|
if (auth === null) throw new Error('retrieveNostrUserAuth() returned null')
|
||||||
|
const nostrRequest: NostrRequest = {}
|
||||||
|
const data = await send(params.pubDestination, {rpcName:'GetDebitAuthorizations',authIdentifier:auth, ...nostrRequest })
|
||||||
|
if (data.status === 'ERROR' && typeof data.reason === 'string') return data
|
||||||
|
if (data.status === 'OK') {
|
||||||
|
const result = data
|
||||||
|
if(!params.checkResult) return { status: 'OK', ...result }
|
||||||
|
const error = Types.DebitAuthorizationsValidate(result)
|
||||||
|
if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message }
|
||||||
|
}
|
||||||
|
return { 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')
|
||||||
|
|
@ -184,6 +237,21 @@ export default (params: NostrClientParams, send: (to:string, message: NostrRequ
|
||||||
}
|
}
|
||||||
return { status: 'ERROR', reason: 'invalid response' }
|
return { status: 'ERROR', reason: 'invalid response' }
|
||||||
},
|
},
|
||||||
|
GetLiveDebitRequests: async (cb: (res:ResultError | ({ status: 'OK' }& Types.LiveDebitRequest)) => void): Promise<void> => {
|
||||||
|
const auth = await params.retrieveNostrUserAuth()
|
||||||
|
if (auth === null) throw new Error('retrieveNostrUserAuth() returned null')
|
||||||
|
const nostrRequest: NostrRequest = {}
|
||||||
|
subscribe(params.pubDestination, {rpcName:'GetLiveDebitRequests',authIdentifier:auth, ...nostrRequest }, (data) => {
|
||||||
|
if (data.status === 'ERROR' && typeof data.reason === 'string') return cb(data)
|
||||||
|
if (data.status === 'OK') {
|
||||||
|
const result = data
|
||||||
|
if(!params.checkResult) return cb({ status: 'OK', ...result })
|
||||||
|
const error = Types.LiveDebitRequestValidate(result)
|
||||||
|
if (error === null) { return cb({ status: 'OK', ...result }) } else return cb({ status: 'ERROR', reason: error.message })
|
||||||
|
}
|
||||||
|
return cb({ 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')
|
||||||
|
|
@ -460,6 +528,45 @@ export default (params: NostrClientParams, send: (to:string, message: NostrRequ
|
||||||
}
|
}
|
||||||
return { status: 'ERROR', reason: 'invalid response' }
|
return { status: 'ERROR', reason: 'invalid response' }
|
||||||
},
|
},
|
||||||
|
ResetDebit: async (request: Types.DebitOperation): Promise<ResultError | ({ status: 'OK' })> => {
|
||||||
|
const auth = await params.retrieveNostrUserAuth()
|
||||||
|
if (auth === null) throw new Error('retrieveNostrUserAuth() returned null')
|
||||||
|
const nostrRequest: NostrRequest = {}
|
||||||
|
nostrRequest.body = request
|
||||||
|
const data = await send(params.pubDestination, {rpcName:'ResetDebit',authIdentifier:auth, ...nostrRequest })
|
||||||
|
if (data.status === 'ERROR' && typeof data.reason === 'string') return data
|
||||||
|
if (data.status === 'OK') {
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
return { status: 'ERROR', reason: 'invalid response' }
|
||||||
|
},
|
||||||
|
RespondToDebit: async (request: Types.DebitResponse): Promise<ResultError | ({ status: 'OK' })> => {
|
||||||
|
const auth = await params.retrieveNostrUserAuth()
|
||||||
|
if (auth === null) throw new Error('retrieveNostrUserAuth() returned null')
|
||||||
|
const nostrRequest: NostrRequest = {}
|
||||||
|
nostrRequest.body = request
|
||||||
|
const data = await send(params.pubDestination, {rpcName:'RespondToDebit',authIdentifier:auth, ...nostrRequest })
|
||||||
|
if (data.status === 'ERROR' && typeof data.reason === 'string') return data
|
||||||
|
if (data.status === 'OK') {
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
return { status: 'ERROR', reason: 'invalid response' }
|
||||||
|
},
|
||||||
|
UpdateCallbackUrl: async (request: Types.CallbackUrl): Promise<ResultError | ({ status: 'OK' }& Types.CallbackUrl)> => {
|
||||||
|
const auth = await params.retrieveNostrUserAuth()
|
||||||
|
if (auth === null) throw new Error('retrieveNostrUserAuth() returned null')
|
||||||
|
const nostrRequest: NostrRequest = {}
|
||||||
|
nostrRequest.body = request
|
||||||
|
const data = await send(params.pubDestination, {rpcName:'UpdateCallbackUrl',authIdentifier:auth, ...nostrRequest })
|
||||||
|
if (data.status === 'ERROR' && typeof data.reason === 'string') return data
|
||||||
|
if (data.status === 'OK') {
|
||||||
|
const result = data
|
||||||
|
if(!params.checkResult) return { status: 'OK', ...result }
|
||||||
|
const error = Types.CallbackUrlValidate(result)
|
||||||
|
if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message }
|
||||||
|
}
|
||||||
|
return { status: 'ERROR', reason: 'invalid response' }
|
||||||
|
},
|
||||||
UseInviteLink: async (request: Types.UseInviteLinkRequest): Promise<ResultError | ({ status: 'OK' })> => {
|
UseInviteLink: async (request: Types.UseInviteLinkRequest): Promise<ResultError | ({ status: 'OK' })> => {
|
||||||
const auth = await params.retrieveNostrGuestWithPubAuth()
|
const auth = await params.retrieveNostrGuestWithPubAuth()
|
||||||
if (auth === null) throw new Error('retrieveNostrGuestWithPubAuth() returned null')
|
if (auth === null) throw new Error('retrieveNostrGuestWithPubAuth() returned null')
|
||||||
|
|
|
||||||
|
|
@ -80,6 +80,38 @@ export default (methods: Types.ServerMethods, opts: NostrOptions) => {
|
||||||
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 'AuthorizeDebit':
|
||||||
|
try {
|
||||||
|
if (!methods.AuthorizeDebit) throw new Error('method: AuthorizeDebit is not implemented')
|
||||||
|
const authContext = await opts.NostrUserAuthGuard(req.appId, req.authIdentifier)
|
||||||
|
stats.guard = process.hrtime.bigint()
|
||||||
|
authCtx = authContext
|
||||||
|
const request = req.body
|
||||||
|
const error = Types.DebitAuthorizationRequestValidate(request)
|
||||||
|
stats.validate = process.hrtime.bigint()
|
||||||
|
if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback)
|
||||||
|
const response = await methods.AuthorizeDebit({rpcName:'AuthorizeDebit', ctx:authContext , req: request})
|
||||||
|
stats.handle = process.hrtime.bigint()
|
||||||
|
res({status: 'OK', ...response})
|
||||||
|
opts.metricsCallback([{ ...info, ...stats, ...authContext }])
|
||||||
|
}catch(ex){ const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e }
|
||||||
|
break
|
||||||
|
case 'BanDebit':
|
||||||
|
try {
|
||||||
|
if (!methods.BanDebit) throw new Error('method: BanDebit is not implemented')
|
||||||
|
const authContext = await opts.NostrUserAuthGuard(req.appId, req.authIdentifier)
|
||||||
|
stats.guard = process.hrtime.bigint()
|
||||||
|
authCtx = authContext
|
||||||
|
const request = req.body
|
||||||
|
const error = Types.DebitOperationValidate(request)
|
||||||
|
stats.validate = process.hrtime.bigint()
|
||||||
|
if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback)
|
||||||
|
await methods.BanDebit({rpcName:'BanDebit', ctx:authContext , req: request})
|
||||||
|
stats.handle = process.hrtime.bigint()
|
||||||
|
res({status: 'OK'})
|
||||||
|
opts.metricsCallback([{ ...info, ...stats, ...authContext }])
|
||||||
|
}catch(ex){ const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e }
|
||||||
|
break
|
||||||
case 'BanUser':
|
case 'BanUser':
|
||||||
try {
|
try {
|
||||||
if (!methods.BanUser) throw new Error('method: BanUser is not implemented')
|
if (!methods.BanUser) throw new Error('method: BanUser is not implemented')
|
||||||
|
|
@ -127,6 +159,30 @@ export default (methods: Types.ServerMethods, opts: NostrOptions) => {
|
||||||
callsMetrics.push({ ...opInfo, ...opStats, ...ctx })
|
callsMetrics.push({ ...opInfo, ...opStats, ...ctx })
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
|
case 'AuthorizeDebit':
|
||||||
|
if (!methods.AuthorizeDebit) {
|
||||||
|
throw new Error('method not defined: AuthorizeDebit')
|
||||||
|
} else {
|
||||||
|
const error = Types.DebitAuthorizationRequestValidate(operation.req)
|
||||||
|
opStats.validate = process.hrtime.bigint()
|
||||||
|
if (error !== null) throw error
|
||||||
|
const res = await methods.AuthorizeDebit({...operation, ctx}); responses.push({ status: 'OK', ...res })
|
||||||
|
opStats.handle = process.hrtime.bigint()
|
||||||
|
callsMetrics.push({ ...opInfo, ...opStats, ...ctx })
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case 'BanDebit':
|
||||||
|
if (!methods.BanDebit) {
|
||||||
|
throw new Error('method not defined: BanDebit')
|
||||||
|
} else {
|
||||||
|
const error = Types.DebitOperationValidate(operation.req)
|
||||||
|
opStats.validate = process.hrtime.bigint()
|
||||||
|
if (error !== null) throw error
|
||||||
|
await methods.BanDebit({...operation, ctx}); responses.push({ status: 'OK' })
|
||||||
|
opStats.handle = process.hrtime.bigint()
|
||||||
|
callsMetrics.push({ ...opInfo, ...opStats, ...ctx })
|
||||||
|
}
|
||||||
|
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')
|
||||||
|
|
@ -139,6 +195,18 @@ export default (methods: Types.ServerMethods, opts: NostrOptions) => {
|
||||||
callsMetrics.push({ ...opInfo, ...opStats, ...ctx })
|
callsMetrics.push({ ...opInfo, ...opStats, ...ctx })
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
|
case 'EditDebit':
|
||||||
|
if (!methods.EditDebit) {
|
||||||
|
throw new Error('method not defined: EditDebit')
|
||||||
|
} else {
|
||||||
|
const error = Types.DebitAuthorizationRequestValidate(operation.req)
|
||||||
|
opStats.validate = process.hrtime.bigint()
|
||||||
|
if (error !== null) throw error
|
||||||
|
await methods.EditDebit({...operation, ctx}); responses.push({ status: 'OK' })
|
||||||
|
opStats.handle = process.hrtime.bigint()
|
||||||
|
callsMetrics.push({ ...opInfo, ...opStats, ...ctx })
|
||||||
|
}
|
||||||
|
break
|
||||||
case 'EnrollAdminToken':
|
case 'EnrollAdminToken':
|
||||||
if (!methods.EnrollAdminToken) {
|
if (!methods.EnrollAdminToken) {
|
||||||
throw new Error('method not defined: EnrollAdminToken')
|
throw new Error('method not defined: EnrollAdminToken')
|
||||||
|
|
@ -151,6 +219,16 @@ export default (methods: Types.ServerMethods, opts: NostrOptions) => {
|
||||||
callsMetrics.push({ ...opInfo, ...opStats, ...ctx })
|
callsMetrics.push({ ...opInfo, ...opStats, ...ctx })
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
|
case 'GetDebitAuthorizations':
|
||||||
|
if (!methods.GetDebitAuthorizations) {
|
||||||
|
throw new Error('method not defined: GetDebitAuthorizations')
|
||||||
|
} else {
|
||||||
|
opStats.validate = opStats.guard
|
||||||
|
const res = await methods.GetDebitAuthorizations({...operation, ctx}); responses.push({ status: 'OK', ...res })
|
||||||
|
opStats.handle = process.hrtime.bigint()
|
||||||
|
callsMetrics.push({ ...opInfo, ...opStats, ...ctx })
|
||||||
|
}
|
||||||
|
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')
|
||||||
|
|
@ -285,6 +363,42 @@ export default (methods: Types.ServerMethods, opts: NostrOptions) => {
|
||||||
callsMetrics.push({ ...opInfo, ...opStats, ...ctx })
|
callsMetrics.push({ ...opInfo, ...opStats, ...ctx })
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
|
case 'ResetDebit':
|
||||||
|
if (!methods.ResetDebit) {
|
||||||
|
throw new Error('method not defined: ResetDebit')
|
||||||
|
} else {
|
||||||
|
const error = Types.DebitOperationValidate(operation.req)
|
||||||
|
opStats.validate = process.hrtime.bigint()
|
||||||
|
if (error !== null) throw error
|
||||||
|
await methods.ResetDebit({...operation, ctx}); responses.push({ status: 'OK' })
|
||||||
|
opStats.handle = process.hrtime.bigint()
|
||||||
|
callsMetrics.push({ ...opInfo, ...opStats, ...ctx })
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case 'RespondToDebit':
|
||||||
|
if (!methods.RespondToDebit) {
|
||||||
|
throw new Error('method not defined: RespondToDebit')
|
||||||
|
} else {
|
||||||
|
const error = Types.DebitResponseValidate(operation.req)
|
||||||
|
opStats.validate = process.hrtime.bigint()
|
||||||
|
if (error !== null) throw error
|
||||||
|
await methods.RespondToDebit({...operation, ctx}); responses.push({ status: 'OK' })
|
||||||
|
opStats.handle = process.hrtime.bigint()
|
||||||
|
callsMetrics.push({ ...opInfo, ...opStats, ...ctx })
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case 'UpdateCallbackUrl':
|
||||||
|
if (!methods.UpdateCallbackUrl) {
|
||||||
|
throw new Error('method not defined: UpdateCallbackUrl')
|
||||||
|
} else {
|
||||||
|
const error = Types.CallbackUrlValidate(operation.req)
|
||||||
|
opStats.validate = process.hrtime.bigint()
|
||||||
|
if (error !== null) throw error
|
||||||
|
const res = await methods.UpdateCallbackUrl({...operation, ctx}); responses.push({ status: 'OK', ...res })
|
||||||
|
opStats.handle = process.hrtime.bigint()
|
||||||
|
callsMetrics.push({ ...opInfo, ...opStats, ...ctx })
|
||||||
|
}
|
||||||
|
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')
|
||||||
|
|
@ -337,6 +451,22 @@ export default (methods: Types.ServerMethods, opts: NostrOptions) => {
|
||||||
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 'EditDebit':
|
||||||
|
try {
|
||||||
|
if (!methods.EditDebit) throw new Error('method: EditDebit is not implemented')
|
||||||
|
const authContext = await opts.NostrUserAuthGuard(req.appId, req.authIdentifier)
|
||||||
|
stats.guard = process.hrtime.bigint()
|
||||||
|
authCtx = authContext
|
||||||
|
const request = req.body
|
||||||
|
const error = Types.DebitAuthorizationRequestValidate(request)
|
||||||
|
stats.validate = process.hrtime.bigint()
|
||||||
|
if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback)
|
||||||
|
await methods.EditDebit({rpcName:'EditDebit', ctx:authContext , req: request})
|
||||||
|
stats.handle = process.hrtime.bigint()
|
||||||
|
res({status: 'OK'})
|
||||||
|
opts.metricsCallback([{ ...info, ...stats, ...authContext }])
|
||||||
|
}catch(ex){ const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e }
|
||||||
|
break
|
||||||
case 'EnrollAdminToken':
|
case 'EnrollAdminToken':
|
||||||
try {
|
try {
|
||||||
if (!methods.EnrollAdminToken) throw new Error('method: EnrollAdminToken is not implemented')
|
if (!methods.EnrollAdminToken) throw new Error('method: EnrollAdminToken is not implemented')
|
||||||
|
|
@ -369,6 +499,19 @@ export default (methods: Types.ServerMethods, opts: NostrOptions) => {
|
||||||
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 'GetDebitAuthorizations':
|
||||||
|
try {
|
||||||
|
if (!methods.GetDebitAuthorizations) throw new Error('method: GetDebitAuthorizations is not implemented')
|
||||||
|
const authContext = await opts.NostrUserAuthGuard(req.appId, req.authIdentifier)
|
||||||
|
stats.guard = process.hrtime.bigint()
|
||||||
|
authCtx = authContext
|
||||||
|
stats.validate = stats.guard
|
||||||
|
const response = await methods.GetDebitAuthorizations({rpcName:'GetDebitAuthorizations', ctx:authContext })
|
||||||
|
stats.handle = process.hrtime.bigint()
|
||||||
|
res({status: 'OK', ...response})
|
||||||
|
opts.metricsCallback([{ ...info, ...stats, ...authContext }])
|
||||||
|
}catch(ex){ const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e }
|
||||||
|
break
|
||||||
case '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')
|
||||||
|
|
@ -411,6 +554,19 @@ export default (methods: Types.ServerMethods, opts: NostrOptions) => {
|
||||||
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 'GetLiveDebitRequests':
|
||||||
|
try {
|
||||||
|
if (!methods.GetLiveDebitRequests) throw new Error('method: GetLiveDebitRequests is not implemented')
|
||||||
|
const authContext = await opts.NostrUserAuthGuard(req.appId, req.authIdentifier)
|
||||||
|
stats.guard = process.hrtime.bigint()
|
||||||
|
authCtx = authContext
|
||||||
|
stats.validate = stats.guard
|
||||||
|
methods.GetLiveDebitRequests({rpcName:'GetLiveDebitRequests', ctx:authContext ,cb: (response, err) => {
|
||||||
|
stats.handle = process.hrtime.bigint()
|
||||||
|
if (err) { logErrorAndReturnResponse(err, err.message, res, logger, { ...info, ...stats, ...authContext }, opts.metricsCallback)} else { res({status: 'OK', ...response});opts.metricsCallback([{ ...info, ...stats, ...authContext }])}
|
||||||
|
}})
|
||||||
|
}catch(ex){ const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e }
|
||||||
|
break
|
||||||
case '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')
|
||||||
|
|
@ -688,6 +844,54 @@ export default (methods: Types.ServerMethods, opts: NostrOptions) => {
|
||||||
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 'ResetDebit':
|
||||||
|
try {
|
||||||
|
if (!methods.ResetDebit) throw new Error('method: ResetDebit is not implemented')
|
||||||
|
const authContext = await opts.NostrUserAuthGuard(req.appId, req.authIdentifier)
|
||||||
|
stats.guard = process.hrtime.bigint()
|
||||||
|
authCtx = authContext
|
||||||
|
const request = req.body
|
||||||
|
const error = Types.DebitOperationValidate(request)
|
||||||
|
stats.validate = process.hrtime.bigint()
|
||||||
|
if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback)
|
||||||
|
await methods.ResetDebit({rpcName:'ResetDebit', ctx:authContext , req: request})
|
||||||
|
stats.handle = process.hrtime.bigint()
|
||||||
|
res({status: 'OK'})
|
||||||
|
opts.metricsCallback([{ ...info, ...stats, ...authContext }])
|
||||||
|
}catch(ex){ const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e }
|
||||||
|
break
|
||||||
|
case 'RespondToDebit':
|
||||||
|
try {
|
||||||
|
if (!methods.RespondToDebit) throw new Error('method: RespondToDebit is not implemented')
|
||||||
|
const authContext = await opts.NostrUserAuthGuard(req.appId, req.authIdentifier)
|
||||||
|
stats.guard = process.hrtime.bigint()
|
||||||
|
authCtx = authContext
|
||||||
|
const request = req.body
|
||||||
|
const error = Types.DebitResponseValidate(request)
|
||||||
|
stats.validate = process.hrtime.bigint()
|
||||||
|
if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback)
|
||||||
|
await methods.RespondToDebit({rpcName:'RespondToDebit', ctx:authContext , req: request})
|
||||||
|
stats.handle = process.hrtime.bigint()
|
||||||
|
res({status: 'OK'})
|
||||||
|
opts.metricsCallback([{ ...info, ...stats, ...authContext }])
|
||||||
|
}catch(ex){ const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e }
|
||||||
|
break
|
||||||
|
case 'UpdateCallbackUrl':
|
||||||
|
try {
|
||||||
|
if (!methods.UpdateCallbackUrl) throw new Error('method: UpdateCallbackUrl is not implemented')
|
||||||
|
const authContext = await opts.NostrUserAuthGuard(req.appId, req.authIdentifier)
|
||||||
|
stats.guard = process.hrtime.bigint()
|
||||||
|
authCtx = authContext
|
||||||
|
const request = req.body
|
||||||
|
const error = Types.CallbackUrlValidate(request)
|
||||||
|
stats.validate = process.hrtime.bigint()
|
||||||
|
if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback)
|
||||||
|
const response = await methods.UpdateCallbackUrl({rpcName:'UpdateCallbackUrl', ctx:authContext , req: request})
|
||||||
|
stats.handle = process.hrtime.bigint()
|
||||||
|
res({status: 'OK', ...response})
|
||||||
|
opts.metricsCallback([{ ...info, ...stats, ...authContext }])
|
||||||
|
}catch(ex){ const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e }
|
||||||
|
break
|
||||||
case 'UseInviteLink':
|
case 'UseInviteLink':
|
||||||
try {
|
try {
|
||||||
if (!methods.UseInviteLink) throw new Error('method: UseInviteLink is not implemented')
|
if (!methods.UseInviteLink) throw new Error('method: UseInviteLink is not implemented')
|
||||||
|
|
|
||||||
|
|
@ -34,8 +34,8 @@ export type UserContext = {
|
||||||
app_user_id: string
|
app_user_id: string
|
||||||
user_id: string
|
user_id: string
|
||||||
}
|
}
|
||||||
export type UserMethodInputs = AddProduct_Input | DecodeInvoice_Input | EnrollAdminToken_Input | GetLNURLChannelLink_Input | GetLnurlPayLink_Input | GetLnurlWithdrawLink_Input | GetPaymentState_Input | GetUserInfo_Input | GetUserOperations_Input | NewAddress_Input | NewInvoice_Input | NewProductInvoice_Input | OpenChannel_Input | PayAddress_Input | PayInvoice_Input | UserHealth_Input
|
export type UserMethodInputs = AddProduct_Input | AuthorizeDebit_Input | BanDebit_Input | DecodeInvoice_Input | EditDebit_Input | EnrollAdminToken_Input | GetDebitAuthorizations_Input | GetLNURLChannelLink_Input | GetLnurlPayLink_Input | GetLnurlWithdrawLink_Input | GetPaymentState_Input | GetUserInfo_Input | GetUserOperations_Input | NewAddress_Input | NewInvoice_Input | NewProductInvoice_Input | OpenChannel_Input | PayAddress_Input | PayInvoice_Input | ResetDebit_Input | RespondToDebit_Input | UpdateCallbackUrl_Input | UserHealth_Input
|
||||||
export type UserMethodOutputs = AddProduct_Output | DecodeInvoice_Output | EnrollAdminToken_Output | GetLNURLChannelLink_Output | GetLnurlPayLink_Output | GetLnurlWithdrawLink_Output | GetPaymentState_Output | GetUserInfo_Output | GetUserOperations_Output | NewAddress_Output | NewInvoice_Output | NewProductInvoice_Output | OpenChannel_Output | PayAddress_Output | PayInvoice_Output | UserHealth_Output
|
export type UserMethodOutputs = AddProduct_Output | AuthorizeDebit_Output | BanDebit_Output | DecodeInvoice_Output | EditDebit_Output | EnrollAdminToken_Output | GetDebitAuthorizations_Output | GetLNURLChannelLink_Output | GetLnurlPayLink_Output | GetLnurlWithdrawLink_Output | GetPaymentState_Output | GetUserInfo_Output | GetUserOperations_Output | NewAddress_Output | NewInvoice_Output | NewProductInvoice_Output | OpenChannel_Output | PayAddress_Output | PayInvoice_Output | ResetDebit_Output | RespondToDebit_Output | UpdateCallbackUrl_Output | UserHealth_Output
|
||||||
export type AuthContext = AdminContext | AppContext | GuestContext | GuestWithPubContext | MetricsContext | UserContext
|
export type AuthContext = AdminContext | AppContext | GuestContext | GuestWithPubContext | MetricsContext | UserContext
|
||||||
|
|
||||||
export type AddApp_Input = {rpcName:'AddApp', req: AddAppRequest}
|
export type AddApp_Input = {rpcName:'AddApp', req: AddAppRequest}
|
||||||
|
|
@ -56,6 +56,12 @@ export type AddProduct_Output = ResultError | ({ status: 'OK' } & Product)
|
||||||
export type AuthApp_Input = {rpcName:'AuthApp', req: AuthAppRequest}
|
export type AuthApp_Input = {rpcName:'AuthApp', req: AuthAppRequest}
|
||||||
export type AuthApp_Output = ResultError | ({ status: 'OK' } & AuthApp)
|
export type AuthApp_Output = ResultError | ({ status: 'OK' } & AuthApp)
|
||||||
|
|
||||||
|
export type AuthorizeDebit_Input = {rpcName:'AuthorizeDebit', req: DebitAuthorizationRequest}
|
||||||
|
export type AuthorizeDebit_Output = ResultError | ({ status: 'OK' } & DebitAuthorization)
|
||||||
|
|
||||||
|
export type BanDebit_Input = {rpcName:'BanDebit', req: DebitOperation}
|
||||||
|
export type BanDebit_Output = ResultError | { status: 'OK' }
|
||||||
|
|
||||||
export type BanUser_Input = {rpcName:'BanUser', req: BanUserRequest}
|
export type BanUser_Input = {rpcName:'BanUser', req: BanUserRequest}
|
||||||
export type BanUser_Output = ResultError | ({ status: 'OK' } & BanUserResponse)
|
export type BanUser_Output = ResultError | ({ status: 'OK' } & BanUserResponse)
|
||||||
|
|
||||||
|
|
@ -68,6 +74,9 @@ export type CreateOneTimeInviteLink_Output = ResultError | ({ status: 'OK' } & C
|
||||||
export type DecodeInvoice_Input = {rpcName:'DecodeInvoice', req: DecodeInvoiceRequest}
|
export type DecodeInvoice_Input = {rpcName:'DecodeInvoice', req: DecodeInvoiceRequest}
|
||||||
export type DecodeInvoice_Output = ResultError | ({ status: 'OK' } & DecodeInvoiceResponse)
|
export type DecodeInvoice_Output = ResultError | ({ status: 'OK' } & DecodeInvoiceResponse)
|
||||||
|
|
||||||
|
export type EditDebit_Input = {rpcName:'EditDebit', req: DebitAuthorizationRequest}
|
||||||
|
export type EditDebit_Output = ResultError | { status: 'OK' }
|
||||||
|
|
||||||
export type EncryptionExchange_Input = {rpcName:'EncryptionExchange', req: EncryptionExchangeRequest}
|
export type EncryptionExchange_Input = {rpcName:'EncryptionExchange', req: EncryptionExchangeRequest}
|
||||||
export type EncryptionExchange_Output = ResultError | { status: 'OK' }
|
export type EncryptionExchange_Output = ResultError | { status: 'OK' }
|
||||||
|
|
||||||
|
|
@ -86,6 +95,9 @@ export type GetAppUserLNURLInfo_Output = ResultError | ({ status: 'OK' } & Lnurl
|
||||||
export type GetAppsMetrics_Input = {rpcName:'GetAppsMetrics', req: AppsMetricsRequest}
|
export type GetAppsMetrics_Input = {rpcName:'GetAppsMetrics', req: AppsMetricsRequest}
|
||||||
export type GetAppsMetrics_Output = ResultError | ({ status: 'OK' } & AppsMetrics)
|
export type GetAppsMetrics_Output = ResultError | ({ status: 'OK' } & AppsMetrics)
|
||||||
|
|
||||||
|
export type GetDebitAuthorizations_Input = {rpcName:'GetDebitAuthorizations'}
|
||||||
|
export type GetDebitAuthorizations_Output = ResultError | ({ status: 'OK' } & DebitAuthorizations)
|
||||||
|
|
||||||
export type GetHttpCreds_Input = {rpcName:'GetHttpCreds', cb:(res: HttpCreds, err:Error|null)=> void}
|
export type GetHttpCreds_Input = {rpcName:'GetHttpCreds', cb:(res: HttpCreds, err:Error|null)=> void}
|
||||||
export type GetHttpCreds_Output = ResultError | { status: 'OK' }
|
export type GetHttpCreds_Output = ResultError | { status: 'OK' }
|
||||||
|
|
||||||
|
|
@ -95,6 +107,9 @@ export type GetInviteLinkState_Output = ResultError | ({ status: 'OK' } & GetInv
|
||||||
export type GetLNURLChannelLink_Input = {rpcName:'GetLNURLChannelLink'}
|
export type GetLNURLChannelLink_Input = {rpcName:'GetLNURLChannelLink'}
|
||||||
export type GetLNURLChannelLink_Output = ResultError | ({ status: 'OK' } & LnurlLinkResponse)
|
export type GetLNURLChannelLink_Output = ResultError | ({ status: 'OK' } & LnurlLinkResponse)
|
||||||
|
|
||||||
|
export type GetLiveDebitRequests_Input = {rpcName:'GetLiveDebitRequests', cb:(res: LiveDebitRequest, err:Error|null)=> void}
|
||||||
|
export type GetLiveDebitRequests_Output = ResultError | { status: 'OK' }
|
||||||
|
|
||||||
export type GetLiveUserOperations_Input = {rpcName:'GetLiveUserOperations', cb:(res: LiveUserOperation, err:Error|null)=> void}
|
export type GetLiveUserOperations_Input = {rpcName:'GetLiveUserOperations', cb:(res: LiveUserOperation, err:Error|null)=> void}
|
||||||
export type GetLiveUserOperations_Output = ResultError | { status: 'OK' }
|
export type GetLiveUserOperations_Output = ResultError | { status: 'OK' }
|
||||||
|
|
||||||
|
|
@ -198,9 +213,15 @@ export type PayInvoice_Output = ResultError | ({ status: 'OK' } & PayInvoiceResp
|
||||||
export type RequestNPubLinkingToken_Input = {rpcName:'RequestNPubLinkingToken', req: RequestNPubLinkingTokenRequest}
|
export type RequestNPubLinkingToken_Input = {rpcName:'RequestNPubLinkingToken', req: RequestNPubLinkingTokenRequest}
|
||||||
export type RequestNPubLinkingToken_Output = ResultError | ({ status: 'OK' } & RequestNPubLinkingTokenResponse)
|
export type RequestNPubLinkingToken_Output = ResultError | ({ status: 'OK' } & RequestNPubLinkingTokenResponse)
|
||||||
|
|
||||||
|
export type ResetDebit_Input = {rpcName:'ResetDebit', req: DebitOperation}
|
||||||
|
export type ResetDebit_Output = ResultError | { status: 'OK' }
|
||||||
|
|
||||||
export type ResetNPubLinkingToken_Input = {rpcName:'ResetNPubLinkingToken', req: RequestNPubLinkingTokenRequest}
|
export type ResetNPubLinkingToken_Input = {rpcName:'ResetNPubLinkingToken', req: RequestNPubLinkingTokenRequest}
|
||||||
export type ResetNPubLinkingToken_Output = ResultError | ({ status: 'OK' } & RequestNPubLinkingTokenResponse)
|
export type ResetNPubLinkingToken_Output = ResultError | ({ status: 'OK' } & RequestNPubLinkingTokenResponse)
|
||||||
|
|
||||||
|
export type RespondToDebit_Input = {rpcName:'RespondToDebit', req: DebitResponse}
|
||||||
|
export type RespondToDebit_Output = ResultError | { status: 'OK' }
|
||||||
|
|
||||||
export type SendAppUserToAppPayment_Input = {rpcName:'SendAppUserToAppPayment', req: SendAppUserToAppPaymentRequest}
|
export type SendAppUserToAppPayment_Input = {rpcName:'SendAppUserToAppPayment', req: SendAppUserToAppPaymentRequest}
|
||||||
export type SendAppUserToAppPayment_Output = ResultError | { status: 'OK' }
|
export type SendAppUserToAppPayment_Output = ResultError | { status: 'OK' }
|
||||||
|
|
||||||
|
|
@ -216,6 +237,9 @@ export type SetMockAppUserBalance_Output = ResultError | { status: 'OK' }
|
||||||
export type SetMockInvoiceAsPaid_Input = {rpcName:'SetMockInvoiceAsPaid', req: SetMockInvoiceAsPaidRequest}
|
export type SetMockInvoiceAsPaid_Input = {rpcName:'SetMockInvoiceAsPaid', req: SetMockInvoiceAsPaidRequest}
|
||||||
export type SetMockInvoiceAsPaid_Output = ResultError | { status: 'OK' }
|
export type SetMockInvoiceAsPaid_Output = ResultError | { status: 'OK' }
|
||||||
|
|
||||||
|
export type UpdateCallbackUrl_Input = {rpcName:'UpdateCallbackUrl', req: CallbackUrl}
|
||||||
|
export type UpdateCallbackUrl_Output = ResultError | ({ status: 'OK' } & CallbackUrl)
|
||||||
|
|
||||||
export type UseInviteLink_Input = {rpcName:'UseInviteLink', req: UseInviteLinkRequest}
|
export type UseInviteLink_Input = {rpcName:'UseInviteLink', req: UseInviteLinkRequest}
|
||||||
export type UseInviteLink_Output = ResultError | { status: 'OK' }
|
export type UseInviteLink_Output = ResultError | { status: 'OK' }
|
||||||
|
|
||||||
|
|
@ -229,18 +253,23 @@ export type ServerMethods = {
|
||||||
AddAppUserInvoice?: (req: AddAppUserInvoice_Input & {ctx: AppContext }) => Promise<NewInvoiceResponse>
|
AddAppUserInvoice?: (req: AddAppUserInvoice_Input & {ctx: AppContext }) => Promise<NewInvoiceResponse>
|
||||||
AddProduct?: (req: AddProduct_Input & {ctx: UserContext }) => Promise<Product>
|
AddProduct?: (req: AddProduct_Input & {ctx: UserContext }) => Promise<Product>
|
||||||
AuthApp?: (req: AuthApp_Input & {ctx: AdminContext }) => Promise<AuthApp>
|
AuthApp?: (req: AuthApp_Input & {ctx: AdminContext }) => Promise<AuthApp>
|
||||||
|
AuthorizeDebit?: (req: AuthorizeDebit_Input & {ctx: UserContext }) => Promise<DebitAuthorization>
|
||||||
|
BanDebit?: (req: BanDebit_Input & {ctx: UserContext }) => Promise<void>
|
||||||
BanUser?: (req: BanUser_Input & {ctx: AdminContext }) => Promise<BanUserResponse>
|
BanUser?: (req: BanUser_Input & {ctx: AdminContext }) => Promise<BanUserResponse>
|
||||||
CreateOneTimeInviteLink?: (req: CreateOneTimeInviteLink_Input & {ctx: AdminContext }) => Promise<CreateOneTimeInviteLinkResponse>
|
CreateOneTimeInviteLink?: (req: CreateOneTimeInviteLink_Input & {ctx: AdminContext }) => Promise<CreateOneTimeInviteLinkResponse>
|
||||||
DecodeInvoice?: (req: DecodeInvoice_Input & {ctx: UserContext }) => Promise<DecodeInvoiceResponse>
|
DecodeInvoice?: (req: DecodeInvoice_Input & {ctx: UserContext }) => Promise<DecodeInvoiceResponse>
|
||||||
|
EditDebit?: (req: EditDebit_Input & {ctx: UserContext }) => Promise<void>
|
||||||
EncryptionExchange?: (req: EncryptionExchange_Input & {ctx: GuestContext }) => Promise<void>
|
EncryptionExchange?: (req: EncryptionExchange_Input & {ctx: GuestContext }) => Promise<void>
|
||||||
EnrollAdminToken?: (req: EnrollAdminToken_Input & {ctx: UserContext }) => Promise<void>
|
EnrollAdminToken?: (req: EnrollAdminToken_Input & {ctx: UserContext }) => Promise<void>
|
||||||
GetApp?: (req: GetApp_Input & {ctx: AppContext }) => Promise<Application>
|
GetApp?: (req: GetApp_Input & {ctx: AppContext }) => Promise<Application>
|
||||||
GetAppUser?: (req: GetAppUser_Input & {ctx: AppContext }) => Promise<AppUser>
|
GetAppUser?: (req: GetAppUser_Input & {ctx: AppContext }) => Promise<AppUser>
|
||||||
GetAppUserLNURLInfo?: (req: GetAppUserLNURLInfo_Input & {ctx: AppContext }) => Promise<LnurlPayInfoResponse>
|
GetAppUserLNURLInfo?: (req: GetAppUserLNURLInfo_Input & {ctx: AppContext }) => Promise<LnurlPayInfoResponse>
|
||||||
GetAppsMetrics?: (req: GetAppsMetrics_Input & {ctx: MetricsContext }) => Promise<AppsMetrics>
|
GetAppsMetrics?: (req: GetAppsMetrics_Input & {ctx: MetricsContext }) => Promise<AppsMetrics>
|
||||||
|
GetDebitAuthorizations?: (req: GetDebitAuthorizations_Input & {ctx: UserContext }) => Promise<DebitAuthorizations>
|
||||||
GetHttpCreds?: (req: GetHttpCreds_Input & {ctx: UserContext }) => Promise<void>
|
GetHttpCreds?: (req: GetHttpCreds_Input & {ctx: UserContext }) => Promise<void>
|
||||||
GetInviteLinkState?: (req: GetInviteLinkState_Input & {ctx: AdminContext }) => Promise<GetInviteTokenStateResponse>
|
GetInviteLinkState?: (req: GetInviteLinkState_Input & {ctx: AdminContext }) => Promise<GetInviteTokenStateResponse>
|
||||||
GetLNURLChannelLink?: (req: GetLNURLChannelLink_Input & {ctx: UserContext }) => Promise<LnurlLinkResponse>
|
GetLNURLChannelLink?: (req: GetLNURLChannelLink_Input & {ctx: UserContext }) => Promise<LnurlLinkResponse>
|
||||||
|
GetLiveDebitRequests?: (req: GetLiveDebitRequests_Input & {ctx: UserContext }) => Promise<void>
|
||||||
GetLiveUserOperations?: (req: GetLiveUserOperations_Input & {ctx: UserContext }) => Promise<void>
|
GetLiveUserOperations?: (req: GetLiveUserOperations_Input & {ctx: UserContext }) => Promise<void>
|
||||||
GetLndMetrics?: (req: GetLndMetrics_Input & {ctx: MetricsContext }) => Promise<LndMetrics>
|
GetLndMetrics?: (req: GetLndMetrics_Input & {ctx: MetricsContext }) => Promise<LndMetrics>
|
||||||
GetLnurlPayInfo?: (req: GetLnurlPayInfo_Input & {ctx: GuestContext }) => Promise<LnurlPayInfoResponse>
|
GetLnurlPayInfo?: (req: GetLnurlPayInfo_Input & {ctx: GuestContext }) => Promise<LnurlPayInfoResponse>
|
||||||
|
|
@ -268,12 +297,15 @@ export type ServerMethods = {
|
||||||
PayAppUserInvoice?: (req: PayAppUserInvoice_Input & {ctx: AppContext }) => Promise<PayInvoiceResponse>
|
PayAppUserInvoice?: (req: PayAppUserInvoice_Input & {ctx: AppContext }) => Promise<PayInvoiceResponse>
|
||||||
PayInvoice?: (req: PayInvoice_Input & {ctx: UserContext }) => Promise<PayInvoiceResponse>
|
PayInvoice?: (req: PayInvoice_Input & {ctx: UserContext }) => Promise<PayInvoiceResponse>
|
||||||
RequestNPubLinkingToken?: (req: RequestNPubLinkingToken_Input & {ctx: AppContext }) => Promise<RequestNPubLinkingTokenResponse>
|
RequestNPubLinkingToken?: (req: RequestNPubLinkingToken_Input & {ctx: AppContext }) => Promise<RequestNPubLinkingTokenResponse>
|
||||||
|
ResetDebit?: (req: ResetDebit_Input & {ctx: UserContext }) => Promise<void>
|
||||||
ResetNPubLinkingToken?: (req: ResetNPubLinkingToken_Input & {ctx: AppContext }) => Promise<RequestNPubLinkingTokenResponse>
|
ResetNPubLinkingToken?: (req: ResetNPubLinkingToken_Input & {ctx: AppContext }) => Promise<RequestNPubLinkingTokenResponse>
|
||||||
|
RespondToDebit?: (req: RespondToDebit_Input & {ctx: UserContext }) => Promise<void>
|
||||||
SendAppUserToAppPayment?: (req: SendAppUserToAppPayment_Input & {ctx: AppContext }) => Promise<void>
|
SendAppUserToAppPayment?: (req: SendAppUserToAppPayment_Input & {ctx: AppContext }) => Promise<void>
|
||||||
SendAppUserToAppUserPayment?: (req: SendAppUserToAppUserPayment_Input & {ctx: AppContext }) => Promise<void>
|
SendAppUserToAppUserPayment?: (req: SendAppUserToAppUserPayment_Input & {ctx: AppContext }) => Promise<void>
|
||||||
SetMockAppBalance?: (req: SetMockAppBalance_Input & {ctx: AppContext }) => Promise<void>
|
SetMockAppBalance?: (req: SetMockAppBalance_Input & {ctx: AppContext }) => Promise<void>
|
||||||
SetMockAppUserBalance?: (req: SetMockAppUserBalance_Input & {ctx: AppContext }) => Promise<void>
|
SetMockAppUserBalance?: (req: SetMockAppUserBalance_Input & {ctx: AppContext }) => Promise<void>
|
||||||
SetMockInvoiceAsPaid?: (req: SetMockInvoiceAsPaid_Input & {ctx: GuestContext }) => Promise<void>
|
SetMockInvoiceAsPaid?: (req: SetMockInvoiceAsPaid_Input & {ctx: GuestContext }) => Promise<void>
|
||||||
|
UpdateCallbackUrl?: (req: UpdateCallbackUrl_Input & {ctx: UserContext }) => Promise<CallbackUrl>
|
||||||
UseInviteLink?: (req: UseInviteLink_Input & {ctx: GuestWithPubContext }) => Promise<void>
|
UseInviteLink?: (req: UseInviteLink_Input & {ctx: GuestWithPubContext }) => Promise<void>
|
||||||
UserHealth?: (req: UserHealth_Input & {ctx: UserContext }) => Promise<void>
|
UserHealth?: (req: UserHealth_Input & {ctx: UserContext }) => Promise<void>
|
||||||
}
|
}
|
||||||
|
|
@ -287,6 +319,15 @@ export const enumCheckAddressType = (e?: AddressType): boolean => {
|
||||||
for (const v in AddressType) if (e === v) return true
|
for (const v in AddressType) if (e === v) return true
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
export enum IntervalType {
|
||||||
|
DAY = 'DAY',
|
||||||
|
MONTH = 'MONTH',
|
||||||
|
WEEK = 'WEEK',
|
||||||
|
}
|
||||||
|
export const enumCheckIntervalType = (e?: IntervalType): boolean => {
|
||||||
|
for (const v in IntervalType) if (e === v) return true
|
||||||
|
return false
|
||||||
|
}
|
||||||
export enum UserOperationType {
|
export enum UserOperationType {
|
||||||
INCOMING_INVOICE = 'INCOMING_INVOICE',
|
INCOMING_INVOICE = 'INCOMING_INVOICE',
|
||||||
INCOMING_TX = 'INCOMING_TX',
|
INCOMING_TX = 'INCOMING_TX',
|
||||||
|
|
@ -747,6 +788,24 @@ export const BannedAppUserValidate = (o?: BannedAppUser, opts: BannedAppUserOpti
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type CallbackUrl = {
|
||||||
|
url: string
|
||||||
|
}
|
||||||
|
export const CallbackUrlOptionalFields: [] = []
|
||||||
|
export type CallbackUrlOptions = OptionsBaseMessage & {
|
||||||
|
checkOptionalsAreSet?: []
|
||||||
|
url_CustomCheck?: (v: string) => boolean
|
||||||
|
}
|
||||||
|
export const CallbackUrlValidate = (o?: CallbackUrl, opts: CallbackUrlOptions = {}, path: string = 'CallbackUrl::root.'): Error | null => {
|
||||||
|
if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message')
|
||||||
|
if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null')
|
||||||
|
|
||||||
|
if (typeof o.url !== 'string') return new Error(`${path}.url: is not a string`)
|
||||||
|
if (opts.url_CustomCheck && !opts.url_CustomCheck(o.url)) return new Error(`${path}.url: custom check failed`)
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
export type ClosedChannel = {
|
export type ClosedChannel = {
|
||||||
capacity: number
|
capacity: number
|
||||||
channel_id: string
|
channel_id: string
|
||||||
|
|
@ -830,6 +889,185 @@ export const CreateOneTimeInviteLinkResponseValidate = (o?: CreateOneTimeInviteL
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type DebitAuthorization = {
|
||||||
|
authorized: boolean
|
||||||
|
debit_id: string
|
||||||
|
npub: string
|
||||||
|
rules: DebitRule[]
|
||||||
|
}
|
||||||
|
export const DebitAuthorizationOptionalFields: [] = []
|
||||||
|
export type DebitAuthorizationOptions = OptionsBaseMessage & {
|
||||||
|
checkOptionalsAreSet?: []
|
||||||
|
authorized_CustomCheck?: (v: boolean) => boolean
|
||||||
|
debit_id_CustomCheck?: (v: string) => boolean
|
||||||
|
npub_CustomCheck?: (v: string) => boolean
|
||||||
|
rules_ItemOptions?: DebitRuleOptions
|
||||||
|
rules_CustomCheck?: (v: DebitRule[]) => boolean
|
||||||
|
}
|
||||||
|
export const DebitAuthorizationValidate = (o?: DebitAuthorization, opts: DebitAuthorizationOptions = {}, path: string = 'DebitAuthorization::root.'): Error | null => {
|
||||||
|
if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message')
|
||||||
|
if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null')
|
||||||
|
|
||||||
|
if (typeof o.authorized !== 'boolean') return new Error(`${path}.authorized: is not a boolean`)
|
||||||
|
if (opts.authorized_CustomCheck && !opts.authorized_CustomCheck(o.authorized)) return new Error(`${path}.authorized: custom check failed`)
|
||||||
|
|
||||||
|
if (typeof o.debit_id !== 'string') return new Error(`${path}.debit_id: is not a string`)
|
||||||
|
if (opts.debit_id_CustomCheck && !opts.debit_id_CustomCheck(o.debit_id)) return new Error(`${path}.debit_id: custom check failed`)
|
||||||
|
|
||||||
|
if (typeof o.npub !== 'string') return new Error(`${path}.npub: is not a string`)
|
||||||
|
if (opts.npub_CustomCheck && !opts.npub_CustomCheck(o.npub)) return new Error(`${path}.npub: custom check failed`)
|
||||||
|
|
||||||
|
if (!Array.isArray(o.rules)) return new Error(`${path}.rules: is not an array`)
|
||||||
|
for (let index = 0; index < o.rules.length; index++) {
|
||||||
|
const rulesErr = DebitRuleValidate(o.rules[index], opts.rules_ItemOptions, `${path}.rules[${index}]`)
|
||||||
|
if (rulesErr !== null) return rulesErr
|
||||||
|
}
|
||||||
|
if (opts.rules_CustomCheck && !opts.rules_CustomCheck(o.rules)) return new Error(`${path}.rules: custom check failed`)
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
export type DebitAuthorizationRequest = {
|
||||||
|
authorize_npub: string
|
||||||
|
request_id?: string
|
||||||
|
rules: DebitRule[]
|
||||||
|
}
|
||||||
|
export type DebitAuthorizationRequestOptionalField = 'request_id'
|
||||||
|
export const DebitAuthorizationRequestOptionalFields: DebitAuthorizationRequestOptionalField[] = ['request_id']
|
||||||
|
export type DebitAuthorizationRequestOptions = OptionsBaseMessage & {
|
||||||
|
checkOptionalsAreSet?: DebitAuthorizationRequestOptionalField[]
|
||||||
|
authorize_npub_CustomCheck?: (v: string) => boolean
|
||||||
|
request_id_CustomCheck?: (v?: string) => boolean
|
||||||
|
rules_ItemOptions?: DebitRuleOptions
|
||||||
|
rules_CustomCheck?: (v: DebitRule[]) => boolean
|
||||||
|
}
|
||||||
|
export const DebitAuthorizationRequestValidate = (o?: DebitAuthorizationRequest, opts: DebitAuthorizationRequestOptions = {}, path: string = 'DebitAuthorizationRequest::root.'): Error | null => {
|
||||||
|
if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message')
|
||||||
|
if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null')
|
||||||
|
|
||||||
|
if (typeof o.authorize_npub !== 'string') return new Error(`${path}.authorize_npub: is not a string`)
|
||||||
|
if (opts.authorize_npub_CustomCheck && !opts.authorize_npub_CustomCheck(o.authorize_npub)) return new Error(`${path}.authorize_npub: custom check failed`)
|
||||||
|
|
||||||
|
if ((o.request_id || opts.allOptionalsAreSet || opts.checkOptionalsAreSet?.includes('request_id')) && typeof o.request_id !== 'string') return new Error(`${path}.request_id: is not a string`)
|
||||||
|
if (opts.request_id_CustomCheck && !opts.request_id_CustomCheck(o.request_id)) return new Error(`${path}.request_id: custom check failed`)
|
||||||
|
|
||||||
|
if (!Array.isArray(o.rules)) return new Error(`${path}.rules: is not an array`)
|
||||||
|
for (let index = 0; index < o.rules.length; index++) {
|
||||||
|
const rulesErr = DebitRuleValidate(o.rules[index], opts.rules_ItemOptions, `${path}.rules[${index}]`)
|
||||||
|
if (rulesErr !== null) return rulesErr
|
||||||
|
}
|
||||||
|
if (opts.rules_CustomCheck && !opts.rules_CustomCheck(o.rules)) return new Error(`${path}.rules: custom check failed`)
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
export type DebitAuthorizations = {
|
||||||
|
debits: DebitAuthorization[]
|
||||||
|
}
|
||||||
|
export const DebitAuthorizationsOptionalFields: [] = []
|
||||||
|
export type DebitAuthorizationsOptions = OptionsBaseMessage & {
|
||||||
|
checkOptionalsAreSet?: []
|
||||||
|
debits_ItemOptions?: DebitAuthorizationOptions
|
||||||
|
debits_CustomCheck?: (v: DebitAuthorization[]) => boolean
|
||||||
|
}
|
||||||
|
export const DebitAuthorizationsValidate = (o?: DebitAuthorizations, opts: DebitAuthorizationsOptions = {}, path: string = 'DebitAuthorizations::root.'): Error | null => {
|
||||||
|
if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message')
|
||||||
|
if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null')
|
||||||
|
|
||||||
|
if (!Array.isArray(o.debits)) return new Error(`${path}.debits: is not an array`)
|
||||||
|
for (let index = 0; index < o.debits.length; index++) {
|
||||||
|
const debitsErr = DebitAuthorizationValidate(o.debits[index], opts.debits_ItemOptions, `${path}.debits[${index}]`)
|
||||||
|
if (debitsErr !== null) return debitsErr
|
||||||
|
}
|
||||||
|
if (opts.debits_CustomCheck && !opts.debits_CustomCheck(o.debits)) return new Error(`${path}.debits: custom check failed`)
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
export type DebitExpirationRule = {
|
||||||
|
expires_at_unix: number
|
||||||
|
}
|
||||||
|
export const DebitExpirationRuleOptionalFields: [] = []
|
||||||
|
export type DebitExpirationRuleOptions = OptionsBaseMessage & {
|
||||||
|
checkOptionalsAreSet?: []
|
||||||
|
expires_at_unix_CustomCheck?: (v: number) => boolean
|
||||||
|
}
|
||||||
|
export const DebitExpirationRuleValidate = (o?: DebitExpirationRule, opts: DebitExpirationRuleOptions = {}, path: string = 'DebitExpirationRule::root.'): Error | null => {
|
||||||
|
if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message')
|
||||||
|
if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null')
|
||||||
|
|
||||||
|
if (typeof o.expires_at_unix !== 'number') return new Error(`${path}.expires_at_unix: is not a number`)
|
||||||
|
if (opts.expires_at_unix_CustomCheck && !opts.expires_at_unix_CustomCheck(o.expires_at_unix)) return new Error(`${path}.expires_at_unix: custom check failed`)
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
export type DebitOperation = {
|
||||||
|
npub: string
|
||||||
|
}
|
||||||
|
export const DebitOperationOptionalFields: [] = []
|
||||||
|
export type DebitOperationOptions = OptionsBaseMessage & {
|
||||||
|
checkOptionalsAreSet?: []
|
||||||
|
npub_CustomCheck?: (v: string) => boolean
|
||||||
|
}
|
||||||
|
export const DebitOperationValidate = (o?: DebitOperation, opts: DebitOperationOptions = {}, path: string = 'DebitOperation::root.'): Error | null => {
|
||||||
|
if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message')
|
||||||
|
if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null')
|
||||||
|
|
||||||
|
if (typeof o.npub !== 'string') return new Error(`${path}.npub: is not a string`)
|
||||||
|
if (opts.npub_CustomCheck && !opts.npub_CustomCheck(o.npub)) return new Error(`${path}.npub: custom check failed`)
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
export type DebitResponse = {
|
||||||
|
npub: string
|
||||||
|
request_id: string
|
||||||
|
response: DebitResponse_response
|
||||||
|
}
|
||||||
|
export const DebitResponseOptionalFields: [] = []
|
||||||
|
export type DebitResponseOptions = OptionsBaseMessage & {
|
||||||
|
checkOptionalsAreSet?: []
|
||||||
|
npub_CustomCheck?: (v: string) => boolean
|
||||||
|
request_id_CustomCheck?: (v: string) => boolean
|
||||||
|
response_Options?: DebitResponse_responseOptions
|
||||||
|
}
|
||||||
|
export const DebitResponseValidate = (o?: DebitResponse, opts: DebitResponseOptions = {}, path: string = 'DebitResponse::root.'): Error | null => {
|
||||||
|
if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message')
|
||||||
|
if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null')
|
||||||
|
|
||||||
|
if (typeof o.npub !== 'string') return new Error(`${path}.npub: is not a string`)
|
||||||
|
if (opts.npub_CustomCheck && !opts.npub_CustomCheck(o.npub)) return new Error(`${path}.npub: custom check failed`)
|
||||||
|
|
||||||
|
if (typeof o.request_id !== 'string') return new Error(`${path}.request_id: is not a string`)
|
||||||
|
if (opts.request_id_CustomCheck && !opts.request_id_CustomCheck(o.request_id)) return new Error(`${path}.request_id: custom check failed`)
|
||||||
|
|
||||||
|
const responseErr = DebitResponse_responseValidate(o.response, opts.response_Options, `${path}.response`)
|
||||||
|
if (responseErr !== null) return responseErr
|
||||||
|
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
export type DebitRule = {
|
||||||
|
rule: DebitRule_rule
|
||||||
|
}
|
||||||
|
export const DebitRuleOptionalFields: [] = []
|
||||||
|
export type DebitRuleOptions = OptionsBaseMessage & {
|
||||||
|
checkOptionalsAreSet?: []
|
||||||
|
rule_Options?: DebitRule_ruleOptions
|
||||||
|
}
|
||||||
|
export const DebitRuleValidate = (o?: DebitRule, opts: DebitRuleOptions = {}, path: string = 'DebitRule::root.'): Error | null => {
|
||||||
|
if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message')
|
||||||
|
if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null')
|
||||||
|
|
||||||
|
const ruleErr = DebitRule_ruleValidate(o.rule, opts.rule_Options, `${path}.rule`)
|
||||||
|
if (ruleErr !== null) return ruleErr
|
||||||
|
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
export type DecodeInvoiceRequest = {
|
export type DecodeInvoiceRequest = {
|
||||||
invoice: string
|
invoice: string
|
||||||
}
|
}
|
||||||
|
|
@ -920,6 +1158,34 @@ export const EnrollAdminTokenRequestValidate = (o?: EnrollAdminTokenRequest, opt
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type FrequencyRule = {
|
||||||
|
amount: number
|
||||||
|
interval: IntervalType
|
||||||
|
number_of_intervals: number
|
||||||
|
}
|
||||||
|
export const FrequencyRuleOptionalFields: [] = []
|
||||||
|
export type FrequencyRuleOptions = OptionsBaseMessage & {
|
||||||
|
checkOptionalsAreSet?: []
|
||||||
|
amount_CustomCheck?: (v: number) => boolean
|
||||||
|
interval_CustomCheck?: (v: IntervalType) => boolean
|
||||||
|
number_of_intervals_CustomCheck?: (v: number) => boolean
|
||||||
|
}
|
||||||
|
export const FrequencyRuleValidate = (o?: FrequencyRule, opts: FrequencyRuleOptions = {}, path: string = 'FrequencyRule::root.'): Error | null => {
|
||||||
|
if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message')
|
||||||
|
if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null')
|
||||||
|
|
||||||
|
if (typeof o.amount !== 'number') return new Error(`${path}.amount: is not a number`)
|
||||||
|
if (opts.amount_CustomCheck && !opts.amount_CustomCheck(o.amount)) return new Error(`${path}.amount: custom check failed`)
|
||||||
|
|
||||||
|
if (!enumCheckIntervalType(o.interval)) return new Error(`${path}.interval: is not a valid IntervalType`)
|
||||||
|
if (opts.interval_CustomCheck && !opts.interval_CustomCheck(o.interval)) return new Error(`${path}.interval: custom check failed`)
|
||||||
|
|
||||||
|
if (typeof o.number_of_intervals !== 'number') return new Error(`${path}.number_of_intervals: is not a number`)
|
||||||
|
if (opts.number_of_intervals_CustomCheck && !opts.number_of_intervals_CustomCheck(o.number_of_intervals)) return new Error(`${path}.number_of_intervals: custom check failed`)
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
export type GetAppUserLNURLInfoRequest = {
|
export type GetAppUserLNURLInfoRequest = {
|
||||||
base_url_override: string
|
base_url_override: string
|
||||||
user_identifier: string
|
user_identifier: string
|
||||||
|
|
@ -1222,6 +1488,35 @@ export const LinkNPubThroughTokenRequestValidate = (o?: LinkNPubThroughTokenRequ
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type LiveDebitRequest = {
|
||||||
|
debit: LiveDebitRequest_debit
|
||||||
|
npub: string
|
||||||
|
request_id: string
|
||||||
|
}
|
||||||
|
export const LiveDebitRequestOptionalFields: [] = []
|
||||||
|
export type LiveDebitRequestOptions = OptionsBaseMessage & {
|
||||||
|
checkOptionalsAreSet?: []
|
||||||
|
debit_Options?: LiveDebitRequest_debitOptions
|
||||||
|
npub_CustomCheck?: (v: string) => boolean
|
||||||
|
request_id_CustomCheck?: (v: string) => boolean
|
||||||
|
}
|
||||||
|
export const LiveDebitRequestValidate = (o?: LiveDebitRequest, opts: LiveDebitRequestOptions = {}, path: string = 'LiveDebitRequest::root.'): Error | null => {
|
||||||
|
if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message')
|
||||||
|
if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null')
|
||||||
|
|
||||||
|
const debitErr = LiveDebitRequest_debitValidate(o.debit, opts.debit_Options, `${path}.debit`)
|
||||||
|
if (debitErr !== null) return debitErr
|
||||||
|
|
||||||
|
|
||||||
|
if (typeof o.npub !== 'string') return new Error(`${path}.npub: is not a string`)
|
||||||
|
if (opts.npub_CustomCheck && !opts.npub_CustomCheck(o.npub)) return new Error(`${path}.npub: custom check failed`)
|
||||||
|
|
||||||
|
if (typeof o.request_id !== 'string') return new Error(`${path}.request_id: is not a string`)
|
||||||
|
if (opts.request_id_CustomCheck && !opts.request_id_CustomCheck(o.request_id)) return new Error(`${path}.request_id: custom check failed`)
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
export type LiveUserOperation = {
|
export type LiveUserOperation = {
|
||||||
operation: UserOperation
|
operation: UserOperation
|
||||||
}
|
}
|
||||||
|
|
@ -1854,13 +2149,16 @@ export const PayAddressResponseValidate = (o?: PayAddressResponse, opts: PayAddr
|
||||||
|
|
||||||
export type PayAppUserInvoiceRequest = {
|
export type PayAppUserInvoiceRequest = {
|
||||||
amount: number
|
amount: number
|
||||||
|
debit_npub?: string
|
||||||
invoice: string
|
invoice: string
|
||||||
user_identifier: string
|
user_identifier: string
|
||||||
}
|
}
|
||||||
export const PayAppUserInvoiceRequestOptionalFields: [] = []
|
export type PayAppUserInvoiceRequestOptionalField = 'debit_npub'
|
||||||
|
export const PayAppUserInvoiceRequestOptionalFields: PayAppUserInvoiceRequestOptionalField[] = ['debit_npub']
|
||||||
export type PayAppUserInvoiceRequestOptions = OptionsBaseMessage & {
|
export type PayAppUserInvoiceRequestOptions = OptionsBaseMessage & {
|
||||||
checkOptionalsAreSet?: []
|
checkOptionalsAreSet?: PayAppUserInvoiceRequestOptionalField[]
|
||||||
amount_CustomCheck?: (v: number) => boolean
|
amount_CustomCheck?: (v: number) => boolean
|
||||||
|
debit_npub_CustomCheck?: (v?: string) => boolean
|
||||||
invoice_CustomCheck?: (v: string) => boolean
|
invoice_CustomCheck?: (v: string) => boolean
|
||||||
user_identifier_CustomCheck?: (v: string) => boolean
|
user_identifier_CustomCheck?: (v: string) => boolean
|
||||||
}
|
}
|
||||||
|
|
@ -1871,6 +2169,9 @@ export const PayAppUserInvoiceRequestValidate = (o?: PayAppUserInvoiceRequest, o
|
||||||
if (typeof o.amount !== 'number') return new Error(`${path}.amount: is not a number`)
|
if (typeof o.amount !== 'number') return new Error(`${path}.amount: is not a number`)
|
||||||
if (opts.amount_CustomCheck && !opts.amount_CustomCheck(o.amount)) return new Error(`${path}.amount: custom check failed`)
|
if (opts.amount_CustomCheck && !opts.amount_CustomCheck(o.amount)) return new Error(`${path}.amount: custom check failed`)
|
||||||
|
|
||||||
|
if ((o.debit_npub || opts.allOptionalsAreSet || opts.checkOptionalsAreSet?.includes('debit_npub')) && typeof o.debit_npub !== 'string') return new Error(`${path}.debit_npub: is not a string`)
|
||||||
|
if (opts.debit_npub_CustomCheck && !opts.debit_npub_CustomCheck(o.debit_npub)) return new Error(`${path}.debit_npub: custom check failed`)
|
||||||
|
|
||||||
if (typeof o.invoice !== 'string') return new Error(`${path}.invoice: is not a string`)
|
if (typeof o.invoice !== 'string') return new Error(`${path}.invoice: is not a string`)
|
||||||
if (opts.invoice_CustomCheck && !opts.invoice_CustomCheck(o.invoice)) return new Error(`${path}.invoice: custom check failed`)
|
if (opts.invoice_CustomCheck && !opts.invoice_CustomCheck(o.invoice)) return new Error(`${path}.invoice: custom check failed`)
|
||||||
|
|
||||||
|
|
@ -1882,12 +2183,15 @@ export const PayAppUserInvoiceRequestValidate = (o?: PayAppUserInvoiceRequest, o
|
||||||
|
|
||||||
export type PayInvoiceRequest = {
|
export type PayInvoiceRequest = {
|
||||||
amount: number
|
amount: number
|
||||||
|
debit_npub?: string
|
||||||
invoice: string
|
invoice: string
|
||||||
}
|
}
|
||||||
export const PayInvoiceRequestOptionalFields: [] = []
|
export type PayInvoiceRequestOptionalField = 'debit_npub'
|
||||||
|
export const PayInvoiceRequestOptionalFields: PayInvoiceRequestOptionalField[] = ['debit_npub']
|
||||||
export type PayInvoiceRequestOptions = OptionsBaseMessage & {
|
export type PayInvoiceRequestOptions = OptionsBaseMessage & {
|
||||||
checkOptionalsAreSet?: []
|
checkOptionalsAreSet?: PayInvoiceRequestOptionalField[]
|
||||||
amount_CustomCheck?: (v: number) => boolean
|
amount_CustomCheck?: (v: number) => boolean
|
||||||
|
debit_npub_CustomCheck?: (v?: string) => boolean
|
||||||
invoice_CustomCheck?: (v: string) => boolean
|
invoice_CustomCheck?: (v: string) => boolean
|
||||||
}
|
}
|
||||||
export const PayInvoiceRequestValidate = (o?: PayInvoiceRequest, opts: PayInvoiceRequestOptions = {}, path: string = 'PayInvoiceRequest::root.'): Error | null => {
|
export const PayInvoiceRequestValidate = (o?: PayInvoiceRequest, opts: PayInvoiceRequestOptions = {}, path: string = 'PayInvoiceRequest::root.'): Error | null => {
|
||||||
|
|
@ -1897,6 +2201,9 @@ export const PayInvoiceRequestValidate = (o?: PayInvoiceRequest, opts: PayInvoic
|
||||||
if (typeof o.amount !== 'number') return new Error(`${path}.amount: is not a number`)
|
if (typeof o.amount !== 'number') return new Error(`${path}.amount: is not a number`)
|
||||||
if (opts.amount_CustomCheck && !opts.amount_CustomCheck(o.amount)) return new Error(`${path}.amount: custom check failed`)
|
if (opts.amount_CustomCheck && !opts.amount_CustomCheck(o.amount)) return new Error(`${path}.amount: custom check failed`)
|
||||||
|
|
||||||
|
if ((o.debit_npub || opts.allOptionalsAreSet || opts.checkOptionalsAreSet?.includes('debit_npub')) && typeof o.debit_npub !== 'string') return new Error(`${path}.debit_npub: is not a string`)
|
||||||
|
if (opts.debit_npub_CustomCheck && !opts.debit_npub_CustomCheck(o.debit_npub)) return new Error(`${path}.debit_npub: custom check failed`)
|
||||||
|
|
||||||
if (typeof o.invoice !== 'string') return new Error(`${path}.invoice: is not a string`)
|
if (typeof o.invoice !== 'string') return new Error(`${path}.invoice: is not a string`)
|
||||||
if (opts.invoice_CustomCheck && !opts.invoice_CustomCheck(o.invoice)) return new Error(`${path}.invoice: custom check failed`)
|
if (opts.invoice_CustomCheck && !opts.invoice_CustomCheck(o.invoice)) return new Error(`${path}.invoice: custom check failed`)
|
||||||
|
|
||||||
|
|
@ -2354,7 +2661,9 @@ export const UseInviteLinkRequestValidate = (o?: UseInviteLinkRequest, opts: Use
|
||||||
export type UserInfo = {
|
export type UserInfo = {
|
||||||
balance: number
|
balance: number
|
||||||
bridge_url: string
|
bridge_url: string
|
||||||
|
callback_url: string
|
||||||
max_withdrawable: number
|
max_withdrawable: number
|
||||||
|
ndebit: string
|
||||||
network_max_fee_bps: number
|
network_max_fee_bps: number
|
||||||
network_max_fee_fixed: number
|
network_max_fee_fixed: number
|
||||||
noffer: string
|
noffer: string
|
||||||
|
|
@ -2367,7 +2676,9 @@ export type UserInfoOptions = OptionsBaseMessage & {
|
||||||
checkOptionalsAreSet?: []
|
checkOptionalsAreSet?: []
|
||||||
balance_CustomCheck?: (v: number) => boolean
|
balance_CustomCheck?: (v: number) => boolean
|
||||||
bridge_url_CustomCheck?: (v: string) => boolean
|
bridge_url_CustomCheck?: (v: string) => boolean
|
||||||
|
callback_url_CustomCheck?: (v: string) => boolean
|
||||||
max_withdrawable_CustomCheck?: (v: number) => boolean
|
max_withdrawable_CustomCheck?: (v: number) => boolean
|
||||||
|
ndebit_CustomCheck?: (v: string) => boolean
|
||||||
network_max_fee_bps_CustomCheck?: (v: number) => boolean
|
network_max_fee_bps_CustomCheck?: (v: number) => boolean
|
||||||
network_max_fee_fixed_CustomCheck?: (v: number) => boolean
|
network_max_fee_fixed_CustomCheck?: (v: number) => boolean
|
||||||
noffer_CustomCheck?: (v: string) => boolean
|
noffer_CustomCheck?: (v: string) => boolean
|
||||||
|
|
@ -2385,9 +2696,15 @@ export const UserInfoValidate = (o?: UserInfo, opts: UserInfoOptions = {}, path:
|
||||||
if (typeof o.bridge_url !== 'string') return new Error(`${path}.bridge_url: is not a string`)
|
if (typeof o.bridge_url !== 'string') return new Error(`${path}.bridge_url: is not a string`)
|
||||||
if (opts.bridge_url_CustomCheck && !opts.bridge_url_CustomCheck(o.bridge_url)) return new Error(`${path}.bridge_url: custom check failed`)
|
if (opts.bridge_url_CustomCheck && !opts.bridge_url_CustomCheck(o.bridge_url)) return new Error(`${path}.bridge_url: custom check failed`)
|
||||||
|
|
||||||
|
if (typeof o.callback_url !== 'string') return new Error(`${path}.callback_url: is not a string`)
|
||||||
|
if (opts.callback_url_CustomCheck && !opts.callback_url_CustomCheck(o.callback_url)) return new Error(`${path}.callback_url: custom check failed`)
|
||||||
|
|
||||||
if (typeof o.max_withdrawable !== 'number') return new Error(`${path}.max_withdrawable: is not a number`)
|
if (typeof o.max_withdrawable !== 'number') return new Error(`${path}.max_withdrawable: is not a number`)
|
||||||
if (opts.max_withdrawable_CustomCheck && !opts.max_withdrawable_CustomCheck(o.max_withdrawable)) return new Error(`${path}.max_withdrawable: custom check failed`)
|
if (opts.max_withdrawable_CustomCheck && !opts.max_withdrawable_CustomCheck(o.max_withdrawable)) return new Error(`${path}.max_withdrawable: custom check failed`)
|
||||||
|
|
||||||
|
if (typeof o.ndebit !== 'string') return new Error(`${path}.ndebit: is not a string`)
|
||||||
|
if (opts.ndebit_CustomCheck && !opts.ndebit_CustomCheck(o.ndebit)) return new Error(`${path}.ndebit: custom check failed`)
|
||||||
|
|
||||||
if (typeof o.network_max_fee_bps !== 'number') return new Error(`${path}.network_max_fee_bps: is not a number`)
|
if (typeof o.network_max_fee_bps !== 'number') return new Error(`${path}.network_max_fee_bps: is not a number`)
|
||||||
if (opts.network_max_fee_bps_CustomCheck && !opts.network_max_fee_bps_CustomCheck(o.network_max_fee_bps)) return new Error(`${path}.network_max_fee_bps: custom check failed`)
|
if (opts.network_max_fee_bps_CustomCheck && !opts.network_max_fee_bps_CustomCheck(o.network_max_fee_bps)) return new Error(`${path}.network_max_fee_bps: custom check failed`)
|
||||||
|
|
||||||
|
|
@ -2553,3 +2870,121 @@ export const UsersInfoValidate = (o?: UsersInfo, opts: UsersInfoOptions = {}, pa
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum DebitResponse_response_type {
|
||||||
|
DENIED = 'denied',
|
||||||
|
INVOICE = 'invoice',
|
||||||
|
}
|
||||||
|
export const enumCheckDebitResponse_response_type = (e?: DebitResponse_response_type): boolean => {
|
||||||
|
for (const v in DebitResponse_response_type) if (e === v) return true
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
export type DebitResponse_response =
|
||||||
|
{type:DebitResponse_response_type.DENIED, denied:Empty}|
|
||||||
|
{type:DebitResponse_response_type.INVOICE, invoice:string}
|
||||||
|
|
||||||
|
export type DebitResponse_responseOptions = {
|
||||||
|
denied_Options?: EmptyOptions
|
||||||
|
invoice_CustomCheck?: (v: string) => boolean
|
||||||
|
}
|
||||||
|
export const DebitResponse_responseValidate = (o?: DebitResponse_response, opts:DebitResponse_responseOptions = {}, path: string = 'DebitResponse_response::root.'): Error | null => {
|
||||||
|
if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null')
|
||||||
|
const stringType: string = o.type
|
||||||
|
switch (o.type) {
|
||||||
|
case DebitResponse_response_type.DENIED:
|
||||||
|
const deniedErr = EmptyValidate(o.denied, opts.denied_Options, `${path}.denied`)
|
||||||
|
if (deniedErr !== null) return deniedErr
|
||||||
|
|
||||||
|
|
||||||
|
break
|
||||||
|
case DebitResponse_response_type.INVOICE:
|
||||||
|
if (typeof o.invoice !== 'string') return new Error(`${path}.invoice: is not a string`)
|
||||||
|
if (opts.invoice_CustomCheck && !opts.invoice_CustomCheck(o.invoice)) return new Error(`${path}.invoice: custom check failed`)
|
||||||
|
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
return new Error(path + ': unknown type '+ stringType)
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
export enum DebitRule_rule_type {
|
||||||
|
EXPIRATION_RULE = 'expiration_rule',
|
||||||
|
FREQUENCY_RULE = 'frequency_rule',
|
||||||
|
}
|
||||||
|
export const enumCheckDebitRule_rule_type = (e?: DebitRule_rule_type): boolean => {
|
||||||
|
for (const v in DebitRule_rule_type) if (e === v) return true
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
export type DebitRule_rule =
|
||||||
|
{type:DebitRule_rule_type.EXPIRATION_RULE, expiration_rule:DebitExpirationRule}|
|
||||||
|
{type:DebitRule_rule_type.FREQUENCY_RULE, frequency_rule:FrequencyRule}
|
||||||
|
|
||||||
|
export type DebitRule_ruleOptions = {
|
||||||
|
expiration_rule_Options?: DebitExpirationRuleOptions
|
||||||
|
frequency_rule_Options?: FrequencyRuleOptions
|
||||||
|
}
|
||||||
|
export const DebitRule_ruleValidate = (o?: DebitRule_rule, opts:DebitRule_ruleOptions = {}, path: string = 'DebitRule_rule::root.'): Error | null => {
|
||||||
|
if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null')
|
||||||
|
const stringType: string = o.type
|
||||||
|
switch (o.type) {
|
||||||
|
case DebitRule_rule_type.EXPIRATION_RULE:
|
||||||
|
const expiration_ruleErr = DebitExpirationRuleValidate(o.expiration_rule, opts.expiration_rule_Options, `${path}.expiration_rule`)
|
||||||
|
if (expiration_ruleErr !== null) return expiration_ruleErr
|
||||||
|
|
||||||
|
|
||||||
|
break
|
||||||
|
case DebitRule_rule_type.FREQUENCY_RULE:
|
||||||
|
const frequency_ruleErr = FrequencyRuleValidate(o.frequency_rule, opts.frequency_rule_Options, `${path}.frequency_rule`)
|
||||||
|
if (frequency_ruleErr !== null) return frequency_ruleErr
|
||||||
|
|
||||||
|
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
return new Error(path + ': unknown type '+ stringType)
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
export enum LiveDebitRequest_debit_type {
|
||||||
|
FREQUENCY = 'frequency',
|
||||||
|
FULL_ACCESS = 'full_access',
|
||||||
|
INVOICE = 'invoice',
|
||||||
|
}
|
||||||
|
export const enumCheckLiveDebitRequest_debit_type = (e?: LiveDebitRequest_debit_type): boolean => {
|
||||||
|
for (const v in LiveDebitRequest_debit_type) if (e === v) return true
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
export type LiveDebitRequest_debit =
|
||||||
|
{type:LiveDebitRequest_debit_type.FREQUENCY, frequency:FrequencyRule}|
|
||||||
|
{type:LiveDebitRequest_debit_type.FULL_ACCESS, full_access:Empty}|
|
||||||
|
{type:LiveDebitRequest_debit_type.INVOICE, invoice:string}
|
||||||
|
|
||||||
|
export type LiveDebitRequest_debitOptions = {
|
||||||
|
frequency_Options?: FrequencyRuleOptions
|
||||||
|
full_access_Options?: EmptyOptions
|
||||||
|
invoice_CustomCheck?: (v: string) => boolean
|
||||||
|
}
|
||||||
|
export const LiveDebitRequest_debitValidate = (o?: LiveDebitRequest_debit, opts:LiveDebitRequest_debitOptions = {}, path: string = 'LiveDebitRequest_debit::root.'): Error | null => {
|
||||||
|
if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null')
|
||||||
|
const stringType: string = o.type
|
||||||
|
switch (o.type) {
|
||||||
|
case LiveDebitRequest_debit_type.FREQUENCY:
|
||||||
|
const frequencyErr = FrequencyRuleValidate(o.frequency, opts.frequency_Options, `${path}.frequency`)
|
||||||
|
if (frequencyErr !== null) return frequencyErr
|
||||||
|
|
||||||
|
|
||||||
|
break
|
||||||
|
case LiveDebitRequest_debit_type.FULL_ACCESS:
|
||||||
|
const full_accessErr = EmptyValidate(o.full_access, opts.full_access_Options, `${path}.full_access`)
|
||||||
|
if (full_accessErr !== null) return full_accessErr
|
||||||
|
|
||||||
|
|
||||||
|
break
|
||||||
|
case LiveDebitRequest_debit_type.INVOICE:
|
||||||
|
if (typeof o.invoice !== 'string') return new Error(`${path}.invoice: is not a string`)
|
||||||
|
if (opts.invoice_CustomCheck && !opts.invoice_CustomCheck(o.invoice)) return new Error(`${path}.invoice: custom check failed`)
|
||||||
|
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
return new Error(path + ': unknown type '+ stringType)
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
|
||||||
Binary file not shown.
|
|
@ -343,6 +343,12 @@ service LightningPub {
|
||||||
option (http_route) = "/api/user/info";
|
option (http_route) = "/api/user/info";
|
||||||
option (nostr) = true;
|
option (nostr) = true;
|
||||||
}
|
}
|
||||||
|
rpc UpdateCallbackUrl(structs.CallbackUrl)returns(structs.CallbackUrl){
|
||||||
|
option (auth_type) = "User";
|
||||||
|
option (http_method) = "post";
|
||||||
|
option (http_route) = "/api/user/cb/update";
|
||||||
|
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";
|
||||||
|
|
@ -430,11 +436,53 @@ service LightningPub {
|
||||||
}
|
}
|
||||||
|
|
||||||
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 GetDebitAuthorizations(structs.Empty) returns (structs.DebitAuthorizations){
|
||||||
|
option (auth_type) = "User";
|
||||||
|
option (http_method) = "get";
|
||||||
|
option (http_route) = "/api/user/debit/get";
|
||||||
|
option (nostr) = true;
|
||||||
|
}
|
||||||
|
rpc AuthorizeDebit(structs.DebitAuthorizationRequest) returns (structs.DebitAuthorization){
|
||||||
|
option (auth_type) = "User";
|
||||||
|
option (http_method) = "post";
|
||||||
|
option (http_route) = "/api/user/debit/authorize";
|
||||||
|
option (nostr) = true;
|
||||||
|
}
|
||||||
|
rpc EditDebit(structs.DebitAuthorizationRequest) returns (structs.Empty){
|
||||||
|
option (auth_type) = "User";
|
||||||
|
option (http_method) = "post";
|
||||||
|
option (http_route) = "/api/user/debit/edit";
|
||||||
|
option (nostr) = true;
|
||||||
|
}
|
||||||
|
rpc BanDebit(structs.DebitOperation) returns (structs.Empty){
|
||||||
|
option (auth_type) = "User";
|
||||||
|
option (http_method) = "post";
|
||||||
|
option (http_route) = "/api/user/debit/ban";
|
||||||
|
option (nostr) = true;
|
||||||
|
}
|
||||||
|
rpc ResetDebit(structs.DebitOperation) returns (structs.Empty){
|
||||||
|
option (auth_type) = "User";
|
||||||
|
option (http_method) = "post";
|
||||||
|
option (http_route) = "/api/user/debit/reset";
|
||||||
|
option (nostr) = true;
|
||||||
|
}
|
||||||
|
rpc RespondToDebit(structs.DebitResponse) returns (structs.Empty){
|
||||||
|
option (auth_type) = "User";
|
||||||
|
option (http_method) = "post";
|
||||||
|
option (http_route) = "/api/user/debit/finish";
|
||||||
|
option (nostr) = true;
|
||||||
|
}
|
||||||
|
rpc GetLiveDebitRequests(structs.Empty) returns (stream structs.LiveDebitRequest){
|
||||||
|
option (auth_type) = "User";
|
||||||
|
option (http_method) = "post";
|
||||||
|
option (http_route) = "/api/user/debit/sub";
|
||||||
|
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";
|
||||||
|
|
|
||||||
|
|
@ -215,6 +215,7 @@ message PayAppUserInvoiceRequest {
|
||||||
string user_identifier = 1;
|
string user_identifier = 1;
|
||||||
string invoice = 2;
|
string invoice = 2;
|
||||||
int64 amount = 3;
|
int64 amount = 3;
|
||||||
|
optional string debit_npub = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
message SendAppUserToAppUserPaymentRequest {
|
message SendAppUserToAppUserPaymentRequest {
|
||||||
|
|
@ -283,6 +284,7 @@ message DecodeInvoiceResponse{
|
||||||
message PayInvoiceRequest{
|
message PayInvoiceRequest{
|
||||||
string invoice = 1;
|
string invoice = 1;
|
||||||
int64 amount = 2;
|
int64 amount = 2;
|
||||||
|
optional string debit_npub = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
message PayInvoiceResponse{
|
message PayInvoiceResponse{
|
||||||
|
|
@ -345,6 +347,10 @@ message HandleLnurlPayResponse {
|
||||||
repeated Empty routes = 2;
|
repeated Empty routes = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message CallbackUrl {
|
||||||
|
string url = 1;
|
||||||
|
}
|
||||||
|
|
||||||
message UserInfo{
|
message UserInfo{
|
||||||
string userId = 1;
|
string userId = 1;
|
||||||
int64 balance = 2;
|
int64 balance = 2;
|
||||||
|
|
@ -354,9 +360,10 @@ message UserInfo{
|
||||||
int64 network_max_fee_bps = 6;
|
int64 network_max_fee_bps = 6;
|
||||||
int64 network_max_fee_fixed = 7;
|
int64 network_max_fee_fixed = 7;
|
||||||
string noffer = 8;
|
string noffer = 8;
|
||||||
string bridge_url = 9;
|
string ndebit = 9;
|
||||||
|
string callback_url = 10;
|
||||||
|
string bridge_url = 11;
|
||||||
}
|
}
|
||||||
|
|
||||||
message GetUserOperationsRequest{
|
message GetUserOperationsRequest{
|
||||||
int64 latestIncomingInvoice = 1;
|
int64 latestIncomingInvoice = 1;
|
||||||
int64 latestOutgoingInvoice = 2;
|
int64 latestOutgoingInvoice = 2;
|
||||||
|
|
@ -477,4 +484,67 @@ message GetInviteTokenStateRequest {
|
||||||
|
|
||||||
message GetInviteTokenStateResponse {
|
message GetInviteTokenStateResponse {
|
||||||
bool used = 1;
|
bool used = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message DebitOperation {
|
||||||
|
string npub = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message DebitAuthorizationRequest {
|
||||||
|
string authorize_npub = 1;
|
||||||
|
repeated DebitRule rules = 2;
|
||||||
|
optional string request_id = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message DebitAuthorization {
|
||||||
|
string debit_id = 1;
|
||||||
|
bool authorized = 2;
|
||||||
|
string npub = 3;
|
||||||
|
repeated DebitRule rules = 4;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
message DebitAuthorizations {
|
||||||
|
repeated DebitAuthorization debits = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message DebitExpirationRule {
|
||||||
|
int64 expires_at_unix = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum IntervalType {
|
||||||
|
DAY = 0;
|
||||||
|
WEEK = 1;
|
||||||
|
MONTH = 2;
|
||||||
|
}
|
||||||
|
message FrequencyRule {
|
||||||
|
int64 number_of_intervals = 1;
|
||||||
|
IntervalType interval = 2;
|
||||||
|
int64 amount = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message DebitRule {
|
||||||
|
oneof rule {
|
||||||
|
DebitExpirationRule expiration_rule = 1;
|
||||||
|
FrequencyRule frequency_rule = 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
message LiveDebitRequest {
|
||||||
|
string request_id = 1;
|
||||||
|
string npub = 2;
|
||||||
|
oneof debit {
|
||||||
|
string invoice = 3;
|
||||||
|
FrequencyRule frequency = 4;
|
||||||
|
Empty full_access = 5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
message DebitResponse {
|
||||||
|
string request_id = 1;
|
||||||
|
string npub = 2;
|
||||||
|
oneof response {
|
||||||
|
Empty denied = 3;
|
||||||
|
string invoice = 4;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,143 +0,0 @@
|
||||||
/*
|
|
||||||
This file contains functions that deal with encoding and decoding nprofiles,
|
|
||||||
but with he addition of bridge urls in the nprofile.
|
|
||||||
These functions are basically the same functions from nostr-tools package
|
|
||||||
but with some tweaks to allow for the bridge inclusion.
|
|
||||||
*/
|
|
||||||
import { bytesToHex, concatBytes, hexToBytes } from '@noble/hashes/utils';
|
|
||||||
import { bech32 } from 'bech32';
|
|
||||||
import { LoadNosrtSettingsFromEnv } from './services/nostr/index.js';
|
|
||||||
|
|
||||||
export const utf8Decoder = new TextDecoder('utf-8')
|
|
||||||
export const utf8Encoder = new TextEncoder()
|
|
||||||
|
|
||||||
|
|
||||||
export type CustomProfilePointer = {
|
|
||||||
pubkey: string
|
|
||||||
relays?: string[]
|
|
||||||
bridge?: string[] // one bridge
|
|
||||||
}
|
|
||||||
|
|
||||||
export type OfferPointer = {
|
|
||||||
pubkey: string,
|
|
||||||
relay: string,
|
|
||||||
offer: string
|
|
||||||
priceType: PriceType,
|
|
||||||
price?: number
|
|
||||||
}
|
|
||||||
export enum PriceType {
|
|
||||||
fixed = 0,
|
|
||||||
variable = 1,
|
|
||||||
spontaneous = 2,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
type TLV = { [t: number]: Uint8Array[] }
|
|
||||||
|
|
||||||
|
|
||||||
const encodeTLV = (tlv: TLV): Uint8Array => {
|
|
||||||
const entries: Uint8Array[] = []
|
|
||||||
|
|
||||||
Object.entries(tlv)
|
|
||||||
/*
|
|
||||||
the original function does a reverse() here,
|
|
||||||
but here it causes the nprofile string to be different,
|
|
||||||
even though it would still decode to the correct original inputs
|
|
||||||
*/
|
|
||||||
//.reverse()
|
|
||||||
.forEach(([t, vs]) => {
|
|
||||||
vs.forEach(v => {
|
|
||||||
const entry = new Uint8Array(v.length + 2)
|
|
||||||
entry.set([parseInt(t)], 0)
|
|
||||||
entry.set([v.length], 1)
|
|
||||||
entry.set(v, 2)
|
|
||||||
entries.push(entry)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
return concatBytes(...entries);
|
|
||||||
}
|
|
||||||
|
|
||||||
export const encodeNprofile = (profile: CustomProfilePointer): string => {
|
|
||||||
const data = encodeTLV({
|
|
||||||
0: [hexToBytes(profile.pubkey)],
|
|
||||||
1: (profile.relays || []).map(url => utf8Encoder.encode(url)),
|
|
||||||
2: (profile.bridge || []).map(url => utf8Encoder.encode(url))
|
|
||||||
});
|
|
||||||
const words = bech32.toWords(data)
|
|
||||||
return bech32.encode("nprofile", words, 5000);
|
|
||||||
}
|
|
||||||
|
|
||||||
export const encodeNoffer = (offer: OfferPointer): string => {
|
|
||||||
let relay = offer.relay
|
|
||||||
if (!relay) {
|
|
||||||
const settings = LoadNosrtSettingsFromEnv()
|
|
||||||
relay = settings.relays[0]
|
|
||||||
}
|
|
||||||
const o: TLV = {
|
|
||||||
0: [hexToBytes(offer.pubkey)],
|
|
||||||
1: [utf8Encoder.encode(relay)],
|
|
||||||
2: [utf8Encoder.encode(offer.offer)],
|
|
||||||
3: [new Uint8Array([Number(offer.priceType)])],
|
|
||||||
}
|
|
||||||
if (offer.price) {
|
|
||||||
o[4] = [new Uint8Array(new BigUint64Array([BigInt(offer.price)]).buffer)]
|
|
||||||
}
|
|
||||||
const data = encodeTLV(o);
|
|
||||||
const words = bech32.toWords(data)
|
|
||||||
return bech32.encode("noffer", words, 5000);
|
|
||||||
}
|
|
||||||
|
|
||||||
const parseTLV = (data: Uint8Array): TLV => {
|
|
||||||
const result: TLV = {}
|
|
||||||
let rest = data
|
|
||||||
while (rest.length > 0) {
|
|
||||||
const t = rest[0]
|
|
||||||
const l = rest[1]
|
|
||||||
const v = rest.slice(2, 2 + l)
|
|
||||||
rest = rest.slice(2 + l)
|
|
||||||
if (v.length < l) throw new Error(`not enough data to read on TLV ${t}`)
|
|
||||||
result[t] = result[t] || []
|
|
||||||
result[t].push(v)
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
export const decodeNoffer = (noffer: string): OfferPointer => {
|
|
||||||
const { prefix, words } = bech32.decode(noffer, 5000)
|
|
||||||
if (prefix !== "noffer") {
|
|
||||||
throw new Error("Expected nprofile prefix");
|
|
||||||
}
|
|
||||||
const data = new Uint8Array(bech32.fromWords(words))
|
|
||||||
|
|
||||||
const tlv = parseTLV(data);
|
|
||||||
if (!tlv[0]?.[0]) throw new Error('missing TLV 0 for noffer')
|
|
||||||
if (tlv[0][0].length !== 32) throw new Error('TLV 0 should be 32 bytes')
|
|
||||||
if (!tlv[1]?.[0]) throw new Error('missing TLV 1 for noffer')
|
|
||||||
if (!tlv[2]?.[0]) throw new Error('missing TLV 2 for noffer')
|
|
||||||
if (!tlv[3]?.[0]) throw new Error('missing TLV 3 for noffer')
|
|
||||||
return {
|
|
||||||
pubkey: bytesToHex(tlv[0][0]),
|
|
||||||
relay: utf8Decoder.decode(tlv[1][0]),
|
|
||||||
offer: utf8Decoder.decode(tlv[2][0]),
|
|
||||||
priceType: tlv[3][0][0],
|
|
||||||
price: tlv[4] ? Number(new BigUint64Array(tlv[4][0])[0]) : undefined
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const decodeNprofile = (nprofile: string): CustomProfilePointer => {
|
|
||||||
const { prefix, words } = bech32.decode(nprofile, 5000)
|
|
||||||
if (prefix !== "nprofile") {
|
|
||||||
throw new Error("Expected nprofile prefix");
|
|
||||||
}
|
|
||||||
const data = new Uint8Array(bech32.fromWords(words))
|
|
||||||
|
|
||||||
const tlv = parseTLV(data);
|
|
||||||
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')
|
|
||||||
|
|
||||||
return {
|
|
||||||
pubkey: bytesToHex(tlv[0][0]),
|
|
||||||
relays: tlv[1] ? tlv[1].map(d => utf8Decoder.decode(d)) : [],
|
|
||||||
bridge: tlv[2] ? tlv[2].map(d => utf8Decoder.decode(d)) : []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -7,7 +7,9 @@ import nostrMiddleware from './nostrMiddleware.js'
|
||||||
import { getLogger } from './services/helpers/logger.js';
|
import { getLogger } from './services/helpers/logger.js';
|
||||||
import { initMainHandler } from './services/main/init.js';
|
import { initMainHandler } from './services/main/init.js';
|
||||||
import { LoadMainSettingsFromEnv } from './services/main/settings.js';
|
import { LoadMainSettingsFromEnv } from './services/main/settings.js';
|
||||||
import { encodeNprofile } from './custom-nip19.js';
|
import { nip19 } from 'nostr-tools'
|
||||||
|
//@ts-ignore
|
||||||
|
const { nprofileEncode } = nip19
|
||||||
|
|
||||||
const start = async () => {
|
const start = async () => {
|
||||||
const log = getLogger({})
|
const log = getLogger({})
|
||||||
|
|
@ -29,7 +31,7 @@ const start = async () => {
|
||||||
log("starting server")
|
log("starting server")
|
||||||
mainHandler.attachNostrSend(Send)
|
mainHandler.attachNostrSend(Send)
|
||||||
mainHandler.StartBeacons()
|
mainHandler.StartBeacons()
|
||||||
const appNprofile = encodeNprofile({ pubkey: liquidityProviderInfo.publicKey, relays: nostrSettings.relays })
|
const appNprofile = nprofileEncode({ pubkey: liquidityProviderInfo.publicKey, relays: nostrSettings.relays })
|
||||||
if (wizard) {
|
if (wizard) {
|
||||||
wizard.AddConnectInfo(appNprofile, nostrSettings.relays)
|
wizard.AddConnectInfo(appNprofile, nostrSettings.relays)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,9 +4,7 @@ import { NostrEvent, NostrSend, NostrSettings } from "./services/nostr/handler.j
|
||||||
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";
|
||||||
import { UnsignedEvent } from "./services/nostr/tools/event.js";
|
import { NdebitData } from "nostr-tools/lib/types/nip68.js";
|
||||||
import { defaultInvoiceExpiry } from "./services/storage/paymentStorage.js";
|
|
||||||
import { Application } from "./services/storage/entity/Application.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({})
|
||||||
|
|
@ -52,6 +50,10 @@ export default (serverMethods: Types.ServerMethods, mainHandler: Main, nostrSett
|
||||||
const offerReq = j as NofferData
|
const offerReq = j as NofferData
|
||||||
mainHandler.handleNip69Noffer(offerReq, event)
|
mainHandler.handleNip69Noffer(offerReq, event)
|
||||||
return
|
return
|
||||||
|
} else if (event.kind === 21002) {
|
||||||
|
const debitReq = j as NdebitData
|
||||||
|
mainHandler.debitManager.handleNip68Debit(debitReq, event)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
if (!j.rpcName) {
|
if (!j.rpcName) {
|
||||||
onClientEvent(j as { requestId: string }, event.pub)
|
onClientEvent(j as { requestId: string }, event.pub)
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,11 @@ 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'
|
||||||
import { encodeNoffer, PriceType } from '../../custom-nip19.js'
|
import { nip19 } from 'nostr-tools'
|
||||||
|
import { LoadNosrtSettingsFromEnv } from '../nostr/index.js'
|
||||||
|
const { ndebitEncode, nofferEncode, OfferPriceType } = nip19
|
||||||
export default class {
|
export default class {
|
||||||
|
|
||||||
storage: Storage
|
storage: Storage
|
||||||
settings: MainSettings
|
settings: MainSettings
|
||||||
applicationManager: ApplicationManager
|
applicationManager: ApplicationManager
|
||||||
|
|
@ -50,9 +53,12 @@ export default class {
|
||||||
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)
|
||||||
|
console.log("User Identifier/pointer here", appUser?.identifier)
|
||||||
|
|
||||||
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
|
||||||
}
|
}
|
||||||
|
const nostrSettings = LoadNosrtSettingsFromEnv()
|
||||||
return {
|
return {
|
||||||
userId: ctx.user_id,
|
userId: ctx.user_id,
|
||||||
balance: user.balance_sats,
|
balance: user.balance_sats,
|
||||||
|
|
@ -61,11 +67,19 @@ export default class {
|
||||||
network_max_fee_bps: this.settings.lndSettings.feeRateBps,
|
network_max_fee_bps: this.settings.lndSettings.feeRateBps,
|
||||||
network_max_fee_fixed: this.settings.lndSettings.feeFixedLimit,
|
network_max_fee_fixed: this.settings.lndSettings.feeFixedLimit,
|
||||||
service_fee_bps: this.settings.outgoingAppUserInvoiceFeeBps,
|
service_fee_bps: this.settings.outgoingAppUserInvoiceFeeBps,
|
||||||
noffer: encodeNoffer({ pubkey: app.nostr_public_key!, offer: appUser.identifier, priceType: PriceType.spontaneous, relay: "" }),
|
noffer: nofferEncode({ pubkey: app.nostr_public_key!, offer: appUser.identifier, priceType: OfferPriceType.Spontaneous, relay: nostrSettings.relays[0] }),
|
||||||
|
ndebit: ndebitEncode({ pubkey: app.nostr_public_key!, pointer: appUser.identifier, relay: nostrSettings.relays[0] }),
|
||||||
|
callback_url: appUser.callback_url,
|
||||||
bridge_url: this.settings.bridgeUrl
|
bridge_url: this.settings.bridgeUrl
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async UpdateCallbackUrl(ctx: Types.UserContext, req: Types.CallbackUrl): Promise<Types.CallbackUrl> {
|
||||||
|
const app = await this.storage.applicationStorage.GetApplication(ctx.app_id)
|
||||||
|
await this.storage.applicationStorage.UpdateUserCallbackUrl(app, ctx.app_user_id, req.url)
|
||||||
|
return { url: req.url }
|
||||||
|
}
|
||||||
|
|
||||||
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: "",
|
||||||
|
|
|
||||||
|
|
@ -8,8 +8,10 @@ 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'
|
||||||
import { encodeNoffer, PriceType } from '../../custom-nip19.js'
|
import { nip69, nip19 } from 'nostr-tools'
|
||||||
|
import { LoadNosrtSettingsFromEnv } from '../nostr/index.js'
|
||||||
|
const { SendNofferRequest } = nip69
|
||||||
|
const { nofferEncode, ndebitEncode, OfferPriceType } = nip19
|
||||||
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 = {
|
||||||
|
|
@ -149,6 +151,7 @@ export default class {
|
||||||
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")
|
||||||
}
|
}
|
||||||
|
const nostrSettings = LoadNosrtSettingsFromEnv()
|
||||||
return {
|
return {
|
||||||
identifier: u.identifier,
|
identifier: u.identifier,
|
||||||
info: {
|
info: {
|
||||||
|
|
@ -159,7 +162,9 @@ export default class {
|
||||||
network_max_fee_bps: this.settings.lndSettings.feeRateBps,
|
network_max_fee_bps: this.settings.lndSettings.feeRateBps,
|
||||||
network_max_fee_fixed: this.settings.lndSettings.feeFixedLimit,
|
network_max_fee_fixed: this.settings.lndSettings.feeFixedLimit,
|
||||||
service_fee_bps: this.settings.outgoingAppUserInvoiceFeeBps,
|
service_fee_bps: this.settings.outgoingAppUserInvoiceFeeBps,
|
||||||
noffer: encodeNoffer({ pubkey: app.nostr_public_key!, offer: u.identifier, priceType: PriceType.spontaneous, relay: "" }),
|
noffer: nofferEncode({ pubkey: app.nostr_public_key!, offer: u.identifier, priceType: OfferPriceType.Spontaneous, relay: nostrSettings.relays[0] }),
|
||||||
|
ndebit: ndebitEncode({ pubkey: app.nostr_public_key!, pointer: u.identifier, relay: nostrSettings.relays[0] }),
|
||||||
|
callback_url: u.callback_url,
|
||||||
bridge_url: this.settings.bridgeUrl
|
bridge_url: this.settings.bridgeUrl
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
@ -181,7 +186,8 @@ export default class {
|
||||||
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 cbUrl = req.http_callback_url || receiver.callback_url || ""
|
||||||
|
const opts: InboundOptionals = { callbackUrl: cbUrl, expiry: defaultInvoiceExpiry, expectedPayer: payer.user, linkedApplication: app }
|
||||||
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)
|
||||||
return {
|
return {
|
||||||
invoice: appUserInvoice.invoice
|
invoice: appUserInvoice.invoice
|
||||||
|
|
@ -192,6 +198,7 @@ export default class {
|
||||||
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)
|
||||||
|
const nostrSettings = LoadNosrtSettingsFromEnv()
|
||||||
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,
|
||||||
|
|
@ -200,7 +207,9 @@ export default class {
|
||||||
network_max_fee_bps: this.settings.lndSettings.feeRateBps,
|
network_max_fee_bps: this.settings.lndSettings.feeRateBps,
|
||||||
network_max_fee_fixed: this.settings.lndSettings.feeFixedLimit,
|
network_max_fee_fixed: this.settings.lndSettings.feeFixedLimit,
|
||||||
service_fee_bps: this.settings.outgoingAppUserInvoiceFeeBps,
|
service_fee_bps: this.settings.outgoingAppUserInvoiceFeeBps,
|
||||||
noffer: encodeNoffer({ pubkey: app.nostr_public_key!, offer: user.identifier, priceType: PriceType.spontaneous, relay: "" }),
|
noffer: nofferEncode({ pubkey: app.nostr_public_key!, offer: user.identifier, priceType: OfferPriceType.Spontaneous, relay: nostrSettings.relays[0] }),
|
||||||
|
ndebit: ndebitEncode({ pubkey: app.nostr_public_key!, pointer: user.identifier, relay: nostrSettings.relays[0] }),
|
||||||
|
callback_url: user.callback_url,
|
||||||
bridge_url: this.settings.bridgeUrl
|
bridge_url: this.settings.bridgeUrl
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
||||||
395
src/services/main/debitManager.ts
Normal file
395
src/services/main/debitManager.ts
Normal file
|
|
@ -0,0 +1,395 @@
|
||||||
|
import crypto from 'crypto';
|
||||||
|
import * as Types from "../../../proto/autogenerated/ts/types.js";
|
||||||
|
import ApplicationManager from "./applicationManager.js";
|
||||||
|
import Storage from '../storage/index.js'
|
||||||
|
import LND from "../lnd/lnd.js"
|
||||||
|
import { ERROR, getLogger } from "../helpers/logger.js";
|
||||||
|
import { DebitAccess, DebitAccessRules } from '../storage/entity/DebitAccess.js';
|
||||||
|
import paymentManager from './paymentManager.js';
|
||||||
|
import { Application } from '../storage/entity/Application.js';
|
||||||
|
import { ApplicationUser } from '../storage/entity/ApplicationUser.js';
|
||||||
|
import { NostrEvent, NostrSend, SendData, SendInitiator } from '../nostr/handler.js';
|
||||||
|
import { UnsignedEvent } from 'nostr-tools';
|
||||||
|
import { BudgetFrequency, NdebitData, NdebitFailure, NdebitSuccess, NdebitSuccessPayment, RecurringDebitTimeUnit } from 'nostr-tools/lib/types/nip68.js';
|
||||||
|
export const expirationRuleName = 'expiration'
|
||||||
|
export const frequencyRuleName = 'frequency'
|
||||||
|
const unitToIntervalType = (unit: RecurringDebitTimeUnit) => {
|
||||||
|
switch (unit) {
|
||||||
|
case 'day': return Types.IntervalType.DAY
|
||||||
|
case 'week': return Types.IntervalType.WEEK
|
||||||
|
case 'month': return Types.IntervalType.MONTH
|
||||||
|
default: throw new Error("invalid unit")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const intervalTypeToUnit = (interval: Types.IntervalType): RecurringDebitTimeUnit => {
|
||||||
|
switch (interval) {
|
||||||
|
case Types.IntervalType.DAY: return 'day'
|
||||||
|
case Types.IntervalType.WEEK: return 'week'
|
||||||
|
case Types.IntervalType.MONTH: return 'month'
|
||||||
|
default: throw new Error("invalid interval")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const IntervalTypeToSeconds = (interval: Types.IntervalType) => {
|
||||||
|
switch (interval) {
|
||||||
|
case Types.IntervalType.DAY: return 24 * 60 * 60
|
||||||
|
case Types.IntervalType.WEEK: return 7 * 24 * 60 * 60
|
||||||
|
case Types.IntervalType.MONTH: return 30 * 24 * 60 * 60
|
||||||
|
default: throw new Error("invalid interval")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const debitRulesToDebitAccessRules = (rule: Types.DebitRule[]): DebitAccessRules | undefined => {
|
||||||
|
let rules: DebitAccessRules | undefined = undefined
|
||||||
|
rule.forEach(r => {
|
||||||
|
if (!rules) {
|
||||||
|
rules = {}
|
||||||
|
}
|
||||||
|
const { rule } = r
|
||||||
|
switch (rule.type) {
|
||||||
|
case Types.DebitRule_rule_type.EXPIRATION_RULE:
|
||||||
|
|
||||||
|
rules[expirationRuleName] = [rule.expiration_rule.expires_at_unix.toString()]
|
||||||
|
break
|
||||||
|
case Types.DebitRule_rule_type.FREQUENCY_RULE:
|
||||||
|
const intervals = rule.frequency_rule.number_of_intervals.toString()
|
||||||
|
const unit = intervalTypeToUnit(rule.frequency_rule.interval)
|
||||||
|
rules[frequencyRuleName] = [intervals, unit, rule.frequency_rule.amount.toString()];
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
throw new Error("invalid rule")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return rules
|
||||||
|
}
|
||||||
|
|
||||||
|
const debitAccessRulesToDebitRules = (rules: DebitAccessRules | null): Types.DebitRule[] => {
|
||||||
|
if (!rules) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
return Object.entries(rules).map(([key, val]) => {
|
||||||
|
switch (key) {
|
||||||
|
case expirationRuleName:
|
||||||
|
return {
|
||||||
|
rule: {
|
||||||
|
type: Types.DebitRule_rule_type.EXPIRATION_RULE,
|
||||||
|
expiration_rule: {
|
||||||
|
expires_at_unix: +val[0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case frequencyRuleName:
|
||||||
|
return {
|
||||||
|
rule: {
|
||||||
|
type: Types.DebitRule_rule_type.FREQUENCY_RULE,
|
||||||
|
frequency_rule: {
|
||||||
|
number_of_intervals: +val[0],
|
||||||
|
interval: unitToIntervalType(val[1] as RecurringDebitTimeUnit),
|
||||||
|
amount: +val[2]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
throw new Error("invalid rule")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const nip68errs = {
|
||||||
|
1: "Request Denied Warning",
|
||||||
|
2: "Temporary Failure",
|
||||||
|
3: "Expired Request",
|
||||||
|
4: "Rate Limited",
|
||||||
|
5: "Invalid Amount",
|
||||||
|
6: "Invalid Request",
|
||||||
|
}
|
||||||
|
type HandleNdebitRes = { status: 'fail', debitRes: NdebitFailure }
|
||||||
|
| { status: 'invoicePaid', op: Types.UserOperation, app: Application, appUser: ApplicationUser, debitRes: NdebitSuccessPayment }
|
||||||
|
| { status: 'authRequired', liveDebitReq: Types.LiveDebitRequest, app: Application, appUser: ApplicationUser }
|
||||||
|
| { status: 'authOk', debitRes: NdebitSuccess }
|
||||||
|
export class DebitManager {
|
||||||
|
|
||||||
|
|
||||||
|
_nostrSend: NostrSend | null = null
|
||||||
|
|
||||||
|
applicationManager: ApplicationManager
|
||||||
|
|
||||||
|
storage: Storage
|
||||||
|
lnd: LND
|
||||||
|
logger = getLogger({ component: 'DebitManager' })
|
||||||
|
constructor(storage: Storage, lnd: LND, applicationManager: ApplicationManager) {
|
||||||
|
this.storage = storage
|
||||||
|
this.lnd = lnd
|
||||||
|
this.applicationManager = applicationManager
|
||||||
|
}
|
||||||
|
|
||||||
|
attachNostrSend = (nostrSend: NostrSend) => {
|
||||||
|
this._nostrSend = nostrSend
|
||||||
|
}
|
||||||
|
nostrSend: NostrSend = (initiator: SendInitiator, data: SendData, relays?: string[] | undefined) => {
|
||||||
|
if (!this._nostrSend) {
|
||||||
|
throw new Error("No nostrSend attached")
|
||||||
|
}
|
||||||
|
this._nostrSend(initiator, data, relays)
|
||||||
|
}
|
||||||
|
|
||||||
|
AuthorizeDebit = async (ctx: Types.UserContext, req: Types.DebitAuthorizationRequest): Promise<Types.DebitAuthorization> => {
|
||||||
|
const access = await this.storage.debitStorage.AddDebitAccess(ctx.app_user_id, {
|
||||||
|
authorize: true,
|
||||||
|
npub: req.authorize_npub,
|
||||||
|
rules: debitRulesToDebitAccessRules(req.rules)
|
||||||
|
})
|
||||||
|
if (req.request_id) {
|
||||||
|
this.sendDebitResponse({ res: 'ok' }, { pub: req.authorize_npub, id: req.request_id, appId: ctx.app_id })
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
debit_id: access.serial_id.toString(),
|
||||||
|
npub: req.authorize_npub,
|
||||||
|
authorized: true,
|
||||||
|
rules: req.rules
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GetDebitAuthorizations = async (ctx: Types.UserContext): Promise<Types.DebitAuthorizations> => {
|
||||||
|
const allDebitsAccesses = await this.storage.debitStorage.GetAllUserDebitAccess(ctx.app_user_id)
|
||||||
|
const debits: Types.DebitAuthorization[] = allDebitsAccesses.map(access => ({
|
||||||
|
debit_id: access.serial_id.toString(),
|
||||||
|
authorized: access.authorized,
|
||||||
|
npub: access.npub,
|
||||||
|
rules: debitAccessRulesToDebitRules(access.rules)
|
||||||
|
}))
|
||||||
|
return { debits }
|
||||||
|
}
|
||||||
|
|
||||||
|
EditDebit = async (ctx: Types.UserContext, req: Types.DebitAuthorizationRequest): Promise<void> => {
|
||||||
|
const access = await this.storage.debitStorage.GetDebitAccess(ctx.app_user_id, req.authorize_npub);
|
||||||
|
if (!access) {
|
||||||
|
throw new Error("Debit does not exist")
|
||||||
|
}
|
||||||
|
await this.storage.debitStorage.UpdateDebitAccessRules(ctx.app_user_id, req.authorize_npub, debitRulesToDebitAccessRules(req.rules));
|
||||||
|
}
|
||||||
|
|
||||||
|
BanDebit = async (ctx: Types.UserContext, req: Types.DebitOperation): Promise<void> => {
|
||||||
|
await this.storage.debitStorage.DenyDebitAccess(ctx.app_user_id, req.npub)
|
||||||
|
}
|
||||||
|
ResetDebit = async (ctx: Types.UserContext, req: Types.DebitOperation): Promise<void> => {
|
||||||
|
await this.storage.debitStorage.RemoveDebitAccess(ctx.app_user_id, req.npub)
|
||||||
|
}
|
||||||
|
|
||||||
|
RespondToDebit = async (ctx: Types.UserContext, req: Types.DebitResponse): Promise<void> => {
|
||||||
|
switch (req.response.type) {
|
||||||
|
case Types.DebitResponse_response_type.DENIED:
|
||||||
|
this.sendDebitResponse({ res: 'GFY', error: nip68errs[1], code: 1 }, { pub: req.npub, id: req.request_id, appId: ctx.app_id })
|
||||||
|
return
|
||||||
|
case Types.DebitResponse_response_type.INVOICE:
|
||||||
|
const app = await this.storage.applicationStorage.GetApplication(ctx.app_id)
|
||||||
|
const appUser = await this.storage.applicationStorage.GetApplicationUser(app, ctx.app_user_id)
|
||||||
|
const { op, payment } = await this.sendDebitPayment(ctx.app_id, ctx.app_user_id, req.npub, req.response.invoice)
|
||||||
|
const debitRes: NdebitSuccessPayment = { res: 'ok', preimage: payment.preimage }
|
||||||
|
this.notifyPaymentSuccess(appUser, debitRes, op, { appId: ctx.app_id, pub: req.npub, id: req.request_id })
|
||||||
|
return
|
||||||
|
default:
|
||||||
|
throw new Error("invalid response type")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handleNip68Debit = async (pointerdata: NdebitData, event: NostrEvent) => {
|
||||||
|
if (!this._nostrSend) {
|
||||||
|
throw new Error("No nostrSend attached")
|
||||||
|
}
|
||||||
|
console.log({ pointerdata, event })
|
||||||
|
const res = await this.payNdebitInvoice(event, pointerdata)
|
||||||
|
console.log({ debitRes: res })
|
||||||
|
if (res.status === 'fail' || res.status === 'authOk') {
|
||||||
|
const e = newNdebitResponse(JSON.stringify(res.debitRes), event)
|
||||||
|
this.nostrSend({ type: 'app', appId: event.appId }, { type: 'event', event: e, encrypt: { toPub: event.pub } })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const { appUser } = res
|
||||||
|
if (res.status === 'authRequired') {
|
||||||
|
const message: Types.LiveDebitRequest & { requestId: string, status: 'OK' } = { ...res.liveDebitReq, requestId: "GetLiveDebitRequests", status: 'OK' }
|
||||||
|
if (appUser.nostr_public_key) {// TODO - fix before support for http streams
|
||||||
|
this.nostrSend({ type: 'app', appId: event.appId }, { type: 'content', content: JSON.stringify(message), pub: appUser.nostr_public_key })
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const { op, debitRes } = res
|
||||||
|
this.notifyPaymentSuccess(appUser, debitRes, op, event)
|
||||||
|
}
|
||||||
|
|
||||||
|
notifyPaymentSuccess = (appUser: ApplicationUser, debitRes: NdebitSuccessPayment, op: Types.UserOperation, event: { pub: string, id: string, appId: string }) => {
|
||||||
|
const message: Types.LiveUserOperation & { requestId: string, status: 'OK' } = { operation: op, requestId: "GetLiveUserOperations", status: 'OK' }
|
||||||
|
if (appUser.nostr_public_key) { // TODO - fix before support for http streams
|
||||||
|
this.nostrSend({ type: 'app', appId: event.appId }, { type: 'content', content: JSON.stringify(message), pub: appUser.nostr_public_key })
|
||||||
|
}
|
||||||
|
this.sendDebitResponse(debitRes, event)
|
||||||
|
}
|
||||||
|
|
||||||
|
sendDebitResponse = (debitRes: NdebitFailure | NdebitSuccess | NdebitSuccessPayment, event: { pub: string, id: string, appId: string }) => {
|
||||||
|
const e = newNdebitResponse(JSON.stringify(debitRes), event)
|
||||||
|
this.nostrSend({ type: 'app', appId: event.appId }, { type: 'event', event: e, encrypt: { toPub: event.pub } })
|
||||||
|
}
|
||||||
|
|
||||||
|
payNdebitInvoice = async (event: NostrEvent, pointerdata: NdebitData): Promise<HandleNdebitRes> => {
|
||||||
|
try {
|
||||||
|
return await this.doNdebit(event, pointerdata)
|
||||||
|
} catch (e: any) {
|
||||||
|
this.logger(ERROR, e.message || e)
|
||||||
|
return { status: 'fail', debitRes: { res: 'GFY', error: nip68errs[1], code: 1 } }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
doNdebit = async (event: NostrEvent, pointerdata: NdebitData): Promise<HandleNdebitRes> => {
|
||||||
|
const { appId, pub: requestorPub } = event
|
||||||
|
const { amount_sats, pointer, bolt11, frequency } = pointerdata
|
||||||
|
if (!pointer) {
|
||||||
|
// TODO: debit from app owner balance
|
||||||
|
return { status: 'fail', debitRes: { res: 'GFY', error: nip68errs[1], code: 1 } }
|
||||||
|
}
|
||||||
|
const appUserId = pointer
|
||||||
|
const app = await this.storage.applicationStorage.GetApplication(appId)
|
||||||
|
const appUser = await this.storage.applicationStorage.GetApplicationUser(app, appUserId)
|
||||||
|
let decodedAmount = null
|
||||||
|
if (bolt11) {
|
||||||
|
const decoded = await this.lnd.DecodeInvoice(bolt11)
|
||||||
|
decodedAmount = decoded.numSatoshis
|
||||||
|
}
|
||||||
|
if (frequency) {
|
||||||
|
const amt = amount_sats || decodedAmount
|
||||||
|
if (!amt) {
|
||||||
|
return { status: 'fail', debitRes: { res: 'GFY', error: nip68errs[5], code: 5 } }
|
||||||
|
}
|
||||||
|
const debitAccess = await this.storage.debitStorage.GetDebitAccess(appUserId, requestorPub)
|
||||||
|
if (!debitAccess) {
|
||||||
|
return {
|
||||||
|
status: 'authRequired', app, appUser, liveDebitReq: {
|
||||||
|
request_id: event.id,
|
||||||
|
npub: requestorPub,
|
||||||
|
debit: {
|
||||||
|
type: Types.LiveDebitRequest_debit_type.FREQUENCY,
|
||||||
|
frequency: {
|
||||||
|
interval: unitToIntervalType(frequency.unit),
|
||||||
|
number_of_intervals: frequency.number,
|
||||||
|
amount: amt,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (!debitAccess.authorized) {
|
||||||
|
return { status: 'fail', debitRes: { res: 'GFY', error: nip68errs[1], code: 1 } }
|
||||||
|
}
|
||||||
|
return { status: 'authOk', debitRes: { res: 'ok' } }
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!bolt11) {
|
||||||
|
if (!amount_sats) {
|
||||||
|
const debitAccess = await this.storage.debitStorage.GetDebitAccess(appUserId, requestorPub)
|
||||||
|
if (!debitAccess) {
|
||||||
|
return {
|
||||||
|
status: 'authRequired', app, appUser, liveDebitReq: {
|
||||||
|
request_id: event.id,
|
||||||
|
npub: requestorPub,
|
||||||
|
debit: {
|
||||||
|
type: Types.LiveDebitRequest_debit_type.FULL_ACCESS,
|
||||||
|
full_access: {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (!debitAccess.authorized) {
|
||||||
|
return { status: 'fail', debitRes: { res: 'GFY', error: nip68errs[1], code: 1 } }
|
||||||
|
}
|
||||||
|
return { status: 'authOk', debitRes: { res: 'ok' } }
|
||||||
|
}
|
||||||
|
return { status: 'fail', debitRes: { res: 'GFY', error: nip68errs[6], code: 6 } }
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!decodedAmount) {
|
||||||
|
return { status: 'fail', debitRes: { res: 'GFY', error: nip68errs[6], code: 6 } }
|
||||||
|
}
|
||||||
|
if (amount_sats && amount_sats !== decodedAmount) {
|
||||||
|
return { status: 'fail', debitRes: { res: 'GFY', error: nip68errs[5], code: 5 } }
|
||||||
|
}
|
||||||
|
|
||||||
|
const authorization = await this.storage.debitStorage.GetDebitAccess(appUserId, requestorPub)
|
||||||
|
if (!authorization) {
|
||||||
|
return {
|
||||||
|
status: 'authRequired', app, appUser, liveDebitReq: {
|
||||||
|
request_id: event.id,
|
||||||
|
npub: requestorPub,
|
||||||
|
debit: {
|
||||||
|
type: Types.LiveDebitRequest_debit_type.INVOICE,
|
||||||
|
invoice: bolt11
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!authorization.authorized) {
|
||||||
|
return { status: 'fail', debitRes: { res: 'GFY', error: nip68errs[1], code: 1 } }
|
||||||
|
}
|
||||||
|
await this.validateAccessRules(authorization, app, appUser)
|
||||||
|
const { op, payment } = await this.sendDebitPayment(appId, appUserId, requestorPub, bolt11)
|
||||||
|
return { status: 'invoicePaid', op, app, appUser, debitRes: { res: 'ok', preimage: payment.preimage } }
|
||||||
|
}
|
||||||
|
|
||||||
|
sendDebitPayment = async (appId: string, appUserId: string, requestorPub: string, bolt11: string) => {
|
||||||
|
const payment = await this.applicationManager.PayAppUserInvoice(appId, { amount: 0, invoice: bolt11, user_identifier: appUserId, debit_npub: requestorPub })
|
||||||
|
await this.storage.debitStorage.IncrementDebitAccess(appUserId, requestorPub, payment.amount_paid + payment.service_fee + payment.network_fee)
|
||||||
|
const op = this.newPaymentOperation(payment, bolt11)
|
||||||
|
return { payment, op }
|
||||||
|
}
|
||||||
|
|
||||||
|
validateAccessRules = async (access: DebitAccess, app: Application, appUser: ApplicationUser): Promise<boolean> => {
|
||||||
|
const { rules } = access
|
||||||
|
if (!rules) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if (rules[expirationRuleName]) {
|
||||||
|
const [expiration] = rules[expirationRuleName]
|
||||||
|
if (+expiration < Date.now()) {
|
||||||
|
await this.storage.debitStorage.RemoveDebitAccess(access.app_user_id, access.npub)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (rules[frequencyRuleName]) {
|
||||||
|
const [number, unit, max] = rules[frequencyRuleName]
|
||||||
|
const intervalType = unitToIntervalType(unit as RecurringDebitTimeUnit)
|
||||||
|
const seconds = IntervalTypeToSeconds(intervalType) * (+number)
|
||||||
|
const sinceUnix = Math.floor(Date.now() / 1000) * seconds
|
||||||
|
const payments = await this.storage.paymentStorage.GetUserDebitPayments(appUser.user.user_id, sinceUnix, access.npub)
|
||||||
|
let total = 0
|
||||||
|
for (const payment of payments) {
|
||||||
|
total += payment.paid_amount
|
||||||
|
}
|
||||||
|
if (total > +max) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
newPaymentOperation = (payment: Types.PayInvoiceResponse, bolt11: string) => {
|
||||||
|
return {
|
||||||
|
amount: payment.amount_paid,
|
||||||
|
paidAtUnix: Math.floor(Date.now() / 1000),
|
||||||
|
inbound: false,
|
||||||
|
type: Types.UserOperationType.OUTGOING_INVOICE,
|
||||||
|
identifier: bolt11,
|
||||||
|
operationId: payment.operation_id,
|
||||||
|
network_fee: payment.network_fee,
|
||||||
|
service_fee: payment.service_fee,
|
||||||
|
confirmed: true,
|
||||||
|
tx_hash: "",
|
||||||
|
internal: payment.network_fee === 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const newNdebitResponse = (content: string, event: { pub: string, id: string }): UnsignedEvent => {
|
||||||
|
return {
|
||||||
|
content,
|
||||||
|
created_at: Math.floor(Date.now() / 1000),
|
||||||
|
kind: 21002,
|
||||||
|
pubkey: "",
|
||||||
|
tags: [
|
||||||
|
['p', event.pub],
|
||||||
|
['e', event.id],
|
||||||
|
],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -11,7 +11,7 @@ import { ERROR, getLogger, PubLogger } from "../helpers/logger.js"
|
||||||
import AppUserManager from "./appUserManager.js"
|
import AppUserManager from "./appUserManager.js"
|
||||||
import { Application } from '../storage/entity/Application.js'
|
import { Application } from '../storage/entity/Application.js'
|
||||||
import { UserReceivingInvoice } from '../storage/entity/UserReceivingInvoice.js'
|
import { UserReceivingInvoice } from '../storage/entity/UserReceivingInvoice.js'
|
||||||
import { UnsignedEvent } from '../nostr/tools/event.js'
|
import { UnsignedEvent } from 'nostr-tools'
|
||||||
import { NostrEvent, NostrSend } from '../nostr/handler.js'
|
import { NostrEvent, NostrSend } from '../nostr/handler.js'
|
||||||
import MetricsManager from '../metrics/index.js'
|
import MetricsManager from '../metrics/index.js'
|
||||||
import { LoggedEvent } from '../storage/eventsLog.js'
|
import { LoggedEvent } from '../storage/eventsLog.js'
|
||||||
|
|
@ -22,6 +22,7 @@ import { RugPullTracker } from "./rugPullTracker.js"
|
||||||
import { AdminManager } from "./adminManager.js"
|
import { AdminManager } from "./adminManager.js"
|
||||||
import { Unlocker } from "./unlocker.js"
|
import { Unlocker } from "./unlocker.js"
|
||||||
import { defaultInvoiceExpiry } from "../storage/paymentStorage.js"
|
import { defaultInvoiceExpiry } from "../storage/paymentStorage.js"
|
||||||
|
import { DebitManager } from "./debitManager.js"
|
||||||
|
|
||||||
type UserOperationsSub = {
|
type UserOperationsSub = {
|
||||||
id: string
|
id: string
|
||||||
|
|
@ -32,6 +33,7 @@ type UserOperationsSub = {
|
||||||
}
|
}
|
||||||
const appTag = "Lightning.Pub"
|
const appTag = "Lightning.Pub"
|
||||||
export type NofferData = { offer: string, amount?: number }
|
export type NofferData = { offer: string, amount?: number }
|
||||||
|
|
||||||
export default class {
|
export default class {
|
||||||
storage: Storage
|
storage: Storage
|
||||||
lnd: LND
|
lnd: LND
|
||||||
|
|
@ -46,6 +48,7 @@ export default class {
|
||||||
metricsManager: MetricsManager
|
metricsManager: MetricsManager
|
||||||
liquidityManager: LiquidityManager
|
liquidityManager: LiquidityManager
|
||||||
liquidityProvider: LiquidityProvider
|
liquidityProvider: LiquidityProvider
|
||||||
|
debitManager: DebitManager
|
||||||
utils: Utils
|
utils: Utils
|
||||||
rugPullTracker: RugPullTracker
|
rugPullTracker: RugPullTracker
|
||||||
unlocker: Unlocker
|
unlocker: Unlocker
|
||||||
|
|
@ -67,6 +70,7 @@ export default class {
|
||||||
this.productManager = new ProductManager(this.storage, this.paymentManager, this.settings)
|
this.productManager = new ProductManager(this.storage, this.paymentManager, this.settings)
|
||||||
this.applicationManager = new ApplicationManager(this.storage, this.settings, this.paymentManager)
|
this.applicationManager = new ApplicationManager(this.storage, this.settings, this.paymentManager)
|
||||||
this.appUserManager = new AppUserManager(this.storage, this.settings, this.applicationManager)
|
this.appUserManager = new AppUserManager(this.storage, this.settings, this.applicationManager)
|
||||||
|
this.debitManager = new DebitManager(this.storage, this.lnd, this.applicationManager)
|
||||||
}
|
}
|
||||||
|
|
||||||
Stop() {
|
Stop() {
|
||||||
|
|
@ -84,6 +88,7 @@ export default class {
|
||||||
attachNostrSend(f: NostrSend) {
|
attachNostrSend(f: NostrSend) {
|
||||||
this.nostrSend = f
|
this.nostrSend = f
|
||||||
this.liquidityProvider.attachNostrSend(f)
|
this.liquidityProvider.attachNostrSend(f)
|
||||||
|
this.debitManager.attachNostrSend(f)
|
||||||
}
|
}
|
||||||
|
|
||||||
htlcCb: HtlcCb = (e) => {
|
htlcCb: HtlcCb = (e) => {
|
||||||
|
|
@ -223,7 +228,8 @@ export default class {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
await fetch(url + "&ok=true")
|
const symbol = url.includes('?') ? "&" : "?"
|
||||||
|
await fetch(url + symbol + "ok=true")
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
log(ERROR, "error sending paid callback for invoice", err.message || "")
|
log(ERROR, "error sending paid callback for invoice", err.message || "")
|
||||||
}
|
}
|
||||||
|
|
@ -313,6 +319,8 @@ export default class {
|
||||||
this.nostrSend({ type: 'app', appId: event.appId }, { type: 'event', event: e, encrypt: { toPub: event.pub } })
|
this.nostrSend({ type: 'app', appId: event.appId }, { type: 'event', event: e, encrypt: { toPub: event.pub } })
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const codeToMessage = (code: number) => {
|
const codeToMessage = (code: number) => {
|
||||||
|
|
@ -338,3 +346,5 @@ const newNofferResponse = (content: string, event: NostrEvent): UnsignedEvent =>
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,6 @@ import { LoadMainSettingsFromEnv, MainSettings } from "./settings.js"
|
||||||
import { Utils } from "../helpers/utilsWrapper.js"
|
import { Utils } from "../helpers/utilsWrapper.js"
|
||||||
import { Wizard } from "../wizard/index.js"
|
import { Wizard } from "../wizard/index.js"
|
||||||
import { AdminManager } from "./adminManager.js"
|
import { AdminManager } from "./adminManager.js"
|
||||||
import { encodeNprofile } from "../../custom-nip19.js"
|
|
||||||
export type AppData = {
|
export type AppData = {
|
||||||
privateKey: string;
|
privateKey: string;
|
||||||
publicKey: string;
|
publicKey: string;
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,9 @@
|
||||||
import newNostrClient from '../../../proto/autogenerated/ts/nostr_client.js'
|
import newNostrClient from '../../../proto/autogenerated/ts/nostr_client.js'
|
||||||
import { NostrRequest } from '../../../proto/autogenerated/ts/nostr_transport.js'
|
import { NostrRequest } from '../../../proto/autogenerated/ts/nostr_transport.js'
|
||||||
import * as Types from '../../../proto/autogenerated/ts/types.js'
|
import * as Types from '../../../proto/autogenerated/ts/types.js'
|
||||||
import { decodeNprofile } from '../../custom-nip19.js'
|
|
||||||
import { getLogger } from '../helpers/logger.js'
|
import { getLogger } from '../helpers/logger.js'
|
||||||
import { Utils } from '../helpers/utilsWrapper.js'
|
import { Utils } from '../helpers/utilsWrapper.js'
|
||||||
import { NostrEvent, NostrSend } from '../nostr/handler.js'
|
import { NostrEvent, NostrSend } from '../nostr/handler.js'
|
||||||
import { relayInit } from '../nostr/tools/relay.js'
|
|
||||||
import { InvoicePaidCb } from '../lnd/settings.js'
|
import { InvoicePaidCb } from '../lnd/settings.js'
|
||||||
import Storage from '../storage/index.js'
|
import Storage from '../storage/index.js'
|
||||||
export type LiquidityRequest = { action: 'spend' | 'receive', amount: number }
|
export type LiquidityRequest = { action: 'spend' | 'receive', amount: number }
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ import { UserReceivingAddress } from '../storage/entity/UserReceivingAddress.js'
|
||||||
import { AddressPaidCb, InvoicePaidCb, PaidInvoice } from '../lnd/settings.js'
|
import { AddressPaidCb, InvoicePaidCb, PaidInvoice } from '../lnd/settings.js'
|
||||||
import { UserReceivingInvoice, ZapInfo } from '../storage/entity/UserReceivingInvoice.js'
|
import { UserReceivingInvoice, ZapInfo } from '../storage/entity/UserReceivingInvoice.js'
|
||||||
import { Payment_PaymentStatus, SendCoinsResponse } from '../../../proto/lnd/lightning.js'
|
import { Payment_PaymentStatus, SendCoinsResponse } from '../../../proto/lnd/lightning.js'
|
||||||
import { Event, verifiedSymbol, verifySignature } from '../nostr/tools/event.js'
|
import { Event, verifiedSymbol, verifyEvent } from 'nostr-tools'
|
||||||
import { AddressReceivingTransaction } from '../storage/entity/AddressReceivingTransaction.js'
|
import { AddressReceivingTransaction } from '../storage/entity/AddressReceivingTransaction.js'
|
||||||
import { UserTransactionPayment } from '../storage/entity/UserTransactionPayment.js'
|
import { UserTransactionPayment } from '../storage/entity/UserTransactionPayment.js'
|
||||||
import { Watchdog } from './watchdog.js'
|
import { Watchdog } from './watchdog.js'
|
||||||
|
|
@ -286,9 +286,9 @@ export default class {
|
||||||
}
|
}
|
||||||
let paymentInfo = { preimage: "", amtPaid: 0, networkFee: 0, serialId: 0 }
|
let paymentInfo = { preimage: "", amtPaid: 0, networkFee: 0, serialId: 0 }
|
||||||
if (internalInvoice) {
|
if (internalInvoice) {
|
||||||
paymentInfo = await this.PayInternalInvoice(userId, internalInvoice, { payAmount, serviceFee }, linkedApplication)
|
paymentInfo = await this.PayInternalInvoice(userId, internalInvoice, { payAmount, serviceFee }, linkedApplication, req.debit_npub)
|
||||||
} else {
|
} else {
|
||||||
paymentInfo = await this.PayExternalInvoice(userId, req.invoice, { payAmount, serviceFee, amountForLnd: req.amount }, linkedApplication)
|
paymentInfo = await this.PayExternalInvoice(userId, req.invoice, { payAmount, serviceFee, amountForLnd: req.amount }, linkedApplication, req.debit_npub)
|
||||||
}
|
}
|
||||||
if (isAppUserPayment && serviceFee > 0) {
|
if (isAppUserPayment && serviceFee > 0) {
|
||||||
await this.storage.userStorage.IncrementUserBalance(linkedApplication.owner.user_id, serviceFee, "fees")
|
await this.storage.userStorage.IncrementUserBalance(linkedApplication.owner.user_id, serviceFee, "fees")
|
||||||
|
|
@ -304,7 +304,7 @@ export default class {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async PayExternalInvoice(userId: string, invoice: string, amounts: { payAmount: number, serviceFee: number, amountForLnd: number }, linkedApplication: Application) {
|
async PayExternalInvoice(userId: string, invoice: string, amounts: { payAmount: number, serviceFee: number, amountForLnd: number }, linkedApplication: Application, debitNpub?: string) {
|
||||||
if (this.settings.disableExternalPayments) {
|
if (this.settings.disableExternalPayments) {
|
||||||
throw new Error("something went wrong sending payment, please try again later")
|
throw new Error("something went wrong sending payment, please try again later")
|
||||||
}
|
}
|
||||||
|
|
@ -325,7 +325,7 @@ export default class {
|
||||||
const pendingPayment = await this.storage.txQueue.PushToQueue({
|
const pendingPayment = await this.storage.txQueue.PushToQueue({
|
||||||
dbTx: true, description: "payment started", exec: async tx => {
|
dbTx: true, description: "payment started", exec: async tx => {
|
||||||
await this.storage.userStorage.DecrementUserBalance(userId, totalAmountToDecrement + routingFeeLimit, invoice, tx)
|
await this.storage.userStorage.DecrementUserBalance(userId, totalAmountToDecrement + routingFeeLimit, invoice, tx)
|
||||||
return await this.storage.paymentStorage.AddPendingExternalPayment(userId, invoice, { payAmount, serviceFee, networkFee: routingFeeLimit }, linkedApplication, provider, tx)
|
return await this.storage.paymentStorage.AddPendingExternalPayment(userId, invoice, { payAmount, serviceFee, networkFee: routingFeeLimit }, linkedApplication, provider, tx, debitNpub)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
this.log("ready to pay")
|
this.log("ready to pay")
|
||||||
|
|
@ -348,7 +348,7 @@ export default class {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async PayInternalInvoice(userId: string, internalInvoice: UserReceivingInvoice, amounts: { payAmount: number, serviceFee: number }, linkedApplication: Application) {
|
async PayInternalInvoice(userId: string, internalInvoice: UserReceivingInvoice, amounts: { payAmount: number, serviceFee: number }, linkedApplication: Application, debitNpub?: string) {
|
||||||
if (internalInvoice.paid_at_unix > 0) {
|
if (internalInvoice.paid_at_unix > 0) {
|
||||||
throw new Error("this invoice was already paid")
|
throw new Error("this invoice was already paid")
|
||||||
}
|
}
|
||||||
|
|
@ -357,7 +357,7 @@ export default class {
|
||||||
await this.storage.userStorage.DecrementUserBalance(userId, totalAmountToDecrement, internalInvoice.invoice)
|
await this.storage.userStorage.DecrementUserBalance(userId, totalAmountToDecrement, internalInvoice.invoice)
|
||||||
try {
|
try {
|
||||||
await this.invoicePaidCb(internalInvoice.invoice, payAmount, 'internal')
|
await this.invoicePaidCb(internalInvoice.invoice, payAmount, 'internal')
|
||||||
const newPayment = await this.storage.paymentStorage.AddInternalPayment(userId, internalInvoice.invoice, payAmount, serviceFee, linkedApplication)
|
const newPayment = await this.storage.paymentStorage.AddInternalPayment(userId, internalInvoice.invoice, payAmount, serviceFee, linkedApplication, debitNpub)
|
||||||
this.utils.stateBundler.AddTxPoint('paidAnInvoice', payAmount, { used: 'internal', from: 'user' })
|
this.utils.stateBundler.AddTxPoint('paidAnInvoice', payAmount, { used: 'internal', from: 'user' })
|
||||||
return { preimage: "", amtPaid: payAmount, networkFee: 0, serialId: newPayment.serial_id }
|
return { preimage: "", amtPaid: payAmount, networkFee: 0, serialId: newPayment.serial_id }
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|
@ -567,7 +567,7 @@ export default class {
|
||||||
validateZapEvent(event: string, amt: number): ZapInfo {
|
validateZapEvent(event: string, amt: number): ZapInfo {
|
||||||
const nostrEvent = JSON.parse(event) as Event
|
const nostrEvent = JSON.parse(event) as Event
|
||||||
delete nostrEvent[verifiedSymbol]
|
delete nostrEvent[verifiedSymbol]
|
||||||
const verified = verifySignature(nostrEvent)
|
const verified = verifyEvent(nostrEvent)
|
||||||
if (!verified) {
|
if (!verified) {
|
||||||
throw new Error("nostr event not valid")
|
throw new Error("nostr event not valid")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,8 @@ 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'
|
||||||
import { encodeNoffer, PriceType } from '../../custom-nip19.js'
|
import { nip19 } from 'nostr-tools'
|
||||||
|
const { nofferEncode, OfferPriceType } = nip19
|
||||||
|
|
||||||
export default class {
|
export default class {
|
||||||
storage: Storage
|
storage: Storage
|
||||||
|
|
@ -26,7 +27,7 @@ export default class {
|
||||||
id: newProduct.product_id,
|
id: newProduct.product_id,
|
||||||
name: newProduct.name,
|
name: newProduct.name,
|
||||||
price_sats: newProduct.price_sats,
|
price_sats: newProduct.price_sats,
|
||||||
noffer: encodeNoffer({ pubkey: user.user_id, offer: offer, priceType: PriceType.fixed, price: newProduct.price_sats, relay: "" })
|
noffer: nofferEncode({ pubkey: user.user_id, offer: offer, priceType: OfferPriceType.Fixed, price: newProduct.price_sats, relay: "" })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,15 @@
|
||||||
//import { SimplePool, Sub, Event, UnsignedEvent, getEventHash, signEvent } from 'nostr-tools'
|
//import { SimplePool, Sub, Event, UnsignedEvent, getEventHash, signEvent } from 'nostr-tools'
|
||||||
import { SimplePool, Sub, Event, UnsignedEvent, getEventHash, finishEvent, relayInit } from './tools/index.js'
|
import WebSocket from 'ws'
|
||||||
import { encryptData, decryptData, getSharedSecret, decodePayload, encodePayload, EncryptedData } from './nip44.js'
|
Object.assign(global, { WebSocket: WebSocket });
|
||||||
|
import { SimplePool, Event, UnsignedEvent, getEventHash, finalizeEvent, Relay, nip44 } from 'nostr-tools'
|
||||||
|
//import { encryptData, decryptData, getSharedSecret, decodePayload, encodePayload, EncryptedData, nip44 } from 'nostr-tools'
|
||||||
import { ERROR, getLogger } from '../helpers/logger.js'
|
import { ERROR, getLogger } from '../helpers/logger.js'
|
||||||
import { encodeNprofile } from '../../custom-nip19.js'
|
import { nip19 } from 'nostr-tools'
|
||||||
|
import { encrypt as encryptV1, decrypt as decryptV1, getSharedSecret as getConversationKeyV1 } from './nip44v1.js'
|
||||||
|
const { nprofileEncode } = nip19
|
||||||
|
const { v2 } = nip44
|
||||||
|
const { encrypt: encryptV2, decrypt: decryptV2, utils } = v2
|
||||||
|
const { getConversationKey: getConversationKeyV2 } = utils
|
||||||
const handledEvents: string[] = [] // TODO: - big memory leak here, add TTL
|
const handledEvents: string[] = [] // TODO: - big memory leak here, add TTL
|
||||||
type AppInfo = { appId: string, publicKey: string, privateKey: string, name: string }
|
type AppInfo = { appId: string, publicKey: string, privateKey: string, name: string }
|
||||||
type ClientInfo = { clientId: string, publicKey: string, privateKey: string, name: string }
|
type ClientInfo = { clientId: string, publicKey: string, privateKey: string, name: string }
|
||||||
|
|
@ -90,11 +97,10 @@ const sendToNostr: NostrSend = (initiator, data, relays) => {
|
||||||
subProcessHandler.Send(initiator, data, relays)
|
subProcessHandler.Send(initiator, data, relays)
|
||||||
}
|
}
|
||||||
send({ type: 'ready' })
|
send({ type: 'ready' })
|
||||||
const supportedKinds = [21000, 21001]
|
const supportedKinds = [21000, 21001, 21002]
|
||||||
export default class Handler {
|
export default class Handler {
|
||||||
pool = new SimplePool()
|
pool = new SimplePool()
|
||||||
settings: NostrSettings
|
settings: NostrSettings
|
||||||
subs: Sub[] = []
|
|
||||||
apps: Record<string, AppInfo> = {}
|
apps: Record<string, AppInfo> = {}
|
||||||
eventCallback: (event: NostrEvent) => void
|
eventCallback: (event: NostrEvent) => void
|
||||||
log = getLogger({ component: "nostrMiddleware" })
|
log = getLogger({ component: "nostrMiddleware" })
|
||||||
|
|
@ -102,7 +108,7 @@ export default class Handler {
|
||||||
this.settings = settings
|
this.settings = settings
|
||||||
this.log("connecting to relays:", settings.relays)
|
this.log("connecting to relays:", settings.relays)
|
||||||
this.settings.apps.forEach(app => {
|
this.settings.apps.forEach(app => {
|
||||||
this.log("appId:", app.appId, "pubkey:", app.publicKey, "nprofile:", encodeNprofile({ pubkey: app.publicKey, relays: settings.relays }))
|
this.log("appId:", app.appId, "pubkey:", app.publicKey, "nprofile:", nprofileEncode({ pubkey: app.publicKey, relays: settings.relays }))
|
||||||
})
|
})
|
||||||
this.eventCallback = eventCallback
|
this.eventCallback = eventCallback
|
||||||
this.settings.apps.forEach(app => {
|
this.settings.apps.forEach(app => {
|
||||||
|
|
@ -114,9 +120,13 @@ export default class Handler {
|
||||||
async Connect() {
|
async Connect() {
|
||||||
const log = getLogger({})
|
const log = getLogger({})
|
||||||
log("conneting to relay...", this.settings.relays[0])
|
log("conneting to relay...", this.settings.relays[0])
|
||||||
const relay = relayInit(this.settings.relays[0]) // TODO: create multiple conns for multiple relays
|
let relay: Relay | null = null
|
||||||
|
//const relay = relayInit(this.settings.relays[0]) // TODO: create multiple conns for multiple relays
|
||||||
try {
|
try {
|
||||||
await relay.connect()
|
relay = await Relay.connect(this.settings.relays[0])
|
||||||
|
if (!relay.connected) {
|
||||||
|
throw new Error("failed to connect to relay")
|
||||||
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
log("failed to connect to relay, will try again in 2 seconds")
|
log("failed to connect to relay, will try again in 2 seconds")
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
|
|
@ -124,34 +134,36 @@ export default class Handler {
|
||||||
}, 2000)
|
}, 2000)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
log("connected, subbing...")
|
log("connected, subbing...")
|
||||||
relay.on('disconnect', () => {
|
relay.onclose = (() => {
|
||||||
log("relay disconnected, will try to reconnect")
|
log("relay disconnected, will try to reconnect")
|
||||||
relay.close()
|
relay.close()
|
||||||
this.Connect()
|
this.Connect()
|
||||||
})
|
})
|
||||||
const sub = relay.sub([
|
const sub = relay.subscribe([
|
||||||
{
|
{
|
||||||
since: Math.ceil(Date.now() / 1000),
|
since: Math.ceil(Date.now() / 1000),
|
||||||
kinds: supportedKinds,
|
kinds: supportedKinds,
|
||||||
'#p': Object.keys(this.apps),
|
'#p': Object.keys(this.apps),
|
||||||
}
|
}
|
||||||
])
|
], {
|
||||||
sub.on('eose', () => {
|
oneose: () => {
|
||||||
log("up to date with nostr events")
|
log("up to date with nostr events")
|
||||||
})
|
},
|
||||||
sub.on('event', async (e) => {
|
onevent: async (e) => {
|
||||||
if (!supportedKinds.includes(e.kind) || !e.pubkey) {
|
if (!supportedKinds.includes(e.kind) || !e.pubkey) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const pubTags = e.tags.find(tags => tags && tags.length > 1 && tags[0] === 'p')
|
const pubTags = e.tags.find(tags => tags && tags.length > 1 && tags[0] === 'p')
|
||||||
if (!pubTags) {
|
if (!pubTags) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const app = this.apps[pubTags[1]]
|
const app = this.apps[pubTags[1]]
|
||||||
if (app) {
|
if (app) {
|
||||||
await this.processEvent(e, app)
|
await this.processEvent(e, app)
|
||||||
return
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
@ -167,8 +179,11 @@ export default class Handler {
|
||||||
const startAtNano = process.hrtime.bigint().toString()
|
const startAtNano = process.hrtime.bigint().toString()
|
||||||
let content = ""
|
let content = ""
|
||||||
try {
|
try {
|
||||||
const decoded = decodePayload(e.content)
|
if (e.kind === 21000) {
|
||||||
content = await decryptData(decoded, getSharedSecret(app.privateKey, e.pubkey))
|
content = decryptV1(e.content, getConversationKeyV1(app.privateKey, e.pubkey))
|
||||||
|
} else {
|
||||||
|
content = decryptV2(e.content, getConversationKeyV2(Buffer.from(app.privateKey, 'hex'), e.pubkey))
|
||||||
|
}
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
this.log(ERROR, "failed to decrypt event", e.message, e.content)
|
this.log(ERROR, "failed to decrypt event", e.message, e.content)
|
||||||
return
|
return
|
||||||
|
|
@ -179,12 +194,12 @@ export default class Handler {
|
||||||
|
|
||||||
async Send(initiator: SendInitiator, data: SendData, relays?: string[]) {
|
async Send(initiator: SendInitiator, data: SendData, relays?: string[]) {
|
||||||
const keys = this.GetSendKeys(initiator)
|
const keys = this.GetSendKeys(initiator)
|
||||||
|
const privateKey = Buffer.from(keys.privateKey, 'hex')
|
||||||
let toSign: UnsignedEvent
|
let toSign: UnsignedEvent
|
||||||
if (data.type === 'content') {
|
if (data.type === 'content') {
|
||||||
let content: string
|
let content: string
|
||||||
try {
|
try {
|
||||||
const decoded = await encryptData(data.content, getSharedSecret(keys.privateKey, data.pub))
|
content = encryptV1(data.content, getConversationKeyV1(keys.privateKey, data.pub))
|
||||||
content = encodePayload(decoded)
|
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
this.log(ERROR, "failed to encrypt content", e.message, data.content)
|
this.log(ERROR, "failed to encrypt content", e.message, data.content)
|
||||||
return
|
return
|
||||||
|
|
@ -197,11 +212,11 @@ export default class Handler {
|
||||||
tags: [['p', data.pub]],
|
tags: [['p', data.pub]],
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
console.log(data)
|
||||||
toSign = data.event
|
toSign = data.event
|
||||||
if (data.encrypt) {
|
if (data.encrypt) {
|
||||||
try {
|
try {
|
||||||
const content = await encryptData(data.event.content, getSharedSecret(keys.privateKey, data.encrypt.toPub))
|
toSign.content = encryptV2(data.event.content, getConversationKeyV2(Buffer.from(keys.privateKey, 'hex'), data.encrypt.toPub))
|
||||||
toSign.content = encodePayload(content)
|
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
this.log(ERROR, "failed to encrypt content", e.message)
|
this.log(ERROR, "failed to encrypt content", e.message)
|
||||||
return
|
return
|
||||||
|
|
@ -212,7 +227,7 @@ export default class Handler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const signed = finishEvent(toSign, keys.privateKey)
|
const signed = finalizeEvent(toSign, Buffer.from(keys.privateKey, 'hex'))
|
||||||
let sent = false
|
let sent = false
|
||||||
const log = getLogger({ appName: keys.name })
|
const log = getLogger({ appName: keys.name })
|
||||||
await Promise.all(this.pool.publish(relays || this.settings.relays, signed).map(async p => {
|
await Promise.all(this.pool.publish(relays || this.settings.relays, signed).map(async p => {
|
||||||
|
|
|
||||||
|
|
@ -12,17 +12,15 @@ export const getSharedSecret = (privateKey: string, publicKey: string) => {
|
||||||
return sha256(key.slice(1, 33));
|
return sha256(key.slice(1, 33));
|
||||||
}
|
}
|
||||||
|
|
||||||
export const encryptData = (content: string, sharedSecret: Uint8Array) => {
|
export const encrypt = (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 encodePayload({ ciphertext, nonce });
|
||||||
ciphertext: Uint8Array.from(ciphertext),
|
|
||||||
nonce: nonce,
|
|
||||||
} as EncryptedData;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const decryptData = (payload: EncryptedData, sharedSecret: Uint8Array) => {
|
export const decrypt = (content: string, sharedSecret: Uint8Array) => {
|
||||||
|
const payload = decodePayload(content);
|
||||||
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;
|
||||||
|
|
@ -1,144 +0,0 @@
|
||||||
import { schnorr } from '@noble/curves/secp256k1'
|
|
||||||
import { sha256 } from '@noble/hashes/sha256'
|
|
||||||
import { bytesToHex } from '@noble/hashes/utils'
|
|
||||||
|
|
||||||
import { getPublicKey } from './keys.js'
|
|
||||||
import { utf8Encoder } from './utils.js'
|
|
||||||
|
|
||||||
/** Designates a verified event signature. */
|
|
||||||
export const verifiedSymbol = Symbol('verified')
|
|
||||||
|
|
||||||
/** @deprecated Use numbers instead. */
|
|
||||||
/* eslint-disable no-unused-vars */
|
|
||||||
export enum Kind {
|
|
||||||
Metadata = 0,
|
|
||||||
Text = 1,
|
|
||||||
RecommendRelay = 2,
|
|
||||||
Contacts = 3,
|
|
||||||
EncryptedDirectMessage = 4,
|
|
||||||
EventDeletion = 5,
|
|
||||||
Repost = 6,
|
|
||||||
Reaction = 7,
|
|
||||||
BadgeAward = 8,
|
|
||||||
ChannelCreation = 40,
|
|
||||||
ChannelMetadata = 41,
|
|
||||||
ChannelMessage = 42,
|
|
||||||
ChannelHideMessage = 43,
|
|
||||||
ChannelMuteUser = 44,
|
|
||||||
Blank = 255,
|
|
||||||
Report = 1984,
|
|
||||||
ZapRequest = 9734,
|
|
||||||
Zap = 9735,
|
|
||||||
RelayList = 10002,
|
|
||||||
ClientAuth = 22242,
|
|
||||||
HttpAuth = 27235,
|
|
||||||
ProfileBadge = 30008,
|
|
||||||
BadgeDefinition = 30009,
|
|
||||||
Article = 30023,
|
|
||||||
FileMetadata = 1063,
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Event<K extends number = number> {
|
|
||||||
kind: K
|
|
||||||
tags: string[][]
|
|
||||||
content: string
|
|
||||||
created_at: number
|
|
||||||
pubkey: string
|
|
||||||
id: string
|
|
||||||
sig: string
|
|
||||||
[verifiedSymbol]?: boolean
|
|
||||||
}
|
|
||||||
|
|
||||||
export type EventTemplate<K extends number = number> = Pick<Event<K>, 'kind' | 'tags' | 'content' | 'created_at'>
|
|
||||||
export type UnsignedEvent<K extends number = number> = Pick<
|
|
||||||
Event<K>,
|
|
||||||
'kind' | 'tags' | 'content' | 'created_at' | 'pubkey'
|
|
||||||
>
|
|
||||||
|
|
||||||
/** An event whose signature has been verified. */
|
|
||||||
export interface VerifiedEvent<K extends number = number> extends Event<K> {
|
|
||||||
[verifiedSymbol]: true
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getBlankEvent(): EventTemplate<Kind.Blank>
|
|
||||||
export function getBlankEvent<K extends number>(kind: K): EventTemplate<K>
|
|
||||||
export function getBlankEvent<K>(kind: K | Kind.Blank = Kind.Blank) {
|
|
||||||
return {
|
|
||||||
kind,
|
|
||||||
content: '',
|
|
||||||
tags: [],
|
|
||||||
created_at: 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function finishEvent<K extends number = number>(t: EventTemplate<K>, privateKey: string): VerifiedEvent<K> {
|
|
||||||
const event = t as VerifiedEvent<K>
|
|
||||||
event.pubkey = getPublicKey(privateKey)
|
|
||||||
event.id = getEventHash(event)
|
|
||||||
event.sig = getSignature(event, privateKey)
|
|
||||||
event[verifiedSymbol] = true
|
|
||||||
return event
|
|
||||||
}
|
|
||||||
|
|
||||||
export function serializeEvent(evt: UnsignedEvent<number>): string {
|
|
||||||
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])
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getEventHash(event: UnsignedEvent<number>): string {
|
|
||||||
let eventHash = sha256(utf8Encoder.encode(serializeEvent(event)))
|
|
||||||
return bytesToHex(eventHash)
|
|
||||||
}
|
|
||||||
|
|
||||||
const isRecord = (obj: unknown): obj is Record<string, unknown> => obj instanceof Object
|
|
||||||
|
|
||||||
export function validateEvent<T>(event: T): event is T & UnsignedEvent<number> {
|
|
||||||
if (!isRecord(event)) return false
|
|
||||||
if (typeof event.kind !== 'number') return false
|
|
||||||
if (typeof event.content !== 'string') return false
|
|
||||||
if (typeof event.created_at !== 'number') return false
|
|
||||||
if (typeof event.pubkey !== 'string') return false
|
|
||||||
if (!event.pubkey.match(/^[a-f0-9]{64}$/)) return false
|
|
||||||
|
|
||||||
if (!Array.isArray(event.tags)) return false
|
|
||||||
for (let i = 0; i < event.tags.length; i++) {
|
|
||||||
let tag = event.tags[i]
|
|
||||||
if (!Array.isArray(tag)) return false
|
|
||||||
for (let j = 0; j < tag.length; j++) {
|
|
||||||
if (typeof tag[j] === 'object') return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 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> {
|
|
||||||
//@ts-ignore
|
|
||||||
if (typeof event[verifiedSymbol] === 'boolean') return event[verifiedSymbol]
|
|
||||||
|
|
||||||
const hash = getEventHash(event)
|
|
||||||
if (hash !== event.id) {
|
|
||||||
return (event[verifiedSymbol] = false)
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
return (event[verifiedSymbol] = schnorr.verify(event.sig, hash, event.pubkey))
|
|
||||||
} catch (err) {
|
|
||||||
return (event[verifiedSymbol] = false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @deprecated Use `getSignature` instead. */
|
|
||||||
export function signEvent(event: UnsignedEvent<number>, key: string): string {
|
|
||||||
console.warn(
|
|
||||||
'nostr-tools: `signEvent` is deprecated and will be removed or changed in the future. Please use `getSignature` instead.',
|
|
||||||
)
|
|
||||||
return getSignature(event, key)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Calculate the signature for an event. */
|
|
||||||
export function getSignature(event: UnsignedEvent<number>, key: string): string {
|
|
||||||
return bytesToHex(schnorr.sign(getEventHash(event), key))
|
|
||||||
}
|
|
||||||
|
|
@ -1,41 +0,0 @@
|
||||||
export function getHex64(json: string, field: string): string {
|
|
||||||
let len = field.length + 3
|
|
||||||
let idx = json.indexOf(`"${field}":`) + len
|
|
||||||
let s = json.slice(idx).indexOf(`"`) + idx + 1
|
|
||||||
return json.slice(s, s + 64)
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getInt(json: string, field: string): number {
|
|
||||||
let len = field.length
|
|
||||||
let idx = json.indexOf(`"${field}":`) + len + 3
|
|
||||||
let sliced = json.slice(idx)
|
|
||||||
let end = Math.min(sliced.indexOf(','), sliced.indexOf('}'))
|
|
||||||
return parseInt(sliced.slice(0, end), 10)
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getSubscriptionId(json: string): string | null {
|
|
||||||
let idx = json.slice(0, 22).indexOf(`"EVENT"`)
|
|
||||||
if (idx === -1) return null
|
|
||||||
|
|
||||||
let pstart = json.slice(idx + 7 + 1).indexOf(`"`)
|
|
||||||
if (pstart === -1) return null
|
|
||||||
let start = idx + 7 + 1 + pstart
|
|
||||||
|
|
||||||
let pend = json.slice(start + 1, 80).indexOf(`"`)
|
|
||||||
if (pend === -1) return null
|
|
||||||
let end = start + 1 + pend
|
|
||||||
|
|
||||||
return json.slice(start + 1, end)
|
|
||||||
}
|
|
||||||
|
|
||||||
export function matchEventId(json: string, id: string): boolean {
|
|
||||||
return id === getHex64(json, 'id')
|
|
||||||
}
|
|
||||||
|
|
||||||
export function matchEventPubkey(json: string, pubkey: string): boolean {
|
|
||||||
return pubkey === getHex64(json, 'pubkey')
|
|
||||||
}
|
|
||||||
|
|
||||||
export function matchEventKind(json: string, kind: number): boolean {
|
|
||||||
return kind === getInt(json, 'kind')
|
|
||||||
}
|
|
||||||
|
|
@ -1,72 +0,0 @@
|
||||||
import { Event } from './event.js'
|
|
||||||
|
|
||||||
export type Filter<K extends number = number> = {
|
|
||||||
ids?: string[]
|
|
||||||
kinds?: K[]
|
|
||||||
authors?: string[]
|
|
||||||
since?: number
|
|
||||||
until?: number
|
|
||||||
limit?: number
|
|
||||||
search?: string
|
|
||||||
[key: `#${string}`]: string[] | undefined
|
|
||||||
}
|
|
||||||
|
|
||||||
export function matchFilter(filter: Filter<number>, event: Event<number>): boolean {
|
|
||||||
if (filter.ids && filter.ids.indexOf(event.id) === -1) {
|
|
||||||
if (!filter.ids.some(prefix => event.id.startsWith(prefix))) {
|
|
||||||
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.some(prefix => event.pubkey.startsWith(prefix))) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (let f in filter) {
|
|
||||||
if (f[0] === '#') {
|
|
||||||
let tagName = f.slice(1)
|
|
||||||
let values = filter[`#${tagName}`]
|
|
||||||
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.until && event.created_at > filter.until) return false
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
export function matchFilters(filters: Filter<number>[], event: Event<number>): boolean {
|
|
||||||
for (let i = 0; i < filters.length; i++) {
|
|
||||||
if (matchFilter(filters[i], event)) return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
export function mergeFilters(...filters: Filter<number>[]): Filter<number> {
|
|
||||||
let result: Filter<number> = {}
|
|
||||||
for (let i = 0; i < filters.length; i++) {
|
|
||||||
let filter = filters[i]
|
|
||||||
Object.entries(filter).forEach(([property, values]) => {
|
|
||||||
if (property === 'kinds' || property === 'ids' || property === 'authors' || property[0] === '#') {
|
|
||||||
// @ts-ignore
|
|
||||||
result[property] = result[property] || []
|
|
||||||
// @ts-ignore
|
|
||||||
for (let v = 0; v < values.length; v++) {
|
|
||||||
// @ts-ignore
|
|
||||||
let value = values[v]
|
|
||||||
// @ts-ignore
|
|
||||||
if (!result[property].includes(value)) result[property].push(value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
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.since && (!result.since || filter.since < result.since)) result.since = filter.since
|
|
||||||
}
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
export * from './event.js'
|
|
||||||
export * from './fakejson.js'
|
|
||||||
export * from './filter.js'
|
|
||||||
export * from './keys.js'
|
|
||||||
export * from './pool.js'
|
|
||||||
export * from './relay.js'
|
|
||||||
export * from './utils.js'
|
|
||||||
|
|
@ -1,10 +0,0 @@
|
||||||
import { schnorr } from '@noble/curves/secp256k1'
|
|
||||||
import { bytesToHex } from '@noble/hashes/utils'
|
|
||||||
|
|
||||||
export function generatePrivateKey(): string {
|
|
||||||
return bytesToHex(schnorr.utils.randomPrivateKey())
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getPublicKey(privateKey: string): string {
|
|
||||||
return bytesToHex(schnorr.getPublicKey(privateKey))
|
|
||||||
}
|
|
||||||
|
|
@ -1,249 +0,0 @@
|
||||||
import { relayInit, eventsGenerator, type Relay, type Sub, type SubscriptionOptions } from './relay.js'
|
|
||||||
import { normalizeURL } from './utils.js'
|
|
||||||
|
|
||||||
import type { Event } from './event.js'
|
|
||||||
import { matchFilters, type Filter } from './filter.js'
|
|
||||||
|
|
||||||
type BatchedRequest = {
|
|
||||||
filters: Filter<any>[]
|
|
||||||
relays: string[]
|
|
||||||
resolve: (events: Event<any>[]) => void
|
|
||||||
events: Event<any>[]
|
|
||||||
}
|
|
||||||
|
|
||||||
export class SimplePool {
|
|
||||||
private _conn: { [url: string]: Relay }
|
|
||||||
private _seenOn: { [id: string]: Set<string> } = {} // a map of all events we've seen in each relay
|
|
||||||
private batchedByKey: { [batchKey: string]: BatchedRequest[] } = {}
|
|
||||||
|
|
||||||
private eoseSubTimeout: number
|
|
||||||
private getTimeout: number
|
|
||||||
private seenOnEnabled: boolean = true
|
|
||||||
private batchInterval: number = 100
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
options: {
|
|
||||||
eoseSubTimeout?: number
|
|
||||||
getTimeout?: number
|
|
||||||
seenOnEnabled?: boolean
|
|
||||||
batchInterval?: number
|
|
||||||
} = {},
|
|
||||||
) {
|
|
||||||
this._conn = {}
|
|
||||||
this.eoseSubTimeout = options.eoseSubTimeout || 3400
|
|
||||||
this.getTimeout = options.getTimeout || 3400
|
|
||||||
this.seenOnEnabled = options.seenOnEnabled !== false
|
|
||||||
this.batchInterval = options.batchInterval || 100
|
|
||||||
}
|
|
||||||
|
|
||||||
close(relays: string[]): void {
|
|
||||||
relays.forEach(url => {
|
|
||||||
let relay = this._conn[normalizeURL(url)]
|
|
||||||
if (relay) relay.close()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
async ensureRelay(url: string): Promise<Relay> {
|
|
||||||
const nm = normalizeURL(url)
|
|
||||||
|
|
||||||
if (!this._conn[nm]) {
|
|
||||||
this._conn[nm] = relayInit(nm, {
|
|
||||||
getTimeout: this.getTimeout * 0.9,
|
|
||||||
listTimeout: this.getTimeout * 0.9,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const relay = this._conn[nm]
|
|
||||||
await relay.connect()
|
|
||||||
return relay
|
|
||||||
}
|
|
||||||
|
|
||||||
sub<K extends number = number>(relays: string[], filters: Filter<K>[], opts?: SubscriptionOptions): Sub<K> {
|
|
||||||
let _knownIds: Set<string> = new Set()
|
|
||||||
let modifiedOpts = { ...(opts || {}) }
|
|
||||||
modifiedOpts.alreadyHaveEvent = (id, url) => {
|
|
||||||
if (opts?.alreadyHaveEvent?.(id, url)) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if (this.seenOnEnabled) {
|
|
||||||
let set = this._seenOn[id] || new Set()
|
|
||||||
set.add(url)
|
|
||||||
this._seenOn[id] = set
|
|
||||||
}
|
|
||||||
return _knownIds.has(id)
|
|
||||||
}
|
|
||||||
|
|
||||||
let subs: Sub[] = []
|
|
||||||
let eventListeners: Set<any> = new Set()
|
|
||||||
let eoseListeners: Set<() => void> = new Set()
|
|
||||||
let eosesMissing = relays.length
|
|
||||||
|
|
||||||
let eoseSent = false
|
|
||||||
let eoseTimeout = setTimeout(
|
|
||||||
() => {
|
|
||||||
eoseSent = true
|
|
||||||
for (let cb of eoseListeners.values()) cb()
|
|
||||||
},
|
|
||||||
opts?.eoseSubTimeout || this.eoseSubTimeout,
|
|
||||||
)
|
|
||||||
|
|
||||||
relays
|
|
||||||
.filter((r, i, a) => a.indexOf(r) === i)
|
|
||||||
.forEach(async relay => {
|
|
||||||
let r
|
|
||||||
try {
|
|
||||||
r = await this.ensureRelay(relay)
|
|
||||||
} catch (err) {
|
|
||||||
handleEose()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (!r) return
|
|
||||||
let s = r.sub(filters, modifiedOpts)
|
|
||||||
s.on('event', event => {
|
|
||||||
_knownIds.add(event.id as string)
|
|
||||||
for (let cb of eventListeners.values()) cb(event)
|
|
||||||
})
|
|
||||||
s.on('eose', () => {
|
|
||||||
if (eoseSent) return
|
|
||||||
handleEose()
|
|
||||||
})
|
|
||||||
subs.push(s)
|
|
||||||
|
|
||||||
function handleEose() {
|
|
||||||
eosesMissing--
|
|
||||||
if (eosesMissing === 0) {
|
|
||||||
clearTimeout(eoseTimeout)
|
|
||||||
for (let cb of eoseListeners.values()) cb()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
let greaterSub: Sub<K> = {
|
|
||||||
sub(filters, opts) {
|
|
||||||
subs.forEach(sub => sub.sub(filters, opts))
|
|
||||||
return greaterSub as any
|
|
||||||
},
|
|
||||||
unsub() {
|
|
||||||
subs.forEach(sub => sub.unsub())
|
|
||||||
},
|
|
||||||
on(type, cb) {
|
|
||||||
if (type === 'event') {
|
|
||||||
eventListeners.add(cb)
|
|
||||||
} else if (type === 'eose') {
|
|
||||||
eoseListeners.add(cb as () => void | Promise<void>)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
off(type, cb) {
|
|
||||||
if (type === 'event') {
|
|
||||||
eventListeners.delete(cb)
|
|
||||||
} else if (type === 'eose') eoseListeners.delete(cb as () => void | Promise<void>)
|
|
||||||
},
|
|
||||||
get events() {
|
|
||||||
return eventsGenerator(greaterSub)
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
return greaterSub
|
|
||||||
}
|
|
||||||
|
|
||||||
get<K extends number = number>(
|
|
||||||
relays: string[],
|
|
||||||
filter: Filter<K>,
|
|
||||||
opts?: SubscriptionOptions,
|
|
||||||
): Promise<Event<K> | null> {
|
|
||||||
return new Promise(resolve => {
|
|
||||||
let sub = this.sub(relays, [filter], opts)
|
|
||||||
let timeout = setTimeout(() => {
|
|
||||||
sub.unsub()
|
|
||||||
resolve(null)
|
|
||||||
}, this.getTimeout)
|
|
||||||
sub.on('event', event => {
|
|
||||||
resolve(event)
|
|
||||||
clearTimeout(timeout)
|
|
||||||
sub.unsub()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
list<K extends number = number>(
|
|
||||||
relays: string[],
|
|
||||||
filters: Filter<K>[],
|
|
||||||
opts?: SubscriptionOptions,
|
|
||||||
): Promise<Event<K>[]> {
|
|
||||||
return new Promise(resolve => {
|
|
||||||
let events: Event<K>[] = []
|
|
||||||
let sub = this.sub(relays, filters, opts)
|
|
||||||
|
|
||||||
sub.on('event', event => {
|
|
||||||
events.push(event)
|
|
||||||
})
|
|
||||||
|
|
||||||
// we can rely on an eose being emitted here because pool.sub() will fake one
|
|
||||||
sub.on('eose', () => {
|
|
||||||
sub.unsub()
|
|
||||||
resolve(events)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
batchedList<K extends number = number>(
|
|
||||||
batchKey: string,
|
|
||||||
relays: string[],
|
|
||||||
filters: Filter<K>[],
|
|
||||||
): Promise<Event<K>[]> {
|
|
||||||
return new Promise(resolve => {
|
|
||||||
if (!this.batchedByKey[batchKey]) {
|
|
||||||
this.batchedByKey[batchKey] = [
|
|
||||||
{
|
|
||||||
filters,
|
|
||||||
relays,
|
|
||||||
resolve,
|
|
||||||
events: [],
|
|
||||||
},
|
|
||||||
]
|
|
||||||
|
|
||||||
setTimeout(() => {
|
|
||||||
Object.keys(this.batchedByKey).forEach(async batchKey => {
|
|
||||||
const batchedRequests = this.batchedByKey[batchKey]
|
|
||||||
|
|
||||||
const filters = [] as Filter[]
|
|
||||||
const relays = [] as string[]
|
|
||||||
batchedRequests.forEach(br => {
|
|
||||||
filters.push(...br.filters)
|
|
||||||
relays.push(...br.relays)
|
|
||||||
})
|
|
||||||
|
|
||||||
const sub = this.sub(relays, filters)
|
|
||||||
sub.on('event', event => {
|
|
||||||
batchedRequests.forEach(br => matchFilters(br.filters, event) && br.events.push(event))
|
|
||||||
})
|
|
||||||
sub.on('eose', () => {
|
|
||||||
sub.unsub()
|
|
||||||
batchedRequests.forEach(br => br.resolve(br.events))
|
|
||||||
})
|
|
||||||
|
|
||||||
delete this.batchedByKey[batchKey]
|
|
||||||
})
|
|
||||||
}, this.batchInterval)
|
|
||||||
} else {
|
|
||||||
this.batchedByKey[batchKey].push({
|
|
||||||
filters,
|
|
||||||
relays,
|
|
||||||
resolve,
|
|
||||||
events: [],
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
publish(relays: string[], event: Event<number>): Promise<void>[] {
|
|
||||||
return relays.map(async relay => {
|
|
||||||
let r = await this.ensureRelay(relay)
|
|
||||||
return r.publish(event)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
seenOn(id: string): string[] {
|
|
||||||
return Array.from(this._seenOn[id]?.values?.() || [])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,402 +0,0 @@
|
||||||
/* global WebSocket */
|
|
||||||
import "websocket-polyfill"
|
|
||||||
import { verifySignature, validateEvent, type Event } from './event.js'
|
|
||||||
import { matchFilters, type Filter } from './filter.js'
|
|
||||||
import { getHex64, getSubscriptionId } from './fakejson.js'
|
|
||||||
import { MessageQueue } from './utils.js'
|
|
||||||
|
|
||||||
type RelayEvent = {
|
|
||||||
connect: () => void | Promise<void>
|
|
||||||
disconnect: () => void | Promise<void>
|
|
||||||
error: () => void | Promise<void>
|
|
||||||
notice: (msg: string) => void | Promise<void>
|
|
||||||
auth: (challenge: string) => void | Promise<void>
|
|
||||||
}
|
|
||||||
export type CountPayload = {
|
|
||||||
count: number
|
|
||||||
}
|
|
||||||
export type SubEvent<K extends number> = {
|
|
||||||
event: (event: Event<K>) => void | Promise<void>
|
|
||||||
count: (payload: CountPayload) => void | Promise<void>
|
|
||||||
eose: () => void | Promise<void>
|
|
||||||
}
|
|
||||||
export type Relay = {
|
|
||||||
url: string
|
|
||||||
status: number
|
|
||||||
connect: () => Promise<void>
|
|
||||||
close: () => void
|
|
||||||
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>[]>
|
|
||||||
get: <K extends number = number>(filter: Filter<K>, opts?: SubscriptionOptions) => Promise<Event<K> | null>
|
|
||||||
count: (filters: Filter[], opts?: SubscriptionOptions) => Promise<CountPayload | null>
|
|
||||||
publish: (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
|
|
||||||
on: <T extends keyof RelayEvent, U extends RelayEvent[T]>(event: T, listener: U) => void
|
|
||||||
}
|
|
||||||
export type Sub<K extends number = number> = {
|
|
||||||
sub: <K extends number = number>(filters: Filter<K>[], opts: SubscriptionOptions) => Sub<K>
|
|
||||||
unsub: () => 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
|
|
||||||
events: AsyncGenerator<Event<K>, void, unknown>
|
|
||||||
}
|
|
||||||
|
|
||||||
export type SubscriptionOptions = {
|
|
||||||
id?: string
|
|
||||||
verb?: 'REQ' | 'COUNT'
|
|
||||||
skipVerification?: boolean
|
|
||||||
alreadyHaveEvent?: null | ((id: string, relay: string) => boolean)
|
|
||||||
eoseSubTimeout?: number
|
|
||||||
}
|
|
||||||
|
|
||||||
const newListeners = (): { [TK in keyof RelayEvent]: RelayEvent[TK][] } => ({
|
|
||||||
connect: [],
|
|
||||||
disconnect: [],
|
|
||||||
error: [],
|
|
||||||
notice: [],
|
|
||||||
auth: [],
|
|
||||||
})
|
|
||||||
|
|
||||||
export function relayInit(
|
|
||||||
url: string,
|
|
||||||
options: {
|
|
||||||
getTimeout?: number
|
|
||||||
listTimeout?: number
|
|
||||||
countTimeout?: number
|
|
||||||
} = {},
|
|
||||||
): Relay {
|
|
||||||
let { listTimeout = 3000, getTimeout = 3000, countTimeout = 3000 } = options
|
|
||||||
|
|
||||||
var ws: WebSocket
|
|
||||||
var openSubs: { [id: string]: { filters: Filter[] } & SubscriptionOptions } = {}
|
|
||||||
var listeners = newListeners()
|
|
||||||
var subListeners: {
|
|
||||||
[subid: string]: { [TK in keyof SubEvent<any>]: SubEvent<any>[TK][] }
|
|
||||||
} = {}
|
|
||||||
var pubListeners: {
|
|
||||||
[eventid: string]: {
|
|
||||||
resolve: (_: unknown) => void
|
|
||||||
reject: (err: Error) => void
|
|
||||||
}
|
|
||||||
} = {}
|
|
||||||
|
|
||||||
var connectionPromise: Promise<void> | undefined
|
|
||||||
async function connectRelay(): Promise<void> {
|
|
||||||
if (connectionPromise) return connectionPromise
|
|
||||||
connectionPromise = new Promise((resolve, reject) => {
|
|
||||||
try {
|
|
||||||
ws = new WebSocket(url)
|
|
||||||
} catch (err) {
|
|
||||||
reject(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
ws.onopen = () => {
|
|
||||||
listeners.connect.forEach(cb => cb())
|
|
||||||
resolve()
|
|
||||||
}
|
|
||||||
ws.onerror = () => {
|
|
||||||
connectionPromise = undefined
|
|
||||||
listeners.error.forEach(cb => cb())
|
|
||||||
reject()
|
|
||||||
}
|
|
||||||
ws.onclose = async () => {
|
|
||||||
connectionPromise = undefined
|
|
||||||
listeners.disconnect.forEach(cb => cb())
|
|
||||||
}
|
|
||||||
|
|
||||||
let incomingMessageQueue: MessageQueue = new MessageQueue()
|
|
||||||
let handleNextInterval: any
|
|
||||||
|
|
||||||
ws.onmessage = e => {
|
|
||||||
incomingMessageQueue.enqueue(e.data)
|
|
||||||
if (!handleNextInterval) {
|
|
||||||
handleNextInterval = setInterval(handleNext, 0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleNext() {
|
|
||||||
if (incomingMessageQueue.size === 0) {
|
|
||||||
clearInterval(handleNextInterval)
|
|
||||||
handleNextInterval = null
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var json = incomingMessageQueue.dequeue()
|
|
||||||
if (!json) return
|
|
||||||
|
|
||||||
let subid = getSubscriptionId(json)
|
|
||||||
if (subid) {
|
|
||||||
let so = openSubs[subid]
|
|
||||||
if (so && so.alreadyHaveEvent && so.alreadyHaveEvent(getHex64(json, 'id'), url)) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
let data = JSON.parse(json)
|
|
||||||
|
|
||||||
// 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
|
|
||||||
|
|
||||||
switch (data[0]) {
|
|
||||||
case 'EVENT': {
|
|
||||||
let id = data[1]
|
|
||||||
let event = data[2]
|
|
||||||
if (
|
|
||||||
validateEvent(event) &&
|
|
||||||
openSubs[id] &&
|
|
||||||
(openSubs[id].skipVerification || verifySignature(event)) &&
|
|
||||||
matchFilters(openSubs[id].filters, event)
|
|
||||||
) {
|
|
||||||
openSubs[id]
|
|
||||||
; (subListeners[id]?.event || []).forEach(cb => cb(event))
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
case 'COUNT':
|
|
||||||
let id = data[1]
|
|
||||||
let payload = data[2]
|
|
||||||
if (openSubs[id]) {
|
|
||||||
; (subListeners[id]?.count || []).forEach(cb => cb(payload))
|
|
||||||
}
|
|
||||||
return
|
|
||||||
case 'EOSE': {
|
|
||||||
let id = data[1]
|
|
||||||
if (id in subListeners) {
|
|
||||||
subListeners[id].eose.forEach(cb => cb())
|
|
||||||
subListeners[id].eose = [] // 'eose' only happens once per sub, so stop listeners here
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
case 'OK': {
|
|
||||||
let id: string = data[1]
|
|
||||||
let ok: boolean = data[2]
|
|
||||||
let reason: string = data[3] || ''
|
|
||||||
if (id in pubListeners) {
|
|
||||||
let { resolve, reject } = pubListeners[id]
|
|
||||||
if (ok) resolve(null)
|
|
||||||
else reject(new Error(reason))
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
case 'NOTICE':
|
|
||||||
let notice = data[1]
|
|
||||||
listeners.notice.forEach(cb => cb(notice))
|
|
||||||
return
|
|
||||||
case 'AUTH': {
|
|
||||||
let challenge = data[1]
|
|
||||||
listeners.auth?.forEach(cb => cb(challenge))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
return connectionPromise
|
|
||||||
}
|
|
||||||
|
|
||||||
function connected() {
|
|
||||||
return ws?.readyState === 1
|
|
||||||
}
|
|
||||||
|
|
||||||
async function connect(): Promise<void> {
|
|
||||||
if (connected()) return // ws already open
|
|
||||||
await connectRelay()
|
|
||||||
}
|
|
||||||
|
|
||||||
async function trySend(params: [string, ...any]) {
|
|
||||||
let msg = JSON.stringify(params)
|
|
||||||
if (!connected()) {
|
|
||||||
await new Promise(resolve => setTimeout(resolve, 1000))
|
|
||||||
if (!connected()) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
ws.send(msg)
|
|
||||||
} catch (err) {
|
|
||||||
console.log(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const sub = <K extends number = number>(
|
|
||||||
filters: Filter<K>[],
|
|
||||||
{
|
|
||||||
verb = 'REQ',
|
|
||||||
skipVerification = false,
|
|
||||||
alreadyHaveEvent = null,
|
|
||||||
id = Math.random().toString().slice(2),
|
|
||||||
}: SubscriptionOptions = {},
|
|
||||||
): Sub<K> => {
|
|
||||||
let subid = id
|
|
||||||
|
|
||||||
openSubs[subid] = {
|
|
||||||
id: subid,
|
|
||||||
filters,
|
|
||||||
skipVerification,
|
|
||||||
alreadyHaveEvent,
|
|
||||||
}
|
|
||||||
trySend([verb, subid, ...filters])
|
|
||||||
|
|
||||||
let subscription: Sub<K> = {
|
|
||||||
sub: (newFilters, newOpts = {}) =>
|
|
||||||
sub(newFilters || filters, {
|
|
||||||
skipVerification: newOpts.skipVerification || skipVerification,
|
|
||||||
alreadyHaveEvent: newOpts.alreadyHaveEvent || alreadyHaveEvent,
|
|
||||||
id: subid,
|
|
||||||
}),
|
|
||||||
unsub: () => {
|
|
||||||
delete openSubs[subid]
|
|
||||||
delete subListeners[subid]
|
|
||||||
trySend(['CLOSE', subid])
|
|
||||||
},
|
|
||||||
on: (type, cb) => {
|
|
||||||
subListeners[subid] = subListeners[subid] || {
|
|
||||||
event: [],
|
|
||||||
count: [],
|
|
||||||
eose: [],
|
|
||||||
}
|
|
||||||
//@ts-ignore
|
|
||||||
subListeners[subid][type].push(cb)
|
|
||||||
},
|
|
||||||
off: (type, cb): void => {
|
|
||||||
let listeners = subListeners[subid]
|
|
||||||
//@ts-ignore
|
|
||||||
let idx = listeners[type].indexOf(cb)
|
|
||||||
if (idx >= 0) listeners[type].splice(idx, 1)
|
|
||||||
},
|
|
||||||
get events() {
|
|
||||||
return eventsGenerator(subscription)
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
return subscription
|
|
||||||
}
|
|
||||||
|
|
||||||
function _publishEvent(event: Event<number>, type: string) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
if (!event.id) {
|
|
||||||
reject(new Error(`event ${event} has no id`))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
let id = event.id
|
|
||||||
trySend([type, event])
|
|
||||||
pubListeners[id] = { resolve, reject }
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
url,
|
|
||||||
sub,
|
|
||||||
on: <T extends keyof RelayEvent, U extends RelayEvent[T]>(type: T, cb: U): void => {
|
|
||||||
//@ts-ignore
|
|
||||||
listeners[type].push(cb)
|
|
||||||
if (type === 'connect' && ws?.readyState === 1) {
|
|
||||||
// i would love to know why we need this
|
|
||||||
; (cb as () => void)()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
off: <T extends keyof RelayEvent, U extends RelayEvent[T]>(type: T, cb: U): void => {
|
|
||||||
//@ts-ignore
|
|
||||||
let index = listeners[type].indexOf(cb)
|
|
||||||
if (index !== -1) listeners[type].splice(index, 1)
|
|
||||||
},
|
|
||||||
list: (filters, opts?: SubscriptionOptions) =>
|
|
||||||
new Promise(resolve => {
|
|
||||||
let s = sub(filters, opts)
|
|
||||||
let events: Event<any>[] = []
|
|
||||||
let timeout = setTimeout(() => {
|
|
||||||
s.unsub()
|
|
||||||
resolve(events)
|
|
||||||
}, listTimeout)
|
|
||||||
s.on('eose', () => {
|
|
||||||
s.unsub()
|
|
||||||
clearTimeout(timeout)
|
|
||||||
resolve(events)
|
|
||||||
})
|
|
||||||
s.on('event', event => {
|
|
||||||
events.push(event)
|
|
||||||
})
|
|
||||||
}),
|
|
||||||
get: (filter, opts?: SubscriptionOptions) =>
|
|
||||||
new Promise(resolve => {
|
|
||||||
let s = sub([filter], opts)
|
|
||||||
let timeout = setTimeout(() => {
|
|
||||||
s.unsub()
|
|
||||||
resolve(null)
|
|
||||||
}, getTimeout)
|
|
||||||
s.on('event', event => {
|
|
||||||
s.unsub()
|
|
||||||
clearTimeout(timeout)
|
|
||||||
resolve(event)
|
|
||||||
})
|
|
||||||
}),
|
|
||||||
count: (filters: Filter[]): Promise<CountPayload | null> =>
|
|
||||||
new Promise(resolve => {
|
|
||||||
let s = sub(filters, { ...sub, verb: 'COUNT' })
|
|
||||||
let timeout = setTimeout(() => {
|
|
||||||
s.unsub()
|
|
||||||
resolve(null)
|
|
||||||
}, countTimeout)
|
|
||||||
s.on('count', (event: CountPayload) => {
|
|
||||||
s.unsub()
|
|
||||||
clearTimeout(timeout)
|
|
||||||
resolve(event)
|
|
||||||
})
|
|
||||||
}),
|
|
||||||
async publish(event): Promise<void> {
|
|
||||||
await _publishEvent(event, 'EVENT')
|
|
||||||
},
|
|
||||||
async auth(event): Promise<void> {
|
|
||||||
await _publishEvent(event, 'AUTH')
|
|
||||||
},
|
|
||||||
connect,
|
|
||||||
close(): void {
|
|
||||||
listeners = newListeners()
|
|
||||||
subListeners = {}
|
|
||||||
pubListeners = {}
|
|
||||||
if (ws?.readyState === WebSocket.OPEN) {
|
|
||||||
ws.close()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
get status() {
|
|
||||||
return ws?.readyState ?? 3
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function* eventsGenerator<K extends number>(sub: Sub<K>): AsyncGenerator<Event<K>, void, unknown> {
|
|
||||||
let nextResolve: ((event: Event<K>) => void) | undefined
|
|
||||||
const eventQueue: Event<K>[] = []
|
|
||||||
|
|
||||||
const pushToQueue = (event: Event<K>) => {
|
|
||||||
if (nextResolve) {
|
|
||||||
nextResolve(event)
|
|
||||||
nextResolve = undefined
|
|
||||||
} else {
|
|
||||||
eventQueue.push(event)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sub.on('event', pushToQueue)
|
|
||||||
|
|
||||||
try {
|
|
||||||
while (true) {
|
|
||||||
if (eventQueue.length > 0) {
|
|
||||||
yield eventQueue.shift()!
|
|
||||||
} else {
|
|
||||||
const event = await new Promise<Event<K>>(resolve => {
|
|
||||||
nextResolve = resolve
|
|
||||||
})
|
|
||||||
yield event
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
sub.off('event', pushToQueue)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,169 +0,0 @@
|
||||||
import type { Event } from './event.js'
|
|
||||||
|
|
||||||
export const utf8Decoder = new TextDecoder('utf-8')
|
|
||||||
export const utf8Encoder = new TextEncoder()
|
|
||||||
|
|
||||||
export function normalizeURL(url: string): string {
|
|
||||||
let p = new URL(url)
|
|
||||||
p.pathname = p.pathname.replace(/\/+/g, '/')
|
|
||||||
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 = ''
|
|
||||||
p.searchParams.sort()
|
|
||||||
p.hash = ''
|
|
||||||
return p.toString()
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// fast insert-into-sorted-array functions adapted from https://github.com/terrymorse58/fast-sorted-array
|
|
||||||
//
|
|
||||||
export function insertEventIntoDescendingList(sortedArray: Event<number>[], event: Event<number>) {
|
|
||||||
let start = 0
|
|
||||||
let end = sortedArray.length - 1
|
|
||||||
let midPoint
|
|
||||||
let position = start
|
|
||||||
|
|
||||||
if (end < 0) {
|
|
||||||
position = 0
|
|
||||||
} else if (event.created_at < sortedArray[end].created_at) {
|
|
||||||
position = end + 1
|
|
||||||
} else if (event.created_at >= sortedArray[start].created_at) {
|
|
||||||
position = start
|
|
||||||
} else
|
|
||||||
while (true) {
|
|
||||||
if (end <= start + 1) {
|
|
||||||
position = end
|
|
||||||
break
|
|
||||||
}
|
|
||||||
midPoint = Math.floor(start + (end - start) / 2)
|
|
||||||
if (sortedArray[midPoint].created_at > event.created_at) {
|
|
||||||
start = midPoint
|
|
||||||
} else if (sortedArray[midPoint].created_at < event.created_at) {
|
|
||||||
end = midPoint
|
|
||||||
} else {
|
|
||||||
// aMidPoint === num
|
|
||||||
position = midPoint
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// insert when num is NOT already in (no duplicates)
|
|
||||||
if (sortedArray[position]?.id !== event.id) {
|
|
||||||
return [...sortedArray.slice(0, position), event, ...sortedArray.slice(position)]
|
|
||||||
}
|
|
||||||
|
|
||||||
return sortedArray
|
|
||||||
}
|
|
||||||
|
|
||||||
export function insertEventIntoAscendingList(sortedArray: Event<number>[], event: Event<number>) {
|
|
||||||
let start = 0
|
|
||||||
let end = sortedArray.length - 1
|
|
||||||
let midPoint
|
|
||||||
let position = start
|
|
||||||
|
|
||||||
if (end < 0) {
|
|
||||||
position = 0
|
|
||||||
} else if (event.created_at > sortedArray[end].created_at) {
|
|
||||||
position = end + 1
|
|
||||||
} else if (event.created_at <= sortedArray[start].created_at) {
|
|
||||||
position = start
|
|
||||||
} else
|
|
||||||
while (true) {
|
|
||||||
if (end <= start + 1) {
|
|
||||||
position = end
|
|
||||||
break
|
|
||||||
}
|
|
||||||
midPoint = Math.floor(start + (end - start) / 2)
|
|
||||||
if (sortedArray[midPoint].created_at < event.created_at) {
|
|
||||||
start = midPoint
|
|
||||||
} else if (sortedArray[midPoint].created_at > event.created_at) {
|
|
||||||
end = midPoint
|
|
||||||
} else {
|
|
||||||
// aMidPoint === num
|
|
||||||
position = midPoint
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// insert when num is NOT already in (no duplicates)
|
|
||||||
if (sortedArray[position]?.id !== event.id) {
|
|
||||||
return [...sortedArray.slice(0, position), event, ...sortedArray.slice(position)]
|
|
||||||
}
|
|
||||||
|
|
||||||
return sortedArray
|
|
||||||
}
|
|
||||||
|
|
||||||
export class MessageNode {
|
|
||||||
private _value: string
|
|
||||||
private _next: MessageNode | null
|
|
||||||
|
|
||||||
public get value(): string {
|
|
||||||
return this._value
|
|
||||||
}
|
|
||||||
public set value(message: string) {
|
|
||||||
this._value = message
|
|
||||||
}
|
|
||||||
public get next(): MessageNode | null {
|
|
||||||
return this._next
|
|
||||||
}
|
|
||||||
public set next(node: MessageNode | null) {
|
|
||||||
this._next = node
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(message: string) {
|
|
||||||
this._value = message
|
|
||||||
this._next = null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class MessageQueue {
|
|
||||||
private _first: MessageNode | null
|
|
||||||
private _last: MessageNode | null
|
|
||||||
|
|
||||||
public get first(): MessageNode | null {
|
|
||||||
return this._first
|
|
||||||
}
|
|
||||||
public set first(messageNode: MessageNode | null) {
|
|
||||||
this._first = messageNode
|
|
||||||
}
|
|
||||||
public get last(): MessageNode | null {
|
|
||||||
return this._last
|
|
||||||
}
|
|
||||||
public set last(messageNode: MessageNode | null) {
|
|
||||||
this._last = messageNode
|
|
||||||
}
|
|
||||||
private _size: number
|
|
||||||
public get size(): number {
|
|
||||||
return this._size
|
|
||||||
}
|
|
||||||
public set size(v: number) {
|
|
||||||
this._size = v
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
this._first = null
|
|
||||||
this._last = null
|
|
||||||
this._size = 0
|
|
||||||
}
|
|
||||||
enqueue(message: string): boolean {
|
|
||||||
const newNode = new MessageNode(message)
|
|
||||||
if (this._size === 0 || !this._last) {
|
|
||||||
this._first = newNode
|
|
||||||
this._last = newNode
|
|
||||||
} else {
|
|
||||||
this._last.next = newNode
|
|
||||||
this._last = newNode
|
|
||||||
}
|
|
||||||
this._size++
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
dequeue(): string | null {
|
|
||||||
if (this._size === 0 || !this._first) return null
|
|
||||||
|
|
||||||
let prev = this._first
|
|
||||||
this._first = prev.next
|
|
||||||
prev.next = null
|
|
||||||
|
|
||||||
this._size--
|
|
||||||
return prev.value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -41,6 +41,9 @@ export default (mainHandler: Main): Types.ServerMethods => {
|
||||||
},
|
},
|
||||||
UserHealth: async () => { },
|
UserHealth: async () => { },
|
||||||
GetUserInfo: ({ ctx }) => mainHandler.appUserManager.GetUserInfo(ctx),
|
GetUserInfo: ({ ctx }) => mainHandler.appUserManager.GetUserInfo(ctx),
|
||||||
|
UpdateCallbackUrl: async ({ ctx, req }) => {
|
||||||
|
return mainHandler.appUserManager.UpdateCallbackUrl(ctx, req)
|
||||||
|
},
|
||||||
GetUserOperations: async ({ ctx, req }) => {
|
GetUserOperations: async ({ ctx, req }) => {
|
||||||
return mainHandler.paymentManager.GetUserOperations(ctx.user_id, req)
|
return mainHandler.paymentManager.GetUserOperations(ctx.user_id, req)
|
||||||
},
|
},
|
||||||
|
|
@ -209,6 +212,7 @@ export default (mainHandler: Main): Types.ServerMethods => {
|
||||||
SetMockAppBalance: async ({ ctx, req }) => {
|
SetMockAppBalance: async ({ ctx, req }) => {
|
||||||
await mainHandler.applicationManager.SetMockAppBalance(ctx.app_id, req)
|
await mainHandler.applicationManager.SetMockAppBalance(ctx.app_id, req)
|
||||||
},
|
},
|
||||||
|
GetLiveDebitRequests: async ({ ctx }) => { },
|
||||||
GetLiveUserOperations: async ({ ctx, cb }) => {
|
GetLiveUserOperations: async ({ ctx, cb }) => {
|
||||||
},
|
},
|
||||||
GetMigrationUpdate: async ({ ctx, cb }) => {
|
GetMigrationUpdate: async ({ ctx, cb }) => {
|
||||||
|
|
@ -261,7 +265,32 @@ export default (mainHandler: Main): Types.ServerMethods => {
|
||||||
})
|
})
|
||||||
if (err != null) throw new Error(err.message)
|
if (err != null) throw new Error(err.message)
|
||||||
return mainHandler.adminManager.GetInviteTokenState(ctx, req);
|
return mainHandler.adminManager.GetInviteTokenState(ctx, req);
|
||||||
|
},
|
||||||
|
AuthorizeDebit: async ({ ctx, req }) => {
|
||||||
|
return mainHandler.debitManager.AuthorizeDebit(ctx, req)
|
||||||
|
},
|
||||||
|
GetDebitAuthorizations: async ({ ctx }) => {
|
||||||
|
return mainHandler.debitManager.GetDebitAuthorizations(ctx)
|
||||||
|
},
|
||||||
|
BanDebit: async ({ ctx, req }) => {
|
||||||
|
const err = Types.DebitOperationValidate(req, {
|
||||||
|
npub_CustomCheck: pub => pub !== '',
|
||||||
|
})
|
||||||
|
if (err != null) throw new Error(err.message)
|
||||||
|
return mainHandler.debitManager.BanDebit(ctx, req)
|
||||||
|
},
|
||||||
|
ResetDebit: async ({ ctx, req }) => {
|
||||||
|
const err = Types.DebitOperationValidate(req, {
|
||||||
|
npub_CustomCheck: pub => pub !== '',
|
||||||
|
})
|
||||||
|
if (err != null) throw new Error(err.message)
|
||||||
|
return mainHandler.debitManager.ResetDebit(ctx, req)
|
||||||
|
},
|
||||||
|
EditDebit: async ({ ctx, req }) => {
|
||||||
|
return mainHandler.debitManager.EditDebit(ctx, req);
|
||||||
|
},
|
||||||
|
RespondToDebit: async ({ ctx, req }) => {
|
||||||
|
return mainHandler.debitManager.RespondToDebit(ctx, req);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
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 { generateSecretKey, 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';
|
||||||
|
|
@ -67,10 +67,11 @@ export default class {
|
||||||
}
|
}
|
||||||
|
|
||||||
async GenerateApplicationKeys(app: Application) {
|
async GenerateApplicationKeys(app: Application) {
|
||||||
const priv = generatePrivateKey()
|
const priv = generateSecretKey()
|
||||||
const pub = getPublicKey(priv)
|
const pub = getPublicKey(priv)
|
||||||
await this.UpdateApplication(app, { nostr_private_key: priv, nostr_public_key: pub })
|
const privString = Buffer.from(priv).toString('hex')
|
||||||
return { privateKey: priv, publicKey: pub, appId: app.app_id, name: app.name }
|
await this.UpdateApplication(app, { nostr_private_key: privString, nostr_public_key: pub })
|
||||||
|
return { privateKey: privString, 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) {
|
||||||
|
|
@ -161,9 +162,11 @@ export default class {
|
||||||
|
|
||||||
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 UpdateUserCallbackUrl(application: Application, userIdentifier: string, callbackUrl: string, entityManager = this.DB) {
|
||||||
|
return entityManager.getRepository(ApplicationUser).update({ application: { app_id: application.app_id }, identifier: userIdentifier }, { callback_url: callbackUrl })
|
||||||
|
}
|
||||||
|
|
||||||
async RemoveApplicationUserAndBaseUser(appUser: ApplicationUser, entityManager = this.DB) {
|
async RemoveApplicationUserAndBaseUser(appUser: ApplicationUser, entityManager = this.DB) {
|
||||||
const baseUser = appUser.user;
|
const baseUser = appUser.user;
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ import { Product } from "./entity/Product.js"
|
||||||
import { LndNodeInfo } from "./entity/LndNodeInfo.js"
|
import { LndNodeInfo } from "./entity/LndNodeInfo.js"
|
||||||
import { TrackedProvider } from "./entity/TrackedProvider.js"
|
import { TrackedProvider } from "./entity/TrackedProvider.js"
|
||||||
import { InviteToken } from "./entity/InviteToken.js"
|
import { InviteToken } from "./entity/InviteToken.js"
|
||||||
|
import { DebitAccess } from "./entity/DebitAccess.js"
|
||||||
|
|
||||||
|
|
||||||
export type DbSettings = {
|
export type DbSettings = {
|
||||||
|
|
@ -61,7 +62,7 @@ export default async (settings: DbSettings, migrations: Function[]): Promise<{ s
|
||||||
// logging: true,
|
// logging: true,
|
||||||
entities: [User, UserReceivingInvoice, UserReceivingAddress, AddressReceivingTransaction, UserInvoicePayment, UserTransactionPayment,
|
entities: [User, UserReceivingInvoice, UserReceivingAddress, AddressReceivingTransaction, UserInvoicePayment, UserTransactionPayment,
|
||||||
UserBasicAuth, UserEphemeralKey, Product, UserToUserPayment, Application, ApplicationUser, UserToUserPayment, LspOrder, LndNodeInfo, TrackedProvider,
|
UserBasicAuth, UserEphemeralKey, Product, UserToUserPayment, Application, ApplicationUser, UserToUserPayment, LspOrder, LndNodeInfo, TrackedProvider,
|
||||||
InviteToken
|
InviteToken, DebitAccess
|
||||||
],
|
],
|
||||||
//synchronize: true,
|
//synchronize: true,
|
||||||
migrations
|
migrations
|
||||||
|
|
|
||||||
58
src/services/storage/debitStorage.ts
Normal file
58
src/services/storage/debitStorage.ts
Normal file
|
|
@ -0,0 +1,58 @@
|
||||||
|
import { DataSource, EntityManager } from "typeorm"
|
||||||
|
import UserStorage from './userStorage.js';
|
||||||
|
import TransactionsQueue from "./transactionsQueue.js";
|
||||||
|
import { DebitAccess, DebitAccessRules } from "./entity/DebitAccess.js";
|
||||||
|
type AccessToAdd = {
|
||||||
|
npub: string
|
||||||
|
rules?: DebitAccessRules
|
||||||
|
authorize: boolean
|
||||||
|
}
|
||||||
|
export default class {
|
||||||
|
DB: DataSource | EntityManager
|
||||||
|
txQueue: TransactionsQueue
|
||||||
|
constructor(DB: DataSource | EntityManager, txQueue: TransactionsQueue) {
|
||||||
|
this.DB = DB
|
||||||
|
this.txQueue = txQueue
|
||||||
|
}
|
||||||
|
|
||||||
|
async AddDebitAccess(appUserId: string, access: AccessToAdd, entityManager = this.DB) {
|
||||||
|
const entry = entityManager.getRepository(DebitAccess).create({
|
||||||
|
app_user_id: appUserId,
|
||||||
|
npub: access.npub,
|
||||||
|
authorized: access.authorize,
|
||||||
|
rules: access.rules,
|
||||||
|
})
|
||||||
|
return this.txQueue.PushToQueue<DebitAccess>({ exec: async db => db.getRepository(DebitAccess).save(entry), dbTx: false })
|
||||||
|
}
|
||||||
|
|
||||||
|
async GetAllUserDebitAccess(appUserId: string) {
|
||||||
|
return this.DB.getRepository(DebitAccess).find({ where: { app_user_id: appUserId } })
|
||||||
|
}
|
||||||
|
|
||||||
|
async GetDebitAccess(appUserId: string, authorizedPub: string) {
|
||||||
|
return this.DB.getRepository(DebitAccess).findOne({ where: { app_user_id: appUserId, npub: authorizedPub } })
|
||||||
|
}
|
||||||
|
|
||||||
|
async IncrementDebitAccess(appUserId: string, authorizedPub: string, amount: number) {
|
||||||
|
return this.DB.getRepository(DebitAccess).increment({ app_user_id: appUserId, npub: authorizedPub }, 'total_debits', amount)
|
||||||
|
}
|
||||||
|
|
||||||
|
async UpdateDebitAccess(appUserId: string, authorizedPub: string, authorized: boolean) {
|
||||||
|
return this.DB.getRepository(DebitAccess).update({ app_user_id: appUserId, npub: authorizedPub }, { authorized })
|
||||||
|
}
|
||||||
|
async UpdateDebitAccessRules(appUserId: string, authorizedPub: string, rules?: DebitAccessRules) {
|
||||||
|
return this.DB.getRepository(DebitAccess).update({ app_user_id: appUserId, npub: authorizedPub }, { rules: rules || null })
|
||||||
|
}
|
||||||
|
|
||||||
|
async DenyDebitAccess(appUserId: string, pub: string) {
|
||||||
|
const access = await this.GetDebitAccess(appUserId, pub)
|
||||||
|
if (!access) {
|
||||||
|
await this.AddDebitAccess(appUserId, { npub: pub, authorize: false })
|
||||||
|
}
|
||||||
|
await this.UpdateDebitAccess(appUserId, pub, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
async RemoveDebitAccess(appUserId: string, authorizedPub: string) {
|
||||||
|
return this.DB.getRepository(DebitAccess).delete({ app_user_id: appUserId, npub: authorizedPub })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -23,6 +23,9 @@ export class ApplicationUser {
|
||||||
@Column({ nullable: true, unique: true })
|
@Column({ nullable: true, unique: true })
|
||||||
nostr_public_key?: string
|
nostr_public_key?: string
|
||||||
|
|
||||||
|
@Column({ default: "" })
|
||||||
|
callback_url: string
|
||||||
|
|
||||||
@CreateDateColumn()
|
@CreateDateColumn()
|
||||||
created_at: Date
|
created_at: Date
|
||||||
|
|
||||||
|
|
|
||||||
30
src/services/storage/entity/DebitAccess.ts
Normal file
30
src/services/storage/entity/DebitAccess.ts
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
import { Entity, PrimaryGeneratedColumn, Column, Index, Check, ManyToOne, JoinColumn, CreateDateColumn, UpdateDateColumn } from "typeorm"
|
||||||
|
export type DebitAccessRules = Record<string/* rule name */, string[]/* rule values */>
|
||||||
|
@Entity()
|
||||||
|
@Index("unique_debit_access", ["app_user_id", "npub"], { unique: true })
|
||||||
|
export class DebitAccess {
|
||||||
|
|
||||||
|
@PrimaryGeneratedColumn()
|
||||||
|
serial_id: number
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
app_user_id: string
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
npub: string
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
authorized: boolean
|
||||||
|
|
||||||
|
@Column({ type: 'simple-json', default: null, nullable: true })
|
||||||
|
rules: DebitAccessRules | null
|
||||||
|
|
||||||
|
@Column({ default: 0 })
|
||||||
|
total_debits: number
|
||||||
|
|
||||||
|
@CreateDateColumn()
|
||||||
|
created_at: Date
|
||||||
|
|
||||||
|
@UpdateDateColumn()
|
||||||
|
updated_at: Date
|
||||||
|
}
|
||||||
|
|
@ -44,6 +44,9 @@ export class UserInvoicePayment {
|
||||||
})
|
})
|
||||||
paymentIndex: number
|
paymentIndex: number
|
||||||
|
|
||||||
|
@Column({ nullable: true })
|
||||||
|
debit_to_pub: string
|
||||||
|
|
||||||
@CreateDateColumn()
|
@CreateDateColumn()
|
||||||
created_at: Date
|
created_at: Date
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ import TransactionsQueue, { TX } from "./transactionsQueue.js";
|
||||||
import EventsLogManager from "./eventsLog.js";
|
import EventsLogManager from "./eventsLog.js";
|
||||||
import { LiquidityStorage } from "./liquidityStorage.js";
|
import { LiquidityStorage } from "./liquidityStorage.js";
|
||||||
import { StateBundler } from "./stateBundler.js";
|
import { StateBundler } from "./stateBundler.js";
|
||||||
|
import DebitStorage from "./debitStorage.js"
|
||||||
export type StorageSettings = {
|
export type StorageSettings = {
|
||||||
dbSettings: DbSettings
|
dbSettings: DbSettings
|
||||||
eventLogPath: string
|
eventLogPath: string
|
||||||
|
|
@ -28,6 +29,7 @@ export default class {
|
||||||
paymentStorage: PaymentStorage
|
paymentStorage: PaymentStorage
|
||||||
metricsStorage: MetricsStorage
|
metricsStorage: MetricsStorage
|
||||||
liquidityStorage: LiquidityStorage
|
liquidityStorage: LiquidityStorage
|
||||||
|
debitStorage: DebitStorage
|
||||||
eventsLog: EventsLogManager
|
eventsLog: EventsLogManager
|
||||||
stateBundler: StateBundler
|
stateBundler: StateBundler
|
||||||
constructor(settings: StorageSettings) {
|
constructor(settings: StorageSettings) {
|
||||||
|
|
@ -44,6 +46,7 @@ export default class {
|
||||||
this.paymentStorage = new PaymentStorage(this.DB, this.userStorage, this.txQueue)
|
this.paymentStorage = new PaymentStorage(this.DB, this.userStorage, this.txQueue)
|
||||||
this.metricsStorage = new MetricsStorage(this.settings)
|
this.metricsStorage = new MetricsStorage(this.settings)
|
||||||
this.liquidityStorage = new LiquidityStorage(this.DB, this.txQueue)
|
this.liquidityStorage = new LiquidityStorage(this.DB, this.txQueue)
|
||||||
|
this.debitStorage = new DebitStorage(this.DB, this.txQueue)
|
||||||
try { if (this.settings.dataDir) fs.mkdirSync(this.settings.dataDir) } catch (e) { }
|
try { if (this.settings.dataDir) fs.mkdirSync(this.settings.dataDir) } catch (e) { }
|
||||||
const executedMetricsMigrations = await this.metricsStorage.Connect(metricsMigrations)
|
const executedMetricsMigrations = await this.metricsStorage.Connect(metricsMigrations)
|
||||||
return { executedMigrations, executedMetricsMigrations };
|
return { executedMigrations, executedMetricsMigrations };
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
import { MigrationInterface, QueryRunner } from "typeorm";
|
||||||
|
|
||||||
|
export class DebitAccess1726496225078 implements MigrationInterface {
|
||||||
|
name = 'DebitAccess1726496225078'
|
||||||
|
|
||||||
|
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.query(`CREATE TABLE "debit_access" ("serial_id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "app_user_id" varchar NOT NULL, "key" varchar NOT NULL, "key_type" varchar NOT NULL, "total_debits" integer NOT NULL DEFAULT (0), "created_at" datetime NOT NULL DEFAULT (datetime('now')), "updated_at" datetime NOT NULL DEFAULT (datetime('now')))`);
|
||||||
|
await queryRunner.query(`CREATE UNIQUE INDEX "unique_debit_access" ON "debit_access" ("app_user_id", "key", "key_type") `);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.query(`DROP INDEX "unique_debit_access"`);
|
||||||
|
await queryRunner.query(`DROP TABLE "debit_access"`);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
import { MigrationInterface, QueryRunner } from "typeorm";
|
||||||
|
|
||||||
|
export class DebitAccessFixes1726685229264 implements MigrationInterface {
|
||||||
|
name = 'DebitAccessFixes1726685229264'
|
||||||
|
|
||||||
|
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.query(`DROP INDEX "unique_debit_access"`);
|
||||||
|
await queryRunner.query(`CREATE TABLE "temporary_debit_access" ("serial_id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "app_user_id" varchar NOT NULL, "total_debits" integer NOT NULL DEFAULT (0), "created_at" datetime NOT NULL DEFAULT (datetime('now')), "updated_at" datetime NOT NULL DEFAULT (datetime('now')))`);
|
||||||
|
await queryRunner.query(`INSERT INTO "temporary_debit_access"("serial_id", "app_user_id", "total_debits", "created_at", "updated_at") SELECT "serial_id", "app_user_id", "total_debits", "created_at", "updated_at" FROM "debit_access"`);
|
||||||
|
await queryRunner.query(`DROP TABLE "debit_access"`);
|
||||||
|
await queryRunner.query(`ALTER TABLE "temporary_debit_access" RENAME TO "debit_access"`);
|
||||||
|
await queryRunner.query(`CREATE TABLE "temporary_debit_access" ("serial_id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "app_user_id" varchar NOT NULL, "total_debits" integer NOT NULL DEFAULT (0), "created_at" datetime NOT NULL DEFAULT (datetime('now')), "updated_at" datetime NOT NULL DEFAULT (datetime('now')), "npub" varchar NOT NULL, "authorized" boolean NOT NULL, "rules" text)`);
|
||||||
|
await queryRunner.query(`INSERT INTO "temporary_debit_access"("serial_id", "app_user_id", "total_debits", "created_at", "updated_at") SELECT "serial_id", "app_user_id", "total_debits", "created_at", "updated_at" FROM "debit_access"`);
|
||||||
|
await queryRunner.query(`DROP TABLE "debit_access"`);
|
||||||
|
await queryRunner.query(`ALTER TABLE "temporary_debit_access" RENAME TO "debit_access"`);
|
||||||
|
await queryRunner.query(`CREATE UNIQUE INDEX "unique_debit_access" ON "debit_access" ("app_user_id", "npub") `);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.query(`DROP INDEX "unique_debit_access"`);
|
||||||
|
await queryRunner.query(`ALTER TABLE "debit_access" RENAME TO "temporary_debit_access"`);
|
||||||
|
await queryRunner.query(`CREATE TABLE "debit_access" ("serial_id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "app_user_id" varchar NOT NULL, "total_debits" integer NOT NULL DEFAULT (0), "created_at" datetime NOT NULL DEFAULT (datetime('now')), "updated_at" datetime NOT NULL DEFAULT (datetime('now')))`);
|
||||||
|
await queryRunner.query(`INSERT INTO "debit_access"("serial_id", "app_user_id", "total_debits", "created_at", "updated_at") SELECT "serial_id", "app_user_id", "total_debits", "created_at", "updated_at" FROM "temporary_debit_access"`);
|
||||||
|
await queryRunner.query(`DROP TABLE "temporary_debit_access"`);
|
||||||
|
await queryRunner.query(`ALTER TABLE "debit_access" RENAME TO "temporary_debit_access"`);
|
||||||
|
await queryRunner.query(`CREATE TABLE "debit_access" ("serial_id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "app_user_id" varchar NOT NULL, "key" varchar NOT NULL, "key_type" varchar NOT NULL, "total_debits" integer NOT NULL DEFAULT (0), "created_at" datetime NOT NULL DEFAULT (datetime('now')), "updated_at" datetime NOT NULL DEFAULT (datetime('now')))`);
|
||||||
|
await queryRunner.query(`INSERT INTO "debit_access"("serial_id", "app_user_id", "total_debits", "created_at", "updated_at") SELECT "serial_id", "app_user_id", "total_debits", "created_at", "updated_at" FROM "temporary_debit_access"`);
|
||||||
|
await queryRunner.query(`DROP TABLE "temporary_debit_access"`);
|
||||||
|
await queryRunner.query(`CREATE UNIQUE INDEX "unique_debit_access" ON "debit_access" ("app_user_id", "key", "key_type") `);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
import { MigrationInterface, QueryRunner } from "typeorm";
|
||||||
|
|
||||||
|
export class DebitToPub1727105758354 implements MigrationInterface {
|
||||||
|
name = 'DebitToPub1727105758354'
|
||||||
|
|
||||||
|
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.query(`DROP INDEX "IDX_a609a4d3d8d9b07b90692a3c45"`);
|
||||||
|
await queryRunner.query(`CREATE TABLE "temporary_user_invoice_payment" ("serial_id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "invoice" varchar NOT NULL, "paid_amount" integer NOT NULL, "routing_fees" integer NOT NULL, "service_fees" integer NOT NULL, "paid_at_unix" integer NOT NULL, "internal" boolean NOT NULL DEFAULT (0), "created_at" datetime NOT NULL DEFAULT (datetime('now')), "updated_at" datetime NOT NULL DEFAULT (datetime('now')), "userSerialId" integer, "linkedApplicationSerialId" integer, "liquidityProvider" varchar, "paymentIndex" integer NOT NULL DEFAULT (-1), "debit_to_pub" varchar, CONSTRAINT "FK_6bcac90887eea1dc61d37db2994" FOREIGN KEY ("linkedApplicationSerialId") REFERENCES "application" ("serial_id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_ef2aa6761ab681bbbd5f94e0fcb" FOREIGN KEY ("userSerialId") REFERENCES "user" ("serial_id") ON DELETE NO ACTION ON UPDATE NO ACTION)`);
|
||||||
|
await queryRunner.query(`INSERT INTO "temporary_user_invoice_payment"("serial_id", "invoice", "paid_amount", "routing_fees", "service_fees", "paid_at_unix", "internal", "created_at", "updated_at", "userSerialId", "linkedApplicationSerialId", "liquidityProvider", "paymentIndex") SELECT "serial_id", "invoice", "paid_amount", "routing_fees", "service_fees", "paid_at_unix", "internal", "created_at", "updated_at", "userSerialId", "linkedApplicationSerialId", "liquidityProvider", "paymentIndex" FROM "user_invoice_payment"`);
|
||||||
|
await queryRunner.query(`DROP TABLE "user_invoice_payment"`);
|
||||||
|
await queryRunner.query(`ALTER TABLE "temporary_user_invoice_payment" RENAME TO "user_invoice_payment"`);
|
||||||
|
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_a609a4d3d8d9b07b90692a3c45" ON "user_invoice_payment" ("invoice") `);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.query(`DROP INDEX "IDX_a609a4d3d8d9b07b90692a3c45"`);
|
||||||
|
await queryRunner.query(`ALTER TABLE "user_invoice_payment" RENAME TO "temporary_user_invoice_payment"`);
|
||||||
|
await queryRunner.query(`CREATE TABLE "user_invoice_payment" ("serial_id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "invoice" varchar NOT NULL, "paid_amount" integer NOT NULL, "routing_fees" integer NOT NULL, "service_fees" integer NOT NULL, "paid_at_unix" integer NOT NULL, "internal" boolean NOT NULL DEFAULT (0), "created_at" datetime NOT NULL DEFAULT (datetime('now')), "updated_at" datetime NOT NULL DEFAULT (datetime('now')), "userSerialId" integer, "linkedApplicationSerialId" integer, "liquidityProvider" varchar, "paymentIndex" integer NOT NULL DEFAULT (-1), CONSTRAINT "FK_6bcac90887eea1dc61d37db2994" FOREIGN KEY ("linkedApplicationSerialId") REFERENCES "application" ("serial_id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_ef2aa6761ab681bbbd5f94e0fcb" FOREIGN KEY ("userSerialId") REFERENCES "user" ("serial_id") ON DELETE NO ACTION ON UPDATE NO ACTION)`);
|
||||||
|
await queryRunner.query(`INSERT INTO "user_invoice_payment"("serial_id", "invoice", "paid_amount", "routing_fees", "service_fees", "paid_at_unix", "internal", "created_at", "updated_at", "userSerialId", "linkedApplicationSerialId", "liquidityProvider", "paymentIndex") SELECT "serial_id", "invoice", "paid_amount", "routing_fees", "service_fees", "paid_at_unix", "internal", "created_at", "updated_at", "userSerialId", "linkedApplicationSerialId", "liquidityProvider", "paymentIndex" FROM "temporary_user_invoice_payment"`);
|
||||||
|
await queryRunner.query(`DROP TABLE "temporary_user_invoice_payment"`);
|
||||||
|
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_a609a4d3d8d9b07b90692a3c45" ON "user_invoice_payment" ("invoice") `);
|
||||||
|
}
|
||||||
|
}
|
||||||
24
src/services/storage/migrations/1727112281043-user_cb_url.ts
Normal file
24
src/services/storage/migrations/1727112281043-user_cb_url.ts
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
import { MigrationInterface, QueryRunner } from "typeorm";
|
||||||
|
|
||||||
|
export class UserCbUrl1727112281043 implements MigrationInterface {
|
||||||
|
name = 'UserCbUrl1727112281043'
|
||||||
|
|
||||||
|
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
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, "callback_url" varchar NOT NULL DEFAULT (''), CONSTRAINT "REL_0796a381bcc624f52e9a155712" UNIQUE ("userSerialId"), CONSTRAINT "UQ_3175dc397c8285d1e532554dea5" UNIQUE ("nostr_public_key"), CONSTRAINT "FK_1b3bdb6f660cd99533a1e673ef1" FOREIGN KEY ("applicationSerialId") REFERENCES "application" ("serial_id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_0796a381bcc624f52e9a155712b" FOREIGN KEY ("userSerialId") REFERENCES "user" ("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(`DROP TABLE "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") `);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.query(`DROP INDEX "IDX_0a0dbb25a73306b037dec82251"`);
|
||||||
|
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 "REL_0796a381bcc624f52e9a155712" UNIQUE ("userSerialId"), CONSTRAINT "UQ_3175dc397c8285d1e532554dea5" UNIQUE ("nostr_public_key"), CONSTRAINT "FK_1b3bdb6f660cd99533a1e673ef1" FOREIGN KEY ("applicationSerialId") REFERENCES "application" ("serial_id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_0796a381bcc624f52e9a155712b" FOREIGN KEY ("userSerialId") REFERENCES "user" ("serial_id") ON DELETE NO ACTION ON UPDATE NO ACTION)`);
|
||||||
|
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(`CREATE UNIQUE INDEX "IDX_0a0dbb25a73306b037dec82251" ON "application_user" ("identifier") `);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -12,7 +12,11 @@ import { CreateInviteTokenTable1721751414878 } from "./1721751414878-create_invi
|
||||||
import { PaymentIndex1721760297610 } from './1721760297610-payment_index.js'
|
import { PaymentIndex1721760297610 } from './1721760297610-payment_index.js'
|
||||||
import { HtlcCount1724266887195 } from './1724266887195-htlc_count.js'
|
import { HtlcCount1724266887195 } from './1724266887195-htlc_count.js'
|
||||||
import { BalanceEvents1724860966825 } from './1724860966825-balance_events.js'
|
import { BalanceEvents1724860966825 } from './1724860966825-balance_events.js'
|
||||||
const allMigrations = [Initial1703170309875, LspOrder1718387847693, LiquidityProvider1719335699480, LndNodeInfo1720187506189, TrackedProvider1720814323679, CreateInviteTokenTable1721751414878, PaymentIndex1721760297610]
|
import { DebitAccess1726496225078 } from './1726496225078-debit_access.js'
|
||||||
|
import { DebitAccessFixes1726685229264 } from './1726685229264-debit_access_fixes.js'
|
||||||
|
import { DebitToPub1727105758354 } from './1727105758354-debit_to_pub.js'
|
||||||
|
import { UserCbUrl1727112281043 } from './1727112281043-user_cb_url.js'
|
||||||
|
const allMigrations = [Initial1703170309875, LspOrder1718387847693, LiquidityProvider1719335699480, LndNodeInfo1720187506189, TrackedProvider1720814323679, CreateInviteTokenTable1721751414878, PaymentIndex1721760297610, DebitAccess1726496225078, DebitAccessFixes1726685229264, DebitToPub1727105758354, UserCbUrl1727112281043]
|
||||||
const allMetricsMigrations = [LndMetrics1703170330183, ChannelRouting1709316653538, HtlcCount1724266887195, BalanceEvents1724860966825]
|
const allMetricsMigrations = [LndMetrics1703170330183, ChannelRouting1709316653538, HtlcCount1724266887195, BalanceEvents1724860966825]
|
||||||
export const TypeOrmMigrationRunner = async (log: PubLogger, storageManager: Storage, settings: DbSettings, arg: string | undefined): Promise<boolean> => {
|
export const TypeOrmMigrationRunner = async (log: PubLogger, storageManager: Storage, settings: DbSettings, arg: string | undefined): Promise<boolean> => {
|
||||||
if (arg === 'fake_initial_migration') {
|
if (arg === 'fake_initial_migration') {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import crypto from 'crypto';
|
import crypto from 'crypto';
|
||||||
import { Between, DataSource, EntityManager, FindOperator, IsNull, LessThanOrEqual, MoreThan, MoreThanOrEqual } from "typeorm"
|
import { Between, DataSource, EntityManager, FindOperator, IsNull, LessThanOrEqual, MoreThan, MoreThanOrEqual, Not } from "typeorm"
|
||||||
import { User } from './entity/User.js';
|
import { User } from './entity/User.js';
|
||||||
import { UserTransactionPayment } from './entity/UserTransactionPayment.js';
|
import { UserTransactionPayment } from './entity/UserTransactionPayment.js';
|
||||||
import { EphemeralKeyType, UserEphemeralKey } from './entity/UserEphemeralKey.js';
|
import { EphemeralKeyType, UserEphemeralKey } from './entity/UserEphemeralKey.js';
|
||||||
|
|
@ -154,9 +154,9 @@ export default class {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async AddPendingExternalPayment(userId: string, invoice: string, amounts: { payAmount: number, serviceFee: number, networkFee: number }, linkedApplication: Application, liquidityProvider: string | undefined,dbTx:DataSource|EntityManager): Promise<UserInvoicePayment> {
|
async AddPendingExternalPayment(userId: string, invoice: string, amounts: { payAmount: number, serviceFee: number, networkFee: number }, linkedApplication: Application, liquidityProvider: string | undefined, dbTx: DataSource | EntityManager, debitNpub?: string): Promise<UserInvoicePayment> {
|
||||||
const newPayment = dbTx.getRepository(UserInvoicePayment).create({
|
const newPayment = dbTx.getRepository(UserInvoicePayment).create({
|
||||||
user: await this.userStorage.GetUser(userId,dbTx),
|
user: await this.userStorage.GetUser(userId, dbTx),
|
||||||
paid_amount: amounts.payAmount,
|
paid_amount: amounts.payAmount,
|
||||||
invoice,
|
invoice,
|
||||||
routing_fees: amounts.networkFee,
|
routing_fees: amounts.networkFee,
|
||||||
|
|
@ -164,7 +164,8 @@ export default class {
|
||||||
paid_at_unix: 0,
|
paid_at_unix: 0,
|
||||||
internal: false,
|
internal: false,
|
||||||
linkedApplication,
|
linkedApplication,
|
||||||
liquidityProvider
|
liquidityProvider,
|
||||||
|
debit_to_pub: debitNpub
|
||||||
})
|
})
|
||||||
return dbTx.getRepository(UserInvoicePayment).save(newPayment)
|
return dbTx.getRepository(UserInvoicePayment).save(newPayment)
|
||||||
}
|
}
|
||||||
|
|
@ -185,7 +186,7 @@ export default class {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async AddInternalPayment(userId: string, invoice: string, amount: number, serviceFees: number, linkedApplication: Application): Promise<UserInvoicePayment> {
|
async AddInternalPayment(userId: string, invoice: string, amount: number, serviceFees: number, linkedApplication: Application, debitNpub?: string): Promise<UserInvoicePayment> {
|
||||||
const newPayment = this.DB.getRepository(UserInvoicePayment).create({
|
const newPayment = this.DB.getRepository(UserInvoicePayment).create({
|
||||||
user: await this.userStorage.GetUser(userId),
|
user: await this.userStorage.GetUser(userId),
|
||||||
paid_amount: amount,
|
paid_amount: amount,
|
||||||
|
|
@ -194,7 +195,8 @@ export default class {
|
||||||
service_fees: serviceFees,
|
service_fees: serviceFees,
|
||||||
paid_at_unix: Math.floor(Date.now() / 1000),
|
paid_at_unix: Math.floor(Date.now() / 1000),
|
||||||
internal: true,
|
internal: true,
|
||||||
linkedApplication
|
linkedApplication,
|
||||||
|
debit_to_pub: debitNpub
|
||||||
})
|
})
|
||||||
return this.txQueue.PushToQueue<UserInvoicePayment>({ exec: async db => db.getRepository(UserInvoicePayment).save(newPayment), dbTx: false, description: `add internal invoice payment for ${userId} linked to ${linkedApplication.app_id}: ${invoice}, amt: ${amount} ` })
|
return this.txQueue.PushToQueue<UserInvoicePayment>({ exec: async db => db.getRepository(UserInvoicePayment).save(newPayment), dbTx: false, description: `add internal invoice payment for ${userId} linked to ${linkedApplication.app_id}: ${invoice}, amt: ${amount} ` })
|
||||||
}
|
}
|
||||||
|
|
@ -215,6 +217,25 @@ export default class {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GetUserDebitPayments(userId: string, sinceUnix: number, debitToNpub: string, entityManager = this.DB): Promise<UserInvoicePayment[]> {
|
||||||
|
const pending = {
|
||||||
|
user: { user_id: userId },
|
||||||
|
debit_to_pub: debitToNpub,
|
||||||
|
paid_at_unix: 0,
|
||||||
|
}
|
||||||
|
const paid = {
|
||||||
|
user: { user_id: userId },
|
||||||
|
debit_to_pub: debitToNpub,
|
||||||
|
paid_at_unix: MoreThan(sinceUnix),
|
||||||
|
}
|
||||||
|
return entityManager.getRepository(UserInvoicePayment).find({
|
||||||
|
where: [pending, paid],
|
||||||
|
order: {
|
||||||
|
paid_at_unix: 'DESC'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
async AddUserTransactionPayment(userId: string, address: string, txHash: string, txOutput: number, amount: number, chainFees: number, serviceFees: number, internal: boolean, height: number, linkedApplication: Application): Promise<UserTransactionPayment> {
|
async AddUserTransactionPayment(userId: string, address: string, txHash: string, txOutput: number, amount: number, chainFees: number, serviceFees: number, internal: boolean, height: number, linkedApplication: Application): Promise<UserTransactionPayment> {
|
||||||
const newTx = this.DB.getRepository(UserTransactionPayment).create({
|
const newTx = this.DB.getRepository(UserTransactionPayment).create({
|
||||||
user: await this.userStorage.GetUser(userId),
|
user: await this.userStorage.GetUser(userId),
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue