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

supabase / storage / 24849848918

23 Apr 2026 05:41PM UTC coverage: 32.29% (-39.0%) from 71.255%
24849848918

Pull #1046

github

web-flow
Merge a19e2e1fd into 82d3f6383
Pull Request #1046: refactor: drop axios from tests and webhooks

1530 of 5420 branches covered (28.23%)

Branch coverage included in aggregate %.

4 of 20 new or added lines in 1 file covered. (20.0%)

3875 existing lines in 165 files now uncovered.

3317 of 9591 relevant lines covered (34.58%)

10.24 hits per line

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

13.93
/src/http/plugins/db.ts
1
import { createMutexByKey } from '@internal/concurrency'
2
import {
3
  getPostgresConnection,
4
  getServiceKeyUser,
5
  getTenantConfig,
6
  TenantConnection,
7
} from '@internal/database'
8
import {
9
  areMigrationsUpToDate,
10
  DBMigration,
11
  lastLocalMigrationName,
12
  progressiveMigrations,
13
  runMigrationsOnTenant,
14
  updateTenantMigrationsState,
15
} from '@internal/database/migrations'
16
import { ERRORS } from '@internal/errors'
17
import { logSchema } from '@internal/monitoring'
18
import fastifyPlugin from 'fastify-plugin'
19
import { getConfig, MultitenantMigrationStrategy } from '../../config'
20

21
declare module 'fastify' {
22
  interface FastifyRequest {
23
    db: TenantConnection
24
    latestMigration?: keyof typeof DBMigration
25
  }
26
}
27

28
const { databaseEnableQueryCancellation, dbMigrationStrategy, isMultitenant, dbMigrationFreezeAt } =
3✔
29
  getConfig()
30

31
export const db = fastifyPlugin(
3✔
32
  async function db(fastify) {
UNCOV
33
    fastify.register(migrations)
×
34

UNCOV
35
    fastify.decorateRequest('db')
×
36

UNCOV
37
    fastify.addHook('preHandler', async (request) => {
×
UNCOV
38
      const adminUser = await getServiceKeyUser(request.tenantId)
×
UNCOV
39
      const userPayload = request.jwtPayload
×
40

UNCOV
41
      if (!userPayload) {
×
42
        throw ERRORS.AccessDenied('JWT payload is missing')
×
43
      }
44

UNCOV
45
      request.db = await getPostgresConnection({
×
46
        user: {
47
          payload: userPayload,
48
          jwt: request.jwt,
49
        },
50
        superUser: adminUser,
51
        tenantId: request.tenantId,
52
        host: request.headers['x-forwarded-host'] as string,
53
        headers: request.headers,
54
        path: request.url,
55
        method: request.method,
UNCOV
56
        operation: () => request.operation?.type,
×
57
      })
58

59
      // Connect abort signal to DB connection for query cancellation
UNCOV
60
      if (request.signals?.disconnect?.signal && databaseEnableQueryCancellation) {
×
61
        request.db.setAbortSignal(request.signals.disconnect.signal)
×
62
      }
63
    })
64

UNCOV
65
    fastify.addHook('onSend', async (request, reply, payload) => {
×
UNCOV
66
      if (request.db) {
×
UNCOV
67
        request.db.dispose().catch((e) => {
×
68
          logSchema.error(request.log, 'Error disposing db connection', {
×
69
            type: 'db-connection',
70
            error: e,
71
            sbReqId: request.sbReqId,
72
          })
73
        })
74
      }
UNCOV
75
      return payload
×
76
    })
77

UNCOV
78
    fastify.addHook('onTimeout', async (request) => {
×
79
      if (request.db) {
×
80
        request.db.dispose().catch((e) => {
×
81
          logSchema.error(request.log, 'Error disposing db connection', {
×
82
            type: 'db-connection',
83
            error: e,
84
            sbReqId: request.sbReqId,
85
          })
86
        })
87
      }
88
    })
89

UNCOV
90
    fastify.addHook('onRequestAbort', async (request) => {
×
UNCOV
91
      if (request.db) {
×
UNCOV
92
        request.db.dispose().catch((e) => {
×
93
          logSchema.error(request.log, 'Error disposing db connection', {
×
94
            type: 'db-connection',
95
            error: e,
96
            sbReqId: request.sbReqId,
97
          })
98
        })
99
      }
100
    })
101
  },
102
  { name: 'db-init' }
103
)
104

105
interface DbSuperUserPluginOptions {
106
  disableHostCheck?: boolean
107
  maxConnections?: number
108
}
109

110
export const dbSuperUser = fastifyPlugin<DbSuperUserPluginOptions>(
3✔
111
  async function dbSuperUser(fastify, opts) {
112
    fastify.register(migrations)
4✔
113
    fastify.decorateRequest('db')
4✔
114

115
    fastify.addHook('preHandler', async (request) => {
4✔
UNCOV
116
      const adminUser = await getServiceKeyUser(request.tenantId)
×
117

UNCOV
118
      request.db = await getPostgresConnection({
×
119
        user: adminUser,
120
        superUser: adminUser,
121
        tenantId: request.tenantId,
122
        host: request.headers['x-forwarded-host'] as string,
123
        path: request.url,
124
        method: request.method,
125
        headers: request.headers,
126
        disableHostCheck: opts.disableHostCheck,
127
        maxConnections: opts.maxConnections,
UNCOV
128
        operation: () => request.operation?.type,
×
129
      })
130

131
      // Connect abort signal to DB connection for query cancellation
UNCOV
132
      if (request.signals?.disconnect?.signal && databaseEnableQueryCancellation) {
×
133
        request.db.setAbortSignal(request.signals.disconnect.signal)
×
134
      }
135
    })
136

137
    fastify.addHook('onSend', async (request, reply, payload) => {
4✔
UNCOV
138
      if (request.db) {
×
UNCOV
139
        request.db.dispose().catch((e) => {
×
140
          logSchema.error(request.log, 'Error disposing db connection', {
×
141
            type: 'db-connection',
142
            error: e,
143
            sbReqId: request.sbReqId,
144
          })
145
        })
146
      }
147

UNCOV
148
      return payload
×
149
    })
150

151
    fastify.addHook('onTimeout', async (request) => {
4✔
152
      if (request.db) {
×
153
        request.db.dispose().catch((e) => {
×
154
          logSchema.error(request.log, 'Error disposing db connection', {
×
155
            type: 'db-connection',
156
            error: e,
157
            sbReqId: request.sbReqId,
158
          })
159
        })
160
      }
161
    })
162

163
    fastify.addHook('onRequestAbort', async (request) => {
4✔
164
      if (request.db) {
×
165
        request.db.dispose().catch((e) => {
×
166
          logSchema.error(request.log, 'Error disposing db connection', {
×
167
            type: 'db-connection',
168
            error: e,
169
            sbReqId: request.sbReqId,
170
          })
171
        })
172
      }
173
    })
174
  },
175
  { name: 'db-superuser-init' }
176
)
177

178
/**
179
 * Handle database migration for multitenant applications when a request is made
180
 */
181
export const migrations = fastifyPlugin(
3✔
182
  async function migrations(fastify) {
183
    fastify.addHook('preHandler', async (req) => {
4✔
UNCOV
184
      if (isMultitenant) {
×
UNCOV
185
        const { migrationVersion } = await getTenantConfig(req.tenantId)
×
UNCOV
186
        req.latestMigration = migrationVersion
×
UNCOV
187
        return
×
188
      }
189

UNCOV
190
      req.latestMigration = await lastLocalMigrationName()
×
191
    })
192

193
    if (dbMigrationStrategy === MultitenantMigrationStrategy.ON_REQUEST) {
4!
194
      const migrationsMutex = createMutexByKey<void>()
4✔
195

196
      fastify.addHook('preHandler', async (request) => {
4✔
197
        // migrations are handled via async migrations
UNCOV
198
        if (!isMultitenant) {
×
UNCOV
199
          return
×
200
        }
201

UNCOV
202
        const tenant = await getTenantConfig(request.tenantId)
×
UNCOV
203
        const migrationsUpToDate = await areMigrationsUpToDate(request.tenantId)
×
204

UNCOV
205
        if (tenant.syncMigrationsDone || migrationsUpToDate) {
×
206
          return
×
207
        }
208

UNCOV
209
        await migrationsMutex(request.tenantId, async () => {
×
UNCOV
210
          const tenant = await getTenantConfig(request.tenantId)
×
211

UNCOV
212
          if (tenant.syncMigrationsDone) {
×
213
            return
×
214
          }
215

UNCOV
216
          await runMigrationsOnTenant({
×
217
            databaseUrl: tenant.databaseUrl,
218
            tenantId: request.tenantId,
219
            upToMigration: dbMigrationFreezeAt,
220
          })
UNCOV
221
          await updateTenantMigrationsState(request.tenantId)
×
UNCOV
222
          tenant.syncMigrationsDone = true
×
223
        })
224
      })
225
    }
226

227
    if (dbMigrationStrategy === MultitenantMigrationStrategy.PROGRESSIVE) {
4!
228
      fastify.addHook('preHandler', async (request) => {
×
229
        if (!isMultitenant) {
×
230
          return
×
231
        }
232

233
        const tenant = await getTenantConfig(request.tenantId)
×
234
        const migrationsUpToDate = await areMigrationsUpToDate(request.tenantId)
×
235

236
        // migrations are up to date
237
        if (tenant.syncMigrationsDone || migrationsUpToDate) {
×
238
          return
×
239
        }
240

241
        progressiveMigrations.addTenant(request.tenantId)
×
242
      })
243
    }
244
  },
245
  { name: 'db-migrations' }
246
)
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