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

supabase / storage / 25853816131

14 May 2026 09:56AM UTC coverage: 75.016% (-0.08%) from 75.097%
25853816131

Pull #1094

github

web-flow
Merge 294fdfcd0 into a1c63fd36
Pull Request #1094: feat: embedded vector store

4187 of 6177 branches covered (67.78%)

Branch coverage included in aggregate %.

223 of 277 new or added lines in 6 files covered. (80.51%)

82 existing lines in 1 file now uncovered.

8379 of 10574 relevant lines covered (79.24%)

405.08 hits per line

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

59.68
/src/http/plugins/vector.ts
1
import { getTenantConfig, multitenantKnex } from '@internal/database'
2
import { deriveVectorDatabaseUrl } from '@internal/database/migrations'
3
import { ERRORS } from '@internal/errors'
4
import {
5
  BucketScopedSingleShard,
6
  KnexShardStoreFactory,
7
  ShardCatalog,
8
  Sharder,
9
  SingleShard,
10
} from '@internal/sharding'
11
import {
12
  createS3VectorClient,
13
  KnexVectorMetadataDB,
14
  PgVectorStore,
15
  S3Vector,
16
  VectorStore,
17
  VectorStoreManager,
18
} from '@storage/protocols/vector'
19
import { FastifyInstance } from 'fastify'
20
import fastifyPlugin from 'fastify-plugin'
21
import Knex from 'knex'
22
import { getConfig } from '../../config'
23

24
declare module 'fastify' {
25
  interface FastifyRequest {
26
    s3Vector: VectorStoreManager
27
  }
28
}
29

30
export const s3vector = fastifyPlugin(async function (fastify: FastifyInstance) {
28✔
31
  const config = getConfig()
270✔
32
  const {
33
    vectorBucketProvider,
34
    vectorDatabaseURL,
35
    vectorS3Buckets,
36
    isMultitenant,
37
    databaseApplicationName,
38
  } = config
270✔
39

40
  // S3 mode: build a singleton client+adapter at boot.
41
  let s3Adapter: S3Vector | undefined
42
  if (vectorBucketProvider === 's3' && vectorS3Buckets.length > 0) {
270✔
43
    s3Adapter = new S3Vector(createS3VectorClient())
269✔
44
  }
45

46
  // pgvector + single-tenant: VECTOR_DATABASE_URL is the maintenance URL the
47
  // migration runner used to CREATE DATABASE; the runtime pool targets the
48
  // derived `storage_vectors` database on the same server.
49
  let stPgVectorAdapter: PgVectorStore | undefined
50
  if (vectorBucketProvider === 'pgvector' && !isMultitenant && vectorDatabaseURL) {
270!
NEW
51
    const vectorKnex = Knex({
×
52
      client: 'pg',
53
      connection: {
54
        connectionString: deriveVectorDatabaseUrl(vectorDatabaseURL),
55
        application_name: databaseApplicationName,
56
      },
57
      pool: { min: 0, max: 10 },
58
    })
NEW
59
    stPgVectorAdapter = new PgVectorStore(vectorKnex)
×
NEW
60
    fastify.addHook('onClose', async () => {
×
NEW
61
      await vectorKnex.destroy()
×
62
    })
63
  }
64

65
  const featureEnabled =
66
    (vectorBucketProvider === 's3' && Boolean(s3Adapter)) ||
270!
67
    (vectorBucketProvider === 'pgvector' && (isMultitenant || Boolean(stPgVectorAdapter)))
68

69
  fastify.addHook('preHandler', async (req) => {
270✔
70
    if (!featureEnabled) {
118✔
71
      throw ERRORS.FeatureNotEnabled('vector', 'Vector service not configured')
1✔
72
    }
73

74
    const { vectorMaxBucketsCount, vectorMaxIndexesCount } = config
117✔
75

76
    let maxBucketCount = vectorMaxBucketsCount
117✔
77
    let maxIndexCount = vectorMaxIndexesCount
117✔
78

79
    if (isMultitenant) {
117!
80
      const { features } = await getTenantConfig(req.tenantId)
×
81
      maxBucketCount = features?.vectorBuckets?.maxBuckets || vectorMaxBucketsCount
×
82
      maxIndexCount = features?.vectorBuckets?.maxIndexes || vectorMaxIndexesCount
×
83
    }
84

85
    const db = req.db.pool.acquire()
117✔
86
    const store = new KnexVectorMetadataDB(db)
117✔
87

88
    // Pick the adapter. In multi-tenant pgvector mode the adapter binds to the
89
    // request's own tenant pool (vectors live in the tenant DB); ST pgvector
90
    // uses the singleton; s3 uses the singleton S3 client.
91
    let adapter: VectorStore
92
    if (vectorBucketProvider === 'pgvector') {
117!
NEW
93
      adapter = isMultitenant ? new PgVectorStore(db) : stPgVectorAdapter!
×
94
    } else {
95
      adapter = s3Adapter!
117✔
96
    }
97

98
    let shard: Sharder
99
    if (vectorBucketProvider === 'pgvector') {
117!
NEW
100
      shard = new BucketScopedSingleShard({
×
101
        keyPrefix: 'pgvector__',
102
        capacity: Number.MAX_SAFE_INTEGER,
103
      })
104
    } else if (isMultitenant) {
117!
NEW
105
      shard = new ShardCatalog(new KnexShardStoreFactory(multitenantKnex))
×
106
    } else {
107
      shard = new SingleShard({
117✔
108
        shardKey: vectorS3Buckets[0],
109
        capacity: 10000,
110
      })
111
    }
112

113
    req.s3Vector = new VectorStoreManager(adapter, store, shard, {
117✔
114
      tenantId: req.tenantId,
115
      maxBucketCount,
116
      maxIndexCount,
117
    })
118
  })
119
})
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