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

supabase / storage / 28793654629

06 Jul 2026 01:05PM UTC coverage: 48.793% (-30.2%) from 79.041%
28793654629

Pull #1206

github

web-flow
Merge 056d0b5f9 into d54b900bf
Pull Request #1206: fix: leak of request into pools

3210 of 7101 branches covered (45.2%)

Branch coverage included in aggregate %.

2 of 2 new or added lines in 2 files covered. (100.0%)

3858 existing lines in 164 files now uncovered.

6208 of 12201 relevant lines covered (50.88%)

63.5 hits per line

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

76.77
/src/http/plugins/db.ts
1
import { createSingleFlightByKey } from '@internal/concurrency'
2
import {
3
  getPostgresConnection,
4
  getServiceKeyUser,
5
  getTenantConfig,
6
  PgTenantConnection,
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: PgTenantConnection
24
    latestMigration?: keyof typeof DBMigration
25
  }
26
}
27

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

31
const migrationSingleFlight = createSingleFlightByKey<void>()
16✔
32

33
export const db = fastifyPlugin(
16✔
34
  async function db(fastify) {
35
    fastify.register(migrations)
3✔
36

37
    fastify.decorateRequest('db')
3✔
38

39
    fastify.addHook('preHandler', async (request) => {
3✔
40
      const adminUser = await getServiceKeyUser(request.tenantId)
3✔
41
      const userPayload = request.jwtPayload
3✔
42

43
      if (!userPayload) {
3!
44
        throw ERRORS.AccessDenied('JWT payload is missing')
×
45
      }
46

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

61
      // Connect abort signal to DB connection for query cancellation
62
      if (databaseEnableQueryCancellation && request.signals) {
3✔
63
        request.db.setAbortSignal(request.signals.disconnect.signal)
1✔
64
      }
65
    })
66

67
    fastify.addHook('onSend', async (request, reply, payload) => {
3✔
68
      disposeRequestConnections(request)
3✔
69
      return payload
3✔
70
    })
71

72
    fastify.addHook('onTimeout', async (request) => {
3✔
73
      disposeRequestConnections(request)
×
74
    })
75

76
    fastify.addHook('onRequestAbort', async (request) => {
3✔
77
      disposeRequestConnections(request)
×
78
    })
79
  },
80
  { name: 'db-init' }
81
)
82

83
interface DbSuperUserPluginOptions {
84
  disableHostCheck?: boolean
85
}
86

87
export const dbSuperUser = fastifyPlugin<DbSuperUserPluginOptions>(
16✔
88
  async function dbSuperUser(fastify, opts) {
89
    fastify.register(migrations)
15✔
90
    fastify.decorateRequest('db')
15✔
91

92
    fastify.addHook('preHandler', async (request) => {
15✔
93
      const adminUser = await getServiceKeyUser(request.tenantId)
15✔
94

95
      request.db = await getPostgresConnection({
15✔
96
        user: adminUser,
97
        superUser: adminUser,
98
        tenantId: request.tenantId,
99
        host: request.headers['x-forwarded-host'] as string,
100
        path: request.url,
101
        method: request.method,
102
        headers: request.headers,
103
        disableHostCheck: opts.disableHostCheck,
UNCOV
104
        operation: () => request.operation?.type,
×
105
      })
106

107
      // Connect abort signal to DB connection for query cancellation
108
      if (databaseEnableQueryCancellation && request.signals) {
15✔
109
        request.db.setAbortSignal(request.signals.disconnect.signal)
1✔
110
      }
111
    })
112

113
    fastify.addHook('onSend', async (request, reply, payload) => {
15✔
114
      disposeRequestConnections(request)
17✔
115
      return payload
17✔
116
    })
117

118
    fastify.addHook('onTimeout', async (request) => {
15✔
119
      disposeRequestConnections(request)
×
120
    })
121

122
    fastify.addHook('onRequestAbort', async (request) => {
15✔
UNCOV
123
      disposeRequestConnections(request)
×
124
    })
125
  },
126
  { name: 'db-superuser-init' }
127
)
128

129
function disposeRequestConnections(request: {
130
  db?: PgTenantConnection
131
  log: Parameters<typeof logSchema.error>[0]
132
  tenantId: string
133
  id: string
134
  sbReqId?: string
135
}) {
136
  request.db?.dispose().catch((e) => {
20✔
137
    logSchema.error(request.log, 'Error disposing db connection', {
×
138
      type: 'db-connection',
139
      tenantId: request.tenantId,
140
      project: request.tenantId,
141
      reqId: request.id,
142
      sbReqId: request.sbReqId,
143
      error: e,
144
    })
145
  })
146
}
147

148
/**
149
 * Handle database migration for multitenant applications when a request is made
150
 */
151
export const migrations = fastifyPlugin(
16✔
152
  async function migrations(fastify) {
153
    fastify.addHook('preHandler', async (req) => {
18✔
154
      if (isMultitenant) {
20✔
155
        const { migrationVersion } = await getTenantConfig(req.tenantId)
13✔
156
        req.latestMigration = migrationVersion
13✔
157
        return
13✔
158
      }
159

160
      req.latestMigration = await lastLocalMigrationName()
7✔
161
    })
162

163
    if (dbMigrationStrategy === MultitenantMigrationStrategy.ON_REQUEST) {
18✔
164
      fastify.addHook('preHandler', async (request) => {
11✔
165
        // migrations are handled via async migrations
166
        if (!isMultitenant) {
13!
UNCOV
167
          return
×
168
        }
169

170
        const tenant = await getTenantConfig(request.tenantId)
13✔
171
        if (tenant.syncMigrationsDone) {
13✔
172
          return
3✔
173
        }
174

175
        await migrationSingleFlight(request.tenantId, async () => {
10✔
176
          if (await areMigrationsUpToDate(request.tenantId)) {
7✔
177
            tenant.syncMigrationsDone = true
1✔
178
            return
1✔
179
          }
180

181
          await runMigrationsOnTenant({
6✔
182
            databaseUrl: tenant.databaseUrl,
183
            tenantId: request.tenantId,
184
            upToMigration: dbMigrationFreezeAt,
185
          })
186
          await updateTenantMigrationsState(request.tenantId)
5✔
187
          tenant.syncMigrationsDone = true
5✔
188
        })
189
      })
190
    }
191

192
    if (dbMigrationStrategy === MultitenantMigrationStrategy.PROGRESSIVE) {
18✔
193
      fastify.addHook('preHandler', async (request) => {
7✔
194
        if (!isMultitenant) {
7!
195
          return
7✔
196
        }
197

198
        const tenant = await getTenantConfig(request.tenantId)
×
199
        if (tenant.syncMigrationsDone) {
×
200
          return
×
201
        }
202

203
        // migrations are up to date
204
        if (await areMigrationsUpToDate(request.tenantId)) {
×
205
          tenant.syncMigrationsDone = true
×
206
          return
×
207
        }
208

209
        progressiveMigrations.addTenant(request.tenantId)
×
210
      })
211
    }
212
  },
213
  { name: 'db-migrations' }
214
)
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