@mastra/vectorize 0.1.6-alpha.1 → 0.1.6-alpha.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,18 +1,23 @@
1
1
 
2
- > @mastra/vectorize@0.1.6-alpha.1 build /home/runner/work/mastra/mastra/stores/vectorize
3
- > tsup src/index.ts --format esm --experimental-dts --clean --treeshake
2
+ > @mastra/vectorize@0.1.6-alpha.3 build /home/runner/work/mastra/mastra/stores/vectorize
3
+ > tsup src/index.ts --format esm,cjs --experimental-dts --clean --treeshake
4
4
 
5
5
  CLI Building entry: src/index.ts
6
6
  CLI Using tsconfig: tsconfig.json
7
7
  CLI tsup v8.3.6
8
8
  TSC Build start
9
- TSC ⚡️ Build success in 13586ms
9
+ TSC ⚡️ Build success in 12974ms
10
10
  DTS Build start
11
11
  CLI Target: es2022
12
12
  Analysis will use the bundled TypeScript version 5.7.3
13
13
  Writing package typings: /home/runner/work/mastra/mastra/stores/vectorize/dist/_tsup-dts-rollup.d.ts
14
- DTS ⚡️ Build success in 10111ms
14
+ Analysis will use the bundled TypeScript version 5.7.3
15
+ Writing package typings: /home/runner/work/mastra/mastra/stores/vectorize/dist/_tsup-dts-rollup.d.cts
16
+ DTS ⚡️ Build success in 17317ms
15
17
  CLI Cleaning output folder
16
18
  ESM Build start
17
- ESM dist/index.js 5.26 KB
18
- ESM ⚡️ Build success in 497ms
19
+ CJS Build start
20
+ CJS dist/index.cjs 5.68 KB
21
+ CJS ⚡️ Build success in 465ms
22
+ ESM dist/index.js 5.48 KB
23
+ ESM ⚡️ Build success in 465ms
package/CHANGELOG.md CHANGED
@@ -1,5 +1,30 @@
1
1
  # @mastra/vectorize
2
2
 
3
+ ## 0.1.6-alpha.3
4
+
5
+ ### Patch Changes
6
+
7
+ - 0fd78ac: Update vector store functions to use object params
8
+ - fd14a3f: Updating filter location from @mastra/core/filter to @mastra/core/vector/filter
9
+ - c4fdac3: Updated tests for upstash and astra
10
+ - 4d4e1e1: Updated vector tests and pinecone
11
+ - bb4f447: Add support for commonjs
12
+ - Updated dependencies [0fd78ac]
13
+ - Updated dependencies [0d25b75]
14
+ - Updated dependencies [fd14a3f]
15
+ - Updated dependencies [3f369a2]
16
+ - Updated dependencies [4d4e1e1]
17
+ - Updated dependencies [bb4f447]
18
+ - @mastra/core@0.4.3-alpha.3
19
+
20
+ ## 0.1.6-alpha.2
21
+
22
+ ### Patch Changes
23
+
24
+ - Updated dependencies [2512a93]
25
+ - Updated dependencies [e62de74]
26
+ - @mastra/core@0.4.3-alpha.2
27
+
3
28
  ## 0.1.6-alpha.1
4
29
 
5
30
  ### Patch Changes
package/README.md CHANGED
@@ -14,7 +14,33 @@ npm install @mastra/vectorize
14
14
  import { VectorizeStore } from '@mastra/vectorize';
15
15
 
16
16
  const vectorStore = new VectorizeStore({
17
- // configuration options
17
+ apiKey: process.env.VECTORIZE_API_KEY,
18
+ projectId: process.env.VECTORIZE_PROJECT_ID
19
+ });
20
+
21
+ // Create a new index
22
+ await vectorStore.createIndex({
23
+ indexName: 'my-index',
24
+ dimension: 1536,
25
+ metric: 'cosine'
26
+ });
27
+
28
+ // Add vectors
29
+ const vectors = [[0.1, 0.2, ...], [0.3, 0.4, ...]];
30
+ const metadata = [{ text: 'doc1' }, { text: 'doc2' }];
31
+ const ids = await vectorStore.upsert({
32
+ indexName: 'my-index',
33
+ vectors,
34
+ metadata
35
+ });
36
+
37
+ // Query vectors
38
+ const results = await vectorStore.query({
39
+ indexName: 'my-index',
40
+ queryVector: [0.1, 0.2, ...],
41
+ topK: 10,
42
+ filter: { text: { $eq: 'doc1' } },
43
+ includeVector: false
18
44
  });
19
45
  ```
20
46
 
@@ -34,6 +60,15 @@ The Vectorize vector store requires the following configuration:
34
60
  - Scalable architecture
35
61
  - Real-time updates and queries
36
62
 
63
+ ## Methods
64
+
65
+ - `createIndex({ indexName, dimension, metric? })`: Create a new index
66
+ - `upsert({ indexName, vectors, metadata?, ids? })`: Add or update vectors
67
+ - `query({ indexName, queryVector, topK?, filter?, includeVector? })`: Search for similar vectors
68
+ - `listIndexes()`: List all indexes
69
+ - `describeIndex(indexName)`: Get index statistics
70
+ - `deleteIndex(indexName)`: Delete an index
71
+
37
72
  ## Related Links
38
73
 
39
74
  - [Vectorize Documentation](https://www.vectorize.com/docs)
@@ -0,0 +1,43 @@
1
+ import { BaseFilterTranslator } from '@mastra/core/vector/filter';
2
+ import Cloudflare from 'cloudflare';
3
+ import type { CreateIndexParams } from '@mastra/core/vector';
4
+ import { MastraVector } from '@mastra/core/vector';
5
+ import type { OperatorSupport } from '@mastra/core/vector/filter';
6
+ import type { ParamsToArgs } from '@mastra/core/vector';
7
+ import type { QueryResult } from '@mastra/core/vector';
8
+ import type { QueryVectorParams } from '@mastra/core/vector';
9
+ import type { UpsertVectorParams } from '@mastra/core/vector';
10
+ import type { VectorFilter } from '@mastra/core/vector/filter';
11
+
12
+ declare class CloudflareVector extends MastraVector {
13
+ client: Cloudflare;
14
+ accountId: string;
15
+ constructor({ accountId, apiToken }: {
16
+ accountId: string;
17
+ apiToken: string;
18
+ });
19
+ upsert(...args: ParamsToArgs<UpsertVectorParams>): Promise<string[]>;
20
+ transformFilter(filter?: VectorFilter): VectorFilter;
21
+ createIndex(...args: ParamsToArgs<CreateIndexParams>): Promise<void>;
22
+ query(...args: ParamsToArgs<QueryVectorParams>): Promise<QueryResult[]>;
23
+ listIndexes(): Promise<string[]>;
24
+ describeIndex(indexName: string): Promise<{
25
+ dimension: number;
26
+ count: number;
27
+ metric: "cosine" | "euclidean" | "dotproduct";
28
+ }>;
29
+ deleteIndex(indexName: string): Promise<void>;
30
+ createMetadataIndex(indexName: string, propertyName: string, indexType: 'string' | 'number' | 'boolean'): Promise<void>;
31
+ deleteMetadataIndex(indexName: string, propertyName: string): Promise<void>;
32
+ listMetadataIndexes(indexName: string): Promise<Cloudflare.Vectorize.Indexes.MetadataIndex.MetadataIndexListResponse.MetadataIndex[]>;
33
+ }
34
+ export { CloudflareVector }
35
+ export { CloudflareVector as CloudflareVector_alias_1 }
36
+
37
+ export declare class VectorizeFilterTranslator extends BaseFilterTranslator {
38
+ protected getSupportedOperators(): OperatorSupport;
39
+ translate(filter?: VectorFilter): VectorFilter;
40
+ private translateNode;
41
+ }
42
+
43
+ export { }
@@ -1,9 +1,13 @@
1
- import { BaseFilterTranslator } from '@mastra/core/filter';
1
+ import { BaseFilterTranslator } from '@mastra/core/vector/filter';
2
2
  import Cloudflare from 'cloudflare';
3
- import type { Filter } from '@mastra/core/filter';
3
+ import type { CreateIndexParams } from '@mastra/core/vector';
4
4
  import { MastraVector } from '@mastra/core/vector';
5
- import type { OperatorSupport } from '@mastra/core/filter';
5
+ import type { OperatorSupport } from '@mastra/core/vector/filter';
6
+ import type { ParamsToArgs } from '@mastra/core/vector';
6
7
  import type { QueryResult } from '@mastra/core/vector';
8
+ import type { QueryVectorParams } from '@mastra/core/vector';
9
+ import type { UpsertVectorParams } from '@mastra/core/vector';
10
+ import type { VectorFilter } from '@mastra/core/vector/filter';
7
11
 
8
12
  declare class CloudflareVector extends MastraVector {
9
13
  client: Cloudflare;
@@ -12,10 +16,10 @@ declare class CloudflareVector extends MastraVector {
12
16
  accountId: string;
13
17
  apiToken: string;
14
18
  });
15
- upsert(indexName: string, vectors: number[][], metadata?: Record<string, any>[], ids?: string[]): Promise<string[]>;
16
- transformFilter(filter?: Filter): Filter | undefined;
17
- createIndex(indexName: string, dimension: number, metric?: 'cosine' | 'euclidean' | 'dotproduct'): Promise<void>;
18
- query(indexName: string, queryVector: number[], topK?: number, filter?: Filter, includeVector?: boolean): Promise<QueryResult[]>;
19
+ upsert(...args: ParamsToArgs<UpsertVectorParams>): Promise<string[]>;
20
+ transformFilter(filter?: VectorFilter): VectorFilter;
21
+ createIndex(...args: ParamsToArgs<CreateIndexParams>): Promise<void>;
22
+ query(...args: ParamsToArgs<QueryVectorParams>): Promise<QueryResult[]>;
19
23
  listIndexes(): Promise<string[]>;
20
24
  describeIndex(indexName: string): Promise<{
21
25
  dimension: number;
@@ -32,7 +36,7 @@ export { CloudflareVector as CloudflareVector_alias_1 }
32
36
 
33
37
  export declare class VectorizeFilterTranslator extends BaseFilterTranslator {
34
38
  protected getSupportedOperators(): OperatorSupport;
35
- translate(filter?: Filter): Filter | undefined;
39
+ translate(filter?: VectorFilter): VectorFilter;
36
40
  private translateNode;
37
41
  }
38
42
 
package/dist/index.cjs ADDED
@@ -0,0 +1,184 @@
1
+ 'use strict';
2
+
3
+ var vector = require('@mastra/core/vector');
4
+ var Cloudflare = require('cloudflare');
5
+ var filter = require('@mastra/core/vector/filter');
6
+
7
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
8
+
9
+ var Cloudflare__default = /*#__PURE__*/_interopDefault(Cloudflare);
10
+
11
+ // src/vector/index.ts
12
+ var VectorizeFilterTranslator = class extends filter.BaseFilterTranslator {
13
+ getSupportedOperators() {
14
+ return {
15
+ ...filter.BaseFilterTranslator.DEFAULT_OPERATORS,
16
+ logical: [],
17
+ array: ["$in", "$nin"],
18
+ element: [],
19
+ regex: [],
20
+ custom: []
21
+ };
22
+ }
23
+ translate(filter) {
24
+ if (this.isEmpty(filter)) return filter;
25
+ this.validateFilter(filter);
26
+ return this.translateNode(filter);
27
+ }
28
+ translateNode(node, currentPath = "") {
29
+ if (this.isRegex(node)) {
30
+ throw new Error("Regex is not supported in Vectorize");
31
+ }
32
+ if (this.isPrimitive(node)) return { $eq: this.normalizeComparisonValue(node) };
33
+ if (Array.isArray(node)) return { $in: this.normalizeArrayValues(node) };
34
+ const entries = Object.entries(node);
35
+ const firstEntry = entries[0];
36
+ if (entries.length === 1 && firstEntry && this.isOperator(firstEntry[0])) {
37
+ const [operator, value] = firstEntry;
38
+ return { [operator]: this.normalizeComparisonValue(value) };
39
+ }
40
+ const result = {};
41
+ for (const [key, value] of entries) {
42
+ const newPath = currentPath ? `${currentPath}.${key}` : key;
43
+ if (this.isOperator(key)) {
44
+ result[key] = this.normalizeComparisonValue(value);
45
+ continue;
46
+ }
47
+ if (typeof value === "object" && value !== null && !Array.isArray(value)) {
48
+ if (Object.keys(value).length === 0) {
49
+ result[newPath] = this.translateNode(value);
50
+ continue;
51
+ }
52
+ const hasOperators = Object.keys(value).some((k) => this.isOperator(k));
53
+ if (hasOperators) {
54
+ result[newPath] = this.translateNode(value);
55
+ } else {
56
+ Object.assign(result, this.translateNode(value, newPath));
57
+ }
58
+ } else {
59
+ result[newPath] = this.translateNode(value);
60
+ }
61
+ }
62
+ return result;
63
+ }
64
+ };
65
+
66
+ // src/vector/index.ts
67
+ var CloudflareVector = class extends vector.MastraVector {
68
+ client;
69
+ accountId;
70
+ constructor({ accountId, apiToken }) {
71
+ super();
72
+ this.accountId = accountId;
73
+ this.client = new Cloudflare__default.default({
74
+ apiKey: apiToken
75
+ });
76
+ }
77
+ async upsert(...args) {
78
+ const params = this.normalizeArgs("upsert", args);
79
+ const { indexName, vectors, metadata, ids } = params;
80
+ const generatedIds = ids || vectors.map(() => crypto.randomUUID());
81
+ const ndjson = vectors.map(
82
+ (vector, index) => JSON.stringify({
83
+ id: generatedIds[index],
84
+ values: vector,
85
+ metadata: metadata?.[index]
86
+ })
87
+ ).join("\n");
88
+ await this.client.vectorize.indexes.upsert(
89
+ indexName,
90
+ {
91
+ account_id: this.accountId,
92
+ body: ndjson
93
+ },
94
+ {
95
+ __binaryRequest: true
96
+ }
97
+ );
98
+ return generatedIds;
99
+ }
100
+ transformFilter(filter) {
101
+ const translator = new VectorizeFilterTranslator();
102
+ return translator.translate(filter);
103
+ }
104
+ async createIndex(...args) {
105
+ const params = this.normalizeArgs("createIndex", args);
106
+ const { indexName, dimension, metric = "cosine" } = params;
107
+ await this.client.vectorize.indexes.create({
108
+ account_id: this.accountId,
109
+ config: {
110
+ dimensions: dimension,
111
+ metric: metric === "dotproduct" ? "dot-product" : metric
112
+ },
113
+ name: indexName
114
+ });
115
+ }
116
+ async query(...args) {
117
+ const params = this.normalizeArgs("query", args);
118
+ const { indexName, queryVector, topK = 10, filter, includeVector = false } = params;
119
+ const translatedFilter = this.transformFilter(filter) ?? {};
120
+ const response = await this.client.vectorize.indexes.query(indexName, {
121
+ account_id: this.accountId,
122
+ vector: queryVector,
123
+ returnValues: includeVector,
124
+ returnMetadata: "all",
125
+ topK,
126
+ filter: translatedFilter
127
+ });
128
+ return response?.matches?.map((match) => {
129
+ return {
130
+ id: match.id,
131
+ metadata: match.metadata,
132
+ score: match.score,
133
+ vector: match.values
134
+ };
135
+ }) || [];
136
+ }
137
+ async listIndexes() {
138
+ const res = await this.client.vectorize.indexes.list({
139
+ account_id: this.accountId
140
+ });
141
+ return res?.result?.map((index) => index.name) || [];
142
+ }
143
+ async describeIndex(indexName) {
144
+ const index = await this.client.vectorize.indexes.get(indexName, {
145
+ account_id: this.accountId
146
+ });
147
+ const described = await this.client.vectorize.indexes.info(indexName, {
148
+ account_id: this.accountId
149
+ });
150
+ return {
151
+ dimension: described?.dimensions,
152
+ // Since vector_count is not available in the response,
153
+ // we might need a separate API call to get the count if needed
154
+ count: described?.vectorCount || 0,
155
+ metric: index?.config?.metric
156
+ };
157
+ }
158
+ async deleteIndex(indexName) {
159
+ await this.client.vectorize.indexes.delete(indexName, {
160
+ account_id: this.accountId
161
+ });
162
+ }
163
+ async createMetadataIndex(indexName, propertyName, indexType) {
164
+ await this.client.vectorize.indexes.metadataIndex.create(indexName, {
165
+ account_id: this.accountId,
166
+ propertyName,
167
+ indexType
168
+ });
169
+ }
170
+ async deleteMetadataIndex(indexName, propertyName) {
171
+ await this.client.vectorize.indexes.metadataIndex.delete(indexName, {
172
+ account_id: this.accountId,
173
+ propertyName
174
+ });
175
+ }
176
+ async listMetadataIndexes(indexName) {
177
+ const res = await this.client.vectorize.indexes.metadataIndex.list(indexName, {
178
+ account_id: this.accountId
179
+ });
180
+ return res?.metadataIndexes ?? [];
181
+ }
182
+ };
183
+
184
+ exports.CloudflareVector = CloudflareVector;
@@ -0,0 +1 @@
1
+ export { CloudflareVector } from './_tsup-dts-rollup.cjs';
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { MastraVector } from '@mastra/core/vector';
2
2
  import Cloudflare from 'cloudflare';
3
- import { BaseFilterTranslator } from '@mastra/core/filter';
3
+ import { BaseFilterTranslator } from '@mastra/core/vector/filter';
4
4
 
5
5
  // src/vector/index.ts
6
6
  var VectorizeFilterTranslator = class extends BaseFilterTranslator {
@@ -68,7 +68,9 @@ var CloudflareVector = class extends MastraVector {
68
68
  apiKey: apiToken
69
69
  });
70
70
  }
71
- async upsert(indexName, vectors, metadata, ids) {
71
+ async upsert(...args) {
72
+ const params = this.normalizeArgs("upsert", args);
73
+ const { indexName, vectors, metadata, ids } = params;
72
74
  const generatedIds = ids || vectors.map(() => crypto.randomUUID());
73
75
  const ndjson = vectors.map(
74
76
  (vector, index) => JSON.stringify({
@@ -91,10 +93,11 @@ var CloudflareVector = class extends MastraVector {
91
93
  }
92
94
  transformFilter(filter) {
93
95
  const translator = new VectorizeFilterTranslator();
94
- const translatedFilter = translator.translate(filter);
95
- return translatedFilter;
96
+ return translator.translate(filter);
96
97
  }
97
- async createIndex(indexName, dimension, metric = "cosine") {
98
+ async createIndex(...args) {
99
+ const params = this.normalizeArgs("createIndex", args);
100
+ const { indexName, dimension, metric = "cosine" } = params;
98
101
  await this.client.vectorize.indexes.create({
99
102
  account_id: this.accountId,
100
103
  config: {
@@ -104,8 +107,10 @@ var CloudflareVector = class extends MastraVector {
104
107
  name: indexName
105
108
  });
106
109
  }
107
- async query(indexName, queryVector, topK = 10, filter, includeVector = false) {
108
- const translatedFilter = this.transformFilter(filter);
110
+ async query(...args) {
111
+ const params = this.normalizeArgs("query", args);
112
+ const { indexName, queryVector, topK = 10, filter, includeVector = false } = params;
113
+ const translatedFilter = this.transformFilter(filter) ?? {};
109
114
  const response = await this.client.vectorize.indexes.query(indexName, {
110
115
  account_id: this.accountId,
111
116
  vector: queryVector,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mastra/vectorize",
3
- "version": "0.1.6-alpha.1",
3
+ "version": "0.1.6-alpha.3",
4
4
  "description": "Cloudflare Vectorize store provider for Mastra",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -10,13 +10,17 @@
10
10
  "import": {
11
11
  "types": "./dist/index.d.ts",
12
12
  "default": "./dist/index.js"
13
+ },
14
+ "require": {
15
+ "types": "./dist/index.d.cts",
16
+ "default": "./dist/index.cjs"
13
17
  }
14
18
  },
15
19
  "./package.json": "./package.json"
16
20
  },
17
21
  "dependencies": {
18
22
  "cloudflare": "^4.0.0",
19
- "@mastra/core": "^0.4.3-alpha.1"
23
+ "@mastra/core": "^0.4.3-alpha.3"
20
24
  },
21
25
  "devDependencies": {
22
26
  "@microsoft/api-extractor": "^7.49.2",
@@ -28,7 +32,7 @@
28
32
  "@internal/lint": "0.0.0"
29
33
  },
30
34
  "scripts": {
31
- "build": "tsup src/index.ts --format esm --experimental-dts --clean --treeshake",
35
+ "build": "tsup src/index.ts --format esm,cjs --experimental-dts --clean --treeshake",
32
36
  "build:watch": "pnpm build --watch",
33
37
  "test": "vitest run",
34
38
  "lint": "eslint ."
@@ -1,5 +1,5 @@
1
- import { BaseFilterTranslator } from '@mastra/core/filter';
2
- import type { Filter, FieldCondition, OperatorSupport } from '@mastra/core/filter';
1
+ import { BaseFilterTranslator } from '@mastra/core/vector/filter';
2
+ import type { VectorFilter, FieldCondition, OperatorSupport } from '@mastra/core/vector/filter';
3
3
 
4
4
  export class VectorizeFilterTranslator extends BaseFilterTranslator {
5
5
  protected override getSupportedOperators(): OperatorSupport {
@@ -13,13 +13,13 @@ export class VectorizeFilterTranslator extends BaseFilterTranslator {
13
13
  };
14
14
  }
15
15
 
16
- translate(filter?: Filter): Filter | undefined {
16
+ translate(filter?: VectorFilter): VectorFilter {
17
17
  if (this.isEmpty(filter)) return filter;
18
- this.validateFilter(filter as Filter);
18
+ this.validateFilter(filter);
19
19
  return this.translateNode(filter);
20
20
  }
21
21
 
22
- private translateNode(node: Filter | FieldCondition, currentPath: string = ''): any {
22
+ private translateNode(node: VectorFilter | FieldCondition, currentPath: string = ''): any {
23
23
  if (this.isRegex(node)) {
24
24
  throw new Error('Regex is not supported in Vectorize');
25
25
  }
@@ -1,8 +1,10 @@
1
1
  import { randomUUID } from 'crypto';
2
- import { describe, it, expect, beforeAll, afterAll } from 'vitest';
2
+ import { describe, it, expect, beforeAll, afterAll, beforeEach, vi, afterEach } from 'vitest';
3
3
 
4
4
  import { CloudflareVector } from './';
5
5
 
6
+ vi.setConfig({ testTimeout: 80_000, hookTimeout: 80_000 });
7
+
6
8
  function waitUntilReady(vector: CloudflareVector, indexName: string) {
7
9
  return new Promise(resolve => {
8
10
  const interval = setInterval(async () => {
@@ -106,7 +108,7 @@ describe('CloudflareVector', () => {
106
108
  const tempIndexName = 'test_temp_index';
107
109
 
108
110
  it('should create and list indexes', async () => {
109
- await vectorDB.createIndex(tempIndexName, VECTOR_DIMENSION, 'cosine');
111
+ await vectorDB.createIndex({ indexName: tempIndexName, dimension: VECTOR_DIMENSION, metric: 'cosine' });
110
112
  await waitUntilReady(vectorDB, tempIndexName);
111
113
  const indexes = await vectorDB.listIndexes();
112
114
  expect(indexes).toContain(tempIndexName);
@@ -131,7 +133,7 @@ describe('CloudflareVector', () => {
131
133
  describe('Vector Operations', () => {
132
134
  let vectorIds: string[];
133
135
  it('should create index before operations', async () => {
134
- await vectorDB.createIndex(testIndexName, VECTOR_DIMENSION, 'cosine');
136
+ await vectorDB.createIndex({ indexName: testIndexName, dimension: VECTOR_DIMENSION, metric: 'cosine' });
135
137
  await waitUntilReady(vectorDB, testIndexName);
136
138
  const indexes = await vectorDB.listIndexes();
137
139
  expect(indexes).toContain(testIndexName);
@@ -142,14 +144,14 @@ describe('CloudflareVector', () => {
142
144
 
143
145
  const testMetadata = [{ label: 'first-dimension' }, { label: 'second-dimension' }, { label: 'third-dimension' }];
144
146
 
145
- vectorIds = await vectorDB.upsert(testIndexName, testVectors, testMetadata);
147
+ vectorIds = await vectorDB.upsert({ indexName: testIndexName, vectors: testVectors, metadata: testMetadata });
146
148
  expect(vectorIds).toHaveLength(3);
147
149
 
148
150
  await waitUntilVectorsIndexed(vectorDB, testIndexName, 3);
149
151
  const stats = await vectorDB.describeIndex(testIndexName);
150
152
  expect(stats.count).toBeGreaterThan(0);
151
153
 
152
- const results = await vectorDB.query(testIndexName, createVector(0, 0.9), 3);
154
+ const results = await vectorDB.query({ indexName: testIndexName, queryVector: createVector(0, 0.9), topK: 3 });
153
155
  expect(results).toHaveLength(3);
154
156
 
155
157
  if (results.length > 0) {
@@ -158,7 +160,12 @@ describe('CloudflareVector', () => {
158
160
  }, 30000);
159
161
 
160
162
  it('should query vectors and return vector in results', async () => {
161
- const results = await vectorDB.query(testIndexName, createVector(0, 0.9), 3, undefined, true);
163
+ const results = await vectorDB.query({
164
+ indexName: testIndexName,
165
+ queryVector: createVector(0, 0.9),
166
+ topK: 3,
167
+ includeVector: true,
168
+ });
162
169
 
163
170
  expect(results).toHaveLength(3);
164
171
 
@@ -171,23 +178,27 @@ describe('CloudflareVector', () => {
171
178
 
172
179
  describe('Error Handling', () => {
173
180
  it('should handle invalid dimension vectors', async () => {
174
- await expect(vectorDB.upsert(testIndexName, [[1.0, 0.0]])).rejects.toThrow();
181
+ await expect(vectorDB.upsert({ indexName: testIndexName, vectors: [[1.0, 0.0]] })).rejects.toThrow();
175
182
  });
176
183
 
177
184
  it('should handle querying with wrong dimensions', async () => {
178
- await expect(vectorDB.query(testIndexName, [1.0, 0.0])).rejects.toThrow();
185
+ await expect(vectorDB.query({ indexName: testIndexName, queryVector: [1.0, 0.0] })).rejects.toThrow();
179
186
  });
180
187
 
181
188
  it('should handle non-existent index operations', async () => {
182
189
  const nonExistentIndex = 'non_existent_index';
183
- await expect(vectorDB.query(nonExistentIndex, createVector(0, 1.0))).rejects.toThrow();
190
+ await expect(
191
+ vectorDB.query({ indexName: nonExistentIndex, queryVector: createVector(0, 1.0) }),
192
+ ).rejects.toThrow();
184
193
  });
185
194
 
186
195
  it('rejects queries with filter keys longer than 512 characters', async () => {
187
196
  const longKey = 'a'.repeat(513);
188
197
  const filter = { [longKey]: 'value' };
189
198
 
190
- await expect(vectorDB.query(testIndexName, createVector(0, 0.9), 10, filter)).rejects.toThrow();
199
+ await expect(
200
+ vectorDB.query({ indexName: testIndexName, queryVector: createVector(0, 0.9), topK: 10, filter }),
201
+ ).rejects.toThrow();
191
202
  });
192
203
 
193
204
  it('rejects queries with filter keys containing invalid characters', async () => {
@@ -198,7 +209,9 @@ describe('CloudflareVector', () => {
198
209
  ];
199
210
 
200
211
  for (const filter of invalidFilters) {
201
- await expect(vectorDB.query(testIndexName, createVector(0, 0.9), 10, filter)).rejects.toThrow();
212
+ await expect(
213
+ vectorDB.query({ indexName: testIndexName, queryVector: createVector(0, 0.9), topK: 10, filter }),
214
+ ).rejects.toThrow();
202
215
  }
203
216
  });
204
217
 
@@ -210,13 +223,17 @@ describe('CloudflareVector', () => {
210
223
  ];
211
224
 
212
225
  for (const filter of validFilters) {
213
- await expect(vectorDB.query(testIndexName, createVector(0, 0.9), 10, filter)).resolves.not.toThrow();
226
+ await expect(
227
+ vectorDB.query({ indexName: testIndexName, queryVector: createVector(0, 0.9), topK: 10, filter }),
228
+ ).resolves.not.toThrow();
214
229
  }
215
230
  });
216
231
 
217
232
  it('rejects queries with empty object field values', async () => {
218
233
  const emptyFilters = { field: {} };
219
- await expect(vectorDB.query(testIndexName, createVector(0, 0.9), 10, emptyFilters)).rejects.toThrow();
234
+ await expect(
235
+ vectorDB.query({ indexName: testIndexName, queryVector: createVector(0, 0.9), topK: 10, filter: emptyFilters }),
236
+ ).rejects.toThrow();
220
237
  });
221
238
 
222
239
  it('rejects oversized filter queries', async () => {
@@ -225,19 +242,27 @@ describe('CloudflareVector', () => {
225
242
  field2: { $in: Array(1000).fill(123) },
226
243
  };
227
244
 
228
- await expect(vectorDB.query(testIndexName, createVector(0, 0.9), 10, largeFilter)).rejects.toThrow();
245
+ await expect(
246
+ vectorDB.query({ indexName: testIndexName, queryVector: createVector(0, 0.9), topK: 10, filter: largeFilter }),
247
+ ).rejects.toThrow();
229
248
  });
230
249
 
231
250
  it('rejects queries with array values in comparison operators', async () => {
232
251
  await expect(
233
- vectorDB.query(testIndexName, createVector(0, 0.9), 10, {
234
- field: { $gt: [] },
252
+ vectorDB.query({
253
+ indexName: testIndexName,
254
+ queryVector: createVector(0, 0.9),
255
+ topK: 10,
256
+ filter: { field: { $gt: [] } },
235
257
  }),
236
258
  ).rejects.toThrow();
237
259
 
238
260
  await expect(
239
- vectorDB.query(testIndexName, createVector(0, 0.9), 10, {
240
- field: { $lt: [1, 2, 3] },
261
+ vectorDB.query({
262
+ indexName: testIndexName,
263
+ queryVector: createVector(0, 0.9),
264
+ topK: 10,
265
+ filter: { field: { $lt: [1, 2, 3] } },
241
266
  }),
242
267
  ).rejects.toThrow();
243
268
  });
@@ -245,7 +270,7 @@ describe('CloudflareVector', () => {
245
270
 
246
271
  describe('Metadata Filter Tests', () => {
247
272
  beforeAll(async () => {
248
- await vectorDB.createIndex(testIndexName2, VECTOR_DIMENSION, 'cosine');
273
+ await vectorDB.createIndex({ indexName: testIndexName2, dimension: VECTOR_DIMENSION, metric: 'cosine' });
249
274
  await waitUntilReady(vectorDB, testIndexName2);
250
275
 
251
276
  await vectorDB.createMetadataIndex(testIndexName2, 'price', 'number');
@@ -327,12 +352,12 @@ describe('CloudflareVector', () => {
327
352
  },
328
353
  ];
329
354
 
330
- await vectorDB.upsert(testIndexName2, vectors, metadata);
355
+ await vectorDB.upsert({ indexName: testIndexName2, vectors, metadata });
331
356
  await waitUntilVectorsIndexed(vectorDB, testIndexName2, vectors.length);
332
357
 
333
358
  const stats = await vectorDB.describeIndex(testIndexName2);
334
359
  expect(stats.count).toBe(vectors.length);
335
- }, 300000);
360
+ }, 800000);
336
361
 
337
362
  afterAll(async () => {
338
363
  const currentMetadata = await vectorDB.listMetadataIndexes(testIndexName2);
@@ -340,12 +365,14 @@ describe('CloudflareVector', () => {
340
365
  await vectorDB.deleteMetadataIndex(testIndexName2, propertyName as string);
341
366
  }
342
367
  await vectorDB.deleteIndex(testIndexName2);
343
- }, 300000);
368
+ }, 800000);
344
369
 
345
370
  describe('Basic Equality Operators', () => {
346
371
  it('filters with $eq operator', async () => {
347
- const results = await vectorDB.query(testIndexName2, createVector(0, 1.0), 10, {
348
- category: 'electronics',
372
+ const results = await vectorDB.query({
373
+ indexName: testIndexName2,
374
+ queryVector: createVector(0, 1.0),
375
+ filter: { category: 'electronics' },
349
376
  });
350
377
  expect(results.length).toBe(2);
351
378
  results.forEach(result => {
@@ -354,8 +381,10 @@ describe('CloudflareVector', () => {
354
381
  });
355
382
 
356
383
  it('filters with $ne operator', async () => {
357
- const results = await vectorDB.query(testIndexName2, createVector(0, 1.0), 10, {
358
- category: { $ne: 'electronics' },
384
+ const results = await vectorDB.query({
385
+ indexName: testIndexName2,
386
+ queryVector: createVector(0, 1.0),
387
+ filter: { category: { $ne: 'electronics' } },
359
388
  });
360
389
  expect(results.length).toBe(2);
361
390
  results.forEach(result => {
@@ -366,8 +395,10 @@ describe('CloudflareVector', () => {
366
395
 
367
396
  describe('Numeric Comparison Operators', () => {
368
397
  it('filters with $gt operator', async () => {
369
- const results = await vectorDB.query(testIndexName2, createVector(0, 1.0), 10, {
370
- price: { $gt: 150 },
398
+ const results = await vectorDB.query({
399
+ indexName: testIndexName2,
400
+ queryVector: createVector(0, 1.0),
401
+ filter: { price: { $gt: 150 } },
371
402
  });
372
403
  expect(results.length).toBe(1);
373
404
  results.forEach(result => {
@@ -376,8 +407,10 @@ describe('CloudflareVector', () => {
376
407
  });
377
408
 
378
409
  it('filters with $gte operator', async () => {
379
- const results = await vectorDB.query(testIndexName2, createVector(0, 1.0), 10, {
380
- price: { $gte: 100 },
410
+ const results = await vectorDB.query({
411
+ indexName: testIndexName2,
412
+ queryVector: createVector(0, 1.0),
413
+ filter: { price: { $gte: 100 } },
381
414
  });
382
415
  expect(results.length).toBe(3);
383
416
  results.forEach(result => {
@@ -387,8 +420,10 @@ describe('CloudflareVector', () => {
387
420
  });
388
421
 
389
422
  it('filters with $lt operator', async () => {
390
- const results = await vectorDB.query(testIndexName2, createVector(0, 1.0), 10, {
391
- price: { $lt: 150 },
423
+ const results = await vectorDB.query({
424
+ indexName: testIndexName2,
425
+ queryVector: createVector(0, 1.0),
426
+ filter: { price: { $lt: 150 } },
392
427
  });
393
428
  expect(results.length).toBe(2);
394
429
  results.forEach(result => {
@@ -398,8 +433,10 @@ describe('CloudflareVector', () => {
398
433
  });
399
434
 
400
435
  it('filters with $lte operator', async () => {
401
- const results = await vectorDB.query(testIndexName2, createVector(0, 1.0), 10, {
402
- price: { $lte: 150 },
436
+ const results = await vectorDB.query({
437
+ indexName: testIndexName2,
438
+ queryVector: createVector(0, 1.0),
439
+ filter: { price: { $lte: 150 } },
403
440
  });
404
441
  expect(results.length).toBe(3);
405
442
  results.forEach(result => {
@@ -411,8 +448,10 @@ describe('CloudflareVector', () => {
411
448
 
412
449
  describe('Array Operators', () => {
413
450
  it('filters with $in operator for exact matches', async () => {
414
- const results = await vectorDB.query(testIndexName2, createVector(0, 1.0), 10, {
415
- category: { $in: ['electronics'] },
451
+ const results = await vectorDB.query({
452
+ indexName: testIndexName2,
453
+ queryVector: createVector(0, 1.0),
454
+ filter: { category: { $in: ['electronics'] } },
416
455
  });
417
456
  expect(results.length).toBe(2);
418
457
  results.forEach(result => {
@@ -421,8 +460,10 @@ describe('CloudflareVector', () => {
421
460
  });
422
461
 
423
462
  it('filters with $nin operator', async () => {
424
- const results = await vectorDB.query(testIndexName2, createVector(0, 1.0), 10, {
425
- category: { $nin: ['electronics'] },
463
+ const results = await vectorDB.query({
464
+ indexName: testIndexName2,
465
+ queryVector: createVector(0, 1.0),
466
+ filter: { category: { $nin: ['electronics'] } },
426
467
  });
427
468
  expect(results.length).toBe(2);
428
469
  results.forEach(result => {
@@ -433,16 +474,20 @@ describe('CloudflareVector', () => {
433
474
 
434
475
  describe('Boolean Operations', () => {
435
476
  it('filters with boolean values', async () => {
436
- const results = await vectorDB.query(testIndexName2, createVector(0, 1.0), 10, {
437
- isActive: true,
477
+ const results = await vectorDB.query({
478
+ indexName: testIndexName2,
479
+ queryVector: createVector(0, 1.0),
480
+ filter: { isActive: true },
438
481
  });
439
482
  expect(results.length).toBe(1);
440
483
  expect(results[0]?.metadata?.isActive).toBe(true);
441
484
  }, 5000);
442
485
 
443
486
  it('filters with $ne on boolean values', async () => {
444
- const results = await vectorDB.query(testIndexName2, createVector(0, 1.0), 10, {
445
- isActive: { $ne: true },
487
+ const results = await vectorDB.query({
488
+ indexName: testIndexName2,
489
+ queryVector: createVector(0, 1.0),
490
+ filter: { isActive: { $ne: true } },
446
491
  });
447
492
  expect(results.length).toBe(3);
448
493
  results.forEach(result => {
@@ -453,8 +498,10 @@ describe('CloudflareVector', () => {
453
498
 
454
499
  describe('Nested Field Operations', () => {
455
500
  it('filters on nested fields with comparison operators', async () => {
456
- const results = await vectorDB.query(testIndexName2, createVector(0, 1.0), 10, {
457
- 'nested.number': { $gt: 100 },
501
+ const results = await vectorDB.query({
502
+ indexName: testIndexName2,
503
+ queryVector: createVector(0, 1.0),
504
+ filter: { 'nested.number': { $gt: 100 } },
458
505
  });
459
506
  expect(results.length).toBe(2);
460
507
  results.forEach(result => {
@@ -463,9 +510,10 @@ describe('CloudflareVector', () => {
463
510
  });
464
511
 
465
512
  it('combines nested field filters with top-level filters', async () => {
466
- const results = await vectorDB.query(testIndexName2, createVector(0, 1.0), 10, {
467
- 'nested.number': { $lt: 200 },
468
- category: 'electronics',
513
+ const results = await vectorDB.query({
514
+ indexName: testIndexName2,
515
+ queryVector: createVector(0, 1.0),
516
+ filter: { 'nested.number': { $lt: 200 }, category: 'electronics' },
469
517
  });
470
518
  expect(results.length).toBe(1);
471
519
  expect(results[0]?.metadata?.nested?.number).toBeLessThan(200);
@@ -473,8 +521,10 @@ describe('CloudflareVector', () => {
473
521
  });
474
522
 
475
523
  it('handles nested string equality', async () => {
476
- const results = await vectorDB.query(testIndexName2, createVector(0, 1.0), 10, {
477
- 'nested.string': 'premium',
524
+ const results = await vectorDB.query({
525
+ indexName: testIndexName2,
526
+ queryVector: createVector(0, 1.0),
527
+ filter: { 'nested.string': 'premium' },
478
528
  });
479
529
  expect(results.length).toBe(3);
480
530
  results.forEach(result => {
@@ -483,9 +533,10 @@ describe('CloudflareVector', () => {
483
533
  }, 10000);
484
534
 
485
535
  it('combines nested numeric and boolean conditions', async () => {
486
- const results = await vectorDB.query(testIndexName2, createVector(0, 1.0), 10, {
487
- 'nested.number': { $gt: 100 },
488
- 'nested.boolean': true,
536
+ const results = await vectorDB.query({
537
+ indexName: testIndexName2,
538
+ queryVector: createVector(0, 1.0),
539
+ filter: { 'nested.number': { $gt: 100 }, 'nested.boolean': true },
489
540
  });
490
541
  expect(results.length).toBe(1);
491
542
  expect(results[0]?.metadata?.nested?.number).toBeGreaterThan(100);
@@ -493,10 +544,10 @@ describe('CloudflareVector', () => {
493
544
  }, 10000);
494
545
 
495
546
  it('handles multiple nested field comparisons', async () => {
496
- const results = await vectorDB.query(testIndexName2, createVector(0, 1.0), 10, {
497
- 'nested.string': 'premium',
498
- 'nested.number': { $lt: 200 },
499
- 'nested.boolean': true,
547
+ const results = await vectorDB.query({
548
+ indexName: testIndexName2,
549
+ queryVector: createVector(0, 1.0),
550
+ filter: { 'nested.string': 'premium', 'nested.number': { $lt: 200 }, 'nested.boolean': true },
500
551
  });
501
552
  expect(results.length).toBe(2);
502
553
  const result = results[0]?.metadata?.nested;
@@ -506,8 +557,10 @@ describe('CloudflareVector', () => {
506
557
  }, 10000);
507
558
 
508
559
  it('handles $in with nested string values', async () => {
509
- const results = await vectorDB.query(testIndexName2, createVector(0, 1.0), 10, {
510
- 'nested.string': { $in: ['premium', 'basic'] },
560
+ const results = await vectorDB.query({
561
+ indexName: testIndexName2,
562
+ queryVector: createVector(0, 1.0),
563
+ filter: { 'nested.string': { $in: ['premium', 'basic'] } },
511
564
  });
512
565
  expect(results.length).toBe(4);
513
566
  results.forEach(result => {
@@ -518,17 +571,20 @@ describe('CloudflareVector', () => {
518
571
 
519
572
  describe('String Operations', () => {
520
573
  it('handles string numbers in numeric comparisons', async () => {
521
- const results = await vectorDB.query(testIndexName2, createVector(0, 1.0), 10, {
522
- price: { $gt: '150' }, // String number
574
+ const results = await vectorDB.query({
575
+ indexName: testIndexName2,
576
+ queryVector: createVector(0, 1.0),
577
+ filter: { price: { $gt: '150' } }, // String number
523
578
  });
524
579
  expect(results.length).toBe(1);
525
580
  expect(Number(results[0]?.metadata?.price)).toBeGreaterThan(150);
526
581
  });
527
582
 
528
583
  it('handles mixed numeric and string comparisons', async () => {
529
- const results = await vectorDB.query(testIndexName2, createVector(0, 1.0), 10, {
530
- price: { $gt: 100 },
531
- category: { $in: ['electronics'] },
584
+ const results = await vectorDB.query({
585
+ indexName: testIndexName2,
586
+ queryVector: createVector(0, 1.0),
587
+ filter: { price: { $gt: 100 }, category: { $in: ['electronics'] } },
532
588
  });
533
589
  expect(results.length).toBe(1);
534
590
  expect(Number(results[0]?.metadata?.price)).toBeGreaterThan(100);
@@ -538,16 +594,20 @@ describe('CloudflareVector', () => {
538
594
 
539
595
  describe('Filter Validation and Edge Cases', () => {
540
596
  it('handles numeric zero values correctly', async () => {
541
- const results = await vectorDB.query(testIndexName2, createVector(0, 1.0), 10, {
542
- rating: { $eq: 0 },
597
+ const results = await vectorDB.query({
598
+ indexName: testIndexName2,
599
+ queryVector: createVector(0, 1.0),
600
+ filter: { rating: { $eq: 0 } },
543
601
  });
544
602
  expect(results.length).toBe(1);
545
603
  expect(results[0]?.metadata?.rating).toBe(0);
546
604
  });
547
605
 
548
606
  it('handles multiple conditions on same field', async () => {
549
- const results = await vectorDB.query(testIndexName2, createVector(0, 1.0), 10, {
550
- price: { $gt: 75, $lt: 200 },
607
+ const results = await vectorDB.query({
608
+ indexName: testIndexName2,
609
+ queryVector: createVector(0, 1.0),
610
+ filter: { price: { $gt: 75, $lt: 200 } },
551
611
  });
552
612
  expect(results.length).toBe(2);
553
613
  results.forEach(result => {
@@ -558,16 +618,20 @@ describe('CloudflareVector', () => {
558
618
  });
559
619
 
560
620
  it('handles exact numeric equality', async () => {
561
- const results = await vectorDB.query(testIndexName2, createVector(0, 1.0), 10, {
562
- price: { $eq: 100 },
621
+ const results = await vectorDB.query({
622
+ indexName: testIndexName2,
623
+ queryVector: createVector(0, 1.0),
624
+ filter: { price: { $eq: 100 } },
563
625
  });
564
626
  expect(results.length).toBe(1);
565
627
  expect(results[0]?.metadata?.price).toBe(100);
566
628
  });
567
629
 
568
630
  it('handles boundary conditions in ranges', async () => {
569
- const results = await vectorDB.query(testIndexName2, createVector(0, 1.0), 10, {
570
- price: { $gte: 75, $lte: 75 },
631
+ const results = await vectorDB.query({
632
+ indexName: testIndexName2,
633
+ queryVector: createVector(0, 1.0),
634
+ filter: { price: { $gte: 75, $lte: 75 } },
571
635
  });
572
636
  expect(results.length).toBe(1);
573
637
  expect(results[0]?.metadata?.price).toBe(75);
@@ -576,16 +640,20 @@ describe('CloudflareVector', () => {
576
640
 
577
641
  describe('String Range Queries', () => {
578
642
  it('handles lexicographical ordering in string range queries', async () => {
579
- const results = await vectorDB.query(testIndexName2, createVector(0, 1.0), 10, {
580
- code: { $gt: 'A123', $lt: 'C789' },
643
+ const results = await vectorDB.query({
644
+ indexName: testIndexName2,
645
+ queryVector: createVector(0, 1.0),
646
+ filter: { code: { $gt: 'A123', $lt: 'C789' } },
581
647
  });
582
648
  expect(results.length).toBe(1);
583
649
  expect(results[0]?.metadata?.code).toBe('B456');
584
650
  }, 5000);
585
651
 
586
652
  it('handles string range queries with special characters', async () => {
587
- const results = await vectorDB.query(testIndexName2, createVector(0, 1.0), 10, {
588
- code: { $gte: 'A', $lt: 'C' },
653
+ const results = await vectorDB.query({
654
+ indexName: testIndexName2,
655
+ queryVector: createVector(0, 1.0),
656
+ filter: { code: { $gte: 'A', $lt: 'C' } },
589
657
  });
590
658
  expect(results.length).toBe(2);
591
659
  results.forEach(result => {
@@ -596,15 +664,19 @@ describe('CloudflareVector', () => {
596
664
 
597
665
  describe('Null and Special Values', () => {
598
666
  it('handles $in with null values', async () => {
599
- const results = await vectorDB.query(testIndexName2, createVector(0, 1.0), 10, {
600
- optionalField: { $in: [null, 'exists'] },
667
+ const results = await vectorDB.query({
668
+ indexName: testIndexName2,
669
+ queryVector: createVector(0, 1.0),
670
+ filter: { optionalField: { $in: [null, 'exists'] } },
601
671
  });
602
672
  expect(results.length).toBe(1);
603
673
  }, 5000);
604
674
 
605
675
  it('handles $ne with null values', async () => {
606
- const results = await vectorDB.query(testIndexName2, createVector(0, 1.0), 10, {
607
- optionalField: { $ne: null },
676
+ const results = await vectorDB.query({
677
+ indexName: testIndexName2,
678
+ queryVector: createVector(0, 1.0),
679
+ filter: { optionalField: { $ne: null } },
608
680
  });
609
681
  expect(results.length).toBe(4);
610
682
  expect(results[0]?.metadata?.optionalField).toBe('exists');
@@ -613,16 +685,19 @@ describe('CloudflareVector', () => {
613
685
 
614
686
  describe('Mixed Type Arrays and Values', () => {
615
687
  it('handles $in with mixed type arrays', async () => {
616
- const results = await vectorDB.query(testIndexName2, createVector(0, 1.0), 10, {
617
- mixedField: { $in: ['string value', 10, null] },
688
+ const results = await vectorDB.query({
689
+ indexName: testIndexName2,
690
+ queryVector: createVector(0, 1.0),
691
+ filter: { mixedField: { $in: ['string value', 10, null] } },
618
692
  });
619
693
  expect(results.length).toBe(2);
620
694
  }, 5000);
621
695
 
622
696
  it('combines different types of filters', async () => {
623
- const results = await vectorDB.query(testIndexName2, createVector(0, 1.0), 10, {
624
- mixedField: { $in: ['string value', true] },
625
- price: { $eq: 100 },
697
+ const results = await vectorDB.query({
698
+ indexName: testIndexName2,
699
+ queryVector: createVector(0, 1.0),
700
+ filter: { mixedField: { $in: ['string value', true] }, price: { $eq: 100 } },
626
701
  });
627
702
  expect(results.length).toBe(1);
628
703
  }, 5000);
@@ -638,7 +713,13 @@ describe('CloudflareVector', () => {
638
713
  'nested.string': longString.slice(0, 200),
639
714
  };
640
715
 
641
- await expect(vectorDB.query(testIndexName2, createVector(0, 1.0), 10, filter)).resolves.toBeDefined();
716
+ await expect(
717
+ vectorDB.query({
718
+ indexName: testIndexName2,
719
+ queryVector: createVector(0, 1.0),
720
+ filter,
721
+ }),
722
+ ).resolves.toBeDefined();
642
723
  }, 5000);
643
724
 
644
725
  it('handles valid range query combinations', async () => {
@@ -650,30 +731,201 @@ describe('CloudflareVector', () => {
650
731
  ];
651
732
 
652
733
  for (const filter of validRangeCombinations) {
653
- await expect(vectorDB.query(testIndexName2, createVector(0, 1.0), 10, filter)).resolves.toBeDefined();
734
+ await expect(
735
+ vectorDB.query({
736
+ indexName: testIndexName2,
737
+ queryVector: createVector(0, 1.0),
738
+ filter,
739
+ }),
740
+ ).resolves.toBeDefined();
654
741
  }
655
742
  }, 5000);
656
743
 
657
744
  it('should handle undefined filter', async () => {
658
- const results1 = await vectorDB.query(testIndexName2, createVector(0, 1.0), 10, undefined);
659
- const results2 = await vectorDB.query(testIndexName2, createVector(0, 1.0), 10);
745
+ const results1 = await vectorDB.query({
746
+ indexName: testIndexName2,
747
+ queryVector: createVector(0, 1.0),
748
+ filter: undefined,
749
+ });
750
+ const results2 = await vectorDB.query({
751
+ indexName: testIndexName2,
752
+ queryVector: createVector(0, 1.0),
753
+ });
660
754
  expect(results1).toEqual(results2);
661
755
  expect(results1.length).toBeGreaterThan(0);
662
756
  });
663
757
 
664
758
  it('should handle empty object filter', async () => {
665
- const results = await vectorDB.query(testIndexName2, createVector(0, 1.0), 10, {});
666
- const results2 = await vectorDB.query(testIndexName2, createVector(0, 1.0), 10);
759
+ const results = await vectorDB.query({
760
+ indexName: testIndexName2,
761
+ queryVector: createVector(0, 1.0),
762
+ filter: {},
763
+ });
764
+ const results2 = await vectorDB.query({
765
+ indexName: testIndexName2,
766
+ queryVector: createVector(0, 1.0),
767
+ });
667
768
  expect(results).toEqual(results2);
668
769
  expect(results.length).toBeGreaterThan(0);
669
770
  });
670
771
 
671
772
  it('should handle null filter', async () => {
672
- const results = await vectorDB.query(testIndexName2, createVector(0, 1.0), 10, null as any);
673
- const results2 = await vectorDB.query(testIndexName2, createVector(0, 1.0), 10);
773
+ const results = await vectorDB.query({
774
+ indexName: testIndexName2,
775
+ queryVector: createVector(0, 1.0),
776
+ filter: null,
777
+ });
778
+ const results2 = await vectorDB.query({
779
+ indexName: testIndexName2,
780
+ queryVector: createVector(0, 1.0),
781
+ });
674
782
  expect(results).toEqual(results2);
675
783
  expect(results.length).toBeGreaterThan(0);
676
784
  });
677
785
  });
678
- }, 3000000);
786
+ }, 800000);
787
+ describe('Deprecation Warnings', () => {
788
+ const indexName = 'testdeprecationwarnings';
789
+
790
+ const indexName2 = 'testdeprecationwarnings2';
791
+
792
+ const indexName3 = 'testdeprecationwarnings3';
793
+
794
+ const indexName4 = 'testdeprecationwarnings4';
795
+
796
+ let warnSpy;
797
+
798
+ beforeAll(async () => {
799
+ try {
800
+ await vectorDB.deleteIndex(indexName);
801
+ } catch {
802
+ // Ignore errors if index doesn't exist
803
+ }
804
+ try {
805
+ await vectorDB.deleteIndex(indexName2);
806
+ } catch {
807
+ // Ignore errors if index doesn't exist
808
+ }
809
+ try {
810
+ await vectorDB.deleteIndex(indexName3);
811
+ } catch {
812
+ // Ignore errors if index doesn't exist
813
+ }
814
+ try {
815
+ await vectorDB.deleteIndex(indexName4);
816
+ } catch {
817
+ // Ignore errors if index doesn't exist
818
+ }
819
+ await vectorDB.createIndex({ indexName: indexName, dimension: VECTOR_DIMENSION });
820
+ await waitUntilReady(vectorDB, indexName);
821
+ });
822
+
823
+ afterAll(async () => {
824
+ try {
825
+ await vectorDB.deleteIndex(indexName);
826
+ } catch {
827
+ // Ignore errors if index doesn't exist
828
+ }
829
+ try {
830
+ await vectorDB.deleteIndex(indexName2);
831
+ } catch {
832
+ // Ignore errors if index doesn't exist
833
+ }
834
+ try {
835
+ await vectorDB.deleteIndex(indexName3);
836
+ } catch {
837
+ // Ignore errors if index doesn't exist
838
+ }
839
+ try {
840
+ await vectorDB.deleteIndex(indexName4);
841
+ } catch {
842
+ // Ignore errors if index doesn't exist
843
+ }
844
+ });
845
+
846
+ beforeEach(async () => {
847
+ warnSpy = vi.spyOn(vectorDB['logger'], 'warn');
848
+ });
849
+
850
+ afterEach(async () => {
851
+ warnSpy.mockRestore();
852
+ try {
853
+ await vectorDB.deleteIndex(indexName2);
854
+ } catch (error) {
855
+ console.warn('Failed to delete test index:', error);
856
+ }
857
+ });
858
+
859
+ it('should show deprecation warning when using individual args for createIndex', async () => {
860
+ await vectorDB.createIndex(indexName2, VECTOR_DIMENSION, 'cosine');
861
+ await waitUntilReady(vectorDB, indexName2);
862
+ expect(warnSpy).toHaveBeenCalledWith(
863
+ expect.stringContaining('Deprecation Warning: Passing individual arguments to createIndex() is deprecated'),
864
+ );
865
+ });
866
+
867
+ it('should show deprecation warning when using individual args for upsert', async () => {
868
+ await vectorDB.upsert(indexName, [createVector(0, 1.0)], [{ test: 'data' }]);
869
+
870
+ expect(warnSpy).toHaveBeenCalledWith(
871
+ expect.stringContaining('Deprecation Warning: Passing individual arguments to upsert() is deprecated'),
872
+ );
873
+ });
874
+
875
+ it('should show deprecation warning when using individual args for query', async () => {
876
+ await vectorDB.query(indexName, createVector(0, 1.0), 5);
877
+
878
+ expect(warnSpy).toHaveBeenCalledWith(
879
+ expect.stringContaining('Deprecation Warning: Passing individual arguments to query() is deprecated'),
880
+ );
881
+ });
882
+
883
+ it('should not show deprecation warning when using object param for query', async () => {
884
+ await vectorDB.query({
885
+ indexName,
886
+ queryVector: createVector(0, 1.0),
887
+ topK: 5,
888
+ });
889
+
890
+ expect(warnSpy).not.toHaveBeenCalled();
891
+ });
892
+
893
+ it('should not show deprecation warning when using object param for createIndex', async () => {
894
+ await vectorDB.createIndex({
895
+ indexName: indexName3,
896
+ dimension: VECTOR_DIMENSION,
897
+ metric: 'cosine',
898
+ });
899
+
900
+ expect(warnSpy).not.toHaveBeenCalled();
901
+ });
902
+
903
+ it('should not show deprecation warning when using object param for upsert', async () => {
904
+ await vectorDB.upsert({
905
+ indexName,
906
+ vectors: [createVector(0, 1.0)],
907
+ metadata: [{ test: 'data' }],
908
+ });
909
+
910
+ expect(warnSpy).not.toHaveBeenCalled();
911
+ });
912
+
913
+ it('should maintain backward compatibility with individual args', async () => {
914
+ // Query
915
+ const queryResults = await vectorDB.query(indexName, createVector(0, 1.0), 5);
916
+ expect(Array.isArray(queryResults)).toBe(true);
917
+
918
+ // CreateIndex
919
+ await expect(vectorDB.createIndex(indexName4, VECTOR_DIMENSION, 'cosine')).resolves.not.toThrow();
920
+ await waitUntilReady(vectorDB, indexName4);
921
+ // Upsert
922
+ const upsertResults = await vectorDB.upsert({
923
+ indexName,
924
+ vectors: [createVector(0, 1.0)],
925
+ metadata: [{ test: 'data' }],
926
+ });
927
+ expect(Array.isArray(upsertResults)).toBe(true);
928
+ expect(upsertResults).toHaveLength(1);
929
+ });
930
+ }, 80000);
679
931
  });
@@ -1,6 +1,12 @@
1
- import type { Filter } from '@mastra/core/filter';
2
1
  import { MastraVector } from '@mastra/core/vector';
3
- import type { QueryResult } from '@mastra/core/vector';
2
+ import type {
3
+ QueryResult,
4
+ CreateIndexParams,
5
+ UpsertVectorParams,
6
+ QueryVectorParams,
7
+ ParamsToArgs,
8
+ } from '@mastra/core/vector';
9
+ import type { VectorFilter } from '@mastra/core/vector/filter';
4
10
  import Cloudflare from 'cloudflare';
5
11
 
6
12
  import { VectorizeFilterTranslator } from './filter';
@@ -18,12 +24,11 @@ export class CloudflareVector extends MastraVector {
18
24
  });
19
25
  }
20
26
 
21
- async upsert(
22
- indexName: string,
23
- vectors: number[][],
24
- metadata?: Record<string, any>[],
25
- ids?: string[],
26
- ): Promise<string[]> {
27
+ async upsert(...args: ParamsToArgs<UpsertVectorParams>): Promise<string[]> {
28
+ const params = this.normalizeArgs<UpsertVectorParams>('upsert', args);
29
+
30
+ const { indexName, vectors, metadata, ids } = params;
31
+
27
32
  const generatedIds = ids || vectors.map(() => crypto.randomUUID());
28
33
 
29
34
  // Create NDJSON string - each line is a JSON object
@@ -52,17 +57,16 @@ export class CloudflareVector extends MastraVector {
52
57
  return generatedIds;
53
58
  }
54
59
 
55
- transformFilter(filter?: Filter) {
60
+ transformFilter(filter?: VectorFilter) {
56
61
  const translator = new VectorizeFilterTranslator();
57
- const translatedFilter = translator.translate(filter);
58
- return translatedFilter;
62
+ return translator.translate(filter);
59
63
  }
60
64
 
61
- async createIndex(
62
- indexName: string,
63
- dimension: number,
64
- metric: 'cosine' | 'euclidean' | 'dotproduct' = 'cosine',
65
- ): Promise<void> {
65
+ async createIndex(...args: ParamsToArgs<CreateIndexParams>): Promise<void> {
66
+ const params = this.normalizeArgs<CreateIndexParams>('createIndex', args);
67
+
68
+ const { indexName, dimension, metric = 'cosine' } = params;
69
+
66
70
  await this.client.vectorize.indexes.create({
67
71
  account_id: this.accountId,
68
72
  config: {
@@ -73,14 +77,12 @@ export class CloudflareVector extends MastraVector {
73
77
  });
74
78
  }
75
79
 
76
- async query(
77
- indexName: string,
78
- queryVector: number[],
79
- topK: number = 10,
80
- filter?: Filter,
81
- includeVector: boolean = false,
82
- ): Promise<QueryResult[]> {
83
- const translatedFilter = this.transformFilter(filter);
80
+ async query(...args: ParamsToArgs<QueryVectorParams>): Promise<QueryResult[]> {
81
+ const params = this.normalizeArgs<QueryVectorParams>('query', args);
82
+
83
+ const { indexName, queryVector, topK = 10, filter, includeVector = false } = params;
84
+
85
+ const translatedFilter = this.transformFilter(filter) ?? {};
84
86
  const response = await this.client.vectorize.indexes.query(indexName, {
85
87
  account_id: this.accountId,
86
88
  vector: queryVector,