commit
a3c1f954d6
34 changed files with 2453 additions and 163 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -15,8 +15,10 @@ data/
|
|||
.wallet_secret
|
||||
.wallet_password
|
||||
.admin_enroll
|
||||
admin.enroll
|
||||
admin.npub
|
||||
app.nprofile
|
||||
.admin_connect
|
||||
admin.connect
|
||||
debug.txt
|
||||
proto/autogenerated/debug.txt
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ import { LndNodeInfo } from "./build/src/services/storage/entity/LndNodeInfo.js"
|
|||
import { TrackedProvider } from "./build/src/services/storage/entity/TrackedProvider.js"
|
||||
import { InviteToken } from "./build/src/services/storage/entity/InviteToken.js"
|
||||
import { DebitAccess } from "./build/src/services/storage/entity/DebitAccess.js"
|
||||
import { UserOffer } from "./build/src/services/storage/entity/UserOffer.js"
|
||||
|
||||
import { Initial1703170309875 } from './build/src/services/storage/migrations/1703170309875-initial.js'
|
||||
import { LspOrder1718387847693 } from './build/src/services/storage/migrations/1718387847693-lsp_order.js'
|
||||
|
|
@ -27,13 +28,14 @@ import { DebitAccess1726496225078 } from './build/src/services/storage/migration
|
|||
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'
|
||||
import { UserOffer1733502626042 } from './build/src/services/storage/migrations/1733502626042-user_offer.js'
|
||||
export default new DataSource({
|
||||
type: "sqlite",
|
||||
database: "db.sqlite",
|
||||
// logging: true,
|
||||
migrations: [Initial1703170309875, LspOrder1718387847693, LiquidityProvider1719335699480, LndNodeInfo1720187506189, CreateInviteTokenTable1721751414878, PaymentIndex1721760297610, DebitAccess1726496225078, DebitAccessFixes1726685229264, DebitToPub1727105758354, UserCbUrl1727112281043],
|
||||
migrations: [Initial1703170309875, LspOrder1718387847693, LiquidityProvider1719335699480, LndNodeInfo1720187506189, CreateInviteTokenTable1721751414878, PaymentIndex1721760297610, DebitAccess1726496225078, DebitAccessFixes1726685229264, DebitToPub1727105758354, UserCbUrl1727112281043, UserOffer1733502626042],
|
||||
entities: [User, UserReceivingInvoice, UserReceivingAddress, AddressReceivingTransaction, UserInvoicePayment, UserTransactionPayment,
|
||||
UserBasicAuth, UserEphemeralKey, Product, UserToUserPayment, Application, ApplicationUser, UserToUserPayment, LspOrder, LndNodeInfo, TrackedProvider, InviteToken, DebitAccess],
|
||||
UserBasicAuth, UserEphemeralKey, Product, UserToUserPayment, Application, ApplicationUser, UserToUserPayment, LspOrder, LndNodeInfo, TrackedProvider, InviteToken, DebitAccess, UserOffer],
|
||||
// synchronize: true,
|
||||
})
|
||||
//npx typeorm migration:generate ./src/services/storage/migrations/usert_cb_url -d ./datasource.js
|
||||
//npx typeorm migration:generate ./src/services/storage/migrations/user_offer -d ./datasource.js
|
||||
10
package-lock.json
generated
10
package-lock.json
generated
|
|
@ -32,7 +32,7 @@
|
|||
"grpc-tools": "^1.12.4",
|
||||
"jsonwebtoken": "^9.0.2",
|
||||
"lodash": "^4.17.21",
|
||||
"nostr-tools": "github:shocknet/nostr-tools#da188cd4bd195f44cc690074a3898f354ae85100",
|
||||
"nostr-tools": "github:shocknet/nostr-tools#27575ffb69d615691242df433a0ccc063f6b8346",
|
||||
"pg": "^8.4.0",
|
||||
"reflect-metadata": "^0.2.2",
|
||||
"rimraf": "^3.0.2",
|
||||
|
|
@ -3796,9 +3796,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/nostr-tools": {
|
||||
"version": "2.8.0",
|
||||
"resolved": "git+ssh://git@github.com/shocknet/nostr-tools.git#da188cd4bd195f44cc690074a3898f354ae85100",
|
||||
"integrity": "sha512-kc41K75rXEnLhqIwlQmjaGsZ9yYTbyP8VW7B2Q+0U/pqaMyt25Nt0QCWiIYS04m0sanvD77OhmddvI1s2ntKog==",
|
||||
"version": "2.10.4",
|
||||
"resolved": "git+ssh://git@github.com/shocknet/nostr-tools.git#27575ffb69d615691242df433a0ccc063f6b8346",
|
||||
"integrity": "sha512-ZQxr1yalFLi5coqG5pHWmjHGehLgCZbQusE/59mre/CgqrFMbGJY77AGTyhDnaGgqRc7B/UJnIvqGVVKhTVRmQ==",
|
||||
"license": "Unlicense",
|
||||
"dependencies": {
|
||||
"@noble/ciphers": "^0.5.1",
|
||||
|
|
@ -3809,7 +3809,7 @@
|
|||
"@scure/bip39": "1.2.1"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"nostr-wasm": "v0.1.0"
|
||||
"nostr-wasm": "0.1.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": ">=5.0.0"
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@
|
|||
"grpc-tools": "^1.12.4",
|
||||
"jsonwebtoken": "^9.0.2",
|
||||
"lodash": "^4.17.21",
|
||||
"nostr-tools": "github:shocknet/nostr-tools#da188cd4bd195f44cc690074a3898f354ae85100",
|
||||
"nostr-tools": "github:shocknet/nostr-tools#27575ffb69d615691242df433a0ccc063f6b8346",
|
||||
"pg": "^8.4.0",
|
||||
"reflect-metadata": "^0.2.2",
|
||||
"rimraf": "^3.0.2",
|
||||
|
|
|
|||
|
|
@ -28,6 +28,11 @@ The nostr server will send back a message response, and inside the body there wi
|
|||
- input: [AddProductRequest](#AddProductRequest)
|
||||
- output: [Product](#Product)
|
||||
|
||||
- AddUserOffer
|
||||
- auth type: __User__
|
||||
- input: [OfferConfig](#OfferConfig)
|
||||
- output: [OfferId](#OfferId)
|
||||
|
||||
- AuthApp
|
||||
- auth type: __Admin__
|
||||
- input: [AuthAppRequest](#AuthAppRequest)
|
||||
|
|
@ -68,6 +73,11 @@ The nostr server will send back a message response, and inside the body there wi
|
|||
- input: [DecodeInvoiceRequest](#DecodeInvoiceRequest)
|
||||
- output: [DecodeInvoiceResponse](#DecodeInvoiceResponse)
|
||||
|
||||
- DeleteUserOffer
|
||||
- auth type: __User__
|
||||
- input: [OfferId](#OfferId)
|
||||
- This methods has an __empty__ __response__ body
|
||||
|
||||
- EditDebit
|
||||
- auth type: __User__
|
||||
- input: [DebitAuthorizationRequest](#DebitAuthorizationRequest)
|
||||
|
|
@ -88,6 +98,11 @@ The nostr server will send back a message response, and inside the body there wi
|
|||
- This methods has an __empty__ __request__ body
|
||||
- output: [DebitAuthorizations](#DebitAuthorizations)
|
||||
|
||||
- GetErrorStats
|
||||
- auth type: __Metrics__
|
||||
- This methods has an __empty__ __request__ body
|
||||
- output: [ErrorStats](#ErrorStats)
|
||||
|
||||
- GetHttpCreds
|
||||
- auth type: __User__
|
||||
- This methods has an __empty__ __request__ body
|
||||
|
|
@ -153,6 +168,21 @@ The nostr server will send back a message response, and inside the body there wi
|
|||
- This methods has an __empty__ __request__ body
|
||||
- output: [UserInfo](#UserInfo)
|
||||
|
||||
- GetUserOffer
|
||||
- auth type: __User__
|
||||
- input: [OfferId](#OfferId)
|
||||
- output: [OfferConfig](#OfferConfig)
|
||||
|
||||
- GetUserOfferInvoices
|
||||
- auth type: __User__
|
||||
- input: [GetUserOfferInvoicesReq](#GetUserOfferInvoicesReq)
|
||||
- output: [OfferInvoices](#OfferInvoices)
|
||||
|
||||
- GetUserOffers
|
||||
- auth type: __User__
|
||||
- This methods has an __empty__ __request__ body
|
||||
- output: [UserOffers](#UserOffers)
|
||||
|
||||
- GetUserOperations
|
||||
- auth type: __User__
|
||||
- input: [GetUserOperationsRequest](#GetUserOperationsRequest)
|
||||
|
|
@ -225,6 +255,11 @@ The nostr server will send back a message response, and inside the body there wi
|
|||
- input: [UpdateChannelPolicyRequest](#UpdateChannelPolicyRequest)
|
||||
- This methods has an __empty__ __response__ body
|
||||
|
||||
- UpdateUserOffer
|
||||
- auth type: __User__
|
||||
- input: [OfferConfig](#OfferConfig)
|
||||
- This methods has an __empty__ __response__ body
|
||||
|
||||
- UseInviteLink
|
||||
- auth type: __GuestWithPub__
|
||||
- input: [UseInviteLinkRequest](#UseInviteLinkRequest)
|
||||
|
|
@ -233,7 +268,7 @@ The nostr server will send back a message response, and inside the body there wi
|
|||
- UserHealth
|
||||
- auth type: __User__
|
||||
- This methods has an __empty__ __request__ body
|
||||
- This methods has an __empty__ __response__ body
|
||||
- output: [UserHealthState](#UserHealthState)
|
||||
|
||||
# HTTP API DEFINITION
|
||||
|
||||
|
|
@ -311,6 +346,13 @@ The nostr server will send back a message response, and inside the body there wi
|
|||
- input: [AddProductRequest](#AddProductRequest)
|
||||
- output: [Product](#Product)
|
||||
|
||||
- AddUserOffer
|
||||
- auth type: __User__
|
||||
- http method: __post__
|
||||
- http route: __/api/user/offer/add__
|
||||
- input: [OfferConfig](#OfferConfig)
|
||||
- output: [OfferId](#OfferId)
|
||||
|
||||
- AuthApp
|
||||
- auth type: __Admin__
|
||||
- http method: __post__
|
||||
|
|
@ -367,6 +409,13 @@ The nostr server will send back a message response, and inside the body there wi
|
|||
- input: [DecodeInvoiceRequest](#DecodeInvoiceRequest)
|
||||
- output: [DecodeInvoiceResponse](#DecodeInvoiceResponse)
|
||||
|
||||
- DeleteUserOffer
|
||||
- auth type: __User__
|
||||
- http method: __post__
|
||||
- http route: __/api/user/offer/delete__
|
||||
- input: [OfferId](#OfferId)
|
||||
- This methods has an __empty__ __response__ body
|
||||
|
||||
- EditDebit
|
||||
- auth type: __User__
|
||||
- http method: __post__
|
||||
|
|
@ -423,6 +472,13 @@ The nostr server will send back a message response, and inside the body there wi
|
|||
- This methods has an __empty__ __request__ body
|
||||
- output: [DebitAuthorizations](#DebitAuthorizations)
|
||||
|
||||
- GetErrorStats
|
||||
- auth type: __Metrics__
|
||||
- http method: __post__
|
||||
- http route: __/api/reports/errors__
|
||||
- This methods has an __empty__ __request__ body
|
||||
- output: [ErrorStats](#ErrorStats)
|
||||
|
||||
- GetHttpCreds
|
||||
- auth type: __User__
|
||||
- http method: __post__
|
||||
|
|
@ -539,6 +595,27 @@ The nostr server will send back a message response, and inside the body there wi
|
|||
- This methods has an __empty__ __request__ body
|
||||
- output: [UserInfo](#UserInfo)
|
||||
|
||||
- GetUserOffer
|
||||
- auth type: __User__
|
||||
- http method: __post__
|
||||
- http route: __/api/user/offer/get__
|
||||
- input: [OfferId](#OfferId)
|
||||
- output: [OfferConfig](#OfferConfig)
|
||||
|
||||
- GetUserOfferInvoices
|
||||
- auth type: __User__
|
||||
- http method: __post__
|
||||
- http route: __/api/user/offer/get/invoices__
|
||||
- input: [GetUserOfferInvoicesReq](#GetUserOfferInvoicesReq)
|
||||
- output: [OfferInvoices](#OfferInvoices)
|
||||
|
||||
- GetUserOffers
|
||||
- auth type: __User__
|
||||
- http method: __get__
|
||||
- http route: __/api/user/offers/get__
|
||||
- This methods has an __empty__ __request__ body
|
||||
- output: [UserOffers](#UserOffers)
|
||||
|
||||
- GetUserOperations
|
||||
- auth type: __User__
|
||||
- http method: __post__
|
||||
|
|
@ -733,6 +810,13 @@ The nostr server will send back a message response, and inside the body there wi
|
|||
- input: [UpdateChannelPolicyRequest](#UpdateChannelPolicyRequest)
|
||||
- This methods has an __empty__ __response__ body
|
||||
|
||||
- UpdateUserOffer
|
||||
- auth type: __User__
|
||||
- http method: __post__
|
||||
- http route: __/api/user/offer/update__
|
||||
- input: [OfferConfig](#OfferConfig)
|
||||
- This methods has an __empty__ __response__ body
|
||||
|
||||
- UseInviteLink
|
||||
- auth type: __GuestWithPub__
|
||||
- http method: __post__
|
||||
|
|
@ -745,7 +829,7 @@ The nostr server will send back a message response, and inside the body there wi
|
|||
- http method: __post__
|
||||
- http route: __/api/user/health__
|
||||
- This methods has an __empty__ __request__ body
|
||||
- This methods has an __empty__ __response__ body
|
||||
- output: [UserHealthState](#UserHealthState)
|
||||
|
||||
# INPUTS AND OUTPUTS
|
||||
|
||||
|
|
@ -764,6 +848,8 @@ The nostr server will send back a message response, and inside the body there wi
|
|||
### AddAppUserInvoiceRequest
|
||||
- __http_callback_url__: _string_
|
||||
- __invoice_req__: _[NewInvoiceRequest](#NewInvoiceRequest)_
|
||||
- __offer_string__: _string_ *this field is optional
|
||||
- __payer_data__: _[PayerData](#PayerData)_ *this field is optional
|
||||
- __payer_identifier__: _string_
|
||||
- __receiver_identifier__: _string_
|
||||
|
||||
|
|
@ -792,6 +878,9 @@ The nostr server will send back a message response, and inside the body there wi
|
|||
- __total_fees__: _number_
|
||||
- __users__: _[UsersInfo](#UsersInfo)_
|
||||
|
||||
### AppUsageMetrics
|
||||
- __app_metrics__: MAP with key: _string_ and value: _[UsageMetricTlv](#UsageMetricTlv)_
|
||||
|
||||
### AppUser
|
||||
- __identifier__: _string_
|
||||
- __info__: _[UserInfo](#UserInfo)_
|
||||
|
|
@ -909,6 +998,18 @@ The nostr server will send back a message response, and inside the body there wi
|
|||
### EnrollAdminTokenRequest
|
||||
- __admin_token__: _string_
|
||||
|
||||
### ErrorStat
|
||||
- __errors__: _number_
|
||||
- __from_unix__: _number_
|
||||
- __total__: _number_
|
||||
|
||||
### ErrorStats
|
||||
- __past10m__: _[ErrorStat](#ErrorStat)_
|
||||
- __past1h__: _[ErrorStat](#ErrorStat)_
|
||||
- __past1m__: _[ErrorStat](#ErrorStat)_
|
||||
- __past24h__: _[ErrorStat](#ErrorStat)_
|
||||
- __past6h__: _[ErrorStat](#ErrorStat)_
|
||||
|
||||
### FrequencyRule
|
||||
- __amount__: _number_
|
||||
- __interval__: _[IntervalType](#IntervalType)_
|
||||
|
|
@ -936,6 +1037,10 @@ The nostr server will send back a message response, and inside the body there wi
|
|||
### GetProductBuyLinkResponse
|
||||
- __link__: _string_
|
||||
|
||||
### GetUserOfferInvoicesReq
|
||||
- __include_unpaid__: _boolean_
|
||||
- __offer_id__: _string_
|
||||
|
||||
### GetUserOperationsRequest
|
||||
- __latestIncomingInvoice__: _number_
|
||||
- __latestIncomingTx__: _number_
|
||||
|
|
@ -1056,6 +1161,28 @@ The nostr server will send back a message response, and inside the body there wi
|
|||
### NewInvoiceResponse
|
||||
- __invoice__: _string_
|
||||
|
||||
### OfferConfig
|
||||
- __callback_url__: _string_
|
||||
- __default_offer__: _boolean_
|
||||
- __expected_data__: MAP with key: _string_ and value: _[OfferDataType](#OfferDataType)_
|
||||
- __label__: _string_
|
||||
- __noffer__: _string_
|
||||
- __offer_id__: _string_
|
||||
- __price_sats__: _number_
|
||||
|
||||
### OfferId
|
||||
- __offer_id__: _string_
|
||||
|
||||
### OfferInvoice
|
||||
- __amount__: _number_
|
||||
- __data__: MAP with key: _string_ and value: _string_
|
||||
- __invoice__: _string_
|
||||
- __offer_id__: _string_
|
||||
- __paid_at_unix__: _number_
|
||||
|
||||
### OfferInvoices
|
||||
- __invoices__: ARRAY of: _[OfferInvoice](#OfferInvoice)_
|
||||
|
||||
### OpenChannel
|
||||
- __active__: _boolean_
|
||||
- __capacity__: _number_
|
||||
|
|
@ -1106,6 +1233,9 @@ The nostr server will send back a message response, and inside the body there wi
|
|||
- __preimage__: _string_
|
||||
- __service_fee__: _number_
|
||||
|
||||
### PayerData
|
||||
- __data__: MAP with key: _string_ and value: _string_
|
||||
|
||||
### PaymentState
|
||||
- __amount__: _number_
|
||||
- __network_fee__: _number_
|
||||
|
|
@ -1172,6 +1302,7 @@ The nostr server will send back a message response, and inside the body there wi
|
|||
- __update__: _[UpdateChannelPolicyRequest_update](#UpdateChannelPolicyRequest_update)_
|
||||
|
||||
### UsageMetric
|
||||
- __app_id__: _string_ *this field is optional
|
||||
- __auth_in_nano__: _number_
|
||||
- __batch__: _boolean_
|
||||
- __batch_size__: _number_
|
||||
|
|
@ -1180,14 +1311,23 @@ The nostr server will send back a message response, and inside the body there wi
|
|||
- __parsed_in_nano__: _number_
|
||||
- __processed_at_ms__: _number_
|
||||
- __rpc_name__: _string_
|
||||
- __success__: _boolean_
|
||||
- __validate_in_nano__: _number_
|
||||
|
||||
### UsageMetricTlv
|
||||
- __available_chunks__: ARRAY of: _number_
|
||||
- __base_64_tlvs__: ARRAY of: _string_
|
||||
- __current_chunk__: _number_
|
||||
|
||||
### UsageMetrics
|
||||
- __metrics__: ARRAY of: _[UsageMetric](#UsageMetric)_
|
||||
- __apps__: MAP with key: _string_ and value: _[AppUsageMetrics](#AppUsageMetrics)_
|
||||
|
||||
### UseInviteLinkRequest
|
||||
- __invite_token__: _string_
|
||||
|
||||
### UserHealthState
|
||||
- __downtime_reason__: _string_
|
||||
|
||||
### UserInfo
|
||||
- __balance__: _number_
|
||||
- __bridge_url__: _string_
|
||||
|
|
@ -1201,6 +1341,9 @@ The nostr server will send back a message response, and inside the body there wi
|
|||
- __userId__: _string_
|
||||
- __user_identifier__: _string_
|
||||
|
||||
### UserOffers
|
||||
- __offers__: ARRAY of: _[OfferConfig](#OfferConfig)_
|
||||
|
||||
### UserOperation
|
||||
- __amount__: _number_
|
||||
- __confirmed__: _boolean_
|
||||
|
|
@ -1239,6 +1382,9 @@ The nostr server will send back a message response, and inside the body there wi
|
|||
- __MONTH__
|
||||
- __WEEK__
|
||||
|
||||
### OfferDataType
|
||||
- __DATA_STRING__
|
||||
|
||||
### OperationType
|
||||
- __CHAIN_OP__
|
||||
- __INVOICE_OP__
|
||||
|
|
|
|||
|
|
@ -60,6 +60,7 @@ type Client struct {
|
|||
AddAppUserInvoice func(req AddAppUserInvoiceRequest) (*NewInvoiceResponse, error)
|
||||
AddPeer func(req AddPeerRequest) error
|
||||
AddProduct func(req AddProductRequest) (*Product, error)
|
||||
AddUserOffer func(req OfferConfig) (*OfferId, error)
|
||||
AuthApp func(req AuthAppRequest) (*AuthApp, error)
|
||||
AuthorizeDebit func(req DebitAuthorizationRequest) (*DebitAuthorization, error)
|
||||
BanDebit func(req DebitOperation) error
|
||||
|
|
@ -68,6 +69,7 @@ type Client struct {
|
|||
CloseChannel func(req CloseChannelRequest) (*CloseChannelResponse, error)
|
||||
CreateOneTimeInviteLink func(req CreateOneTimeInviteLinkRequest) (*CreateOneTimeInviteLinkResponse, error)
|
||||
DecodeInvoice func(req DecodeInvoiceRequest) (*DecodeInvoiceResponse, error)
|
||||
DeleteUserOffer func(req OfferId) error
|
||||
EditDebit func(req DebitAuthorizationRequest) error
|
||||
EncryptionExchange func(req EncryptionExchangeRequest) error
|
||||
EnrollAdminToken func(req EnrollAdminTokenRequest) error
|
||||
|
|
@ -76,6 +78,7 @@ type Client struct {
|
|||
GetAppUserLNURLInfo func(req GetAppUserLNURLInfoRequest) (*LnurlPayInfoResponse, error)
|
||||
GetAppsMetrics func(req AppsMetricsRequest) (*AppsMetrics, error)
|
||||
GetDebitAuthorizations func() (*DebitAuthorizations, error)
|
||||
GetErrorStats func() (*ErrorStats, error)
|
||||
GetHttpCreds func() (*HttpCreds, error)
|
||||
GetInviteLinkState func(req GetInviteTokenStateRequest) (*GetInviteTokenStateResponse, error)
|
||||
GetLNURLChannelLink func() (*LnurlLinkResponse, error)
|
||||
|
|
@ -92,6 +95,9 @@ type Client struct {
|
|||
GetSeed func() (*LndSeed, error)
|
||||
GetUsageMetrics func() (*UsageMetrics, error)
|
||||
GetUserInfo func() (*UserInfo, error)
|
||||
GetUserOffer func(req OfferId) (*OfferConfig, error)
|
||||
GetUserOfferInvoices func(req GetUserOfferInvoicesReq) (*OfferInvoices, error)
|
||||
GetUserOffers func() (*UserOffers, error)
|
||||
GetUserOperations func(req GetUserOperationsRequest) (*GetUserOperationsResponse, error)
|
||||
HandleLnurlAddress func(routeParams HandleLnurlAddress_RouteParams) (*LnurlPayInfoResponse, error)
|
||||
HandleLnurlPay func(query HandleLnurlPay_Query) (*HandleLnurlPayResponse, error)
|
||||
|
|
@ -118,8 +124,9 @@ type Client struct {
|
|||
SetMockInvoiceAsPaid func(req SetMockInvoiceAsPaidRequest) error
|
||||
UpdateCallbackUrl func(req CallbackUrl) (*CallbackUrl, error)
|
||||
UpdateChannelPolicy func(req UpdateChannelPolicyRequest) error
|
||||
UpdateUserOffer func(req OfferConfig) error
|
||||
UseInviteLink func(req UseInviteLinkRequest) error
|
||||
UserHealth func() error
|
||||
UserHealth func() (*UserHealthState, error)
|
||||
}
|
||||
|
||||
func NewClient(params ClientParams) *Client {
|
||||
|
|
@ -293,6 +300,35 @@ func NewClient(params ClientParams) *Client {
|
|||
}
|
||||
return &res, nil
|
||||
},
|
||||
AddUserOffer: func(req OfferConfig) (*OfferId, error) {
|
||||
auth, err := params.RetrieveUserAuth()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
finalRoute := "/api/user/offer/add"
|
||||
body, err := json.Marshal(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resBody, err := doPostRequest(params.BaseURL+finalRoute, body, auth)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result := ResultError{}
|
||||
err = json.Unmarshal(resBody, &result)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if result.Status == "ERROR" {
|
||||
return nil, fmt.Errorf(result.Reason)
|
||||
}
|
||||
res := OfferId{}
|
||||
err = json.Unmarshal(resBody, &res)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &res, nil
|
||||
},
|
||||
AuthApp: func(req AuthAppRequest) (*AuthApp, error) {
|
||||
auth, err := params.RetrieveAdminAuth()
|
||||
if err != nil {
|
||||
|
|
@ -492,6 +528,30 @@ func NewClient(params ClientParams) *Client {
|
|||
}
|
||||
return &res, nil
|
||||
},
|
||||
DeleteUserOffer: func(req OfferId) error {
|
||||
auth, err := params.RetrieveUserAuth()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
finalRoute := "/api/user/offer/delete"
|
||||
body, err := json.Marshal(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
resBody, err := doPostRequest(params.BaseURL+finalRoute, body, auth)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
result := ResultError{}
|
||||
err = json.Unmarshal(resBody, &result)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if result.Status == "ERROR" {
|
||||
return fmt.Errorf(result.Reason)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
EditDebit: func(req DebitAuthorizationRequest) error {
|
||||
auth, err := params.RetrieveUserAuth()
|
||||
if err != nil {
|
||||
|
|
@ -699,6 +759,32 @@ func NewClient(params ClientParams) *Client {
|
|||
}
|
||||
return &res, nil
|
||||
},
|
||||
GetErrorStats: func() (*ErrorStats, error) {
|
||||
auth, err := params.RetrieveMetricsAuth()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
finalRoute := "/api/reports/errors"
|
||||
body := []byte{}
|
||||
resBody, err := doPostRequest(params.BaseURL+finalRoute, body, auth)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result := ResultError{}
|
||||
err = json.Unmarshal(resBody, &result)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if result.Status == "ERROR" {
|
||||
return nil, fmt.Errorf(result.Reason)
|
||||
}
|
||||
res := ErrorStats{}
|
||||
err = json.Unmarshal(resBody, &res)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &res, nil
|
||||
},
|
||||
// server streaming method: GetHttpCreds not implemented
|
||||
GetInviteLinkState: func(req GetInviteTokenStateRequest) (*GetInviteTokenStateResponse, error) {
|
||||
auth, err := params.RetrieveAdminAuth()
|
||||
|
|
@ -1023,6 +1109,86 @@ func NewClient(params ClientParams) *Client {
|
|||
}
|
||||
return &res, nil
|
||||
},
|
||||
GetUserOffer: func(req OfferId) (*OfferConfig, error) {
|
||||
auth, err := params.RetrieveUserAuth()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
finalRoute := "/api/user/offer/get"
|
||||
body, err := json.Marshal(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resBody, err := doPostRequest(params.BaseURL+finalRoute, body, auth)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result := ResultError{}
|
||||
err = json.Unmarshal(resBody, &result)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if result.Status == "ERROR" {
|
||||
return nil, fmt.Errorf(result.Reason)
|
||||
}
|
||||
res := OfferConfig{}
|
||||
err = json.Unmarshal(resBody, &res)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &res, nil
|
||||
},
|
||||
GetUserOfferInvoices: func(req GetUserOfferInvoicesReq) (*OfferInvoices, error) {
|
||||
auth, err := params.RetrieveUserAuth()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
finalRoute := "/api/user/offer/get/invoices"
|
||||
body, err := json.Marshal(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resBody, err := doPostRequest(params.BaseURL+finalRoute, body, auth)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result := ResultError{}
|
||||
err = json.Unmarshal(resBody, &result)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if result.Status == "ERROR" {
|
||||
return nil, fmt.Errorf(result.Reason)
|
||||
}
|
||||
res := OfferInvoices{}
|
||||
err = json.Unmarshal(resBody, &res)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &res, nil
|
||||
},
|
||||
GetUserOffers: func() (*UserOffers, error) {
|
||||
auth, err := params.RetrieveUserAuth()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
finalRoute := "/api/user/offers/get"
|
||||
resBody, err := doGetRequest(params.BaseURL+finalRoute, auth)
|
||||
result := ResultError{}
|
||||
err = json.Unmarshal(resBody, &result)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if result.Status == "ERROR" {
|
||||
return nil, fmt.Errorf(result.Reason)
|
||||
}
|
||||
res := UserOffers{}
|
||||
err = json.Unmarshal(resBody, &res)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &res, nil
|
||||
},
|
||||
GetUserOperations: func(req GetUserOperationsRequest) (*GetUserOperationsResponse, error) {
|
||||
auth, err := params.RetrieveUserAuth()
|
||||
if err != nil {
|
||||
|
|
@ -1717,6 +1883,30 @@ func NewClient(params ClientParams) *Client {
|
|||
}
|
||||
return nil
|
||||
},
|
||||
UpdateUserOffer: func(req OfferConfig) error {
|
||||
auth, err := params.RetrieveUserAuth()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
finalRoute := "/api/user/offer/update"
|
||||
body, err := json.Marshal(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
resBody, err := doPostRequest(params.BaseURL+finalRoute, body, auth)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
result := ResultError{}
|
||||
err = json.Unmarshal(resBody, &result)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if result.Status == "ERROR" {
|
||||
return fmt.Errorf(result.Reason)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
UseInviteLink: func(req UseInviteLinkRequest) error {
|
||||
auth, err := params.RetrieveGuestWithPubAuth()
|
||||
if err != nil {
|
||||
|
|
@ -1741,26 +1931,31 @@ func NewClient(params ClientParams) *Client {
|
|||
}
|
||||
return nil
|
||||
},
|
||||
UserHealth: func() error {
|
||||
UserHealth: func() (*UserHealthState, error) {
|
||||
auth, err := params.RetrieveUserAuth()
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
finalRoute := "/api/user/health"
|
||||
body := []byte{}
|
||||
resBody, err := doPostRequest(params.BaseURL+finalRoute, body, auth)
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
result := ResultError{}
|
||||
err = json.Unmarshal(resBody, &result)
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
if result.Status == "ERROR" {
|
||||
return fmt.Errorf(result.Reason)
|
||||
return nil, fmt.Errorf(result.Reason)
|
||||
}
|
||||
return nil
|
||||
res := UserHealthState{}
|
||||
err = json.Unmarshal(resBody, &res)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &res, nil
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -64,6 +64,12 @@ const (
|
|||
WEEK IntervalType = "WEEK"
|
||||
)
|
||||
|
||||
type OfferDataType string
|
||||
|
||||
const (
|
||||
DATA_STRING OfferDataType = "DATA_STRING"
|
||||
)
|
||||
|
||||
type OperationType string
|
||||
|
||||
const (
|
||||
|
|
@ -94,6 +100,8 @@ type AddAppRequest struct {
|
|||
type AddAppUserInvoiceRequest struct {
|
||||
Http_callback_url string `json:"http_callback_url"`
|
||||
Invoice_req *NewInvoiceRequest `json:"invoice_req"`
|
||||
Offer_string string `json:"offer_string"`
|
||||
Payer_data *PayerData `json:"payer_data"`
|
||||
Payer_identifier string `json:"payer_identifier"`
|
||||
Receiver_identifier string `json:"receiver_identifier"`
|
||||
}
|
||||
|
|
@ -122,6 +130,9 @@ type AppMetrics struct {
|
|||
Total_fees int64 `json:"total_fees"`
|
||||
Users *UsersInfo `json:"users"`
|
||||
}
|
||||
type AppUsageMetrics struct {
|
||||
App_metrics map[string]UsageMetricTlv `json:"app_metrics"`
|
||||
}
|
||||
type AppUser struct {
|
||||
Identifier string `json:"identifier"`
|
||||
Info *UserInfo `json:"info"`
|
||||
|
|
@ -239,6 +250,18 @@ type EncryptionExchangeRequest struct {
|
|||
type EnrollAdminTokenRequest struct {
|
||||
Admin_token string `json:"admin_token"`
|
||||
}
|
||||
type ErrorStat struct {
|
||||
Errors int64 `json:"errors"`
|
||||
From_unix int64 `json:"from_unix"`
|
||||
Total int64 `json:"total"`
|
||||
}
|
||||
type ErrorStats struct {
|
||||
Past10m *ErrorStat `json:"past10m"`
|
||||
Past1h *ErrorStat `json:"past1h"`
|
||||
Past1m *ErrorStat `json:"past1m"`
|
||||
Past24h *ErrorStat `json:"past24h"`
|
||||
Past6h *ErrorStat `json:"past6h"`
|
||||
}
|
||||
type FrequencyRule struct {
|
||||
Amount int64 `json:"amount"`
|
||||
Interval IntervalType `json:"interval"`
|
||||
|
|
@ -266,6 +289,10 @@ type GetPaymentStateRequest struct {
|
|||
type GetProductBuyLinkResponse struct {
|
||||
Link string `json:"link"`
|
||||
}
|
||||
type GetUserOfferInvoicesReq struct {
|
||||
Include_unpaid bool `json:"include_unpaid"`
|
||||
Offer_id string `json:"offer_id"`
|
||||
}
|
||||
type GetUserOperationsRequest struct {
|
||||
Latestincominginvoice int64 `json:"latestIncomingInvoice"`
|
||||
Latestincomingtx int64 `json:"latestIncomingTx"`
|
||||
|
|
@ -386,6 +413,28 @@ type NewInvoiceRequest struct {
|
|||
type NewInvoiceResponse struct {
|
||||
Invoice string `json:"invoice"`
|
||||
}
|
||||
type OfferConfig struct {
|
||||
Callback_url string `json:"callback_url"`
|
||||
Default_offer bool `json:"default_offer"`
|
||||
Expected_data map[string]OfferDataType `json:"expected_data"`
|
||||
Label string `json:"label"`
|
||||
Noffer string `json:"noffer"`
|
||||
Offer_id string `json:"offer_id"`
|
||||
Price_sats int64 `json:"price_sats"`
|
||||
}
|
||||
type OfferId struct {
|
||||
Offer_id string `json:"offer_id"`
|
||||
}
|
||||
type OfferInvoice struct {
|
||||
Amount int64 `json:"amount"`
|
||||
Data map[string]string `json:"data"`
|
||||
Invoice string `json:"invoice"`
|
||||
Offer_id string `json:"offer_id"`
|
||||
Paid_at_unix int64 `json:"paid_at_unix"`
|
||||
}
|
||||
type OfferInvoices struct {
|
||||
Invoices []OfferInvoice `json:"invoices"`
|
||||
}
|
||||
type OpenChannel struct {
|
||||
Active bool `json:"active"`
|
||||
Capacity int64 `json:"capacity"`
|
||||
|
|
@ -436,6 +485,9 @@ type PayInvoiceResponse struct {
|
|||
Preimage string `json:"preimage"`
|
||||
Service_fee int64 `json:"service_fee"`
|
||||
}
|
||||
type PayerData struct {
|
||||
Data map[string]string `json:"data"`
|
||||
}
|
||||
type PaymentState struct {
|
||||
Amount int64 `json:"amount"`
|
||||
Network_fee int64 `json:"network_fee"`
|
||||
|
|
@ -502,6 +554,7 @@ type UpdateChannelPolicyRequest struct {
|
|||
Update *UpdateChannelPolicyRequest_update `json:"update"`
|
||||
}
|
||||
type UsageMetric struct {
|
||||
App_id string `json:"app_id"`
|
||||
Auth_in_nano int64 `json:"auth_in_nano"`
|
||||
Batch bool `json:"batch"`
|
||||
Batch_size int64 `json:"batch_size"`
|
||||
|
|
@ -510,14 +563,23 @@ type UsageMetric struct {
|
|||
Parsed_in_nano int64 `json:"parsed_in_nano"`
|
||||
Processed_at_ms int64 `json:"processed_at_ms"`
|
||||
Rpc_name string `json:"rpc_name"`
|
||||
Success bool `json:"success"`
|
||||
Validate_in_nano int64 `json:"validate_in_nano"`
|
||||
}
|
||||
type UsageMetricTlv struct {
|
||||
Available_chunks []int64 `json:"available_chunks"`
|
||||
Base_64_tlvs []string `json:"base_64_tlvs"`
|
||||
Current_chunk int64 `json:"current_chunk"`
|
||||
}
|
||||
type UsageMetrics struct {
|
||||
Metrics []UsageMetric `json:"metrics"`
|
||||
Apps map[string]AppUsageMetrics `json:"apps"`
|
||||
}
|
||||
type UseInviteLinkRequest struct {
|
||||
Invite_token string `json:"invite_token"`
|
||||
}
|
||||
type UserHealthState struct {
|
||||
Downtime_reason string `json:"downtime_reason"`
|
||||
}
|
||||
type UserInfo struct {
|
||||
Balance int64 `json:"balance"`
|
||||
Bridge_url string `json:"bridge_url"`
|
||||
|
|
@ -531,6 +593,9 @@ type UserInfo struct {
|
|||
Userid string `json:"userId"`
|
||||
User_identifier string `json:"user_identifier"`
|
||||
}
|
||||
type UserOffers struct {
|
||||
Offers []OfferConfig `json:"offers"`
|
||||
}
|
||||
type UserOperation struct {
|
||||
Amount int64 `json:"amount"`
|
||||
Confirmed bool `json:"confirmed"`
|
||||
|
|
|
|||
|
|
@ -166,6 +166,28 @@ export default (methods: Types.ServerMethods, opts: ServerOptions) => {
|
|||
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.AddUserOffer) throw new Error('method: AddUserOffer is not implemented')
|
||||
app.post('/api/user/offer/add', async (req, res) => {
|
||||
const info: Types.RequestInfo = { rpcName: 'AddUserOffer', 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.AddUserOffer) throw new Error('method: AddUserOffer 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.OfferConfigValidate(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.AddUserOffer({rpcName:'AddUserOffer', ctx:authContext , req: request})
|
||||
stats.handle = process.hrtime.bigint()
|
||||
res.json({status: 'OK', ...response})
|
||||
opts.metricsCallback([{ ...info, ...stats, ...authContext }])
|
||||
} catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e }
|
||||
})
|
||||
if (!opts.allowNotImplementedMethods && !methods.AuthApp) throw new Error('method: AuthApp is not implemented')
|
||||
app.post('/api/admin/app/auth', async (req, res) => {
|
||||
const info: Types.RequestInfo = { rpcName: 'AuthApp', batch: false, nostr: false, batchSize: 0}
|
||||
|
|
@ -287,6 +309,18 @@ export default (methods: Types.ServerMethods, opts: ServerOptions) => {
|
|||
callsMetrics.push({ ...opInfo, ...opStats, ...ctx })
|
||||
}
|
||||
break
|
||||
case 'AddUserOffer':
|
||||
if (!methods.AddUserOffer) {
|
||||
throw new Error('method AddUserOffer not found' )
|
||||
} else {
|
||||
const error = Types.OfferConfigValidate(operation.req)
|
||||
opStats.validate = process.hrtime.bigint()
|
||||
if (error !== null) throw error
|
||||
const res = await methods.AddUserOffer({...operation, ctx}); responses.push({ status: 'OK', ...res })
|
||||
opStats.handle = process.hrtime.bigint()
|
||||
callsMetrics.push({ ...opInfo, ...opStats, ...ctx })
|
||||
}
|
||||
break
|
||||
case 'AuthorizeDebit':
|
||||
if (!methods.AuthorizeDebit) {
|
||||
throw new Error('method AuthorizeDebit not found' )
|
||||
|
|
@ -323,6 +357,18 @@ export default (methods: Types.ServerMethods, opts: ServerOptions) => {
|
|||
callsMetrics.push({ ...opInfo, ...opStats, ...ctx })
|
||||
}
|
||||
break
|
||||
case 'DeleteUserOffer':
|
||||
if (!methods.DeleteUserOffer) {
|
||||
throw new Error('method DeleteUserOffer not found' )
|
||||
} else {
|
||||
const error = Types.OfferIdValidate(operation.req)
|
||||
opStats.validate = process.hrtime.bigint()
|
||||
if (error !== null) throw error
|
||||
await methods.DeleteUserOffer({...operation, ctx}); responses.push({ status: 'OK' })
|
||||
opStats.handle = process.hrtime.bigint()
|
||||
callsMetrics.push({ ...opInfo, ...opStats, ...ctx })
|
||||
}
|
||||
break
|
||||
case 'EditDebit':
|
||||
if (!methods.EditDebit) {
|
||||
throw new Error('method EditDebit not found' )
|
||||
|
|
@ -409,6 +455,40 @@ export default (methods: Types.ServerMethods, opts: ServerOptions) => {
|
|||
callsMetrics.push({ ...opInfo, ...opStats, ...ctx })
|
||||
}
|
||||
break
|
||||
case 'GetUserOffer':
|
||||
if (!methods.GetUserOffer) {
|
||||
throw new Error('method GetUserOffer not found' )
|
||||
} else {
|
||||
const error = Types.OfferIdValidate(operation.req)
|
||||
opStats.validate = process.hrtime.bigint()
|
||||
if (error !== null) throw error
|
||||
const res = await methods.GetUserOffer({...operation, ctx}); responses.push({ status: 'OK', ...res })
|
||||
opStats.handle = process.hrtime.bigint()
|
||||
callsMetrics.push({ ...opInfo, ...opStats, ...ctx })
|
||||
}
|
||||
break
|
||||
case 'GetUserOfferInvoices':
|
||||
if (!methods.GetUserOfferInvoices) {
|
||||
throw new Error('method GetUserOfferInvoices not found' )
|
||||
} else {
|
||||
const error = Types.GetUserOfferInvoicesReqValidate(operation.req)
|
||||
opStats.validate = process.hrtime.bigint()
|
||||
if (error !== null) throw error
|
||||
const res = await methods.GetUserOfferInvoices({...operation, ctx}); responses.push({ status: 'OK', ...res })
|
||||
opStats.handle = process.hrtime.bigint()
|
||||
callsMetrics.push({ ...opInfo, ...opStats, ...ctx })
|
||||
}
|
||||
break
|
||||
case 'GetUserOffers':
|
||||
if (!methods.GetUserOffers) {
|
||||
throw new Error('method GetUserOffers not found' )
|
||||
} else {
|
||||
opStats.validate = opStats.guard
|
||||
const res = await methods.GetUserOffers({...operation, ctx}); responses.push({ status: 'OK', ...res })
|
||||
opStats.handle = process.hrtime.bigint()
|
||||
callsMetrics.push({ ...opInfo, ...opStats, ...ctx })
|
||||
}
|
||||
break
|
||||
case 'GetUserOperations':
|
||||
if (!methods.GetUserOperations) {
|
||||
throw new Error('method GetUserOperations not found' )
|
||||
|
|
@ -515,12 +595,24 @@ export default (methods: Types.ServerMethods, opts: ServerOptions) => {
|
|||
callsMetrics.push({ ...opInfo, ...opStats, ...ctx })
|
||||
}
|
||||
break
|
||||
case 'UpdateUserOffer':
|
||||
if (!methods.UpdateUserOffer) {
|
||||
throw new Error('method UpdateUserOffer not found' )
|
||||
} else {
|
||||
const error = Types.OfferConfigValidate(operation.req)
|
||||
opStats.validate = process.hrtime.bigint()
|
||||
if (error !== null) throw error
|
||||
await methods.UpdateUserOffer({...operation, ctx}); responses.push({ status: 'OK' })
|
||||
opStats.handle = process.hrtime.bigint()
|
||||
callsMetrics.push({ ...opInfo, ...opStats, ...ctx })
|
||||
}
|
||||
break
|
||||
case 'UserHealth':
|
||||
if (!methods.UserHealth) {
|
||||
throw new Error('method UserHealth not found' )
|
||||
} else {
|
||||
opStats.validate = opStats.guard
|
||||
await methods.UserHealth({...operation, ctx}); responses.push({ status: 'OK' })
|
||||
const res = await methods.UserHealth({...operation, ctx}); responses.push({ status: 'OK', ...res })
|
||||
opStats.handle = process.hrtime.bigint()
|
||||
callsMetrics.push({ ...opInfo, ...opStats, ...ctx })
|
||||
}
|
||||
|
|
@ -601,6 +693,28 @@ export default (methods: Types.ServerMethods, opts: ServerOptions) => {
|
|||
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.DeleteUserOffer) throw new Error('method: DeleteUserOffer is not implemented')
|
||||
app.post('/api/user/offer/delete', async (req, res) => {
|
||||
const info: Types.RequestInfo = { rpcName: 'DeleteUserOffer', 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.DeleteUserOffer) throw new Error('method: DeleteUserOffer 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.OfferIdValidate(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.DeleteUserOffer({rpcName:'DeleteUserOffer', 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.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}
|
||||
|
|
@ -771,6 +885,25 @@ export default (methods: Types.ServerMethods, opts: ServerOptions) => {
|
|||
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.GetErrorStats) throw new Error('method: GetErrorStats is not implemented')
|
||||
app.post('/api/reports/errors', async (req, res) => {
|
||||
const info: Types.RequestInfo = { rpcName: 'GetErrorStats', 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.GetErrorStats) throw new Error('method: GetErrorStats is not implemented')
|
||||
const authContext = await opts.MetricsAuthGuard(req.headers['authorization'])
|
||||
authCtx = authContext
|
||||
stats.guard = process.hrtime.bigint()
|
||||
stats.validate = stats.guard
|
||||
const query = req.query
|
||||
const params = req.params
|
||||
const response = await methods.GetErrorStats({rpcName:'GetErrorStats', 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')
|
||||
app.post('/api/admin/app/invite/get', async (req, res) => {
|
||||
const info: Types.RequestInfo = { rpcName: 'GetInviteLinkState', batch: false, nostr: false, batchSize: 0}
|
||||
|
|
@ -1011,6 +1144,69 @@ export default (methods: Types.ServerMethods, opts: ServerOptions) => {
|
|||
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.GetUserOffer) throw new Error('method: GetUserOffer is not implemented')
|
||||
app.post('/api/user/offer/get', async (req, res) => {
|
||||
const info: Types.RequestInfo = { rpcName: 'GetUserOffer', 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.GetUserOffer) throw new Error('method: GetUserOffer 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.OfferIdValidate(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.GetUserOffer({rpcName:'GetUserOffer', 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.GetUserOfferInvoices) throw new Error('method: GetUserOfferInvoices is not implemented')
|
||||
app.post('/api/user/offer/get/invoices', async (req, res) => {
|
||||
const info: Types.RequestInfo = { rpcName: 'GetUserOfferInvoices', 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.GetUserOfferInvoices) throw new Error('method: GetUserOfferInvoices 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.GetUserOfferInvoicesReqValidate(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.GetUserOfferInvoices({rpcName:'GetUserOfferInvoices', 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.GetUserOffers) throw new Error('method: GetUserOffers is not implemented')
|
||||
app.get('/api/user/offers/get', async (req, res) => {
|
||||
const info: Types.RequestInfo = { rpcName: 'GetUserOffers', 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.GetUserOffers) throw new Error('method: GetUserOffers 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.GetUserOffers({rpcName:'GetUserOffers', 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.GetUserOperations) throw new Error('method: GetUserOperations is not implemented')
|
||||
app.post('/api/user/operations', async (req, res) => {
|
||||
const info: Types.RequestInfo = { rpcName: 'GetUserOperations', batch: false, nostr: false, batchSize: 0}
|
||||
|
|
@ -1565,6 +1761,28 @@ export default (methods: Types.ServerMethods, opts: ServerOptions) => {
|
|||
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.UpdateUserOffer) throw new Error('method: UpdateUserOffer is not implemented')
|
||||
app.post('/api/user/offer/update', async (req, res) => {
|
||||
const info: Types.RequestInfo = { rpcName: 'UpdateUserOffer', 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.UpdateUserOffer) throw new Error('method: UpdateUserOffer 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.OfferConfigValidate(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.UpdateUserOffer({rpcName:'UpdateUserOffer', 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.UseInviteLink) throw new Error('method: UseInviteLink is not implemented')
|
||||
app.post('/api/guest/invite', async (req, res) => {
|
||||
const info: Types.RequestInfo = { rpcName: 'UseInviteLink', batch: false, nostr: false, batchSize: 0}
|
||||
|
|
@ -1600,9 +1818,9 @@ export default (methods: Types.ServerMethods, opts: ServerOptions) => {
|
|||
stats.validate = stats.guard
|
||||
const query = req.query
|
||||
const params = req.params
|
||||
await methods.UserHealth({rpcName:'UserHealth', ctx:authContext })
|
||||
const response = await methods.UserHealth({rpcName:'UserHealth', ctx:authContext })
|
||||
stats.handle = process.hrtime.bigint()
|
||||
res.json({status: 'OK'})
|
||||
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 }
|
||||
})
|
||||
|
|
|
|||
|
|
@ -98,6 +98,20 @@ export default (params: ClientParams) => ({
|
|||
}
|
||||
return { status: 'ERROR', reason: 'invalid response' }
|
||||
},
|
||||
AddUserOffer: async (request: Types.OfferConfig): Promise<ResultError | ({ status: 'OK' }& Types.OfferId)> => {
|
||||
const auth = await params.retrieveUserAuth()
|
||||
if (auth === null) throw new Error('retrieveUserAuth() returned null')
|
||||
let finalRoute = '/api/user/offer/add'
|
||||
const { data } = await axios.post(params.baseUrl + finalRoute, request, { headers: { 'authorization': auth } })
|
||||
if (data.status === 'ERROR' && typeof data.reason === 'string') return data
|
||||
if (data.status === 'OK') {
|
||||
const result = data
|
||||
if(!params.checkResult) return { status: 'OK', ...result }
|
||||
const error = Types.OfferIdValidate(result)
|
||||
if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message }
|
||||
}
|
||||
return { status: 'ERROR', reason: 'invalid response' }
|
||||
},
|
||||
AuthApp: async (request: Types.AuthAppRequest): Promise<ResultError | ({ status: 'OK' }& Types.AuthApp)> => {
|
||||
const auth = await params.retrieveAdminAuth()
|
||||
if (auth === null) throw new Error('retrieveAdminAuth() returned null')
|
||||
|
|
@ -204,6 +218,17 @@ export default (params: ClientParams) => ({
|
|||
}
|
||||
return { status: 'ERROR', reason: 'invalid response' }
|
||||
},
|
||||
DeleteUserOffer: async (request: Types.OfferId): Promise<ResultError | ({ status: 'OK' })> => {
|
||||
const auth = await params.retrieveUserAuth()
|
||||
if (auth === null) throw new Error('retrieveUserAuth() returned null')
|
||||
let finalRoute = '/api/user/offer/delete'
|
||||
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' }
|
||||
},
|
||||
EditDebit: async (request: Types.DebitAuthorizationRequest): Promise<ResultError | ({ status: 'OK' })> => {
|
||||
const auth = await params.retrieveUserAuth()
|
||||
if (auth === null) throw new Error('retrieveUserAuth() returned null')
|
||||
|
|
@ -307,6 +332,20 @@ export default (params: ClientParams) => ({
|
|||
}
|
||||
return { status: 'ERROR', reason: 'invalid response' }
|
||||
},
|
||||
GetErrorStats: async (): Promise<ResultError | ({ status: 'OK' }& Types.ErrorStats)> => {
|
||||
const auth = await params.retrieveMetricsAuth()
|
||||
if (auth === null) throw new Error('retrieveMetricsAuth() returned null')
|
||||
let finalRoute = '/api/reports/errors'
|
||||
const { data } = await axios.post(params.baseUrl + finalRoute, {}, { headers: { 'authorization': auth } })
|
||||
if (data.status === 'ERROR' && typeof data.reason === 'string') return data
|
||||
if (data.status === 'OK') {
|
||||
const result = data
|
||||
if(!params.checkResult) return { status: 'OK', ...result }
|
||||
const error = Types.ErrorStatsValidate(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')},
|
||||
GetInviteLinkState: async (request: Types.GetInviteTokenStateRequest): Promise<ResultError | ({ status: 'OK' }& Types.GetInviteTokenStateResponse)> => {
|
||||
const auth = await params.retrieveAdminAuth()
|
||||
|
|
@ -483,6 +522,48 @@ export default (params: ClientParams) => ({
|
|||
}
|
||||
return { status: 'ERROR', reason: 'invalid response' }
|
||||
},
|
||||
GetUserOffer: async (request: Types.OfferId): Promise<ResultError | ({ status: 'OK' }& Types.OfferConfig)> => {
|
||||
const auth = await params.retrieveUserAuth()
|
||||
if (auth === null) throw new Error('retrieveUserAuth() returned null')
|
||||
let finalRoute = '/api/user/offer/get'
|
||||
const { data } = await axios.post(params.baseUrl + finalRoute, request, { headers: { 'authorization': auth } })
|
||||
if (data.status === 'ERROR' && typeof data.reason === 'string') return data
|
||||
if (data.status === 'OK') {
|
||||
const result = data
|
||||
if(!params.checkResult) return { status: 'OK', ...result }
|
||||
const error = Types.OfferConfigValidate(result)
|
||||
if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message }
|
||||
}
|
||||
return { status: 'ERROR', reason: 'invalid response' }
|
||||
},
|
||||
GetUserOfferInvoices: async (request: Types.GetUserOfferInvoicesReq): Promise<ResultError | ({ status: 'OK' }& Types.OfferInvoices)> => {
|
||||
const auth = await params.retrieveUserAuth()
|
||||
if (auth === null) throw new Error('retrieveUserAuth() returned null')
|
||||
let finalRoute = '/api/user/offer/get/invoices'
|
||||
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.OfferInvoicesValidate(result)
|
||||
if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message }
|
||||
}
|
||||
return { status: 'ERROR', reason: 'invalid response' }
|
||||
},
|
||||
GetUserOffers: async (): Promise<ResultError | ({ status: 'OK' }& Types.UserOffers)> => {
|
||||
const auth = await params.retrieveUserAuth()
|
||||
if (auth === null) throw new Error('retrieveUserAuth() returned null')
|
||||
let finalRoute = '/api/user/offers/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.UserOffersValidate(result)
|
||||
if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message }
|
||||
}
|
||||
return { status: 'ERROR', reason: 'invalid response' }
|
||||
},
|
||||
GetUserOperations: async (request: Types.GetUserOperationsRequest): Promise<ResultError | ({ status: 'OK' }& Types.GetUserOperationsResponse)> => {
|
||||
const auth = await params.retrieveUserAuth()
|
||||
if (auth === null) throw new Error('retrieveUserAuth() returned null')
|
||||
|
|
@ -821,6 +902,17 @@ export default (params: ClientParams) => ({
|
|||
}
|
||||
return { status: 'ERROR', reason: 'invalid response' }
|
||||
},
|
||||
UpdateUserOffer: async (request: Types.OfferConfig): Promise<ResultError | ({ status: 'OK' })> => {
|
||||
const auth = await params.retrieveUserAuth()
|
||||
if (auth === null) throw new Error('retrieveUserAuth() returned null')
|
||||
let finalRoute = '/api/user/offer/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') {
|
||||
return data
|
||||
}
|
||||
return { status: 'ERROR', reason: 'invalid response' }
|
||||
},
|
||||
UseInviteLink: async (request: Types.UseInviteLinkRequest): Promise<ResultError | ({ status: 'OK' })> => {
|
||||
const auth = await params.retrieveGuestWithPubAuth()
|
||||
if (auth === null) throw new Error('retrieveGuestWithPubAuth() returned null')
|
||||
|
|
@ -832,14 +924,17 @@ export default (params: ClientParams) => ({
|
|||
}
|
||||
return { status: 'ERROR', reason: 'invalid response' }
|
||||
},
|
||||
UserHealth: async (): Promise<ResultError | ({ status: 'OK' })> => {
|
||||
UserHealth: async (): Promise<ResultError | ({ status: 'OK' }& Types.UserHealthState)> => {
|
||||
const auth = await params.retrieveUserAuth()
|
||||
if (auth === null) throw new Error('retrieveUserAuth() returned null')
|
||||
let finalRoute = '/api/user/health'
|
||||
const { data } = await axios.post(params.baseUrl + finalRoute, {}, { headers: { 'authorization': auth } })
|
||||
if (data.status === 'ERROR' && typeof data.reason === 'string') return data
|
||||
if (data.status === 'OK') {
|
||||
return data
|
||||
const result = data
|
||||
if(!params.checkResult) return { status: 'OK', ...result }
|
||||
const error = Types.UserHealthStateValidate(result)
|
||||
if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message }
|
||||
}
|
||||
return { status: 'ERROR', reason: 'invalid response' }
|
||||
},
|
||||
|
|
|
|||
|
|
@ -54,6 +54,21 @@ export default (params: NostrClientParams, send: (to:string, message: NostrRequ
|
|||
}
|
||||
return { status: 'ERROR', reason: 'invalid response' }
|
||||
},
|
||||
AddUserOffer: async (request: Types.OfferConfig): Promise<ResultError | ({ status: 'OK' }& Types.OfferId)> => {
|
||||
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:'AddUserOffer',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.OfferIdValidate(result)
|
||||
if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message }
|
||||
}
|
||||
return { status: 'ERROR', reason: 'invalid response' }
|
||||
},
|
||||
AuthApp: async (request: Types.AuthAppRequest): Promise<ResultError | ({ status: 'OK' }& Types.AuthApp)> => {
|
||||
const auth = await params.retrieveNostrAdminAuth()
|
||||
if (auth === null) throw new Error('retrieveNostrAdminAuth() returned null')
|
||||
|
|
@ -167,6 +182,18 @@ export default (params: NostrClientParams, send: (to:string, message: NostrRequ
|
|||
}
|
||||
return { status: 'ERROR', reason: 'invalid response' }
|
||||
},
|
||||
DeleteUserOffer: async (request: Types.OfferId): 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:'DeleteUserOffer',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' }
|
||||
},
|
||||
EditDebit: async (request: Types.DebitAuthorizationRequest): Promise<ResultError | ({ status: 'OK' })> => {
|
||||
const auth = await params.retrieveNostrUserAuth()
|
||||
if (auth === null) throw new Error('retrieveNostrUserAuth() returned null')
|
||||
|
|
@ -220,6 +247,20 @@ export default (params: NostrClientParams, send: (to:string, message: NostrRequ
|
|||
}
|
||||
return { status: 'ERROR', reason: 'invalid response' }
|
||||
},
|
||||
GetErrorStats: async (): Promise<ResultError | ({ status: 'OK' }& Types.ErrorStats)> => {
|
||||
const auth = await params.retrieveNostrMetricsAuth()
|
||||
if (auth === null) throw new Error('retrieveNostrMetricsAuth() returned null')
|
||||
const nostrRequest: NostrRequest = {}
|
||||
const data = await send(params.pubDestination, {rpcName:'GetErrorStats',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.ErrorStatsValidate(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> => {
|
||||
const auth = await params.retrieveNostrUserAuth()
|
||||
if (auth === null) throw new Error('retrieveNostrUserAuth() returned null')
|
||||
|
|
@ -409,6 +450,50 @@ export default (params: NostrClientParams, send: (to:string, message: NostrRequ
|
|||
}
|
||||
return { status: 'ERROR', reason: 'invalid response' }
|
||||
},
|
||||
GetUserOffer: async (request: Types.OfferId): Promise<ResultError | ({ status: 'OK' }& Types.OfferConfig)> => {
|
||||
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:'GetUserOffer',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.OfferConfigValidate(result)
|
||||
if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message }
|
||||
}
|
||||
return { status: 'ERROR', reason: 'invalid response' }
|
||||
},
|
||||
GetUserOfferInvoices: async (request: Types.GetUserOfferInvoicesReq): Promise<ResultError | ({ status: 'OK' }& Types.OfferInvoices)> => {
|
||||
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:'GetUserOfferInvoices',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.OfferInvoicesValidate(result)
|
||||
if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message }
|
||||
}
|
||||
return { status: 'ERROR', reason: 'invalid response' }
|
||||
},
|
||||
GetUserOffers: async (): Promise<ResultError | ({ status: 'OK' }& Types.UserOffers)> => {
|
||||
const auth = await params.retrieveNostrUserAuth()
|
||||
if (auth === null) throw new Error('retrieveNostrUserAuth() returned null')
|
||||
const nostrRequest: NostrRequest = {}
|
||||
const data = await send(params.pubDestination, {rpcName:'GetUserOffers',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.UserOffersValidate(result)
|
||||
if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message }
|
||||
}
|
||||
return { status: 'ERROR', reason: 'invalid response' }
|
||||
},
|
||||
GetUserOperations: async (request: Types.GetUserOperationsRequest): Promise<ResultError | ({ status: 'OK' }& Types.GetUserOperationsResponse)> => {
|
||||
const auth = await params.retrieveNostrUserAuth()
|
||||
if (auth === null) throw new Error('retrieveNostrUserAuth() returned null')
|
||||
|
|
@ -606,6 +691,18 @@ export default (params: NostrClientParams, send: (to:string, message: NostrRequ
|
|||
}
|
||||
return { status: 'ERROR', reason: 'invalid response' }
|
||||
},
|
||||
UpdateUserOffer: async (request: Types.OfferConfig): 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:'UpdateUserOffer',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' }
|
||||
},
|
||||
UseInviteLink: async (request: Types.UseInviteLinkRequest): Promise<ResultError | ({ status: 'OK' })> => {
|
||||
const auth = await params.retrieveNostrGuestWithPubAuth()
|
||||
if (auth === null) throw new Error('retrieveNostrGuestWithPubAuth() returned null')
|
||||
|
|
@ -618,14 +715,17 @@ export default (params: NostrClientParams, send: (to:string, message: NostrRequ
|
|||
}
|
||||
return { status: 'ERROR', reason: 'invalid response' }
|
||||
},
|
||||
UserHealth: async (): Promise<ResultError | ({ status: 'OK' })> => {
|
||||
UserHealth: async (): Promise<ResultError | ({ status: 'OK' }& Types.UserHealthState)> => {
|
||||
const auth = await params.retrieveNostrUserAuth()
|
||||
if (auth === null) throw new Error('retrieveNostrUserAuth() returned null')
|
||||
const nostrRequest: NostrRequest = {}
|
||||
const data = await send(params.pubDestination, {rpcName:'UserHealth',authIdentifier:auth, ...nostrRequest })
|
||||
if (data.status === 'ERROR' && typeof data.reason === 'string') return data
|
||||
if (data.status === 'OK') {
|
||||
return data
|
||||
const result = data
|
||||
if(!params.checkResult) return { status: 'OK', ...result }
|
||||
const error = Types.UserHealthStateValidate(result)
|
||||
if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message }
|
||||
}
|
||||
return { status: 'ERROR', reason: 'invalid response' }
|
||||
},
|
||||
|
|
|
|||
|
|
@ -80,6 +80,22 @@ export default (methods: Types.ServerMethods, opts: NostrOptions) => {
|
|||
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 'AddUserOffer':
|
||||
try {
|
||||
if (!methods.AddUserOffer) throw new Error('method: AddUserOffer 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.OfferConfigValidate(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.AddUserOffer({rpcName:'AddUserOffer', ctx:authContext , req: request})
|
||||
stats.handle = process.hrtime.bigint()
|
||||
res({status: 'OK', ...response})
|
||||
opts.metricsCallback([{ ...info, ...stats, ...authContext }])
|
||||
}catch(ex){ const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e }
|
||||
break
|
||||
case 'AuthApp':
|
||||
try {
|
||||
if (!methods.AuthApp) throw new Error('method: AuthApp is not implemented')
|
||||
|
|
@ -175,6 +191,18 @@ export default (methods: Types.ServerMethods, opts: NostrOptions) => {
|
|||
callsMetrics.push({ ...opInfo, ...opStats, ...ctx })
|
||||
}
|
||||
break
|
||||
case 'AddUserOffer':
|
||||
if (!methods.AddUserOffer) {
|
||||
throw new Error('method not defined: AddUserOffer')
|
||||
} else {
|
||||
const error = Types.OfferConfigValidate(operation.req)
|
||||
opStats.validate = process.hrtime.bigint()
|
||||
if (error !== null) throw error
|
||||
const res = await methods.AddUserOffer({...operation, ctx}); responses.push({ status: 'OK', ...res })
|
||||
opStats.handle = process.hrtime.bigint()
|
||||
callsMetrics.push({ ...opInfo, ...opStats, ...ctx })
|
||||
}
|
||||
break
|
||||
case 'AuthorizeDebit':
|
||||
if (!methods.AuthorizeDebit) {
|
||||
throw new Error('method not defined: AuthorizeDebit')
|
||||
|
|
@ -211,6 +239,18 @@ export default (methods: Types.ServerMethods, opts: NostrOptions) => {
|
|||
callsMetrics.push({ ...opInfo, ...opStats, ...ctx })
|
||||
}
|
||||
break
|
||||
case 'DeleteUserOffer':
|
||||
if (!methods.DeleteUserOffer) {
|
||||
throw new Error('method not defined: DeleteUserOffer')
|
||||
} else {
|
||||
const error = Types.OfferIdValidate(operation.req)
|
||||
opStats.validate = process.hrtime.bigint()
|
||||
if (error !== null) throw error
|
||||
await methods.DeleteUserOffer({...operation, ctx}); responses.push({ status: 'OK' })
|
||||
opStats.handle = process.hrtime.bigint()
|
||||
callsMetrics.push({ ...opInfo, ...opStats, ...ctx })
|
||||
}
|
||||
break
|
||||
case 'EditDebit':
|
||||
if (!methods.EditDebit) {
|
||||
throw new Error('method not defined: EditDebit')
|
||||
|
|
@ -297,6 +337,40 @@ export default (methods: Types.ServerMethods, opts: NostrOptions) => {
|
|||
callsMetrics.push({ ...opInfo, ...opStats, ...ctx })
|
||||
}
|
||||
break
|
||||
case 'GetUserOffer':
|
||||
if (!methods.GetUserOffer) {
|
||||
throw new Error('method not defined: GetUserOffer')
|
||||
} else {
|
||||
const error = Types.OfferIdValidate(operation.req)
|
||||
opStats.validate = process.hrtime.bigint()
|
||||
if (error !== null) throw error
|
||||
const res = await methods.GetUserOffer({...operation, ctx}); responses.push({ status: 'OK', ...res })
|
||||
opStats.handle = process.hrtime.bigint()
|
||||
callsMetrics.push({ ...opInfo, ...opStats, ...ctx })
|
||||
}
|
||||
break
|
||||
case 'GetUserOfferInvoices':
|
||||
if (!methods.GetUserOfferInvoices) {
|
||||
throw new Error('method not defined: GetUserOfferInvoices')
|
||||
} else {
|
||||
const error = Types.GetUserOfferInvoicesReqValidate(operation.req)
|
||||
opStats.validate = process.hrtime.bigint()
|
||||
if (error !== null) throw error
|
||||
const res = await methods.GetUserOfferInvoices({...operation, ctx}); responses.push({ status: 'OK', ...res })
|
||||
opStats.handle = process.hrtime.bigint()
|
||||
callsMetrics.push({ ...opInfo, ...opStats, ...ctx })
|
||||
}
|
||||
break
|
||||
case 'GetUserOffers':
|
||||
if (!methods.GetUserOffers) {
|
||||
throw new Error('method not defined: GetUserOffers')
|
||||
} else {
|
||||
opStats.validate = opStats.guard
|
||||
const res = await methods.GetUserOffers({...operation, ctx}); responses.push({ status: 'OK', ...res })
|
||||
opStats.handle = process.hrtime.bigint()
|
||||
callsMetrics.push({ ...opInfo, ...opStats, ...ctx })
|
||||
}
|
||||
break
|
||||
case 'GetUserOperations':
|
||||
if (!methods.GetUserOperations) {
|
||||
throw new Error('method not defined: GetUserOperations')
|
||||
|
|
@ -403,12 +477,24 @@ export default (methods: Types.ServerMethods, opts: NostrOptions) => {
|
|||
callsMetrics.push({ ...opInfo, ...opStats, ...ctx })
|
||||
}
|
||||
break
|
||||
case 'UpdateUserOffer':
|
||||
if (!methods.UpdateUserOffer) {
|
||||
throw new Error('method not defined: UpdateUserOffer')
|
||||
} else {
|
||||
const error = Types.OfferConfigValidate(operation.req)
|
||||
opStats.validate = process.hrtime.bigint()
|
||||
if (error !== null) throw error
|
||||
await methods.UpdateUserOffer({...operation, ctx}); responses.push({ status: 'OK' })
|
||||
opStats.handle = process.hrtime.bigint()
|
||||
callsMetrics.push({ ...opInfo, ...opStats, ...ctx })
|
||||
}
|
||||
break
|
||||
case 'UserHealth':
|
||||
if (!methods.UserHealth) {
|
||||
throw new Error('method not defined: UserHealth')
|
||||
} else {
|
||||
opStats.validate = opStats.guard
|
||||
await methods.UserHealth({...operation, ctx}); responses.push({ status: 'OK' })
|
||||
const res = await methods.UserHealth({...operation, ctx}); responses.push({ status: 'OK', ...res })
|
||||
opStats.handle = process.hrtime.bigint()
|
||||
callsMetrics.push({ ...opInfo, ...opStats, ...ctx })
|
||||
}
|
||||
|
|
@ -471,6 +557,22 @@ export default (methods: Types.ServerMethods, opts: NostrOptions) => {
|
|||
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 'DeleteUserOffer':
|
||||
try {
|
||||
if (!methods.DeleteUserOffer) throw new Error('method: DeleteUserOffer 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.OfferIdValidate(request)
|
||||
stats.validate = process.hrtime.bigint()
|
||||
if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback)
|
||||
await methods.DeleteUserOffer({rpcName:'DeleteUserOffer', 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 'EditDebit':
|
||||
try {
|
||||
if (!methods.EditDebit) throw new Error('method: EditDebit is not implemented')
|
||||
|
|
@ -532,6 +634,19 @@ export default (methods: Types.ServerMethods, opts: NostrOptions) => {
|
|||
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 'GetErrorStats':
|
||||
try {
|
||||
if (!methods.GetErrorStats) throw new Error('method: GetErrorStats is not implemented')
|
||||
const authContext = await opts.NostrMetricsAuthGuard(req.appId, req.authIdentifier)
|
||||
stats.guard = process.hrtime.bigint()
|
||||
authCtx = authContext
|
||||
stats.validate = stats.guard
|
||||
const response = await methods.GetErrorStats({rpcName:'GetErrorStats', 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':
|
||||
try {
|
||||
if (!methods.GetHttpCreds) throw new Error('method: GetHttpCreds is not implemented')
|
||||
|
|
@ -710,6 +825,51 @@ export default (methods: Types.ServerMethods, opts: NostrOptions) => {
|
|||
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 'GetUserOffer':
|
||||
try {
|
||||
if (!methods.GetUserOffer) throw new Error('method: GetUserOffer 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.OfferIdValidate(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.GetUserOffer({rpcName:'GetUserOffer', 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 'GetUserOfferInvoices':
|
||||
try {
|
||||
if (!methods.GetUserOfferInvoices) throw new Error('method: GetUserOfferInvoices 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.GetUserOfferInvoicesReqValidate(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.GetUserOfferInvoices({rpcName:'GetUserOfferInvoices', 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 'GetUserOffers':
|
||||
try {
|
||||
if (!methods.GetUserOffers) throw new Error('method: GetUserOffers 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.GetUserOffers({rpcName:'GetUserOffers', 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 'GetUserOperations':
|
||||
try {
|
||||
if (!methods.GetUserOperations) throw new Error('method: GetUserOperations is not implemented')
|
||||
|
|
@ -928,6 +1088,22 @@ export default (methods: Types.ServerMethods, opts: NostrOptions) => {
|
|||
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 'UpdateUserOffer':
|
||||
try {
|
||||
if (!methods.UpdateUserOffer) throw new Error('method: UpdateUserOffer 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.OfferConfigValidate(request)
|
||||
stats.validate = process.hrtime.bigint()
|
||||
if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback)
|
||||
await methods.UpdateUserOffer({rpcName:'UpdateUserOffer', 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 'UseInviteLink':
|
||||
try {
|
||||
if (!methods.UseInviteLink) throw new Error('method: UseInviteLink is not implemented')
|
||||
|
|
@ -951,9 +1127,9 @@ export default (methods: Types.ServerMethods, opts: NostrOptions) => {
|
|||
stats.guard = process.hrtime.bigint()
|
||||
authCtx = authContext
|
||||
stats.validate = stats.guard
|
||||
await methods.UserHealth({rpcName:'UserHealth', ctx:authContext })
|
||||
const response = await methods.UserHealth({rpcName:'UserHealth', ctx:authContext })
|
||||
stats.handle = process.hrtime.bigint()
|
||||
res({status: 'OK'})
|
||||
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
|
||||
|
|
|
|||
|
|
@ -27,15 +27,15 @@ export type GuestWithPubMethodOutputs = LinkNPubThroughToken_Output | UseInviteL
|
|||
export type MetricsContext = {
|
||||
operator_id: string
|
||||
}
|
||||
export type MetricsMethodInputs = GetAppsMetrics_Input | GetLndMetrics_Input | GetUsageMetrics_Input
|
||||
export type MetricsMethodOutputs = GetAppsMetrics_Output | GetLndMetrics_Output | GetUsageMetrics_Output
|
||||
export type MetricsMethodInputs = GetAppsMetrics_Input | GetErrorStats_Input | GetLndMetrics_Input | GetUsageMetrics_Input
|
||||
export type MetricsMethodOutputs = GetAppsMetrics_Output | GetErrorStats_Output | GetLndMetrics_Output | GetUsageMetrics_Output
|
||||
export type UserContext = {
|
||||
app_id: string
|
||||
app_user_id: string
|
||||
user_id: string
|
||||
}
|
||||
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 | PayAddress_Input | PayInvoice_Input | ResetDebit_Input | RespondToDebit_Input | UpdateCallbackUrl_Input | UserHealth_Input
|
||||
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 | PayAddress_Output | PayInvoice_Output | ResetDebit_Output | RespondToDebit_Output | UpdateCallbackUrl_Output | UserHealth_Output
|
||||
export type UserMethodInputs = AddProduct_Input | AddUserOffer_Input | AuthorizeDebit_Input | BanDebit_Input | DecodeInvoice_Input | DeleteUserOffer_Input | EditDebit_Input | EnrollAdminToken_Input | GetDebitAuthorizations_Input | GetLNURLChannelLink_Input | GetLnurlPayLink_Input | GetLnurlWithdrawLink_Input | GetPaymentState_Input | GetUserInfo_Input | GetUserOffer_Input | GetUserOfferInvoices_Input | GetUserOffers_Input | GetUserOperations_Input | NewAddress_Input | NewInvoice_Input | NewProductInvoice_Input | PayAddress_Input | PayInvoice_Input | ResetDebit_Input | RespondToDebit_Input | UpdateCallbackUrl_Input | UpdateUserOffer_Input | UserHealth_Input
|
||||
export type UserMethodOutputs = AddProduct_Output | AddUserOffer_Output | AuthorizeDebit_Output | BanDebit_Output | DecodeInvoice_Output | DeleteUserOffer_Output | EditDebit_Output | EnrollAdminToken_Output | GetDebitAuthorizations_Output | GetLNURLChannelLink_Output | GetLnurlPayLink_Output | GetLnurlWithdrawLink_Output | GetPaymentState_Output | GetUserInfo_Output | GetUserOffer_Output | GetUserOfferInvoices_Output | GetUserOffers_Output | GetUserOperations_Output | NewAddress_Output | NewInvoice_Output | NewProductInvoice_Output | PayAddress_Output | PayInvoice_Output | ResetDebit_Output | RespondToDebit_Output | UpdateCallbackUrl_Output | UpdateUserOffer_Output | UserHealth_Output
|
||||
export type AuthContext = AdminContext | AppContext | GuestContext | GuestWithPubContext | MetricsContext | UserContext
|
||||
|
||||
export type AddApp_Input = {rpcName:'AddApp', req: AddAppRequest}
|
||||
|
|
@ -56,6 +56,9 @@ export type AddPeer_Output = ResultError | { status: 'OK' }
|
|||
export type AddProduct_Input = {rpcName:'AddProduct', req: AddProductRequest}
|
||||
export type AddProduct_Output = ResultError | ({ status: 'OK' } & Product)
|
||||
|
||||
export type AddUserOffer_Input = {rpcName:'AddUserOffer', req: OfferConfig}
|
||||
export type AddUserOffer_Output = ResultError | ({ status: 'OK' } & OfferId)
|
||||
|
||||
export type AuthApp_Input = {rpcName:'AuthApp', req: AuthAppRequest}
|
||||
export type AuthApp_Output = ResultError | ({ status: 'OK' } & AuthApp)
|
||||
|
||||
|
|
@ -80,6 +83,9 @@ export type CreateOneTimeInviteLink_Output = ResultError | ({ status: 'OK' } & C
|
|||
export type DecodeInvoice_Input = {rpcName:'DecodeInvoice', req: DecodeInvoiceRequest}
|
||||
export type DecodeInvoice_Output = ResultError | ({ status: 'OK' } & DecodeInvoiceResponse)
|
||||
|
||||
export type DeleteUserOffer_Input = {rpcName:'DeleteUserOffer', req: OfferId}
|
||||
export type DeleteUserOffer_Output = ResultError | { status: 'OK' }
|
||||
|
||||
export type EditDebit_Input = {rpcName:'EditDebit', req: DebitAuthorizationRequest}
|
||||
export type EditDebit_Output = ResultError | { status: 'OK' }
|
||||
|
||||
|
|
@ -104,6 +110,9 @@ export type GetAppsMetrics_Output = ResultError | ({ status: 'OK' } & AppsMetric
|
|||
export type GetDebitAuthorizations_Input = {rpcName:'GetDebitAuthorizations'}
|
||||
export type GetDebitAuthorizations_Output = ResultError | ({ status: 'OK' } & DebitAuthorizations)
|
||||
|
||||
export type GetErrorStats_Input = {rpcName:'GetErrorStats'}
|
||||
export type GetErrorStats_Output = ResultError | ({ status: 'OK' } & ErrorStats)
|
||||
|
||||
export type GetHttpCreds_Input = {rpcName:'GetHttpCreds', cb:(res: HttpCreds, err:Error|null)=> void}
|
||||
export type GetHttpCreds_Output = ResultError | { status: 'OK' }
|
||||
|
||||
|
|
@ -158,6 +167,15 @@ export type GetUsageMetrics_Output = ResultError | ({ status: 'OK' } & UsageMetr
|
|||
export type GetUserInfo_Input = {rpcName:'GetUserInfo'}
|
||||
export type GetUserInfo_Output = ResultError | ({ status: 'OK' } & UserInfo)
|
||||
|
||||
export type GetUserOffer_Input = {rpcName:'GetUserOffer', req: OfferId}
|
||||
export type GetUserOffer_Output = ResultError | ({ status: 'OK' } & OfferConfig)
|
||||
|
||||
export type GetUserOfferInvoices_Input = {rpcName:'GetUserOfferInvoices', req: GetUserOfferInvoicesReq}
|
||||
export type GetUserOfferInvoices_Output = ResultError | ({ status: 'OK' } & OfferInvoices)
|
||||
|
||||
export type GetUserOffers_Input = {rpcName:'GetUserOffers'}
|
||||
export type GetUserOffers_Output = ResultError | ({ status: 'OK' } & UserOffers)
|
||||
|
||||
export type GetUserOperations_Input = {rpcName:'GetUserOperations', req: GetUserOperationsRequest}
|
||||
export type GetUserOperations_Output = ResultError | ({ status: 'OK' } & GetUserOperationsResponse)
|
||||
|
||||
|
|
@ -252,11 +270,14 @@ export type UpdateCallbackUrl_Output = ResultError | ({ status: 'OK' } & Callbac
|
|||
export type UpdateChannelPolicy_Input = {rpcName:'UpdateChannelPolicy', req: UpdateChannelPolicyRequest}
|
||||
export type UpdateChannelPolicy_Output = ResultError | { status: 'OK' }
|
||||
|
||||
export type UpdateUserOffer_Input = {rpcName:'UpdateUserOffer', req: OfferConfig}
|
||||
export type UpdateUserOffer_Output = ResultError | { status: 'OK' }
|
||||
|
||||
export type UseInviteLink_Input = {rpcName:'UseInviteLink', req: UseInviteLinkRequest}
|
||||
export type UseInviteLink_Output = ResultError | { status: 'OK' }
|
||||
|
||||
export type UserHealth_Input = {rpcName:'UserHealth'}
|
||||
export type UserHealth_Output = ResultError | { status: 'OK' }
|
||||
export type UserHealth_Output = ResultError | ({ status: 'OK' } & UserHealthState)
|
||||
|
||||
export type ServerMethods = {
|
||||
AddApp?: (req: AddApp_Input & {ctx: AdminContext }) => Promise<AuthApp>
|
||||
|
|
@ -265,6 +286,7 @@ export type ServerMethods = {
|
|||
AddAppUserInvoice?: (req: AddAppUserInvoice_Input & {ctx: AppContext }) => Promise<NewInvoiceResponse>
|
||||
AddPeer?: (req: AddPeer_Input & {ctx: AdminContext }) => Promise<void>
|
||||
AddProduct?: (req: AddProduct_Input & {ctx: UserContext }) => Promise<Product>
|
||||
AddUserOffer?: (req: AddUserOffer_Input & {ctx: UserContext }) => Promise<OfferId>
|
||||
AuthApp?: (req: AuthApp_Input & {ctx: AdminContext }) => Promise<AuthApp>
|
||||
AuthorizeDebit?: (req: AuthorizeDebit_Input & {ctx: UserContext }) => Promise<DebitAuthorization>
|
||||
BanDebit?: (req: BanDebit_Input & {ctx: UserContext }) => Promise<void>
|
||||
|
|
@ -272,6 +294,7 @@ export type ServerMethods = {
|
|||
CloseChannel?: (req: CloseChannel_Input & {ctx: AdminContext }) => Promise<CloseChannelResponse>
|
||||
CreateOneTimeInviteLink?: (req: CreateOneTimeInviteLink_Input & {ctx: AdminContext }) => Promise<CreateOneTimeInviteLinkResponse>
|
||||
DecodeInvoice?: (req: DecodeInvoice_Input & {ctx: UserContext }) => Promise<DecodeInvoiceResponse>
|
||||
DeleteUserOffer?: (req: DeleteUserOffer_Input & {ctx: UserContext }) => Promise<void>
|
||||
EditDebit?: (req: EditDebit_Input & {ctx: UserContext }) => Promise<void>
|
||||
EncryptionExchange?: (req: EncryptionExchange_Input & {ctx: GuestContext }) => Promise<void>
|
||||
EnrollAdminToken?: (req: EnrollAdminToken_Input & {ctx: UserContext }) => Promise<void>
|
||||
|
|
@ -280,6 +303,7 @@ export type ServerMethods = {
|
|||
GetAppUserLNURLInfo?: (req: GetAppUserLNURLInfo_Input & {ctx: AppContext }) => Promise<LnurlPayInfoResponse>
|
||||
GetAppsMetrics?: (req: GetAppsMetrics_Input & {ctx: MetricsContext }) => Promise<AppsMetrics>
|
||||
GetDebitAuthorizations?: (req: GetDebitAuthorizations_Input & {ctx: UserContext }) => Promise<DebitAuthorizations>
|
||||
GetErrorStats?: (req: GetErrorStats_Input & {ctx: MetricsContext }) => Promise<ErrorStats>
|
||||
GetHttpCreds?: (req: GetHttpCreds_Input & {ctx: UserContext }) => Promise<void>
|
||||
GetInviteLinkState?: (req: GetInviteLinkState_Input & {ctx: AdminContext }) => Promise<GetInviteTokenStateResponse>
|
||||
GetLNURLChannelLink?: (req: GetLNURLChannelLink_Input & {ctx: UserContext }) => Promise<LnurlLinkResponse>
|
||||
|
|
@ -296,6 +320,9 @@ export type ServerMethods = {
|
|||
GetSeed?: (req: GetSeed_Input & {ctx: AdminContext }) => Promise<LndSeed>
|
||||
GetUsageMetrics?: (req: GetUsageMetrics_Input & {ctx: MetricsContext }) => Promise<UsageMetrics>
|
||||
GetUserInfo?: (req: GetUserInfo_Input & {ctx: UserContext }) => Promise<UserInfo>
|
||||
GetUserOffer?: (req: GetUserOffer_Input & {ctx: UserContext }) => Promise<OfferConfig>
|
||||
GetUserOfferInvoices?: (req: GetUserOfferInvoices_Input & {ctx: UserContext }) => Promise<OfferInvoices>
|
||||
GetUserOffers?: (req: GetUserOffers_Input & {ctx: UserContext }) => Promise<UserOffers>
|
||||
GetUserOperations?: (req: GetUserOperations_Input & {ctx: UserContext }) => Promise<GetUserOperationsResponse>
|
||||
HandleLnurlAddress?: (req: HandleLnurlAddress_Input & {ctx: GuestContext }) => Promise<LnurlPayInfoResponse>
|
||||
HandleLnurlPay?: (req: HandleLnurlPay_Input & {ctx: GuestContext }) => Promise<HandleLnurlPayResponse>
|
||||
|
|
@ -322,8 +349,9 @@ export type ServerMethods = {
|
|||
SetMockInvoiceAsPaid?: (req: SetMockInvoiceAsPaid_Input & {ctx: GuestContext }) => Promise<void>
|
||||
UpdateCallbackUrl?: (req: UpdateCallbackUrl_Input & {ctx: UserContext }) => Promise<CallbackUrl>
|
||||
UpdateChannelPolicy?: (req: UpdateChannelPolicy_Input & {ctx: AdminContext }) => Promise<void>
|
||||
UpdateUserOffer?: (req: UpdateUserOffer_Input & {ctx: UserContext }) => 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<UserHealthState>
|
||||
}
|
||||
|
||||
export enum AddressType {
|
||||
|
|
@ -344,6 +372,13 @@ export const enumCheckIntervalType = (e?: IntervalType): boolean => {
|
|||
for (const v in IntervalType) if (e === v) return true
|
||||
return false
|
||||
}
|
||||
export enum OfferDataType {
|
||||
DATA_STRING = 'DATA_STRING',
|
||||
}
|
||||
export const enumCheckOfferDataType = (e?: OfferDataType): boolean => {
|
||||
for (const v in OfferDataType) if (e === v) return true
|
||||
return false
|
||||
}
|
||||
export enum OperationType {
|
||||
CHAIN_OP = 'CHAIN_OP',
|
||||
INVOICE_OP = 'INVOICE_OP',
|
||||
|
|
@ -424,14 +459,19 @@ export const AddAppRequestValidate = (o?: AddAppRequest, opts: AddAppRequestOpti
|
|||
export type AddAppUserInvoiceRequest = {
|
||||
http_callback_url: string
|
||||
invoice_req: NewInvoiceRequest
|
||||
offer_string?: string
|
||||
payer_data?: PayerData
|
||||
payer_identifier: string
|
||||
receiver_identifier: string
|
||||
}
|
||||
export const AddAppUserInvoiceRequestOptionalFields: [] = []
|
||||
export type AddAppUserInvoiceRequestOptionalField = 'offer_string' | 'payer_data'
|
||||
export const AddAppUserInvoiceRequestOptionalFields: AddAppUserInvoiceRequestOptionalField[] = ['offer_string', 'payer_data']
|
||||
export type AddAppUserInvoiceRequestOptions = OptionsBaseMessage & {
|
||||
checkOptionalsAreSet?: []
|
||||
checkOptionalsAreSet?: AddAppUserInvoiceRequestOptionalField[]
|
||||
http_callback_url_CustomCheck?: (v: string) => boolean
|
||||
invoice_req_Options?: NewInvoiceRequestOptions
|
||||
offer_string_CustomCheck?: (v?: string) => boolean
|
||||
payer_data_Options?: PayerDataOptions
|
||||
payer_identifier_CustomCheck?: (v: string) => boolean
|
||||
receiver_identifier_CustomCheck?: (v: string) => boolean
|
||||
}
|
||||
|
|
@ -446,6 +486,15 @@ export const AddAppUserInvoiceRequestValidate = (o?: AddAppUserInvoiceRequest, o
|
|||
if (invoice_reqErr !== null) return invoice_reqErr
|
||||
|
||||
|
||||
if ((o.offer_string || opts.allOptionalsAreSet || opts.checkOptionalsAreSet?.includes('offer_string')) && typeof o.offer_string !== 'string') return new Error(`${path}.offer_string: is not a string`)
|
||||
if (opts.offer_string_CustomCheck && !opts.offer_string_CustomCheck(o.offer_string)) return new Error(`${path}.offer_string: custom check failed`)
|
||||
|
||||
if (typeof o.payer_data === 'object' || opts.allOptionalsAreSet || opts.checkOptionalsAreSet?.includes('payer_data')) {
|
||||
const payer_dataErr = PayerDataValidate(o.payer_data, opts.payer_data_Options, `${path}.payer_data`)
|
||||
if (payer_dataErr !== null) return payer_dataErr
|
||||
}
|
||||
|
||||
|
||||
if (typeof o.payer_identifier !== 'string') return new Error(`${path}.payer_identifier: is not a string`)
|
||||
if (opts.payer_identifier_CustomCheck && !opts.payer_identifier_CustomCheck(o.payer_identifier)) return new Error(`${path}.payer_identifier: custom check failed`)
|
||||
|
||||
|
|
@ -599,6 +648,28 @@ export const AppMetricsValidate = (o?: AppMetrics, opts: AppMetricsOptions = {},
|
|||
return null
|
||||
}
|
||||
|
||||
export type AppUsageMetrics = {
|
||||
app_metrics: Record<string, UsageMetricTlv>
|
||||
}
|
||||
export const AppUsageMetricsOptionalFields: [] = []
|
||||
export type AppUsageMetricsOptions = OptionsBaseMessage & {
|
||||
checkOptionalsAreSet?: []
|
||||
app_metrics_EntryOptions?: UsageMetricTlvOptions
|
||||
app_metrics_CustomCheck?: (v: Record<string, UsageMetricTlv>) => boolean
|
||||
}
|
||||
export const AppUsageMetricsValidate = (o?: AppUsageMetrics, opts: AppUsageMetricsOptions = {}, path: string = 'AppUsageMetrics::root.'): Error | null => {
|
||||
if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message')
|
||||
if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null')
|
||||
|
||||
if (typeof o.app_metrics !== 'object' || o.app_metrics === null) return new Error(`${path}.app_metrics: is not an object or is null`)
|
||||
for (const key in o.app_metrics) {
|
||||
const app_metricsErr = UsageMetricTlvValidate(o.app_metrics[key], opts.app_metrics_EntryOptions, `${path}.app_metrics['${key}']`)
|
||||
if (app_metricsErr !== null) return app_metricsErr
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
export type AppUser = {
|
||||
identifier: string
|
||||
info: UserInfo
|
||||
|
|
@ -1304,6 +1375,77 @@ export const EnrollAdminTokenRequestValidate = (o?: EnrollAdminTokenRequest, opt
|
|||
return null
|
||||
}
|
||||
|
||||
export type ErrorStat = {
|
||||
errors: number
|
||||
from_unix: number
|
||||
total: number
|
||||
}
|
||||
export const ErrorStatOptionalFields: [] = []
|
||||
export type ErrorStatOptions = OptionsBaseMessage & {
|
||||
checkOptionalsAreSet?: []
|
||||
errors_CustomCheck?: (v: number) => boolean
|
||||
from_unix_CustomCheck?: (v: number) => boolean
|
||||
total_CustomCheck?: (v: number) => boolean
|
||||
}
|
||||
export const ErrorStatValidate = (o?: ErrorStat, opts: ErrorStatOptions = {}, path: string = 'ErrorStat::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.errors !== 'number') return new Error(`${path}.errors: is not a number`)
|
||||
if (opts.errors_CustomCheck && !opts.errors_CustomCheck(o.errors)) return new Error(`${path}.errors: custom check failed`)
|
||||
|
||||
if (typeof o.from_unix !== 'number') return new Error(`${path}.from_unix: is not a number`)
|
||||
if (opts.from_unix_CustomCheck && !opts.from_unix_CustomCheck(o.from_unix)) return new Error(`${path}.from_unix: custom check failed`)
|
||||
|
||||
if (typeof o.total !== 'number') return new Error(`${path}.total: is not a number`)
|
||||
if (opts.total_CustomCheck && !opts.total_CustomCheck(o.total)) return new Error(`${path}.total: custom check failed`)
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
export type ErrorStats = {
|
||||
past10m: ErrorStat
|
||||
past1h: ErrorStat
|
||||
past1m: ErrorStat
|
||||
past24h: ErrorStat
|
||||
past6h: ErrorStat
|
||||
}
|
||||
export const ErrorStatsOptionalFields: [] = []
|
||||
export type ErrorStatsOptions = OptionsBaseMessage & {
|
||||
checkOptionalsAreSet?: []
|
||||
past10m_Options?: ErrorStatOptions
|
||||
past1h_Options?: ErrorStatOptions
|
||||
past1m_Options?: ErrorStatOptions
|
||||
past24h_Options?: ErrorStatOptions
|
||||
past6h_Options?: ErrorStatOptions
|
||||
}
|
||||
export const ErrorStatsValidate = (o?: ErrorStats, opts: ErrorStatsOptions = {}, path: string = 'ErrorStats::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 past10mErr = ErrorStatValidate(o.past10m, opts.past10m_Options, `${path}.past10m`)
|
||||
if (past10mErr !== null) return past10mErr
|
||||
|
||||
|
||||
const past1hErr = ErrorStatValidate(o.past1h, opts.past1h_Options, `${path}.past1h`)
|
||||
if (past1hErr !== null) return past1hErr
|
||||
|
||||
|
||||
const past1mErr = ErrorStatValidate(o.past1m, opts.past1m_Options, `${path}.past1m`)
|
||||
if (past1mErr !== null) return past1mErr
|
||||
|
||||
|
||||
const past24hErr = ErrorStatValidate(o.past24h, opts.past24h_Options, `${path}.past24h`)
|
||||
if (past24hErr !== null) return past24hErr
|
||||
|
||||
|
||||
const past6hErr = ErrorStatValidate(o.past6h, opts.past6h_Options, `${path}.past6h`)
|
||||
if (past6hErr !== null) return past6hErr
|
||||
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
export type FrequencyRule = {
|
||||
amount: number
|
||||
interval: IntervalType
|
||||
|
|
@ -1463,6 +1605,29 @@ export const GetProductBuyLinkResponseValidate = (o?: GetProductBuyLinkResponse,
|
|||
return null
|
||||
}
|
||||
|
||||
export type GetUserOfferInvoicesReq = {
|
||||
include_unpaid: boolean
|
||||
offer_id: string
|
||||
}
|
||||
export const GetUserOfferInvoicesReqOptionalFields: [] = []
|
||||
export type GetUserOfferInvoicesReqOptions = OptionsBaseMessage & {
|
||||
checkOptionalsAreSet?: []
|
||||
include_unpaid_CustomCheck?: (v: boolean) => boolean
|
||||
offer_id_CustomCheck?: (v: string) => boolean
|
||||
}
|
||||
export const GetUserOfferInvoicesReqValidate = (o?: GetUserOfferInvoicesReq, opts: GetUserOfferInvoicesReqOptions = {}, path: string = 'GetUserOfferInvoicesReq::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.include_unpaid !== 'boolean') return new Error(`${path}.include_unpaid: is not a boolean`)
|
||||
if (opts.include_unpaid_CustomCheck && !opts.include_unpaid_CustomCheck(o.include_unpaid)) return new Error(`${path}.include_unpaid: custom check failed`)
|
||||
|
||||
if (typeof o.offer_id !== 'string') return new Error(`${path}.offer_id: is not a string`)
|
||||
if (opts.offer_id_CustomCheck && !opts.offer_id_CustomCheck(o.offer_id)) return new Error(`${path}.offer_id: custom check failed`)
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
export type GetUserOperationsRequest = {
|
||||
latestIncomingInvoice: number
|
||||
latestIncomingTx: number
|
||||
|
|
@ -2201,6 +2366,137 @@ export const NewInvoiceResponseValidate = (o?: NewInvoiceResponse, opts: NewInvo
|
|||
return null
|
||||
}
|
||||
|
||||
export type OfferConfig = {
|
||||
callback_url: string
|
||||
default_offer: boolean
|
||||
expected_data: Record<string, OfferDataType>
|
||||
label: string
|
||||
noffer: string
|
||||
offer_id: string
|
||||
price_sats: number
|
||||
}
|
||||
export const OfferConfigOptionalFields: [] = []
|
||||
export type OfferConfigOptions = OptionsBaseMessage & {
|
||||
checkOptionalsAreSet?: []
|
||||
callback_url_CustomCheck?: (v: string) => boolean
|
||||
default_offer_CustomCheck?: (v: boolean) => boolean
|
||||
expected_data_CustomCheck?: (v: Record<string, OfferDataType>) => boolean
|
||||
label_CustomCheck?: (v: string) => boolean
|
||||
noffer_CustomCheck?: (v: string) => boolean
|
||||
offer_id_CustomCheck?: (v: string) => boolean
|
||||
price_sats_CustomCheck?: (v: number) => boolean
|
||||
}
|
||||
export const OfferConfigValidate = (o?: OfferConfig, opts: OfferConfigOptions = {}, path: string = 'OfferConfig::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.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.default_offer !== 'boolean') return new Error(`${path}.default_offer: is not a boolean`)
|
||||
if (opts.default_offer_CustomCheck && !opts.default_offer_CustomCheck(o.default_offer)) return new Error(`${path}.default_offer: custom check failed`)
|
||||
|
||||
if (typeof o.expected_data !== 'object' || o.expected_data === null) return new Error(`${path}.expected_data: is not an object or is null`)
|
||||
for (const key in o.expected_data) {
|
||||
if (!enumCheckOfferDataType(o.expected_data[key])) return new Error(`${path}.expected_data['${key}']: is not a OfferDataType`)
|
||||
}
|
||||
|
||||
if (typeof o.label !== 'string') return new Error(`${path}.label: is not a string`)
|
||||
if (opts.label_CustomCheck && !opts.label_CustomCheck(o.label)) return new Error(`${path}.label: custom check failed`)
|
||||
|
||||
if (typeof o.noffer !== 'string') return new Error(`${path}.noffer: is not a string`)
|
||||
if (opts.noffer_CustomCheck && !opts.noffer_CustomCheck(o.noffer)) return new Error(`${path}.noffer: custom check failed`)
|
||||
|
||||
if (typeof o.offer_id !== 'string') return new Error(`${path}.offer_id: is not a string`)
|
||||
if (opts.offer_id_CustomCheck && !opts.offer_id_CustomCheck(o.offer_id)) return new Error(`${path}.offer_id: custom check failed`)
|
||||
|
||||
if (typeof o.price_sats !== 'number') return new Error(`${path}.price_sats: is not a number`)
|
||||
if (opts.price_sats_CustomCheck && !opts.price_sats_CustomCheck(o.price_sats)) return new Error(`${path}.price_sats: custom check failed`)
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
export type OfferId = {
|
||||
offer_id: string
|
||||
}
|
||||
export const OfferIdOptionalFields: [] = []
|
||||
export type OfferIdOptions = OptionsBaseMessage & {
|
||||
checkOptionalsAreSet?: []
|
||||
offer_id_CustomCheck?: (v: string) => boolean
|
||||
}
|
||||
export const OfferIdValidate = (o?: OfferId, opts: OfferIdOptions = {}, path: string = 'OfferId::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.offer_id !== 'string') return new Error(`${path}.offer_id: is not a string`)
|
||||
if (opts.offer_id_CustomCheck && !opts.offer_id_CustomCheck(o.offer_id)) return new Error(`${path}.offer_id: custom check failed`)
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
export type OfferInvoice = {
|
||||
amount: number
|
||||
data: Record<string, string>
|
||||
invoice: string
|
||||
offer_id: string
|
||||
paid_at_unix: number
|
||||
}
|
||||
export const OfferInvoiceOptionalFields: [] = []
|
||||
export type OfferInvoiceOptions = OptionsBaseMessage & {
|
||||
checkOptionalsAreSet?: []
|
||||
amount_CustomCheck?: (v: number) => boolean
|
||||
data_CustomCheck?: (v: Record<string, string>) => boolean
|
||||
invoice_CustomCheck?: (v: string) => boolean
|
||||
offer_id_CustomCheck?: (v: string) => boolean
|
||||
paid_at_unix_CustomCheck?: (v: number) => boolean
|
||||
}
|
||||
export const OfferInvoiceValidate = (o?: OfferInvoice, opts: OfferInvoiceOptions = {}, path: string = 'OfferInvoice::root.'): Error | null => {
|
||||
if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message')
|
||||
if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null')
|
||||
|
||||
if (typeof o.amount !== 'number') return new Error(`${path}.amount: is not a number`)
|
||||
if (opts.amount_CustomCheck && !opts.amount_CustomCheck(o.amount)) return new Error(`${path}.amount: custom check failed`)
|
||||
|
||||
if (typeof o.data !== 'object' || o.data === null) return new Error(`${path}.data: is not an object or is null`)
|
||||
for (const key in o.data) {
|
||||
if (typeof o.data[key] !== 'string') return new Error(`${path}.data['${key}']: 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 (typeof o.offer_id !== 'string') return new Error(`${path}.offer_id: is not a string`)
|
||||
if (opts.offer_id_CustomCheck && !opts.offer_id_CustomCheck(o.offer_id)) return new Error(`${path}.offer_id: custom check failed`)
|
||||
|
||||
if (typeof o.paid_at_unix !== 'number') return new Error(`${path}.paid_at_unix: is not a number`)
|
||||
if (opts.paid_at_unix_CustomCheck && !opts.paid_at_unix_CustomCheck(o.paid_at_unix)) return new Error(`${path}.paid_at_unix: custom check failed`)
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
export type OfferInvoices = {
|
||||
invoices: OfferInvoice[]
|
||||
}
|
||||
export const OfferInvoicesOptionalFields: [] = []
|
||||
export type OfferInvoicesOptions = OptionsBaseMessage & {
|
||||
checkOptionalsAreSet?: []
|
||||
invoices_ItemOptions?: OfferInvoiceOptions
|
||||
invoices_CustomCheck?: (v: OfferInvoice[]) => boolean
|
||||
}
|
||||
export const OfferInvoicesValidate = (o?: OfferInvoices, opts: OfferInvoicesOptions = {}, path: string = 'OfferInvoices::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.invoices)) return new Error(`${path}.invoices: is not an array`)
|
||||
for (let index = 0; index < o.invoices.length; index++) {
|
||||
const invoicesErr = OfferInvoiceValidate(o.invoices[index], opts.invoices_ItemOptions, `${path}.invoices[${index}]`)
|
||||
if (invoicesErr !== null) return invoicesErr
|
||||
}
|
||||
if (opts.invoices_CustomCheck && !opts.invoices_CustomCheck(o.invoices)) return new Error(`${path}.invoices: custom check failed`)
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
export type OpenChannel = {
|
||||
active: boolean
|
||||
capacity: number
|
||||
|
|
@ -2482,6 +2778,26 @@ export const PayInvoiceResponseValidate = (o?: PayInvoiceResponse, opts: PayInvo
|
|||
return null
|
||||
}
|
||||
|
||||
export type PayerData = {
|
||||
data: Record<string, string>
|
||||
}
|
||||
export const PayerDataOptionalFields: [] = []
|
||||
export type PayerDataOptions = OptionsBaseMessage & {
|
||||
checkOptionalsAreSet?: []
|
||||
data_CustomCheck?: (v: Record<string, string>) => boolean
|
||||
}
|
||||
export const PayerDataValidate = (o?: PayerData, opts: PayerDataOptions = {}, path: string = 'PayerData::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.data !== 'object' || o.data === null) return new Error(`${path}.data: is not an object or is null`)
|
||||
for (const key in o.data) {
|
||||
if (typeof o.data[key] !== 'string') return new Error(`${path}.data['${key}']: is not a string`)
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
export type PaymentState = {
|
||||
amount: number
|
||||
network_fee: number
|
||||
|
|
@ -2852,6 +3168,7 @@ export const UpdateChannelPolicyRequestValidate = (o?: UpdateChannelPolicyReques
|
|||
}
|
||||
|
||||
export type UsageMetric = {
|
||||
app_id?: string
|
||||
auth_in_nano: number
|
||||
batch: boolean
|
||||
batch_size: number
|
||||
|
|
@ -2860,11 +3177,14 @@ export type UsageMetric = {
|
|||
parsed_in_nano: number
|
||||
processed_at_ms: number
|
||||
rpc_name: string
|
||||
success: boolean
|
||||
validate_in_nano: number
|
||||
}
|
||||
export const UsageMetricOptionalFields: [] = []
|
||||
export type UsageMetricOptionalField = 'app_id'
|
||||
export const UsageMetricOptionalFields: UsageMetricOptionalField[] = ['app_id']
|
||||
export type UsageMetricOptions = OptionsBaseMessage & {
|
||||
checkOptionalsAreSet?: []
|
||||
checkOptionalsAreSet?: UsageMetricOptionalField[]
|
||||
app_id_CustomCheck?: (v?: string) => boolean
|
||||
auth_in_nano_CustomCheck?: (v: number) => boolean
|
||||
batch_CustomCheck?: (v: boolean) => boolean
|
||||
batch_size_CustomCheck?: (v: number) => boolean
|
||||
|
|
@ -2873,12 +3193,16 @@ export type UsageMetricOptions = OptionsBaseMessage & {
|
|||
parsed_in_nano_CustomCheck?: (v: number) => boolean
|
||||
processed_at_ms_CustomCheck?: (v: number) => boolean
|
||||
rpc_name_CustomCheck?: (v: string) => boolean
|
||||
success_CustomCheck?: (v: boolean) => boolean
|
||||
validate_in_nano_CustomCheck?: (v: number) => boolean
|
||||
}
|
||||
export const UsageMetricValidate = (o?: UsageMetric, opts: UsageMetricOptions = {}, path: string = 'UsageMetric::root.'): Error | null => {
|
||||
if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message')
|
||||
if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null')
|
||||
|
||||
if ((o.app_id || opts.allOptionalsAreSet || opts.checkOptionalsAreSet?.includes('app_id')) && typeof o.app_id !== 'string') return new Error(`${path}.app_id: is not a string`)
|
||||
if (opts.app_id_CustomCheck && !opts.app_id_CustomCheck(o.app_id)) return new Error(`${path}.app_id: custom check failed`)
|
||||
|
||||
if (typeof o.auth_in_nano !== 'number') return new Error(`${path}.auth_in_nano: is not a number`)
|
||||
if (opts.auth_in_nano_CustomCheck && !opts.auth_in_nano_CustomCheck(o.auth_in_nano)) return new Error(`${path}.auth_in_nano: custom check failed`)
|
||||
|
||||
|
|
@ -2903,31 +3227,67 @@ export const UsageMetricValidate = (o?: UsageMetric, opts: UsageMetricOptions =
|
|||
if (typeof o.rpc_name !== 'string') return new Error(`${path}.rpc_name: is not a string`)
|
||||
if (opts.rpc_name_CustomCheck && !opts.rpc_name_CustomCheck(o.rpc_name)) return new Error(`${path}.rpc_name: custom check failed`)
|
||||
|
||||
if (typeof o.success !== 'boolean') return new Error(`${path}.success: is not a boolean`)
|
||||
if (opts.success_CustomCheck && !opts.success_CustomCheck(o.success)) return new Error(`${path}.success: custom check failed`)
|
||||
|
||||
if (typeof o.validate_in_nano !== 'number') return new Error(`${path}.validate_in_nano: is not a number`)
|
||||
if (opts.validate_in_nano_CustomCheck && !opts.validate_in_nano_CustomCheck(o.validate_in_nano)) return new Error(`${path}.validate_in_nano: custom check failed`)
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
export type UsageMetricTlv = {
|
||||
available_chunks: number[]
|
||||
base_64_tlvs: string[]
|
||||
current_chunk: number
|
||||
}
|
||||
export const UsageMetricTlvOptionalFields: [] = []
|
||||
export type UsageMetricTlvOptions = OptionsBaseMessage & {
|
||||
checkOptionalsAreSet?: []
|
||||
available_chunks_CustomCheck?: (v: number[]) => boolean
|
||||
base_64_tlvs_CustomCheck?: (v: string[]) => boolean
|
||||
current_chunk_CustomCheck?: (v: number) => boolean
|
||||
}
|
||||
export const UsageMetricTlvValidate = (o?: UsageMetricTlv, opts: UsageMetricTlvOptions = {}, path: string = 'UsageMetricTlv::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.available_chunks)) return new Error(`${path}.available_chunks: is not an array`)
|
||||
for (let index = 0; index < o.available_chunks.length; index++) {
|
||||
if (typeof o.available_chunks[index] !== 'number') return new Error(`${path}.available_chunks[${index}]: is not a number`)
|
||||
}
|
||||
if (opts.available_chunks_CustomCheck && !opts.available_chunks_CustomCheck(o.available_chunks)) return new Error(`${path}.available_chunks: custom check failed`)
|
||||
|
||||
if (!Array.isArray(o.base_64_tlvs)) return new Error(`${path}.base_64_tlvs: is not an array`)
|
||||
for (let index = 0; index < o.base_64_tlvs.length; index++) {
|
||||
if (typeof o.base_64_tlvs[index] !== 'string') return new Error(`${path}.base_64_tlvs[${index}]: is not a string`)
|
||||
}
|
||||
if (opts.base_64_tlvs_CustomCheck && !opts.base_64_tlvs_CustomCheck(o.base_64_tlvs)) return new Error(`${path}.base_64_tlvs: custom check failed`)
|
||||
|
||||
if (typeof o.current_chunk !== 'number') return new Error(`${path}.current_chunk: is not a number`)
|
||||
if (opts.current_chunk_CustomCheck && !opts.current_chunk_CustomCheck(o.current_chunk)) return new Error(`${path}.current_chunk: custom check failed`)
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
export type UsageMetrics = {
|
||||
metrics: UsageMetric[]
|
||||
apps: Record<string, AppUsageMetrics>
|
||||
}
|
||||
export const UsageMetricsOptionalFields: [] = []
|
||||
export type UsageMetricsOptions = OptionsBaseMessage & {
|
||||
checkOptionalsAreSet?: []
|
||||
metrics_ItemOptions?: UsageMetricOptions
|
||||
metrics_CustomCheck?: (v: UsageMetric[]) => boolean
|
||||
apps_EntryOptions?: AppUsageMetricsOptions
|
||||
apps_CustomCheck?: (v: Record<string, AppUsageMetrics>) => boolean
|
||||
}
|
||||
export const UsageMetricsValidate = (o?: UsageMetrics, opts: UsageMetricsOptions = {}, path: string = 'UsageMetrics::root.'): Error | null => {
|
||||
if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message')
|
||||
if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null')
|
||||
|
||||
if (!Array.isArray(o.metrics)) return new Error(`${path}.metrics: is not an array`)
|
||||
for (let index = 0; index < o.metrics.length; index++) {
|
||||
const metricsErr = UsageMetricValidate(o.metrics[index], opts.metrics_ItemOptions, `${path}.metrics[${index}]`)
|
||||
if (metricsErr !== null) return metricsErr
|
||||
if (typeof o.apps !== 'object' || o.apps === null) return new Error(`${path}.apps: is not an object or is null`)
|
||||
for (const key in o.apps) {
|
||||
const appsErr = AppUsageMetricsValidate(o.apps[key], opts.apps_EntryOptions, `${path}.apps['${key}']`)
|
||||
if (appsErr !== null) return appsErr
|
||||
}
|
||||
if (opts.metrics_CustomCheck && !opts.metrics_CustomCheck(o.metrics)) return new Error(`${path}.metrics: custom check failed`)
|
||||
|
||||
return null
|
||||
}
|
||||
|
|
@ -2950,6 +3310,24 @@ export const UseInviteLinkRequestValidate = (o?: UseInviteLinkRequest, opts: Use
|
|||
return null
|
||||
}
|
||||
|
||||
export type UserHealthState = {
|
||||
downtime_reason: string
|
||||
}
|
||||
export const UserHealthStateOptionalFields: [] = []
|
||||
export type UserHealthStateOptions = OptionsBaseMessage & {
|
||||
checkOptionalsAreSet?: []
|
||||
downtime_reason_CustomCheck?: (v: string) => boolean
|
||||
}
|
||||
export const UserHealthStateValidate = (o?: UserHealthState, opts: UserHealthStateOptions = {}, path: string = 'UserHealthState::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.downtime_reason !== 'string') return new Error(`${path}.downtime_reason: is not a string`)
|
||||
if (opts.downtime_reason_CustomCheck && !opts.downtime_reason_CustomCheck(o.downtime_reason)) return new Error(`${path}.downtime_reason: custom check failed`)
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
export type UserInfo = {
|
||||
balance: number
|
||||
bridge_url: string
|
||||
|
|
@ -3018,6 +3396,29 @@ export const UserInfoValidate = (o?: UserInfo, opts: UserInfoOptions = {}, path:
|
|||
return null
|
||||
}
|
||||
|
||||
export type UserOffers = {
|
||||
offers: OfferConfig[]
|
||||
}
|
||||
export const UserOffersOptionalFields: [] = []
|
||||
export type UserOffersOptions = OptionsBaseMessage & {
|
||||
checkOptionalsAreSet?: []
|
||||
offers_ItemOptions?: OfferConfigOptions
|
||||
offers_CustomCheck?: (v: OfferConfig[]) => boolean
|
||||
}
|
||||
export const UserOffersValidate = (o?: UserOffers, opts: UserOffersOptions = {}, path: string = 'UserOffers::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.offers)) return new Error(`${path}.offers: is not an array`)
|
||||
for (let index = 0; index < o.offers.length; index++) {
|
||||
const offersErr = OfferConfigValidate(o.offers[index], opts.offers_ItemOptions, `${path}.offers[${index}]`)
|
||||
if (offersErr !== null) return offersErr
|
||||
}
|
||||
if (opts.offers_CustomCheck && !opts.offers_CustomCheck(o.offers)) return new Error(`${path}.offers: custom check failed`)
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
export type UserOperation = {
|
||||
amount: number
|
||||
confirmed: boolean
|
||||
|
|
|
|||
|
|
@ -178,6 +178,12 @@ service LightningPub {
|
|||
option (http_route) = "/api/reports/usage";
|
||||
option (nostr) = true;
|
||||
}
|
||||
rpc GetErrorStats(structs.Empty) returns (structs.ErrorStats) {
|
||||
option (auth_type) = "Metrics";
|
||||
option (http_method) = "post";
|
||||
option (http_route) = "/api/reports/errors";
|
||||
option (nostr) = true;
|
||||
}
|
||||
|
||||
rpc GetAppsMetrics(structs.AppsMetricsRequest) returns (structs.AppsMetrics) {
|
||||
option (auth_type) = "Metrics";
|
||||
|
|
@ -364,7 +370,7 @@ service LightningPub {
|
|||
// </App>
|
||||
|
||||
// <User>
|
||||
rpc UserHealth(structs.Empty)returns(structs.Empty){
|
||||
rpc UserHealth(structs.Empty)returns(structs.UserHealthState){
|
||||
option (auth_type) = "User";
|
||||
option (http_method) = "post";
|
||||
option (http_route) = "/api/user/health";
|
||||
|
|
@ -467,6 +473,48 @@ service LightningPub {
|
|||
option (http_route) = "/api/user/lnurl_channel/url";
|
||||
option (nostr) = true;
|
||||
}
|
||||
|
||||
rpc GetUserOffers(structs.Empty) returns (structs.UserOffers){
|
||||
option (auth_type) = "User";
|
||||
option (http_method) = "get";
|
||||
option (http_route) = "/api/user/offers/get";
|
||||
option (nostr) = true;
|
||||
}
|
||||
|
||||
rpc GetUserOffer(structs.OfferId) returns (structs.OfferConfig){
|
||||
option (auth_type) = "User";
|
||||
option (http_method) = "post";
|
||||
option (http_route) = "/api/user/offer/get";
|
||||
option (nostr) = true;
|
||||
}
|
||||
rpc GetUserOfferInvoices(structs.GetUserOfferInvoicesReq) returns (structs.OfferInvoices){
|
||||
option (auth_type) = "User";
|
||||
option (http_method) = "post";
|
||||
option (http_route) = "/api/user/offer/get/invoices";
|
||||
option (nostr) = true;
|
||||
}
|
||||
|
||||
rpc UpdateUserOffer(structs.OfferConfig) returns (structs.Empty){
|
||||
option (auth_type) = "User";
|
||||
option (http_method) = "post";
|
||||
option (http_route) = "/api/user/offer/update";
|
||||
option (nostr) = true;
|
||||
}
|
||||
|
||||
rpc DeleteUserOffer(structs.OfferId) returns (structs.Empty){
|
||||
option (auth_type) = "User";
|
||||
option (http_method) = "post";
|
||||
option (http_route) = "/api/user/offer/delete";
|
||||
option (nostr) = true;
|
||||
}
|
||||
|
||||
rpc AddUserOffer(structs.OfferConfig) returns (structs.OfferId){
|
||||
option (auth_type) = "User";
|
||||
option (http_method) = "post";
|
||||
option (http_route) = "/api/user/offer/add";
|
||||
option (nostr) = true;
|
||||
}
|
||||
|
||||
rpc GetDebitAuthorizations(structs.Empty) returns (structs.DebitAuthorizations){
|
||||
option (auth_type) = "User";
|
||||
option (http_method) = "get";
|
||||
|
|
|
|||
|
|
@ -15,6 +15,24 @@ message EncryptionExchangeRequest {
|
|||
string deviceId = 2;
|
||||
}
|
||||
|
||||
message UserHealthState {
|
||||
string downtime_reason = 1;
|
||||
}
|
||||
|
||||
message ErrorStat {
|
||||
int64 from_unix = 1;
|
||||
int64 total = 2;
|
||||
int64 errors = 3;
|
||||
}
|
||||
|
||||
message ErrorStats {
|
||||
ErrorStat past24h = 1;
|
||||
ErrorStat past6h = 2;
|
||||
ErrorStat past1h = 3;
|
||||
ErrorStat past10m = 4;
|
||||
ErrorStat past1m = 5;
|
||||
}
|
||||
|
||||
message UsageMetric {
|
||||
int64 processed_at_ms = 1;
|
||||
int64 parsed_in_nano = 2;
|
||||
|
|
@ -25,10 +43,23 @@ message UsageMetric {
|
|||
bool batch = 7;
|
||||
bool nostr = 8;
|
||||
int64 batch_size = 9;
|
||||
bool success = 10;
|
||||
optional string app_id = 11;
|
||||
}
|
||||
|
||||
message UsageMetricTlv {
|
||||
repeated string base_64_tlvs = 1;
|
||||
int64 current_chunk = 2;
|
||||
repeated int64 available_chunks = 3;
|
||||
|
||||
}
|
||||
|
||||
message AppUsageMetrics {
|
||||
map<string,UsageMetricTlv> app_metrics = 1;
|
||||
}
|
||||
|
||||
message UsageMetrics {
|
||||
repeated UsageMetric metrics = 1;
|
||||
map<string,AppUsageMetrics> apps = 1;
|
||||
}
|
||||
|
||||
message AppsMetricsRequest {
|
||||
|
|
@ -269,6 +300,8 @@ message AddAppUserInvoiceRequest {
|
|||
string payer_identifier = 2;
|
||||
string http_callback_url = 3;
|
||||
NewInvoiceRequest invoice_req = 4;
|
||||
optional PayerData payer_data = 5;
|
||||
optional string offer_string = 6;
|
||||
}
|
||||
|
||||
message GetAppUserRequest {
|
||||
|
|
@ -331,6 +364,10 @@ message PayAddressResponse{
|
|||
int64 network_fee = 4;
|
||||
}
|
||||
|
||||
message PayerData {
|
||||
map<string,string> data = 1;
|
||||
}
|
||||
|
||||
message NewInvoiceRequest{
|
||||
int64 amountSats = 1;
|
||||
string memo = 2;
|
||||
|
|
@ -613,4 +650,43 @@ message DebitResponse {
|
|||
Empty denied = 3;
|
||||
string invoice = 4;
|
||||
}
|
||||
}
|
||||
|
||||
enum OfferDataType {
|
||||
DATA_STRING = 0;
|
||||
}
|
||||
|
||||
message OfferId {
|
||||
string offer_id = 1;
|
||||
}
|
||||
|
||||
message OfferConfig {
|
||||
string offer_id = 1;
|
||||
string label = 2;
|
||||
int64 price_sats = 3;
|
||||
string callback_url = 4;
|
||||
map<string, OfferDataType> expected_data = 5;
|
||||
string noffer = 6;
|
||||
bool default_offer = 7;
|
||||
}
|
||||
|
||||
message UserOffers {
|
||||
repeated OfferConfig offers = 1;
|
||||
}
|
||||
|
||||
message GetUserOfferInvoicesReq {
|
||||
string offer_id = 1;
|
||||
bool include_unpaid = 2;
|
||||
}
|
||||
|
||||
message OfferInvoices {
|
||||
repeated OfferInvoice invoices = 1;
|
||||
}
|
||||
|
||||
message OfferInvoice {
|
||||
string invoice = 1;
|
||||
string offer_id = 2;
|
||||
int64 paid_at_unix = 3;
|
||||
int64 amount = 4;
|
||||
map<string,string> data = 5;
|
||||
}
|
||||
|
|
@ -64,11 +64,11 @@ get_log_info() {
|
|||
|
||||
log "Retrieving connection information..."
|
||||
|
||||
# Wait for either .admin_connect or app.nprofile to appear
|
||||
# Wait for either admin.connect or app.nprofile to appear
|
||||
START_TIME=$(date +%s)
|
||||
while [ $(($(date +%s) - START_TIME)) -lt $MAX_WAIT_TIME ]; do
|
||||
if [ -f "$DATA_DIR/.admin_connect" ]; then
|
||||
admin_connect=$(cat "$DATA_DIR/.admin_connect")
|
||||
if [ -f "$DATA_DIR/admin.connect" ]; then
|
||||
admin_connect=$(cat "$DATA_DIR/admin.connect")
|
||||
# Check if the admin_connect string is complete (contains both nprofile and secret)
|
||||
if [[ $admin_connect == nprofile* ]] && [[ $admin_connect == *:* ]]; then
|
||||
log "An admin has not yet been enrolled."
|
||||
|
|
@ -87,10 +87,10 @@ get_log_info() {
|
|||
sleep $WAIT_INTERVAL
|
||||
done
|
||||
|
||||
if [ ! -f "$DATA_DIR/.admin_connect" ] && [ ! -f "$DATA_DIR/app.nprofile" ]; then
|
||||
log "Neither .admin_connect nor app.nprofile file found after waiting. Please check the service status."
|
||||
if [ ! -f "$DATA_DIR/admin.connect" ] && [ ! -f "$DATA_DIR/app.nprofile" ]; then
|
||||
log "Neither admin.connect nor app.nprofile file found after waiting. Please check the service status."
|
||||
exit 1
|
||||
elif [ -f "$DATA_DIR/.admin_connect" ] && ! [[ $(cat "$DATA_DIR/.admin_connect") == nprofile1* ]] && ! [[ $(cat "$DATA_DIR/.admin_connect") == *:* ]]; then
|
||||
elif [ -f "$DATA_DIR/admin.connect" ] && ! [[ $(cat "$DATA_DIR/admin.connect") == nprofile1* ]] && ! [[ $(cat "$DATA_DIR/admin.connect") == *:* ]]; then
|
||||
log "Admin connect information is incomplete. Please check the service status."
|
||||
exit 1
|
||||
fi
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ install_lightning_pub() {
|
|||
|
||||
# Merge if upgrade
|
||||
if [ $upgrade_status -eq 100 ]; then
|
||||
rsync -a --quiet --exclude='*.sqlite' --exclude='.env' --exclude='logs' --exclude='node_modules' --exclude='.jwt_secret' --exclude='.wallet_secret' --exclude='admin.npub' --exclude='app.nprofile' --exclude='.admin_connect' --exclude='.admin_enroll' $USER_HOME/lightning_pub_temp/ $USER_HOME/lightning_pub/
|
||||
rsync -a --quiet --exclude='*.sqlite' --exclude='.env' --exclude='logs' --exclude='node_modules' --exclude='.jwt_secret' --exclude='.wallet_secret' --exclude='admin.npub' --exclude='app.nprofile' --exclude='admin.connect' --exclude='admin.enroll' $USER_HOME/lightning_pub_temp/ $USER_HOME/lightning_pub/
|
||||
else
|
||||
mv $USER_HOME/lightning_pub_temp $USER_HOME/lightning_pub
|
||||
fi
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ export default (serverMethods: Types.ServerMethods, mainHandler: Main, nostrSett
|
|||
}
|
||||
if (event.kind === 21001) {
|
||||
const offerReq = j as NofferData
|
||||
mainHandler.handleNip69Noffer(offerReq, event)
|
||||
mainHandler.offerManager.handleNip69Noffer(offerReq, event)
|
||||
return
|
||||
} else if (event.kind === 21002) {
|
||||
const debitReq = j as NdebitData
|
||||
|
|
|
|||
90
src/services/helpers/tlv.ts
Normal file
90
src/services/helpers/tlv.ts
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
import { bytesToHex, concatBytes } from '@noble/hashes/utils'
|
||||
import * as Types from '../../../proto/autogenerated/ts/types.js'
|
||||
export const utf8Decoder: TextDecoder = new TextDecoder('utf-8')
|
||||
export const utf8Encoder: TextEncoder = new TextEncoder()
|
||||
|
||||
export const encodeListTLV = (list: Uint8Array[]): TLV => {
|
||||
const tlv: TLV = {}
|
||||
tlv[64] = list
|
||||
return tlv
|
||||
}
|
||||
|
||||
export const decodeListTLV = (tlv: TLV): Uint8Array[] => {
|
||||
return tlv[64]
|
||||
}
|
||||
|
||||
export const usageMetricsToTlv = (metric: Types.UsageMetric): TLV => {
|
||||
const tlv: TLV = {}
|
||||
tlv[2] = [integerToUint8Array(Math.ceil(metric.processed_at_ms / 1000))] // 6 -> 6
|
||||
tlv[3] = [integerToUint8Array(Math.ceil(metric.parsed_in_nano / 1000))] // 6 -> 12
|
||||
tlv[4] = [integerToUint8Array(Math.ceil(metric.auth_in_nano / 1000))] // 6 -> 18
|
||||
tlv[5] = [integerToUint8Array(Math.ceil(metric.validate_in_nano / 1000))] // 6 -> 24
|
||||
tlv[6] = [integerToUint8Array(Math.ceil(metric.handle_in_nano / 1000))] // 6 -> 30
|
||||
tlv[7] = [integerToUint8Array(metric.batch_size)] // 6 -> 36
|
||||
tlv[8] = [new Uint8Array([metric.batch ? 1 : 0])] // 3 -> 39
|
||||
tlv[9] = [new Uint8Array([metric.nostr ? 1 : 0])] // 3 -> 42
|
||||
tlv[10] = [new Uint8Array([metric.success ? 1 : 0])] // 3 -> 45
|
||||
return tlv
|
||||
}
|
||||
|
||||
export const tlvToUsageMetrics = (rpcName: string, tlv: TLV): Types.UsageMetric => {
|
||||
const metric: Types.UsageMetric = {
|
||||
rpc_name: rpcName,
|
||||
processed_at_ms: parseInt(bytesToHex(tlv[2][0]), 16) * 1000,
|
||||
parsed_in_nano: parseInt(bytesToHex(tlv[3][0]), 16) * 1000,
|
||||
auth_in_nano: parseInt(bytesToHex(tlv[4][0]), 16) * 1000,
|
||||
validate_in_nano: parseInt(bytesToHex(tlv[5][0]), 16) * 1000,
|
||||
handle_in_nano: parseInt(bytesToHex(tlv[6][0]), 16) * 1000,
|
||||
batch_size: parseInt(bytesToHex(tlv[7][0]), 16),
|
||||
batch: tlv[8][0][0] === 1,
|
||||
nostr: tlv[9][0][0] === 1,
|
||||
success: tlv[10][0][0] === 1,
|
||||
}
|
||||
return metric
|
||||
}
|
||||
|
||||
export const integerToUint8Array = (number: number): Uint8Array => {
|
||||
// Create a Uint8Array with enough space to hold a 32-bit integer (4 bytes).
|
||||
const uint8Array = new Uint8Array(4)
|
||||
|
||||
// Use bitwise operations to extract the bytes.
|
||||
uint8Array[0] = (number >> 24) & 0xff // Most significant byte (MSB)
|
||||
uint8Array[1] = (number >> 16) & 0xff
|
||||
uint8Array[2] = (number >> 8) & 0xff
|
||||
uint8Array[3] = number & 0xff // Least significant byte (LSB)
|
||||
|
||||
return uint8Array
|
||||
}
|
||||
|
||||
export type TLV = { [t: number]: Uint8Array[] }
|
||||
export 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 encodeTLV = (tlv: TLV): Uint8Array => {
|
||||
const entries: Uint8Array[] = []
|
||||
Object.entries(tlv)
|
||||
.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)
|
||||
}
|
||||
|
|
@ -193,7 +193,10 @@ export default class {
|
|||
if (req.invoice_req.zap) {
|
||||
zapInfo = this.paymentManager.validateZapEvent(req.invoice_req.zap, req.invoice_req.amountSats)
|
||||
}
|
||||
const opts: InboundOptionals = { callbackUrl: cbUrl, expiry: defaultInvoiceExpiry, expectedPayer: payer.user, linkedApplication: app, zapInfo }
|
||||
const opts: InboundOptionals = {
|
||||
callbackUrl: cbUrl, expiry: defaultInvoiceExpiry, expectedPayer: payer.user, linkedApplication: app, zapInfo,
|
||||
offerId: req.offer_string, payerData: req.payer_data?.data
|
||||
}
|
||||
const appUserInvoice = await this.paymentManager.NewInvoice(receiver.user.user_id, req.invoice_req, opts)
|
||||
return {
|
||||
invoice: appUserInvoice.invoice
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ import { Unlocker } from "./unlocker.js"
|
|||
import { defaultInvoiceExpiry } from "../storage/paymentStorage.js"
|
||||
import { DebitManager } from "./debitManager.js"
|
||||
import { NofferData } from "nostr-tools/lib/types/nip69.js"
|
||||
import { OfferManager } from "./offerManager.js"
|
||||
|
||||
type UserOperationsSub = {
|
||||
id: string
|
||||
|
|
@ -49,6 +50,7 @@ export default class {
|
|||
liquidityManager: LiquidityManager
|
||||
liquidityProvider: LiquidityProvider
|
||||
debitManager: DebitManager
|
||||
offerManager: OfferManager
|
||||
utils: Utils
|
||||
rugPullTracker: RugPullTracker
|
||||
unlocker: Unlocker
|
||||
|
|
@ -71,6 +73,8 @@ export default class {
|
|||
this.applicationManager = new ApplicationManager(this.storage, this.settings, this.paymentManager)
|
||||
this.appUserManager = new AppUserManager(this.storage, this.settings, this.applicationManager)
|
||||
this.debitManager = new DebitManager(this.storage, this.lnd, this.applicationManager)
|
||||
this.offerManager = new OfferManager(this.storage, this.lnd, this.applicationManager, this.productManager)
|
||||
|
||||
}
|
||||
|
||||
Stop() {
|
||||
|
|
@ -89,6 +93,7 @@ export default class {
|
|||
this.nostrSend = f
|
||||
this.liquidityProvider.attachNostrSend(f)
|
||||
this.debitManager.attachNostrSend(f)
|
||||
this.offerManager.attachNostrSend(f)
|
||||
}
|
||||
|
||||
htlcCb: HtlcCb = (e) => {
|
||||
|
|
@ -215,11 +220,15 @@ export default class {
|
|||
if (fee > 0) {
|
||||
await this.storage.userStorage.IncrementUserBalance(userInvoice.linkedApplication.owner.user_id, fee, 'fees', tx)
|
||||
}
|
||||
await this.triggerPaidCallback(log, userInvoice.callbackUrl)
|
||||
await this.triggerPaidCallback(log, userInvoice.callbackUrl, { invoice: paymentRequest, amount, other: userInvoice.payer_data })
|
||||
const operationId = `${Types.UserOperationType.INCOMING_INVOICE}-${userInvoice.serial_id}`
|
||||
const op = { amount, paidAtUnix: Date.now() / 1000, inbound: true, type: Types.UserOperationType.INCOMING_INVOICE, identifier: userInvoice.invoice, operationId, network_fee: 0, service_fee: fee, confirmed: true, tx_hash: "", internal }
|
||||
this.sendOperationToNostr(userInvoice.linkedApplication, userInvoice.user.user_id, op)
|
||||
this.createZapReceipt(log, userInvoice)
|
||||
try {
|
||||
this.createZapReceipt(log, userInvoice)
|
||||
} catch (err: any) {
|
||||
log(ERROR, "cannot create zap receipt", err.message || "")
|
||||
}
|
||||
this.liquidityManager.afterInInvoicePaid()
|
||||
this.utils.stateBundler.AddTxPoint('invoiceWasPaid', amount, { used, from: 'system', timeDiscount: true })
|
||||
} catch (err: any) {
|
||||
|
|
@ -229,13 +238,21 @@ export default class {
|
|||
})
|
||||
}
|
||||
|
||||
async triggerPaidCallback(log: PubLogger, url: string) {
|
||||
async triggerPaidCallback(log: PubLogger, url: string, { invoice, amount, other }: { invoice: string, amount: number, other?: Record<string, string> }) {
|
||||
if (!url) {
|
||||
return
|
||||
}
|
||||
let finalUrl = url.replace(`%[invoice]`, invoice).replace(`%[amount]`, amount.toString())
|
||||
if (other) {
|
||||
for (const [key, value] of Object.entries(other)) {
|
||||
finalUrl = finalUrl.replace(`%[${key}]`, value)
|
||||
}
|
||||
}
|
||||
try {
|
||||
const symbol = url.includes('?') ? "&" : "?"
|
||||
await fetch(url + symbol + "ok=true")
|
||||
const symbol = finalUrl.includes('?') ? "&" : "?"
|
||||
finalUrl = finalUrl + symbol + "ok=true"
|
||||
log("sending paid callback to", finalUrl)
|
||||
await fetch(finalUrl)
|
||||
} catch (err: any) {
|
||||
log(ERROR, "error sending paid callback for invoice", err.message || "")
|
||||
}
|
||||
|
|
@ -286,70 +303,6 @@ export default class {
|
|||
log({ unsigned: event })
|
||||
this.nostrSend({ type: 'app', appId: invoice.linkedApplication.app_id }, { type: 'event', event }, zapInfo.relays || undefined)
|
||||
}
|
||||
|
||||
async getNofferInvoice(offerReq: NofferData, appId: string): Promise<{ success: true, invoice: string } | { success: false, code: number, max: number }> {
|
||||
try {
|
||||
|
||||
const { remote } = await this.lnd.ChannelBalance()
|
||||
const { offer, amount } = offerReq
|
||||
const split = offer.split(':')
|
||||
if (split.length === 1) {
|
||||
if (!amount || isNaN(amount) || amount < 10 || amount > remote) {
|
||||
return { success: false, code: 5, max: remote }
|
||||
}
|
||||
const res = await this.applicationManager.AddAppUserInvoice(appId, {
|
||||
http_callback_url: "", payer_identifier: split[0], receiver_identifier: split[0],
|
||||
invoice_req: { amountSats: amount, memo: "Default NIP-69 Offer", zap: offerReq.zap }
|
||||
})
|
||||
return { success: true, invoice: res.invoice }
|
||||
} else if (split[0] === 'p') {
|
||||
const product = await this.productManager.NewProductInvoice(split[1])
|
||||
return { success: true, invoice: product.invoice }
|
||||
} else {
|
||||
return { success: false, code: 1, max: remote }
|
||||
}
|
||||
} catch (e: any) {
|
||||
getLogger({ component: "noffer" })(ERROR, e.message || e)
|
||||
return { success: false, code: 1, max: 0 }
|
||||
}
|
||||
}
|
||||
|
||||
async handleNip69Noffer(offerReq: NofferData, event: NostrEvent) {
|
||||
const offerInvoice = await this.getNofferInvoice(offerReq, event.appId)
|
||||
if (!offerInvoice.success) {
|
||||
const code = offerInvoice.code
|
||||
const e = newNofferResponse(JSON.stringify({ code, error: codeToMessage(code), range: { min: 10, max: offerInvoice.max } }), event)
|
||||
this.nostrSend({ type: 'app', appId: event.appId }, { type: 'event', event: e, encrypt: { toPub: event.pub } })
|
||||
return
|
||||
}
|
||||
const e = newNofferResponse(JSON.stringify({ bolt11: offerInvoice.invoice }), event)
|
||||
this.nostrSend({ type: 'app', appId: event.appId }, { type: 'event', event: e, encrypt: { toPub: event.pub } })
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
const codeToMessage = (code: number) => {
|
||||
switch (code) {
|
||||
case 1: return 'Invalid Offer'
|
||||
case 2: return 'Temporary Failure'
|
||||
case 3: return 'Expired Offer'
|
||||
case 4: return 'Unsupported Feature'
|
||||
case 5: return 'Invalid Amount'
|
||||
default: throw new Error("unknown error code" + code)
|
||||
}
|
||||
}
|
||||
|
||||
const newNofferResponse = (content: string, event: NostrEvent): UnsignedEvent => {
|
||||
return {
|
||||
content,
|
||||
created_at: Math.floor(Date.now() / 1000),
|
||||
kind: 21001,
|
||||
pubkey: "",
|
||||
tags: [
|
||||
['p', event.pub],
|
||||
['e', event.id],
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
259
src/services/main/offerManager.ts
Normal file
259
src/services/main/offerManager.ts
Normal file
|
|
@ -0,0 +1,259 @@
|
|||
import crypto from 'crypto';
|
||||
import * as Types from "../../../proto/autogenerated/ts/types.js";
|
||||
import ApplicationManager from "./applicationManager.js";
|
||||
import ProductManager from "./productManager.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';
|
||||
import { NofferData } from "nostr-tools/lib/types/nip69.js"
|
||||
import { UserOffer } from '../storage/entity/UserOffer.js';
|
||||
import { DeepPartial } from 'typeorm';
|
||||
import { nip19 } from 'nostr-tools';
|
||||
import { LoadNosrtSettingsFromEnv } from '../nostr/index.js';
|
||||
|
||||
const mapToOfferConfig = (appUserId: string, offer: UserOffer, { pubkey, relay }: { pubkey: string, relay: string }): Types.OfferConfig => {
|
||||
if (offer.expected_data) {
|
||||
const keys = Object.keys(offer.expected_data)
|
||||
for (const key of keys) {
|
||||
const v = offer.expected_data[key] as Types.OfferDataType
|
||||
if (!Types.OfferDataType[v]) {
|
||||
offer.expected_data[key] = Types.OfferDataType.DATA_STRING
|
||||
}
|
||||
}
|
||||
}
|
||||
const offerStr = offer.offer_id
|
||||
const priceType: nip19.OfferPriceType = offer.price_sats === 0 ? nip19.OfferPriceType.Spontaneous : nip19.OfferPriceType.Fixed
|
||||
const noffer = nip19.nofferEncode({ pubkey, offer: offerStr, priceType, relay, price: offer.price_sats || undefined })
|
||||
return {
|
||||
label: offer.label,
|
||||
price_sats: offer.price_sats,
|
||||
callback_url: offer.callback_url,
|
||||
expected_data: (offer.expected_data || {}) as Record<string, Types.OfferDataType>,
|
||||
offer_id: offer.offer_id,
|
||||
noffer: noffer,
|
||||
default_offer: appUserId === offer.app_user_id
|
||||
}
|
||||
}
|
||||
export class OfferManager {
|
||||
|
||||
|
||||
_nostrSend: NostrSend | null = null
|
||||
|
||||
applicationManager: ApplicationManager
|
||||
productManager: ProductManager
|
||||
storage: Storage
|
||||
lnd: LND
|
||||
logger = getLogger({ component: 'DebitManager' })
|
||||
constructor(storage: Storage, lnd: LND, applicationManager: ApplicationManager, productManager: ProductManager) {
|
||||
this.storage = storage
|
||||
this.lnd = lnd
|
||||
this.applicationManager = applicationManager
|
||||
this.productManager = productManager
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
async AddUserOffer(ctx: Types.UserContext, req: Types.OfferConfig): Promise<Types.OfferId> {
|
||||
const newOffer = await this.storage.offerStorage.AddUserOffer(ctx.app_user_id, {
|
||||
expected_data: req.expected_data,
|
||||
label: req.label,
|
||||
price_sats: req.price_sats,
|
||||
callback_url: req.callback_url,
|
||||
})
|
||||
return {
|
||||
offer_id: newOffer.offer_id
|
||||
}
|
||||
}
|
||||
|
||||
async DeleteUserOffer(ctx: Types.UserContext, req: Types.OfferId) {
|
||||
await this.storage.offerStorage.DeleteUserOffer(ctx.app_user_id, req.offer_id)
|
||||
}
|
||||
|
||||
async UpdateUserOffer(ctx: Types.UserContext, req: Types.OfferConfig) {
|
||||
await this.storage.offerStorage.UpdateUserOffer(ctx.app_user_id, req.offer_id, {
|
||||
expected_data: req.expected_data,
|
||||
label: req.label,
|
||||
price_sats: req.price_sats,
|
||||
callback_url: req.callback_url,
|
||||
})
|
||||
}
|
||||
async GetUserOfferInvoices(ctx: Types.UserContext, req: Types.GetUserOfferInvoicesReq): Promise<Types.OfferInvoices> {
|
||||
const userOffer = await this.storage.offerStorage.GetUserOffer(ctx.app_user_id, req.offer_id)
|
||||
if (!userOffer) {
|
||||
throw new Error("Offer not found")
|
||||
}
|
||||
const i = await this.storage.paymentStorage.GetOfferInvoices(req.offer_id, req.include_unpaid)
|
||||
return {
|
||||
invoices: i.map(i => ({
|
||||
invoice: i.invoice,
|
||||
offer_id: i.offer_id || "",
|
||||
paid_at_unix: i.paid_at_unix,
|
||||
amount: i.paid_amount,
|
||||
data: i.payer_data || {}
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
async GetUserOffer(ctx: Types.UserContext, req: Types.OfferId): Promise<Types.OfferConfig> {
|
||||
const app = await this.applicationManager.GetApp(ctx.app_id)
|
||||
if (!app) {
|
||||
throw new Error("App not found")
|
||||
}
|
||||
const offer = await this.storage.offerStorage.GetUserOffer(ctx.app_user_id, req.offer_id)
|
||||
if (!offer) {
|
||||
throw new Error("Offer not found")
|
||||
}
|
||||
const nostrSettings = LoadNosrtSettingsFromEnv()
|
||||
return mapToOfferConfig(ctx.app_user_id, offer, { pubkey: app.npub, relay: nostrSettings.relays[0] })
|
||||
}
|
||||
|
||||
async GetUserOffers(ctx: Types.UserContext): Promise<Types.UserOffers> {
|
||||
const app = await this.applicationManager.GetApp(ctx.app_id)
|
||||
if (!app) {
|
||||
throw new Error("App not found")
|
||||
}
|
||||
const offers = await this.storage.offerStorage.GetUserOffers(ctx.app_user_id)
|
||||
const defaultOffer = offers.find(o => o.app_user_id === o.offer_id)
|
||||
let toAppend: UserOffer | undefined = undefined
|
||||
if (!defaultOffer) {
|
||||
toAppend = await this.storage.offerStorage.AddDefaultUserOffer(ctx.app_user_id)
|
||||
}
|
||||
if (toAppend) {
|
||||
offers.push(toAppend)
|
||||
}
|
||||
const nostrSettings = LoadNosrtSettingsFromEnv()
|
||||
return {
|
||||
offers: offers.map(o => mapToOfferConfig(ctx.app_user_id, o, { pubkey: app.npub, relay: nostrSettings.relays[0] }))
|
||||
}
|
||||
}
|
||||
|
||||
ValidateExpectedData(userOffer: UserOffer, payerData: any): { passed: false, validated: undefined } | { passed: true, validated: Record<string, string> } {
|
||||
const expected = userOffer.expected_data
|
||||
if (!expected) {
|
||||
return { passed: true, validated: {} }
|
||||
}
|
||||
const expectedKeys = Object.keys(expected)
|
||||
if (expectedKeys.length === 0) {
|
||||
return { passed: true, validated: {} }
|
||||
}
|
||||
if (typeof payerData !== 'object' || payerData === null) {
|
||||
return { passed: false, validated: undefined }
|
||||
}
|
||||
const validated: Record<string, string> = {}
|
||||
for (const key of expectedKeys) {
|
||||
if (typeof payerData[key] !== 'string') {
|
||||
return { passed: false, validated: undefined }
|
||||
}
|
||||
validated[key] = payerData[key]
|
||||
}
|
||||
return { passed: true, validated }
|
||||
}
|
||||
|
||||
async handleNip69Noffer(offerReq: NofferData, event: NostrEvent) {
|
||||
const offerInvoice = await this.getNofferInvoice(offerReq, event.appId)
|
||||
if (!offerInvoice.success) {
|
||||
const code = offerInvoice.code
|
||||
const e = newNofferResponse(JSON.stringify({ code, error: codeToMessage(code), range: { min: 10, max: offerInvoice.max } }), event)
|
||||
this.nostrSend({ type: 'app', appId: event.appId }, { type: 'event', event: e, encrypt: { toPub: event.pub } })
|
||||
return
|
||||
}
|
||||
const e = newNofferResponse(JSON.stringify({ bolt11: offerInvoice.invoice }), event)
|
||||
this.nostrSend({ type: 'app', appId: event.appId }, { type: 'event', event: e, encrypt: { toPub: event.pub } })
|
||||
return
|
||||
}
|
||||
|
||||
async HandleDefaultUserOffer(offerReq: NofferData, appId: string, remote: number): Promise<{ success: true, invoice: string } | { success: false, code: number, max: number }> {
|
||||
const { amount, offer } = offerReq
|
||||
if (!amount || isNaN(amount) || amount < 10 || amount > remote) {
|
||||
return { success: false, code: 5, max: remote }
|
||||
}
|
||||
const res = await this.applicationManager.AddAppUserInvoice(appId, {
|
||||
http_callback_url: "", payer_identifier: offer, receiver_identifier: offer,
|
||||
invoice_req: { amountSats: amount, memo: "Default NIP-69 Offer", zap: offerReq.zap },
|
||||
offer_string: 'offer'
|
||||
})
|
||||
return { success: true, invoice: res.invoice }
|
||||
}
|
||||
|
||||
async HandleUserOffer(offerReq: NofferData, appId: string, remote: number): Promise<{ success: true, invoice: string } | { success: false, code: number, max: number }> {
|
||||
const { amount, offer } = offerReq
|
||||
const userOffer = await this.storage.offerStorage.GetOffer(offer)
|
||||
if (!userOffer) {
|
||||
return this.HandleDefaultUserOffer(offerReq, appId, remote)
|
||||
}
|
||||
let amt = userOffer.price_sats
|
||||
if (userOffer.price_sats === 0) {
|
||||
if (!amount || isNaN(amount) || amount < 10 || amount > remote) {
|
||||
return { success: false, code: 5, max: remote }
|
||||
}
|
||||
amt = amount
|
||||
}
|
||||
const { passed, validated } = this.ValidateExpectedData(userOffer, offerReq.payer_data)
|
||||
if (!passed) {
|
||||
return { success: false, code: 1, max: remote }
|
||||
}
|
||||
const res = await this.applicationManager.AddAppUserInvoice(appId, {
|
||||
http_callback_url: userOffer.callback_url, payer_identifier: userOffer.app_user_id, receiver_identifier: userOffer.app_user_id,
|
||||
invoice_req: { amountSats: amt, memo: userOffer.label, zap: offerReq.zap },
|
||||
payer_data: validated ? { data: validated } : undefined,
|
||||
offer_string: offer
|
||||
})
|
||||
return { success: true, invoice: res.invoice }
|
||||
}
|
||||
|
||||
async getNofferInvoice(offerReq: NofferData, appId: string): Promise<{ success: true, invoice: string } | { success: false, code: number, max: number }> {
|
||||
try {
|
||||
const { remote } = await this.lnd.ChannelBalance()
|
||||
const split = offerReq.offer.split(':')
|
||||
if (split.length === 1) {
|
||||
return this.HandleUserOffer(offerReq, appId, remote)
|
||||
} else if (split[0] === 'p') {
|
||||
const product = await this.productManager.NewProductInvoice(split[1])
|
||||
return { success: true, invoice: product.invoice }
|
||||
} else {
|
||||
return { success: false, code: 1, max: remote }
|
||||
}
|
||||
} catch (e: any) {
|
||||
getLogger({ component: "noffer" })(ERROR, e.message || e)
|
||||
return { success: false, code: 1, max: 0 }
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
const newNofferResponse = (content: string, event: NostrEvent): UnsignedEvent => {
|
||||
return {
|
||||
content,
|
||||
created_at: Math.floor(Date.now() / 1000),
|
||||
kind: 21001,
|
||||
pubkey: "",
|
||||
tags: [
|
||||
['p', event.pub],
|
||||
['e', event.id],
|
||||
],
|
||||
}
|
||||
}
|
||||
const codeToMessage = (code: number) => {
|
||||
switch (code) {
|
||||
case 1: return 'Invalid Offer'
|
||||
case 2: return 'Temporary Failure'
|
||||
case 3: return 'Expired Offer'
|
||||
case 4: return 'Unsupported Feature'
|
||||
case 5: return 'Invalid Amount'
|
||||
default: throw new Error("unknown error code" + code)
|
||||
}
|
||||
}
|
||||
|
|
@ -575,7 +575,7 @@ export default class {
|
|||
const e = this.parseTags("e", nostrEvent.tags)
|
||||
const relays = this.parseTags("relays", nostrEvent.tags, { required: true, multiples: true })
|
||||
const amount = this.parseTags("amount", nostrEvent.tags)
|
||||
if (+amount !== amt) {
|
||||
if (amount.length > 0 && +amount[0] !== amt) {
|
||||
throw new Error("amount mismatch")
|
||||
}
|
||||
return { pub: p[0], eventId: e.length > 0 ? e[0] : "", relays, description: event }
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
import fs from 'fs'
|
||||
import Storage from '../storage/index.js'
|
||||
import * as Types from '../../../proto/autogenerated/ts/types.js'
|
||||
import { Application } from '../storage/entity/Application.js'
|
||||
|
|
@ -7,20 +8,27 @@ import { BalanceEvent } from '../storage/entity/BalanceEvent.js'
|
|||
import { ChannelBalanceEvent } from '../storage/entity/ChannelsBalanceEvent.js'
|
||||
import LND from '../lnd/lnd.js'
|
||||
import HtlcTracker from './htlcTracker.js'
|
||||
const maxEvents = 100_000
|
||||
export default class Handler {
|
||||
import { MainSettings } from '../main/settings.js'
|
||||
import { getLogger } from '../helpers/logger.js'
|
||||
import { encodeTLV, usageMetricsToTlv } from '../helpers/tlv.js'
|
||||
import { ChannelCloseSummary_ClosureType } from '../../../proto/lnd/lightning.js'
|
||||
|
||||
|
||||
export default class Handler {
|
||||
|
||||
storage: Storage
|
||||
lnd: LND
|
||||
htlcTracker: HtlcTracker
|
||||
metrics: Types.UsageMetric[] = []
|
||||
logger = getLogger({ component: "metrics" })
|
||||
constructor(storage: Storage, lnd: LND) {
|
||||
this.storage = storage
|
||||
this.lnd = lnd
|
||||
this.htlcTracker = new HtlcTracker(this.storage)
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
async HtlcCb(htlc: HtlcEvent) {
|
||||
await this.htlcTracker.onHtlcEvent(htlc)
|
||||
}
|
||||
|
|
@ -29,7 +37,6 @@ export default class Handler {
|
|||
const providers = await this.storage.liquidityStorage.GetTrackedProviders()
|
||||
const channels = await this.lnd.GetChannelBalance()
|
||||
let providerTotal = 0
|
||||
console.log({ providers })
|
||||
providers.forEach(p => {
|
||||
if (p.provider_type === 'lnPub') {
|
||||
providerTotal += p.latest_balance
|
||||
|
|
@ -62,30 +69,94 @@ export default class Handler {
|
|||
}))
|
||||
}
|
||||
|
||||
AddMetrics(newMetrics: (Types.RequestMetric & { app_id?: string })[]) {
|
||||
const parsed: Types.UsageMetric[] = newMetrics.map(m => ({
|
||||
rpc_name: m.rpcName,
|
||||
batch: m.batch,
|
||||
nostr: m.nostr,
|
||||
batch_size: m.batchSize,
|
||||
parsed_in_nano: Number(m.parse - m.start),
|
||||
auth_in_nano: Number(m.guard - m.parse),
|
||||
validate_in_nano: Number(m.validate - m.guard),
|
||||
handle_in_nano: Number(m.handle - m.validate),
|
||||
success: !m.error,
|
||||
app_id: m.app_id ? m.app_id : "",
|
||||
processed_at_ms: m.startMs
|
||||
}))
|
||||
const len = this.metrics.push(...parsed)
|
||||
if (len > maxEvents) {
|
||||
this.metrics.splice(0, len - maxEvents)
|
||||
}
|
||||
}
|
||||
async GetUsageMetrics(): Promise<Types.UsageMetrics> {
|
||||
return {
|
||||
metrics: this.metrics
|
||||
}
|
||||
return this.storage.metricsEventStorage.LoadLatestMetrics()
|
||||
}
|
||||
|
||||
async GetErrorStats(): Promise<Types.ErrorStats> {
|
||||
const last24h = this.storage.metricsEventStorage.getlast24hCache()
|
||||
const nowUnix = Math.floor(Date.now() / 1000)
|
||||
const stats: Types.ErrorStats = {
|
||||
past24h: { errors: 0, total: 0, from_unix: nowUnix - 60 * 60 * 24 },
|
||||
past6h: { errors: 0, total: 0, from_unix: nowUnix - 60 * 60 * 6 },
|
||||
past1h: { errors: 0, total: 0, from_unix: nowUnix - 60 * 60 },
|
||||
past10m: { errors: 0, total: 0, from_unix: nowUnix - 60 * 10 },
|
||||
past1m: { errors: 0, total: 0, from_unix: nowUnix - 60 },
|
||||
}
|
||||
for (let i = last24h.length - 1; i >= 0; i--) {
|
||||
const e = last24h[i]
|
||||
if (e.ts < stats.past24h.from_unix) {
|
||||
break
|
||||
}
|
||||
|
||||
stats.past24h.total += e.ok + e.fail
|
||||
stats.past24h.errors += e.fail
|
||||
|
||||
if (e.ts >= stats.past6h.from_unix) {
|
||||
stats.past6h.total += e.ok + e.fail
|
||||
stats.past6h.errors += e.fail
|
||||
}
|
||||
|
||||
if (e.ts >= stats.past1h.from_unix) {
|
||||
stats.past1h.total += e.ok + e.fail
|
||||
stats.past1h.errors += e.fail
|
||||
}
|
||||
|
||||
if (e.ts >= stats.past10m.from_unix) {
|
||||
stats.past10m.total += e.ok + e.fail
|
||||
stats.past10m.errors += e.fail
|
||||
}
|
||||
|
||||
if (e.ts >= stats.past1m.from_unix) {
|
||||
stats.past1m.total += e.ok + e.fail
|
||||
stats.past1m.errors += e.fail
|
||||
}
|
||||
}
|
||||
return stats
|
||||
}
|
||||
|
||||
|
||||
|
||||
AddMetrics(newMetrics: (Types.RequestMetric & { app_id?: string })[]) {
|
||||
newMetrics.forEach(m => {
|
||||
const appId = m.app_id || "_root"
|
||||
const um: Types.UsageMetric = {
|
||||
rpc_name: m.rpcName,
|
||||
batch: m.batch,
|
||||
nostr: m.nostr,
|
||||
batch_size: m.batchSize,
|
||||
parsed_in_nano: Number(m.parse - m.start),
|
||||
auth_in_nano: Number(m.guard - m.parse),
|
||||
validate_in_nano: Number(m.validate - m.guard),
|
||||
handle_in_nano: Number(m.handle - m.validate),
|
||||
success: !m.error,
|
||||
app_id: m.app_id ? m.app_id : "",
|
||||
processed_at_ms: m.startMs
|
||||
}
|
||||
const tlv = usageMetricsToTlv(um)
|
||||
this.storage.metricsEventStorage.AddMetricEvent(appId, m.rpcName, encodeTLV(tlv), !m.error)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* addTrackedMetric = (appId: string, method: string, metric: Uint8Array) => {
|
||||
if (!this.metaReady) {
|
||||
throw new Error("meta metrics not ready")
|
||||
}
|
||||
const tlvString = Buffer.from(metric).toString("base64")
|
||||
if (!this.metrics[appId]) {
|
||||
this.metrics[appId] = { app_metrics: {} }
|
||||
}
|
||||
if (!this.metrics[appId].app_metrics[method]) {
|
||||
this.metrics[appId].app_metrics[method] = { base_64_tlvs: [] }
|
||||
}
|
||||
const len = this.metrics[appId].app_metrics[method].base_64_tlvs.push(tlvString)
|
||||
if (len > maxEvents) {
|
||||
this.metrics[appId].app_metrics[method].base_64_tlvs.splice(0, len - maxEvents)
|
||||
}
|
||||
} */
|
||||
|
||||
async GetAppsMetrics(req: Types.AppsMetricsRequest): Promise<Types.AppsMetrics> {
|
||||
const dbApps = await this.storage.applicationStorage.GetApplications()
|
||||
const apps = await Promise.all(dbApps.map(app => this.GetAppMetrics(req, app)))
|
||||
|
|
@ -251,7 +322,7 @@ export default class Handler {
|
|||
externalBalance.push({ x: e.block_height, y: e.external_balance })
|
||||
}
|
||||
})
|
||||
const closed = await Promise.all(closedChannels.map(async c => {
|
||||
const closed = await Promise.all(closedChannels.filter(c => c.closeType !== ChannelCloseSummary_ClosureType.FUNDING_CANCELED).map(async c => {
|
||||
const tx = await this.lnd.GetTx(c.closingTxHash)
|
||||
return { capacity: Number(c.capacity), channel_id: c.chanId, closed_height: c.closeHeight, close_tx_timestamp: Number(tx.timeStamp) }
|
||||
}))
|
||||
|
|
|
|||
|
|
@ -7,6 +7,9 @@ export default (mainHandler: Main): Types.ServerMethods => {
|
|||
GetUsageMetrics: async ({ ctx }) => {
|
||||
return mainHandler.metricsManager.GetUsageMetrics()
|
||||
},
|
||||
GetErrorStats: async ({ ctx }) => {
|
||||
return mainHandler.metricsManager.GetErrorStats()
|
||||
},
|
||||
GetAppsMetrics: async ({ ctx, req }) => {
|
||||
return mainHandler.metricsManager.GetAppsMetrics(req)
|
||||
},
|
||||
|
|
@ -73,7 +76,10 @@ export default (mainHandler: Main): Types.ServerMethods => {
|
|||
if (err != null) throw new Error(err.message)
|
||||
await mainHandler.paymentManager.SetMockInvoiceAsPaid(req)
|
||||
},
|
||||
UserHealth: async () => { },
|
||||
UserHealth: async () => {
|
||||
try { await mainHandler.lnd.Health(); return { downtime_reason: "" } }
|
||||
catch (e: any) { return { downtime_reason: e.message } }
|
||||
},
|
||||
GetUserInfo: ({ ctx }) => mainHandler.appUserManager.GetUserInfo(ctx),
|
||||
UpdateCallbackUrl: async ({ ctx, req }) => {
|
||||
return mainHandler.appUserManager.UpdateCallbackUrl(ctx, req)
|
||||
|
|
@ -323,6 +329,40 @@ export default (mainHandler: Main): Types.ServerMethods => {
|
|||
},
|
||||
RespondToDebit: async ({ ctx, req }) => {
|
||||
return mainHandler.debitManager.RespondToDebit(ctx, req);
|
||||
},
|
||||
AddUserOffer: async ({ ctx, req }) => {
|
||||
const err = Types.OfferConfigValidate(req, {
|
||||
label_CustomCheck: label => label !== '',
|
||||
})
|
||||
if (err != null) throw new Error(err.message)
|
||||
return mainHandler.offerManager.AddUserOffer(ctx, req)
|
||||
},
|
||||
DeleteUserOffer: async ({ ctx, req }) => {
|
||||
const err = Types.OfferIdValidate(req, {
|
||||
offer_id_CustomCheck: id => id !== ''
|
||||
})
|
||||
if (err != null) throw new Error(err.message)
|
||||
return mainHandler.offerManager.DeleteUserOffer(ctx, req)
|
||||
},
|
||||
UpdateUserOffer: async ({ ctx, req }) => {
|
||||
return mainHandler.offerManager.UpdateUserOffer(ctx, req)
|
||||
},
|
||||
GetUserOffers: async ({ ctx }) => {
|
||||
return mainHandler.offerManager.GetUserOffers(ctx)
|
||||
},
|
||||
GetUserOffer: async ({ ctx, req }) => {
|
||||
const err = Types.OfferIdValidate(req, {
|
||||
offer_id_CustomCheck: id => id !== ''
|
||||
})
|
||||
if (err != null) throw new Error(err.message)
|
||||
return mainHandler.offerManager.GetUserOffer(ctx, req)
|
||||
},
|
||||
GetUserOfferInvoices: async ({ ctx, req }) => {
|
||||
const err = Types.GetUserOfferInvoicesReqValidate(req, {
|
||||
offer_id_CustomCheck: id => id !== ''
|
||||
})
|
||||
if (err != null) throw new Error(err.message)
|
||||
return mainHandler.offerManager.GetUserOfferInvoices(ctx, req)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -23,6 +23,7 @@ import { TrackedProvider } from "./entity/TrackedProvider.js"
|
|||
import { InviteToken } from "./entity/InviteToken.js"
|
||||
import { DebitAccess } from "./entity/DebitAccess.js"
|
||||
import { RootOperation } from "./entity/RootOperation.js"
|
||||
import { UserOffer } from "./entity/UserOffer.js"
|
||||
|
||||
|
||||
export type DbSettings = {
|
||||
|
|
@ -63,7 +64,7 @@ export default async (settings: DbSettings, migrations: Function[]): Promise<{ s
|
|||
// logging: true,
|
||||
entities: [User, UserReceivingInvoice, UserReceivingAddress, AddressReceivingTransaction, UserInvoicePayment, UserTransactionPayment,
|
||||
UserBasicAuth, UserEphemeralKey, Product, UserToUserPayment, Application, ApplicationUser, UserToUserPayment, LspOrder, LndNodeInfo, TrackedProvider,
|
||||
InviteToken, DebitAccess
|
||||
InviteToken, DebitAccess, UserOffer
|
||||
],
|
||||
//synchronize: true,
|
||||
migrations
|
||||
|
|
|
|||
37
src/services/storage/entity/UserOffer.ts
Normal file
37
src/services/storage/entity/UserOffer.ts
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
import { Entity, PrimaryGeneratedColumn, Column, ManyToOne, CreateDateColumn, UpdateDateColumn } from "typeorm"
|
||||
import { User } from "./User.js"
|
||||
|
||||
@Entity()
|
||||
export class UserOffer {
|
||||
|
||||
@PrimaryGeneratedColumn()
|
||||
serial_id: number
|
||||
|
||||
@Column()
|
||||
app_user_id: string
|
||||
|
||||
@Column({ unique: true, nullable: false })
|
||||
offer_id: string
|
||||
|
||||
@Column()
|
||||
label: string
|
||||
|
||||
@Column({ default: 0 })
|
||||
price_sats: number
|
||||
|
||||
@Column({ default: "" })
|
||||
callback_url: string
|
||||
|
||||
@Column({
|
||||
nullable: true,
|
||||
type: 'simple-json',
|
||||
default: null
|
||||
})
|
||||
expected_data: Record<string, string> | null
|
||||
|
||||
@CreateDateColumn()
|
||||
created_at: Date
|
||||
|
||||
@UpdateDateColumn()
|
||||
updated_at: Date
|
||||
}
|
||||
|
|
@ -58,6 +58,15 @@ export class UserReceivingInvoice {
|
|||
})
|
||||
zap_info?: ZapInfo
|
||||
|
||||
@Column({
|
||||
nullable: true,
|
||||
type: 'simple-json'
|
||||
})
|
||||
payer_data?: Record<string, string>
|
||||
|
||||
@Column({ default: "" })
|
||||
offer_id?: string
|
||||
|
||||
@Column({
|
||||
nullable: true,
|
||||
})
|
||||
|
|
|
|||
|
|
@ -6,11 +6,13 @@ import ApplicationStorage from './applicationStorage.js'
|
|||
import UserStorage from "./userStorage.js";
|
||||
import PaymentStorage from "./paymentStorage.js";
|
||||
import MetricsStorage from "./metricsStorage.js";
|
||||
import MetricsEventStorage from "./metricsEventStorage.js";
|
||||
import TransactionsQueue, { TX } from "./transactionsQueue.js";
|
||||
import EventsLogManager from "./eventsLog.js";
|
||||
import { LiquidityStorage } from "./liquidityStorage.js";
|
||||
import { StateBundler } from "./stateBundler.js";
|
||||
import DebitStorage from "./debitStorage.js"
|
||||
import OfferStorage from "./offerStorage.js"
|
||||
export type StorageSettings = {
|
||||
dbSettings: DbSettings
|
||||
eventLogPath: string
|
||||
|
|
@ -28,8 +30,10 @@ export default class {
|
|||
userStorage: UserStorage
|
||||
paymentStorage: PaymentStorage
|
||||
metricsStorage: MetricsStorage
|
||||
metricsEventStorage: MetricsEventStorage
|
||||
liquidityStorage: LiquidityStorage
|
||||
debitStorage: DebitStorage
|
||||
offerStorage: OfferStorage
|
||||
eventsLog: EventsLogManager
|
||||
stateBundler: StateBundler
|
||||
constructor(settings: StorageSettings) {
|
||||
|
|
@ -45,8 +49,10 @@ export default class {
|
|||
this.applicationStorage = new ApplicationStorage(this.DB, this.userStorage, this.txQueue)
|
||||
this.paymentStorage = new PaymentStorage(this.DB, this.userStorage, this.txQueue)
|
||||
this.metricsStorage = new MetricsStorage(this.settings)
|
||||
this.metricsEventStorage = new MetricsEventStorage(this.settings)
|
||||
this.liquidityStorage = new LiquidityStorage(this.DB, this.txQueue)
|
||||
this.debitStorage = new DebitStorage(this.DB, this.txQueue)
|
||||
this.offerStorage = new OfferStorage(this.DB, this.txQueue)
|
||||
try { if (this.settings.dataDir) fs.mkdirSync(this.settings.dataDir) } catch (e) { }
|
||||
const executedMetricsMigrations = await this.metricsStorage.Connect(metricsMigrations)
|
||||
return { executedMigrations, executedMetricsMigrations };
|
||||
|
|
|
|||
211
src/services/storage/metricsEventStorage.ts
Normal file
211
src/services/storage/metricsEventStorage.ts
Normal file
|
|
@ -0,0 +1,211 @@
|
|||
import fs from 'fs'
|
||||
import * as Types from '../../../proto/autogenerated/ts/types.js'
|
||||
import { StorageSettings } from "./index.js";
|
||||
import { decodeListTLV, encodeListTLV, encodeTLV, parseTLV } from '../helpers/tlv.js';
|
||||
const chunkSizeBytes = 128 * 1024
|
||||
export default class {
|
||||
settings: StorageSettings
|
||||
metricsPath: string
|
||||
cachePath: string
|
||||
metaReady = false
|
||||
metricsMeta: Record<string, Record<string, { chunks: number[] }>> = {}
|
||||
pendingMetrics: Record<string, Record<string, { tlvs: Uint8Array[] }>> = {}
|
||||
last24hCache: { ts: number, ok: number, fail: number }[] = []
|
||||
lastPersistedMetrics: number = 0
|
||||
lastPersistedCache: number = 0
|
||||
constructor(settings: StorageSettings) {
|
||||
this.settings = settings;
|
||||
this.metricsPath = [settings.dataDir, "metric_events"].join("/")
|
||||
this.cachePath = [settings.dataDir, "metric_cache"].join("/")
|
||||
if (!fs.existsSync(this.cachePath)) {
|
||||
fs.mkdirSync(this.cachePath, { recursive: true });
|
||||
}
|
||||
this.initMetricsMeta()
|
||||
this.loadCache()
|
||||
setInterval(() => {
|
||||
if (Date.now() - this.lastPersistedMetrics > 1000 * 60 * 4) {
|
||||
this.persistMetrics()
|
||||
}
|
||||
if (Date.now() - this.lastPersistedCache > 1000 * 60 * 4) {
|
||||
this.persistCache()
|
||||
}
|
||||
}, 1000 * 60 * 5)
|
||||
process.on('exit', () => {
|
||||
this.persistMetrics()
|
||||
this.persistCache()
|
||||
});
|
||||
|
||||
// catch ctrl+c event and exit normally
|
||||
process.on('SIGINT', () => {
|
||||
console.log('Ctrl-C...');
|
||||
process.exit(2);
|
||||
});
|
||||
|
||||
//catch uncaught exceptions, trace, then exit normally
|
||||
process.on('uncaughtException', (e) => {
|
||||
console.log('Uncaught Exception...');
|
||||
console.log(e.stack);
|
||||
process.exit(99);
|
||||
});
|
||||
}
|
||||
|
||||
getlast24hCache = () => { return this.last24hCache }
|
||||
|
||||
rotateCache = (nowUnix: number) => {
|
||||
const yesterday = nowUnix - 60 * 60 * 24
|
||||
const latest = this.last24hCache.findIndex(c => c.ts >= yesterday)
|
||||
if (latest === -1) {
|
||||
this.last24hCache = []
|
||||
return
|
||||
} else if (latest === 0) {
|
||||
return
|
||||
}
|
||||
this.last24hCache = this.last24hCache.slice(latest)
|
||||
}
|
||||
|
||||
pushToCache = (ok: boolean) => {
|
||||
const now = Math.floor(Date.now() / 1000)
|
||||
this.rotateCache(now)
|
||||
if (this.last24hCache.length === 0) {
|
||||
this.last24hCache.push({ ts: now, ok: ok ? 1 : 0, fail: ok ? 0 : 1 })
|
||||
return
|
||||
}
|
||||
const last = this.last24hCache[this.last24hCache.length - 1]
|
||||
if (last.ts === now) {
|
||||
last.ok += ok ? 1 : 0
|
||||
last.fail += ok ? 0 : 1
|
||||
} else {
|
||||
this.last24hCache.push({ ts: now, ok: ok ? 1 : 0, fail: ok ? 0 : 1 })
|
||||
}
|
||||
}
|
||||
|
||||
persistCache = () => {
|
||||
const last24CachePath = [this.cachePath, "last24hSF.json"].join("/")
|
||||
fs.writeFileSync(last24CachePath, JSON.stringify(this.last24hCache), {})
|
||||
}
|
||||
|
||||
loadCache = () => {
|
||||
const last24CachePath = [this.cachePath, "last24hSF.json"].join("/")
|
||||
if (fs.existsSync(last24CachePath)) {
|
||||
this.last24hCache = JSON.parse(fs.readFileSync(last24CachePath, 'utf-8'))
|
||||
this.rotateCache(Math.floor(Date.now() / 1000))
|
||||
}
|
||||
}
|
||||
|
||||
AddMetricEvent = (appId: string, method: string, metric: Uint8Array, success: boolean) => {
|
||||
if (!this.metaReady) {
|
||||
throw new Error("meta metrics not ready")
|
||||
}
|
||||
if (!this.pendingMetrics[appId]) {
|
||||
this.pendingMetrics[appId] = {}
|
||||
}
|
||||
if (!this.pendingMetrics[appId][method]) {
|
||||
this.pendingMetrics[appId][method] = { tlvs: [] }
|
||||
}
|
||||
this.pendingMetrics[appId][method].tlvs.push(metric)
|
||||
this.pushToCache(success)
|
||||
|
||||
}
|
||||
|
||||
LoadLatestMetrics = async (): Promise<Types.UsageMetrics> => {
|
||||
this.persistMetrics()
|
||||
const metrics: Types.UsageMetrics = { apps: {} }
|
||||
this.foreachMetricMethodFile((app, method, tlvFiles) => {
|
||||
if (tlvFiles.length === 0) { return }
|
||||
const methodPath = [this.metricsPath, app, method].join("/")
|
||||
const latest = tlvFiles[tlvFiles.length - 1]
|
||||
const tlvFile = [methodPath, `${latest}.mtlv`].join("/")
|
||||
const tlv = fs.readFileSync(tlvFile)
|
||||
const decoded = decodeListTLV(parseTLV(tlv))
|
||||
if (!metrics.apps[app]) {
|
||||
metrics.apps[app] = { app_metrics: {} }
|
||||
}
|
||||
metrics.apps[app].app_metrics[method] = {
|
||||
base_64_tlvs: decoded.map(d => Buffer.from(d).toString('base64')),
|
||||
current_chunk: latest,
|
||||
available_chunks: tlvFiles
|
||||
}
|
||||
})
|
||||
return metrics
|
||||
}
|
||||
|
||||
persistMetrics = () => {
|
||||
if (!this.metaReady) {
|
||||
throw new Error("meta metrics not ready")
|
||||
}
|
||||
this.lastPersistedMetrics = Date.now()
|
||||
const tosync = this.pendingMetrics
|
||||
this.pendingMetrics = {}
|
||||
const apps = Object.keys(tosync)
|
||||
apps.map(app => {
|
||||
const appPath = [this.metricsPath, app].join("/")
|
||||
if (!fs.existsSync(appPath)) {
|
||||
fs.mkdirSync(appPath, { recursive: true });
|
||||
}
|
||||
const methods = Object.keys(tosync[app])
|
||||
methods.map(methodName => {
|
||||
const methodPath = [appPath, methodName].join("/")
|
||||
if (!fs.existsSync(methodPath)) {
|
||||
fs.mkdirSync(methodPath, { recursive: true });
|
||||
}
|
||||
const method = tosync[app][methodName]
|
||||
const meta = this.getMetricsMeta(app, methodName)
|
||||
const chunks = meta.chunks.length > 0 ? meta.chunks : [0]
|
||||
const latest = chunks[chunks.length - 1]
|
||||
const tlv = encodeTLV(encodeListTLV(method.tlvs))
|
||||
const tlvFile = [methodPath, `${latest}.mtlv`].join("/")
|
||||
fs.appendFileSync(tlvFile, Buffer.from(tlv))
|
||||
if (fs.lstatSync(tlvFile).size > chunkSizeBytes) {
|
||||
this.updateMetricsMeta(app, methodName, [...chunks, latest + 1])
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
initMetricsMeta = () => {
|
||||
this.foreachMetricMethodFile((app, method, tlvFiles) => {
|
||||
this.updateMetricsMeta(app, method, tlvFiles)
|
||||
})
|
||||
this.metaReady = true
|
||||
}
|
||||
|
||||
updateMetricsMeta = (appId: string, method: string, sortedChunks: number[]) => {
|
||||
if (!this.metricsMeta[appId]) {
|
||||
this.metricsMeta[appId] = {}
|
||||
}
|
||||
this.metricsMeta[appId][method] = { chunks: sortedChunks }
|
||||
}
|
||||
|
||||
getMetricsMeta = (appId: string, method: string) => {
|
||||
if (!this.metricsMeta[appId]) {
|
||||
return { chunks: [] }
|
||||
}
|
||||
return this.metricsMeta[appId][method] || { chunks: [] }
|
||||
}
|
||||
|
||||
foreachMetricMethodFile = (cb: (appId: string, method: string, tlvFiles: number[]) => void) => {
|
||||
if (!fs.existsSync(this.metricsPath)) {
|
||||
fs.mkdirSync(this.metricsPath, { recursive: true });
|
||||
}
|
||||
const apps = fs.readdirSync(this.metricsPath)
|
||||
apps.forEach(appDir => {
|
||||
const appPath = [this.metricsPath, appDir].join("/")
|
||||
if (!fs.lstatSync(appPath).isDirectory()) {
|
||||
return
|
||||
}
|
||||
const methods = fs.readdirSync(appPath)
|
||||
methods.forEach(methodDir => {
|
||||
const methodPath = [appPath, methodDir].join("/")
|
||||
if (!fs.lstatSync(methodPath).isDirectory()) {
|
||||
return
|
||||
}
|
||||
const tlvFiles = fs.readdirSync(methodPath)
|
||||
.filter(f => f.endsWith(".mtlv"))
|
||||
.map(f => +f.slice(0, -".mtlv".length))
|
||||
.filter(n => !isNaN(n))
|
||||
.sort((a, b) => a - b)
|
||||
cb(appDir, methodDir, tlvFiles)
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
26
src/services/storage/migrations/1733502626042-user_offer.ts
Normal file
26
src/services/storage/migrations/1733502626042-user_offer.ts
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
import { MigrationInterface, QueryRunner } from "typeorm";
|
||||
|
||||
export class UserOffer1733502626042 implements MigrationInterface {
|
||||
name = 'UserOffer1733502626042'
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(`CREATE TABLE "user_offer" ("serial_id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "app_user_id" varchar NOT NULL, "offer_id" varchar NOT NULL, "label" varchar NOT NULL, "price_sats" integer NOT NULL DEFAULT (0), "callback_url" varchar NOT NULL DEFAULT (''), "expected_data" text, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "updated_at" datetime NOT NULL DEFAULT (datetime('now')), CONSTRAINT "UQ_478f72095abd8a516d3a309a5c5" UNIQUE ("offer_id"))`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_a131e6b58f084f1340538681b5"`);
|
||||
await queryRunner.query(`CREATE TABLE "temporary_user_receiving_invoice" ("serial_id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "invoice" varchar NOT NULL, "expires_at_unix" integer NOT NULL, "paid_at_unix" integer NOT NULL DEFAULT (0), "internal" boolean NOT NULL DEFAULT (0), "paidByLnd" boolean NOT NULL DEFAULT (0), "callbackUrl" varchar NOT NULL DEFAULT (''), "paid_amount" integer NOT NULL DEFAULT (0), "service_fee" integer NOT NULL DEFAULT (0), "zap_info" text, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "updated_at" datetime NOT NULL DEFAULT (datetime('now')), "userSerialId" integer, "productProductId" varchar, "payerSerialId" integer, "linkedApplicationSerialId" integer, "liquidityProvider" varchar, "payer_data" text, "offer_id" varchar NOT NULL DEFAULT (''), CONSTRAINT "FK_2c0dfb3483f3e5e7e3cdd5dc71f" FOREIGN KEY ("userSerialId") REFERENCES "user" ("serial_id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_5263bde2a519db9ea608b702ec8" FOREIGN KEY ("productProductId") REFERENCES "product" ("product_id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_d4bb1e4c60e8a869f1f43ca2e31" FOREIGN KEY ("payerSerialId") REFERENCES "user" ("serial_id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_714a8b7d4f89f8a802ca181b789" FOREIGN KEY ("linkedApplicationSerialId") REFERENCES "application" ("serial_id") ON DELETE NO ACTION ON UPDATE NO ACTION)`);
|
||||
await queryRunner.query(`INSERT INTO "temporary_user_receiving_invoice"("serial_id", "invoice", "expires_at_unix", "paid_at_unix", "internal", "paidByLnd", "callbackUrl", "paid_amount", "service_fee", "zap_info", "created_at", "updated_at", "userSerialId", "productProductId", "payerSerialId", "linkedApplicationSerialId", "liquidityProvider") SELECT "serial_id", "invoice", "expires_at_unix", "paid_at_unix", "internal", "paidByLnd", "callbackUrl", "paid_amount", "service_fee", "zap_info", "created_at", "updated_at", "userSerialId", "productProductId", "payerSerialId", "linkedApplicationSerialId", "liquidityProvider" FROM "user_receiving_invoice"`);
|
||||
await queryRunner.query(`DROP TABLE "user_receiving_invoice"`);
|
||||
await queryRunner.query(`ALTER TABLE "temporary_user_receiving_invoice" RENAME TO "user_receiving_invoice"`);
|
||||
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_a131e6b58f084f1340538681b5" ON "user_receiving_invoice" ("invoice") `);
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(`DROP INDEX "IDX_a131e6b58f084f1340538681b5"`);
|
||||
await queryRunner.query(`ALTER TABLE "user_receiving_invoice" RENAME TO "temporary_user_receiving_invoice"`);
|
||||
await queryRunner.query(`CREATE TABLE "user_receiving_invoice" ("serial_id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "invoice" varchar NOT NULL, "expires_at_unix" integer NOT NULL, "paid_at_unix" integer NOT NULL DEFAULT (0), "internal" boolean NOT NULL DEFAULT (0), "paidByLnd" boolean NOT NULL DEFAULT (0), "callbackUrl" varchar NOT NULL DEFAULT (''), "paid_amount" integer NOT NULL DEFAULT (0), "service_fee" integer NOT NULL DEFAULT (0), "zap_info" text, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "updated_at" datetime NOT NULL DEFAULT (datetime('now')), "userSerialId" integer, "productProductId" varchar, "payerSerialId" integer, "linkedApplicationSerialId" integer, "liquidityProvider" varchar, CONSTRAINT "FK_2c0dfb3483f3e5e7e3cdd5dc71f" FOREIGN KEY ("userSerialId") REFERENCES "user" ("serial_id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_5263bde2a519db9ea608b702ec8" FOREIGN KEY ("productProductId") REFERENCES "product" ("product_id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_d4bb1e4c60e8a869f1f43ca2e31" FOREIGN KEY ("payerSerialId") REFERENCES "user" ("serial_id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_714a8b7d4f89f8a802ca181b789" FOREIGN KEY ("linkedApplicationSerialId") REFERENCES "application" ("serial_id") ON DELETE NO ACTION ON UPDATE NO ACTION)`);
|
||||
await queryRunner.query(`INSERT INTO "user_receiving_invoice"("serial_id", "invoice", "expires_at_unix", "paid_at_unix", "internal", "paidByLnd", "callbackUrl", "paid_amount", "service_fee", "zap_info", "created_at", "updated_at", "userSerialId", "productProductId", "payerSerialId", "linkedApplicationSerialId", "liquidityProvider") SELECT "serial_id", "invoice", "expires_at_unix", "paid_at_unix", "internal", "paidByLnd", "callbackUrl", "paid_amount", "service_fee", "zap_info", "created_at", "updated_at", "userSerialId", "productProductId", "payerSerialId", "linkedApplicationSerialId", "liquidityProvider" FROM "temporary_user_receiving_invoice"`);
|
||||
await queryRunner.query(`DROP TABLE "temporary_user_receiving_invoice"`);
|
||||
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_a131e6b58f084f1340538681b5" ON "user_receiving_invoice" ("invoice") `);
|
||||
await queryRunner.query(`DROP TABLE "user_offer"`);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -17,7 +17,8 @@ import { DebitAccessFixes1726685229264 } from './1726685229264-debit_access_fixe
|
|||
import { DebitToPub1727105758354 } from './1727105758354-debit_to_pub.js'
|
||||
import { UserCbUrl1727112281043 } from './1727112281043-user_cb_url.js'
|
||||
import { RootOps1732566440447 } from './1732566440447-root_ops.js'
|
||||
const allMigrations = [Initial1703170309875, LspOrder1718387847693, LiquidityProvider1719335699480, LndNodeInfo1720187506189, TrackedProvider1720814323679, CreateInviteTokenTable1721751414878, PaymentIndex1721760297610, DebitAccess1726496225078, DebitAccessFixes1726685229264, DebitToPub1727105758354, UserCbUrl1727112281043]
|
||||
import { UserOffer1733502626042 } from './1733502626042-user_offer.js'
|
||||
const allMigrations = [Initial1703170309875, LspOrder1718387847693, LiquidityProvider1719335699480, LndNodeInfo1720187506189, TrackedProvider1720814323679, CreateInviteTokenTable1721751414878, PaymentIndex1721760297610, DebitAccess1726496225078, DebitAccessFixes1726685229264, DebitToPub1727105758354, UserCbUrl1727112281043, UserOffer1733502626042]
|
||||
const allMetricsMigrations = [LndMetrics1703170330183, ChannelRouting1709316653538, HtlcCount1724266887195, BalanceEvents1724860966825, RootOps1732566440447]
|
||||
export const TypeOrmMigrationRunner = async (log: PubLogger, storageManager: Storage, settings: DbSettings, arg: string | undefined): Promise<boolean> => {
|
||||
if (arg === 'fake_initial_migration') {
|
||||
|
|
|
|||
49
src/services/storage/offerStorage.ts
Normal file
49
src/services/storage/offerStorage.ts
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
import { DataSource, EntityManager } from "typeorm"
|
||||
import crypto from 'crypto';
|
||||
import UserStorage from './userStorage.js';
|
||||
import TransactionsQueue from "./transactionsQueue.js";
|
||||
import { DebitAccess, DebitAccessRules } from "./entity/DebitAccess.js";
|
||||
import { UserOffer } from "./entity/UserOffer.js";
|
||||
export default class {
|
||||
|
||||
|
||||
DB: DataSource | EntityManager
|
||||
txQueue: TransactionsQueue
|
||||
constructor(DB: DataSource | EntityManager, txQueue: TransactionsQueue) {
|
||||
this.DB = DB
|
||||
this.txQueue = txQueue
|
||||
}
|
||||
async AddDefaultUserOffer(appUserId: string): Promise<UserOffer> {
|
||||
const newUserOffer = this.DB.getRepository(UserOffer).create({
|
||||
app_user_id: appUserId,
|
||||
offer_id: appUserId,
|
||||
label: 'Default NIP-69 Offer',
|
||||
})
|
||||
return this.txQueue.PushToQueue<UserOffer>({ exec: async db => db.getRepository(UserOffer).save(newUserOffer), dbTx: false, description: `add default offer for ${appUserId}` })
|
||||
}
|
||||
async AddUserOffer(appUserId: string, req: Partial<UserOffer>): Promise<UserOffer> {
|
||||
const newUserOffer = this.DB.getRepository(UserOffer).create({
|
||||
...req,
|
||||
app_user_id: appUserId,
|
||||
offer_id: crypto.randomBytes(34).toString('hex')
|
||||
})
|
||||
return this.txQueue.PushToQueue<UserOffer>({ exec: async db => db.getRepository(UserOffer).save(newUserOffer), dbTx: false, description: `add offer for ${appUserId}: ${req.label} ` })
|
||||
}
|
||||
|
||||
async DeleteUserOffer(appUserId: string, offerId: string, entityManager = this.DB) {
|
||||
await entityManager.getRepository(UserOffer).delete({ app_user_id: appUserId, offer_id: offerId })
|
||||
}
|
||||
async UpdateUserOffer(app_user_id: string, offerId: string, req: Partial<UserOffer>) {
|
||||
return this.DB.getRepository(UserOffer).update({ app_user_id, offer_id: offerId }, req)
|
||||
}
|
||||
|
||||
async GetUserOffers(app_user_id: string): Promise<UserOffer[]> {
|
||||
return this.DB.getRepository(UserOffer).find({ where: { app_user_id } })
|
||||
}
|
||||
async GetUserOffer(app_user_id: string, offer_id: string): Promise<UserOffer | null> {
|
||||
return this.DB.getRepository(UserOffer).findOne({ where: { app_user_id, offer_id } })
|
||||
}
|
||||
async GetOffer(offer_id: string): Promise<UserOffer | null> {
|
||||
return this.DB.getRepository(UserOffer).findOne({ where: { offer_id } })
|
||||
}
|
||||
}
|
||||
|
|
@ -13,7 +13,7 @@ import { UserToUserPayment } from './entity/UserToUserPayment.js';
|
|||
import { Application } from './entity/Application.js';
|
||||
import TransactionsQueue from "./transactionsQueue.js";
|
||||
import { LoggedEvent } from './eventsLog.js';
|
||||
export type InboundOptionals = { product?: Product, callbackUrl?: string, expiry: number, expectedPayer?: User, linkedApplication?: Application, zapInfo?: ZapInfo }
|
||||
export type InboundOptionals = { product?: Product, callbackUrl?: string, expiry: number, expectedPayer?: User, linkedApplication?: Application, zapInfo?: ZapInfo, offerId?: string, payerData?: Record<string, string> }
|
||||
export const defaultInvoiceExpiry = 60 * 60
|
||||
export default class {
|
||||
DB: DataSource | EntityManager
|
||||
|
|
@ -102,7 +102,9 @@ export default class {
|
|||
payer: options.expectedPayer,
|
||||
linkedApplication: options.linkedApplication,
|
||||
zap_info: options.zapInfo,
|
||||
liquidityProvider: providerDestination
|
||||
liquidityProvider: providerDestination,
|
||||
offer_id: options.offerId,
|
||||
payer_data: options.payerData,
|
||||
})
|
||||
return this.txQueue.PushToQueue<UserReceivingInvoice>({ exec: async db => db.getRepository(UserReceivingInvoice).save(newUserInvoice), dbTx: false, description: `add invoice for ${user.user_id} linked to ${options.linkedApplication?.app_id}: ${invoice} ` })
|
||||
}
|
||||
|
|
@ -452,4 +454,12 @@ export default class {
|
|||
async GetPendingPayments(entityManager = this.DB) {
|
||||
return entityManager.getRepository(UserInvoicePayment).find({ where: { paid_at_unix: 0 } })
|
||||
}
|
||||
|
||||
async GetOfferInvoices(offerId: string, includeUnpaid: boolean, entityManager = this.DB) {
|
||||
const where: { offer_id: string, paid_at_unix?: FindOperator<number> } = { offer_id: offerId }
|
||||
if (!includeUnpaid) {
|
||||
where.paid_at_unix = MoreThan(0)
|
||||
}
|
||||
return entityManager.getRepository(UserReceivingInvoice).find({ where })
|
||||
}
|
||||
}
|
||||
|
|
@ -34,7 +34,7 @@ export class StateBundler {
|
|||
latestReport = Date.now()
|
||||
reportLog = getLogger({ component: 'stateBundlerReport' })
|
||||
constructor() {
|
||||
process.on('exit', () => {
|
||||
/* process.on('exit', () => {
|
||||
this.Report()
|
||||
});
|
||||
|
||||
|
|
@ -49,7 +49,7 @@ export class StateBundler {
|
|||
console.log('Uncaught Exception...');
|
||||
console.log(e.stack);
|
||||
process.exit(99);
|
||||
});
|
||||
}); */
|
||||
}
|
||||
|
||||
increment = (key: string, value: number) => {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue