Skip to content

Conversation

@techiejd
Copy link
Owner

@techiejd techiejd commented Jan 10, 2026

Allows for VectorizedPayload.search and VectorizedPayload.queueEmbed.


Note

Introduces a local API on the Payload instance for programmatic vector search and embedding queueing.

  • Adds VectorizedPayload with payload.search(params) and payload.queueEmbed(params); exposes isVectorizedPayload type guard
  • Refactors vector search to createVectorSearchHandlers returning { vectorSearch, requestHandler } for reuse
  • Hooks onInit to attach local methods; reuses collection hook logic via an internal embed-queue map
  • Updates README.md and CHANGELOG.md with usage docs and examples; bumps package.json to 0.4.5
  • Adds/updates tests: vectorizedPayload.spec.ts, vectorSearch.spec.ts, extensionFieldsVectorSearch.spec.ts, schemaName.spec.ts, plus shared expectations helper

Written by Cursor Bugbot for commit 243fef6. This will update automatically on new commits. Configure here.

Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR is being reviewed by Cursor Bugbot

Details

You are on the Bugbot Free tier. On this plan, Bugbot will review limited PRs each billing cycle.

To receive Bugbot reviews on all of your PRs, visit the Cursor dashboard to activate Pro and start your 14-day free trial.

})()

// Perform cosine similarity search using Drizzle
return await performCosineSearch(payload, queryEmbedding, knowledgePool, limit, where)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing knowledge pool validation in direct search function

Medium Severity

The new vectorSearch function doesn't validate that knowledgePool exists in knowledgePools before accessing poolConfig.embedQuery(). When calling payload.search() with an invalid pool name, poolConfig will be undefined, causing a cryptic TypeError: Cannot read properties of undefined (reading 'embedQuery') instead of a clear error message. The requestHandler has this validation (checking if (!poolConfig) and returning a proper error), but the direct function exposed via payload.search() lacks it.

🔬 Verification Test

Why verification test was not possible: This requires a running Payload CMS instance with PostgreSQL and pgvector to test. The bug can be verified by code inspection - comparing lines 70-76 in requestHandler which validates poolConfig exists before proceeding, versus lines 39-42 in vectorSearch which directly accesses poolConfig.embedQuery(query) without any null check. An invalid pool name would cause knowledgePools[knowledgePool] to return undefined, and then calling .embedQuery() on undefined would throw a TypeError.

Fix in Cursor Fix in Web

})()

// Perform cosine similarity search using Drizzle
return await performCosineSearch(payload, queryEmbedding, knowledgePool, limit, where)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Empty query not validated in direct search API

Low Severity

The new vectorSearch function doesn't validate that query is a non-empty string, unlike the requestHandler which explicitly rejects empty strings with !query || typeof query !== 'string'. When calling payload.search({ query: '', knowledgePool: 'default' }), the empty string passes to poolConfig.embedQuery(''), which may cause unnecessary API calls to the embedding service or unexpected behavior, depending on the implementation. The HTTP endpoint and direct API now behave inconsistently for empty query inputs.

🔬 Verification Test

Why verification test was not possible: This requires a running Payload CMS instance with a configured embedding function to test. The bug can be verified by code inspection - comparing line 60 in requestHandler which checks !query || typeof query !== 'string' and returns a 400 error for empty strings, versus the vectorSearch function (lines 32-47) which has no such validation and directly calls poolConfig.embedQuery(query) with whatever value is passed.

Fix in Cursor Fix in Web

import type { PostgresAdapterArgs } from '@payloadcms/db-postgres'
import { createVectorizeTask } from './tasks/vectorize.js'
import { createVectorSearchHandler } from './endpoints/vectorSearch.js'
import { createVectorSearchHandlers } from './endpoints/vectorSearch.js'
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Type guard function not exported from main entry point

High Severity

The new isVectorizedPayload type guard function is added to types.ts but is not re-exported from the main entry point. Line 21 uses export type * from './types.js' which only re-exports types, not runtime values like functions. While isPostgresPayload is explicitly imported as a value on line 14 and thus available, isVectorizedPayload is not imported, making it inaccessible via import { isVectorizedPayload } from 'payloadcms-vectorize' as documented in the README. Users following the documentation will get a runtime import error.

🔬 Verification Test

Why verification test was not possible: This can be verified by code inspection. The export type * syntax in TypeScript only re-exports type declarations, not runtime values. Since isVectorizedPayload is a function (runtime value) and is not explicitly imported and re-exported in index.ts, it will not be available when importing from 'payloadcms-vectorize'. The test file works around this by importing directly from ../../src/types.js rather than from the package entry point.

Fix in Cursor Fix in Web

@techiejd techiejd merged commit 335e298 into main Jan 10, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants