• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

cameri / nostream / 24342667594

13 Apr 2026 12:12PM UTC coverage: 42.555% (-13.0%) from 55.529%
24342667594

Pull #468

github

web-flow
Merge 4fd541f37 into 1410824d2
Pull Request #468: Phase3: UI Implementation for Dashboard

424 of 1204 branches covered (35.22%)

Branch coverage included in aggregate %.

164 of 540 new or added lines in 14 files covered. (30.37%)

373 existing lines in 23 files now uncovered.

1385 of 3047 relevant lines covered (45.45%)

7.7 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

15.69
/src/controllers/callbacks/nodeless-callback-controller.ts
1
import { always, applySpec, ifElse, is, path, prop, propEq, propSatisfies } from 'ramda'
2✔
2
import { Request, Response } from 'express'
3

4
import { Invoice, InvoiceStatus } from '../../@types/invoice'
2✔
5
import { createLogger } from '../../factories/logger-factory'
2✔
6
import { createSettings } from '../../factories/settings-factory'
2✔
7
import { fromNodelessInvoice } from '../../utils/transform'
2✔
8
import { hmacSha256 } from '../../utils/secret'
2✔
9
import { IController } from '../../@types/controllers'
10
import { IPaymentsService } from '../../@types/services'
11

12
const debug = createLogger('nodeless-callback-controller')
2✔
13

14
export class NodelessCallbackController implements IController {
2✔
15
  public constructor(
UNCOV
16
    private readonly paymentsService: IPaymentsService,
×
17
  ) {}
18

19
  // TODO: Validate
20
  public async handleRequest(
21
    request: Request,
22
    response: Response,
23
  ) {
UNCOV
24
    debug('callback request headers: %o', request.headers)
×
25
    debug('callback request body: %O', request.body)
×
26

UNCOV
27
    const settings = createSettings()
×
28
    const paymentProcessor = settings.payments?.processor
×
29

30
    const expected = hmacSha256(process.env.NODELESS_WEBHOOK_SECRET, (request as any).rawBody).toString('hex')
×
31
    const actual = request.headers['nodeless-signature']
×
32

UNCOV
33
    if (expected !== actual) {
×
UNCOV
34
      console.error('nodeless callback request rejected: signature mismatch:', { expected, actual })
×
35
      response
×
36
        .status(403)
37
        .send('Forbidden')
38
      return
×
39
    }
40

41
    if (paymentProcessor !== 'nodeless') {
×
42
      debug('denied request from %s to /callbacks/nodeless which is not the current payment processor')
×
UNCOV
43
      response
×
44
        .status(403)
45
        .send('Forbidden')
46
      return
×
47
    }
48

49
    const nodelessInvoice = applySpec({
×
50
      id: prop('uuid'),
51
      status: prop('status'),
52
      satsAmount: prop('amount'),
53
      metadata: prop('metadata'),
54
      paidAt: ifElse(
55
        propEq('status', 'paid'),
56
        always(new Date().toISOString()),
57
        always(null),
58
      ),
59
      createdAt: ifElse(
60
        propSatisfies(is(String), 'createdAt'),
61
        prop('createdAt'),
62
        path(['metadata', 'createdAt']),
63
      ),
64
    })(request.body)
65

UNCOV
66
    debug('nodeless invoice: %O', nodelessInvoice)
×
67

UNCOV
68
    const invoice = fromNodelessInvoice(nodelessInvoice)
×
69

UNCOV
70
    debug('invoice: %O', invoice)
×
71

72
    let updatedInvoice: Invoice
UNCOV
73
    try {
×
UNCOV
74
      updatedInvoice = await this.paymentsService.updateInvoiceStatus(invoice)
×
UNCOV
75
      debug('updated invoice: %O', updatedInvoice)
×
76
    } catch (error) {
77
      console.error(`Unable to persist invoice ${invoice.id}`, error)
×
78

79
      throw error
×
80
    }
81

UNCOV
82
    if (
×
83
      updatedInvoice.status !== InvoiceStatus.COMPLETED
×
84
      && !updatedInvoice.confirmedAt
85
    ) {
86
      response
×
87
        .status(200)
88
        .send()
89

90
      return
×
91
    }
92

93
    invoice.amountPaid = invoice.amountRequested
×
UNCOV
94
    updatedInvoice.amountPaid = invoice.amountRequested
×
95

UNCOV
96
    try {
×
97
      await this.paymentsService.confirmInvoice(invoice)
×
UNCOV
98
      await this.paymentsService.sendInvoiceUpdateNotification(updatedInvoice)
×
99
    } catch (error) {
UNCOV
100
      console.error(`Unable to confirm invoice ${invoice.id}`, error)
×
101

UNCOV
102
      throw error
×
103
    }
104

105
    response
×
106
      .status(200)
107
      .setHeader('content-type', 'application/json; charset=utf8')
108
      .send('{"status":"ok"}')
109
  }
110
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc