payment stream + unreachable provider + fess calc fix

This commit is contained in:
boufni95 2025-11-19 15:46:35 +00:00
parent d319c1d4be
commit c8ede119d6
16 changed files with 365 additions and 64 deletions

View file

@ -275,6 +275,11 @@ The nostr server will send back a message response, and inside the body there wi
- input: [PayInvoiceRequest](#PayInvoiceRequest)
- output: [PayInvoiceResponse](#PayInvoiceResponse)
- PayInvoiceStream
- auth type: __User__
- input: [PayInvoiceRequest](#PayInvoiceRequest)
- output: [InvoicePaymentStream](#InvoicePaymentStream)
- PingSubProcesses
- auth type: __Metrics__
- This methods has an __empty__ __request__ body
@ -860,6 +865,13 @@ The nostr server will send back a message response, and inside the body there wi
- input: [PayInvoiceRequest](#PayInvoiceRequest)
- output: [PayInvoiceResponse](#PayInvoiceResponse)
- PayInvoiceStream
- auth type: __User__
- http method: __post__
- http route: __/api/user/invoice/pay/stream__
- input: [PayInvoiceRequest](#PayInvoiceRequest)
- output: [InvoicePaymentStream](#InvoicePaymentStream)
- PingSubProcesses
- auth type: __Metrics__
- http method: __post__
@ -1256,6 +1268,9 @@ The nostr server will send back a message response, and inside the body there wi
- __token__: _string_
- __url__: _string_
### InvoicePaymentStream
- __update__: _[InvoicePaymentStream_update](#InvoicePaymentStream_update)_
### LatestBundleMetricReq
- __limit__: _number_ *this field is optional
@ -1460,12 +1475,14 @@ The nostr server will send back a message response, and inside the body there wi
### PayAppUserInvoiceRequest
- __amount__: _number_
- __debit_npub__: _string_ *this field is optional
- __fee_limit_sats__: _number_ *this field is optional
- __invoice__: _string_
- __user_identifier__: _string_
### PayInvoiceRequest
- __amount__: _number_
- __debit_npub__: _string_ *this field is optional
- __fee_limit_sats__: _number_ *this field is optional
- __invoice__: _string_
### PayInvoiceResponse

View file

@ -121,6 +121,7 @@ type Client struct {
PayAddress func(req PayAddressRequest) (*PayAddressResponse, error)
PayAppUserInvoice func(req PayAppUserInvoiceRequest) (*PayInvoiceResponse, error)
PayInvoice func(req PayInvoiceRequest) (*PayInvoiceResponse, error)
PayInvoiceStream func(req PayInvoiceRequest) (*InvoicePaymentStream, error)
PingSubProcesses func() error
RequestNPubLinkingToken func(req RequestNPubLinkingTokenRequest) (*RequestNPubLinkingTokenResponse, error)
ResetDebit func(req DebitOperation) error
@ -1835,6 +1836,7 @@ func NewClient(params ClientParams) *Client {
}
return &res, nil
},
// server streaming method: PayInvoiceStream not implemented
PingSubProcesses: func() error {
auth, err := params.RetrieveMetricsAuth()
if err != nil {

View file

@ -341,6 +341,9 @@ type HttpCreds struct {
Token string `json:"token"`
Url string `json:"url"`
}
type InvoicePaymentStream struct {
Update *InvoicePaymentStream_update `json:"update"`
}
type LatestBundleMetricReq struct {
Limit int64 `json:"limit"`
}
@ -545,13 +548,15 @@ type PayAddressResponse struct {
type PayAppUserInvoiceRequest struct {
Amount int64 `json:"amount"`
Debit_npub string `json:"debit_npub"`
Fee_limit_sats int64 `json:"fee_limit_sats"`
Invoice string `json:"invoice"`
User_identifier string `json:"user_identifier"`
}
type PayInvoiceRequest struct {
Amount int64 `json:"amount"`
Debit_npub string `json:"debit_npub"`
Invoice string `json:"invoice"`
Amount int64 `json:"amount"`
Debit_npub string `json:"debit_npub"`
Fee_limit_sats int64 `json:"fee_limit_sats"`
Invoice string `json:"invoice"`
}
type PayInvoiceResponse struct {
Amount_paid int64 `json:"amount_paid"`
@ -751,6 +756,18 @@ type DebitRule_rule struct {
Expiration_rule *DebitExpirationRule `json:"expiration_rule"`
Frequency_rule *FrequencyRule `json:"frequency_rule"`
}
type InvoicePaymentStream_update_type string
const (
ACK InvoicePaymentStream_update_type = "ack"
DONE InvoicePaymentStream_update_type = "done"
)
type InvoicePaymentStream_update struct {
Type InvoicePaymentStream_update_type `json:"type"`
Ack *Empty `json:"ack"`
Done *PayInvoiceResponse `json:"done"`
}
type LiveDebitRequest_debit_type string
const (

View file

@ -881,6 +881,7 @@ export default (params: ClientParams) => ({
}
return { status: 'ERROR', reason: 'invalid response' }
},
PayInvoiceStream: async (request: Types.PayInvoiceRequest, cb: (v:ResultError | ({ status: 'OK' }& Types.InvoicePaymentStream)) => void): Promise<void> => { throw new Error('http streams are not supported')},
PingSubProcesses: async (): Promise<ResultError | ({ status: 'OK' })> => {
const auth = await params.retrieveMetricsAuth()
if (auth === null) throw new Error('retrieveMetricsAuth() returned null')

View file

@ -755,6 +755,22 @@ export default (params: NostrClientParams, send: (to:string, message: NostrRequ
}
return { status: 'ERROR', reason: 'invalid response' }
},
PayInvoiceStream: async (request: Types.PayInvoiceRequest, cb: (res:ResultError | ({ status: 'OK' }& Types.InvoicePaymentStream)) => void): Promise<void> => {
const auth = await params.retrieveNostrUserAuth()
if (auth === null) throw new Error('retrieveNostrUserAuth() returned null')
const nostrRequest: NostrRequest = {}
nostrRequest.body = request
subscribe(params.pubDestination, {rpcName:'PayInvoiceStream',authIdentifier:auth, ...nostrRequest }, (data) => {
if (data.status === 'ERROR' && typeof data.reason === 'string') return cb(data)
if (data.status === 'OK') {
const result = data
if(!params.checkResult) return cb({ status: 'OK', ...result })
const error = Types.InvoicePaymentStreamValidate(result)
if (error === null) { return cb({ status: 'OK', ...result }) } else return cb({ status: 'ERROR', reason: error.message })
}
return cb({ status: 'ERROR', reason: 'invalid response' })
})
},
PingSubProcesses: async (): Promise<ResultError | ({ status: 'OK' })> => {
const auth = await params.retrieveNostrMetricsAuth()
if (auth === null) throw new Error('retrieveNostrMetricsAuth() returned null')

View file

@ -1190,6 +1190,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 'PayInvoiceStream':
try {
if (!methods.PayInvoiceStream) throw new Error('method: PayInvoiceStream is not implemented')
const authContext = await opts.NostrUserAuthGuard(req.appId, req.authIdentifier)
stats.guard = process.hrtime.bigint()
authCtx = authContext
const request = req.body
const error = Types.PayInvoiceRequestValidate(request)
stats.validate = process.hrtime.bigint()
if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback)
methods.PayInvoiceStream({rpcName:'PayInvoiceStream', ctx:authContext , req: request ,cb: (response, err) => {
stats.handle = process.hrtime.bigint()
if (err) { logErrorAndReturnResponse(err, err.message, res, logger, { ...info, ...stats, ...authContext }, opts.metricsCallback)} else { res({status: 'OK', ...response});opts.metricsCallback([{ ...info, ...stats, ...authContext }])}
}})
}catch(ex){ const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e }
break
case 'PingSubProcesses':
try {
if (!methods.PingSubProcesses) throw new Error('method: PingSubProcesses is not implemented')

View file

@ -262,6 +262,9 @@ export type PayAppUserInvoice_Output = ResultError | ({ status: 'OK' } & PayInvo
export type PayInvoice_Input = {rpcName:'PayInvoice', req: PayInvoiceRequest}
export type PayInvoice_Output = ResultError | ({ status: 'OK' } & PayInvoiceResponse)
export type PayInvoiceStream_Input = {rpcName:'PayInvoiceStream', req: PayInvoiceRequest, cb:(res: InvoicePaymentStream, err:Error|null)=> void}
export type PayInvoiceStream_Output = ResultError | { status: 'OK' }
export type PingSubProcesses_Input = {rpcName:'PingSubProcesses'}
export type PingSubProcesses_Output = ResultError | { status: 'OK' }
@ -389,6 +392,7 @@ export type ServerMethods = {
PayAddress?: (req: PayAddress_Input & {ctx: UserContext }) => Promise<PayAddressResponse>
PayAppUserInvoice?: (req: PayAppUserInvoice_Input & {ctx: AppContext }) => Promise<PayInvoiceResponse>
PayInvoice?: (req: PayInvoice_Input & {ctx: UserContext }) => Promise<PayInvoiceResponse>
PayInvoiceStream?: (req: PayInvoiceStream_Input & {ctx: UserContext }) => Promise<void>
PingSubProcesses?: (req: PingSubProcesses_Input & {ctx: MetricsContext }) => Promise<void>
RequestNPubLinkingToken?: (req: RequestNPubLinkingToken_Input & {ctx: AppContext }) => Promise<RequestNPubLinkingTokenResponse>
ResetDebit?: (req: ResetDebit_Input & {ctx: UserContext }) => Promise<void>
@ -1980,6 +1984,25 @@ export const HttpCredsValidate = (o?: HttpCreds, opts: HttpCredsOptions = {}, pa
return null
}
export type InvoicePaymentStream = {
update: InvoicePaymentStream_update
}
export const InvoicePaymentStreamOptionalFields: [] = []
export type InvoicePaymentStreamOptions = OptionsBaseMessage & {
checkOptionalsAreSet?: []
update_Options?: InvoicePaymentStream_updateOptions
}
export const InvoicePaymentStreamValidate = (o?: InvoicePaymentStream, opts: InvoicePaymentStreamOptions = {}, path: string = 'InvoicePaymentStream::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 updateErr = InvoicePaymentStream_updateValidate(o.update, opts.update_Options, `${path}.update`)
if (updateErr !== null) return updateErr
return null
}
export type LatestBundleMetricReq = {
limit?: number
}
@ -3192,15 +3215,17 @@ export const PayAddressResponseValidate = (o?: PayAddressResponse, opts: PayAddr
export type PayAppUserInvoiceRequest = {
amount: number
debit_npub?: string
fee_limit_sats?: number
invoice: string
user_identifier: string
}
export type PayAppUserInvoiceRequestOptionalField = 'debit_npub'
export const PayAppUserInvoiceRequestOptionalFields: PayAppUserInvoiceRequestOptionalField[] = ['debit_npub']
export type PayAppUserInvoiceRequestOptionalField = 'debit_npub' | 'fee_limit_sats'
export const PayAppUserInvoiceRequestOptionalFields: PayAppUserInvoiceRequestOptionalField[] = ['debit_npub', 'fee_limit_sats']
export type PayAppUserInvoiceRequestOptions = OptionsBaseMessage & {
checkOptionalsAreSet?: PayAppUserInvoiceRequestOptionalField[]
amount_CustomCheck?: (v: number) => boolean
debit_npub_CustomCheck?: (v?: string) => boolean
fee_limit_sats_CustomCheck?: (v?: number) => boolean
invoice_CustomCheck?: (v: string) => boolean
user_identifier_CustomCheck?: (v: string) => boolean
}
@ -3214,6 +3239,9 @@ export const PayAppUserInvoiceRequestValidate = (o?: PayAppUserInvoiceRequest, o
if ((o.debit_npub || opts.allOptionalsAreSet || opts.checkOptionalsAreSet?.includes('debit_npub')) && typeof o.debit_npub !== 'string') return new Error(`${path}.debit_npub: is not a string`)
if (opts.debit_npub_CustomCheck && !opts.debit_npub_CustomCheck(o.debit_npub)) return new Error(`${path}.debit_npub: custom check failed`)
if ((o.fee_limit_sats || opts.allOptionalsAreSet || opts.checkOptionalsAreSet?.includes('fee_limit_sats')) && typeof o.fee_limit_sats !== 'number') return new Error(`${path}.fee_limit_sats: is not a number`)
if (opts.fee_limit_sats_CustomCheck && !opts.fee_limit_sats_CustomCheck(o.fee_limit_sats)) return new Error(`${path}.fee_limit_sats: custom check failed`)
if (typeof o.invoice !== 'string') return new Error(`${path}.invoice: is not a string`)
if (opts.invoice_CustomCheck && !opts.invoice_CustomCheck(o.invoice)) return new Error(`${path}.invoice: custom check failed`)
@ -3226,14 +3254,16 @@ export const PayAppUserInvoiceRequestValidate = (o?: PayAppUserInvoiceRequest, o
export type PayInvoiceRequest = {
amount: number
debit_npub?: string
fee_limit_sats?: number
invoice: string
}
export type PayInvoiceRequestOptionalField = 'debit_npub'
export const PayInvoiceRequestOptionalFields: PayInvoiceRequestOptionalField[] = ['debit_npub']
export type PayInvoiceRequestOptionalField = 'debit_npub' | 'fee_limit_sats'
export const PayInvoiceRequestOptionalFields: PayInvoiceRequestOptionalField[] = ['debit_npub', 'fee_limit_sats']
export type PayInvoiceRequestOptions = OptionsBaseMessage & {
checkOptionalsAreSet?: PayInvoiceRequestOptionalField[]
amount_CustomCheck?: (v: number) => boolean
debit_npub_CustomCheck?: (v?: string) => boolean
fee_limit_sats_CustomCheck?: (v?: number) => boolean
invoice_CustomCheck?: (v: string) => boolean
}
export const PayInvoiceRequestValidate = (o?: PayInvoiceRequest, opts: PayInvoiceRequestOptions = {}, path: string = 'PayInvoiceRequest::root.'): Error | null => {
@ -3246,6 +3276,9 @@ export const PayInvoiceRequestValidate = (o?: PayInvoiceRequest, opts: PayInvoic
if ((o.debit_npub || opts.allOptionalsAreSet || opts.checkOptionalsAreSet?.includes('debit_npub')) && typeof o.debit_npub !== 'string') return new Error(`${path}.debit_npub: is not a string`)
if (opts.debit_npub_CustomCheck && !opts.debit_npub_CustomCheck(o.debit_npub)) return new Error(`${path}.debit_npub: custom check failed`)
if ((o.fee_limit_sats || opts.allOptionalsAreSet || opts.checkOptionalsAreSet?.includes('fee_limit_sats')) && typeof o.fee_limit_sats !== 'number') return new Error(`${path}.fee_limit_sats: is not a number`)
if (opts.fee_limit_sats_CustomCheck && !opts.fee_limit_sats_CustomCheck(o.fee_limit_sats)) return new Error(`${path}.fee_limit_sats: custom check failed`)
if (typeof o.invoice !== 'string') return new Error(`${path}.invoice: is not a string`)
if (opts.invoice_CustomCheck && !opts.invoice_CustomCheck(o.invoice)) return new Error(`${path}.invoice: custom check failed`)
@ -4322,6 +4355,43 @@ export const DebitRule_ruleValidate = (o?: DebitRule_rule, opts:DebitRule_ruleOp
if (frequency_ruleErr !== null) return frequency_ruleErr
break
default:
return new Error(path + ': unknown type '+ stringType)
}
return null
}
export enum InvoicePaymentStream_update_type {
ACK = 'ack',
DONE = 'done',
}
export const enumCheckInvoicePaymentStream_update_type = (e?: InvoicePaymentStream_update_type): boolean => {
for (const v in InvoicePaymentStream_update_type) if (e === v) return true
return false
}
export type InvoicePaymentStream_update =
{type:InvoicePaymentStream_update_type.ACK, ack:Empty}|
{type:InvoicePaymentStream_update_type.DONE, done:PayInvoiceResponse}
export type InvoicePaymentStream_updateOptions = {
ack_Options?: EmptyOptions
done_Options?: PayInvoiceResponseOptions
}
export const InvoicePaymentStream_updateValidate = (o?: InvoicePaymentStream_update, opts:InvoicePaymentStream_updateOptions = {}, path: string = 'InvoicePaymentStream_update::root.'): Error | null => {
if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null')
const stringType: string = o.type
switch (o.type) {
case InvoicePaymentStream_update_type.ACK:
const ackErr = EmptyValidate(o.ack, opts.ack_Options, `${path}.ack`)
if (ackErr !== null) return ackErr
break
case InvoicePaymentStream_update_type.DONE:
const doneErr = PayInvoiceResponseValidate(o.done, opts.done_Options, `${path}.done`)
if (doneErr !== null) return doneErr
break
default:
return new Error(path + ': unknown type '+ stringType)

View file

@ -517,6 +517,13 @@ service LightningPub {
option (nostr) = true;
}
rpc PayInvoiceStream(structs.PayInvoiceRequest) returns (stream structs.InvoicePaymentStream){
option (auth_type) = "User";
option (http_method) = "post";
option (http_route) = "/api/user/invoice/pay/stream";
option (nostr) = true;
}
rpc GetPaymentState(structs.GetPaymentStateRequest) returns (structs.PaymentState){
option (auth_type) = "User";
option (http_method) = "post";

View file

@ -390,6 +390,7 @@ message PayAppUserInvoiceRequest {
string invoice = 2;
int64 amount = 3;
optional string debit_npub = 4;
optional int64 fee_limit_sats = 5;
}
message SendAppUserToAppUserPaymentRequest {
@ -466,6 +467,7 @@ message PayInvoiceRequest{
string invoice = 1;
int64 amount = 2;
optional string debit_npub = 3;
optional int64 fee_limit_sats = 4;
}
message PayInvoiceResponse{
@ -476,6 +478,13 @@ message PayInvoiceResponse{
int64 network_fee = 5;
}
message InvoicePaymentStream {
oneof update {
Empty ack = 1;
PayInvoiceResponse done = 2;
}
}
message GetPaymentStateRequest{
string invoice = 1;