@kernl-sdk/turbopuffer 0.1.3 → 0.1.4

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,343 +0,0 @@
1
- import { describe, it, expect, beforeAll, afterAll } from "vitest";
2
- import { TurbopufferSearchIndex } from "../search.js";
3
- const TURBOPUFFER_API_KEY = process.env.TURBOPUFFER_API_KEY;
4
- const TURBOPUFFER_REGION = process.env.TURBOPUFFER_REGION ?? "api";
5
- describe("TurbopufferSearchIndex integration", () => {
6
- if (!TURBOPUFFER_API_KEY) {
7
- it.skip("requires TURBOPUFFER_API_KEY to be set", () => { });
8
- return;
9
- }
10
- let tpuf;
11
- const testIndexId = `kernl-test-${Date.now()}`;
12
- beforeAll(() => {
13
- tpuf = new TurbopufferSearchIndex({
14
- apiKey: TURBOPUFFER_API_KEY,
15
- region: TURBOPUFFER_REGION,
16
- });
17
- });
18
- afterAll(async () => {
19
- // Clean up test index
20
- try {
21
- await tpuf.deleteIndex(testIndexId);
22
- }
23
- catch {
24
- // Ignore errors if index doesn't exist
25
- }
26
- });
27
- describe("createIndex", () => {
28
- it("creates a new index with schema", async () => {
29
- await tpuf.createIndex({
30
- id: testIndexId,
31
- schema: {
32
- content: { type: "string", fts: true },
33
- vector: { type: "vector", dimensions: 384 },
34
- category: { type: "string", filterable: true },
35
- },
36
- });
37
- // Verify the index was created by describing it
38
- const stats = await tpuf.describeIndex(testIndexId);
39
- expect(stats.id).toBe(testIndexId);
40
- expect(stats.status).toBe("ready");
41
- });
42
- it("throws if vector field is not named 'vector'", async () => {
43
- await expect(tpuf.createIndex({
44
- id: `${testIndexId}-invalid`,
45
- schema: {
46
- embedding: { type: "vector", dimensions: 384 },
47
- },
48
- })).rejects.toThrow(/requires vector fields to be named "vector"/);
49
- });
50
- });
51
- describe("listIndexes", () => {
52
- it("returns a CursorPage of indexes", async () => {
53
- const page = await tpuf.listIndexes();
54
- expect(page).toBeDefined();
55
- expect(page.items).toBeDefined();
56
- expect(Array.isArray(page.items)).toBe(true);
57
- // Each item should have an id
58
- for (const idx of page.items) {
59
- expect(typeof idx.id).toBe("string");
60
- }
61
- });
62
- it("supports pagination with limit", async () => {
63
- const page = await tpuf.listIndexes({ limit: 2 });
64
- expect(page.items.length).toBeLessThanOrEqual(2);
65
- });
66
- it("supports prefix filtering", async () => {
67
- const page = await tpuf.listIndexes({ prefix: "kernl-test-" });
68
- expect(page).toBeDefined();
69
- expect(Array.isArray(page.items)).toBe(true);
70
- // Should find our test index
71
- const found = page.items.some((idx) => idx.id === testIndexId);
72
- expect(found).toBe(true);
73
- // All results should match prefix
74
- for (const idx of page.items) {
75
- expect(idx.id.startsWith("kernl-test-")).toBe(true);
76
- }
77
- });
78
- it("supports async iteration via collect()", async () => {
79
- const page = await tpuf.listIndexes({ limit: 5 });
80
- const all = await page.collect();
81
- expect(Array.isArray(all)).toBe(true);
82
- expect(all.length).toBeGreaterThanOrEqual(page.items.length);
83
- });
84
- it("supports for-await iteration", async () => {
85
- const page = await tpuf.listIndexes({ limit: 3 });
86
- const collected = [];
87
- for await (const idx of page) {
88
- collected.push(idx.id);
89
- if (collected.length >= 3)
90
- break;
91
- }
92
- expect(collected.length).toBeLessThanOrEqual(3);
93
- });
94
- });
95
- describe("describeIndex", () => {
96
- it("returns stats for the test index", async () => {
97
- const stats = await tpuf.describeIndex(testIndexId);
98
- expect(stats.id).toBe(testIndexId);
99
- expect(typeof stats.count).toBe("number");
100
- expect(stats.count).toBeGreaterThanOrEqual(0);
101
- expect(stats.status).toBe("ready");
102
- if (stats.sizeb !== undefined) {
103
- expect(typeof stats.sizeb).toBe("number");
104
- }
105
- });
106
- it("throws for non-existent index", async () => {
107
- await expect(tpuf.describeIndex("non-existent-index-12345")).rejects.toThrow();
108
- });
109
- });
110
- describe("deleteIndex", () => {
111
- it("deletes an existing index", async () => {
112
- // Create a temporary index to delete
113
- const tempId = `kernl-test-delete-${Date.now()}`;
114
- await tpuf.createIndex({
115
- id: tempId,
116
- schema: {
117
- text: { type: "string" },
118
- },
119
- });
120
- // Verify it exists
121
- const stats = await tpuf.describeIndex(tempId);
122
- expect(stats.id).toBe(tempId);
123
- // Delete it
124
- await tpuf.deleteIndex(tempId);
125
- // Verify it's gone
126
- await expect(tpuf.describeIndex(tempId)).rejects.toThrow();
127
- });
128
- });
129
- describe("upsert", () => {
130
- it("inserts a document with vector", async () => {
131
- const vec = new Array(384).fill(0.1);
132
- const index = tpuf.index(testIndexId);
133
- await index.upsert({
134
- id: "doc-1",
135
- fields: {
136
- content: "Hello world",
137
- vector: { kind: "vector", values: vec },
138
- category: "greeting",
139
- },
140
- });
141
- // Verify via query
142
- const hits = await index.query({
143
- query: [{ vector: vec }],
144
- topK: 10,
145
- include: ["category"],
146
- });
147
- expect(hits.length).toBeGreaterThanOrEqual(1);
148
- const doc = hits.find((h) => h.id === "doc-1");
149
- expect(doc).toBeDefined();
150
- expect(doc?.document?.category).toBe("greeting");
151
- });
152
- it("updates an existing document", async () => {
153
- const vec = new Array(384).fill(0.2);
154
- const index = tpuf.index(testIndexId);
155
- // Upsert same id with different content
156
- await index.upsert({
157
- id: "doc-1",
158
- fields: {
159
- content: "Updated content",
160
- vector: { kind: "vector", values: vec },
161
- category: "updated",
162
- },
163
- });
164
- // Verify via query
165
- const hits = await index.query({
166
- query: [{ vector: vec }],
167
- topK: 10,
168
- include: ["category"],
169
- });
170
- const doc = hits.find((h) => h.id === "doc-1");
171
- expect(doc).toBeDefined();
172
- expect(doc?.document?.category).toBe("updated");
173
- });
174
- });
175
- describe("upsert (multiple)", () => {
176
- it("inserts multiple documents", async () => {
177
- const index = tpuf.index(testIndexId);
178
- await index.upsert([
179
- {
180
- id: "doc-2",
181
- fields: {
182
- content: "Second document",
183
- vector: { kind: "vector", values: new Array(384).fill(0.3) },
184
- category: "test",
185
- },
186
- },
187
- {
188
- id: "doc-3",
189
- fields: {
190
- content: "Third document",
191
- vector: { kind: "vector", values: new Array(384).fill(0.4) },
192
- category: "test",
193
- },
194
- },
195
- ]);
196
- // Verify via query with filter
197
- const hits = await index.query({
198
- query: [{ vector: new Array(384).fill(0.3) }],
199
- topK: 10,
200
- filter: { category: "test" },
201
- include: true,
202
- });
203
- expect(hits.length).toBeGreaterThanOrEqual(2);
204
- const ids = hits.map((h) => h.id);
205
- expect(ids).toContain("doc-2");
206
- expect(ids).toContain("doc-3");
207
- });
208
- it("handles empty array", async () => {
209
- const index = tpuf.index(testIndexId);
210
- // Should not throw
211
- await index.upsert([]);
212
- });
213
- });
214
- describe("query", () => {
215
- it("performs vector search", async () => {
216
- const index = tpuf.index(testIndexId);
217
- const hits = await index.query({
218
- query: [{ vector: new Array(384).fill(0.1) }],
219
- topK: 5,
220
- });
221
- expect(hits.length).toBeGreaterThan(0);
222
- expect(hits[0]).toHaveProperty("id");
223
- expect(hits[0]).toHaveProperty("score");
224
- expect(hits[0]).toHaveProperty("index", testIndexId);
225
- });
226
- it("returns requested fields", async () => {
227
- const index = tpuf.index(testIndexId);
228
- const hits = await index.query({
229
- query: [{ vector: new Array(384).fill(0.1) }],
230
- topK: 5,
231
- include: ["content", "category"],
232
- });
233
- expect(hits.length).toBeGreaterThan(0);
234
- expect(hits[0].document).toBeDefined();
235
- expect(hits[0].document).toHaveProperty("content");
236
- expect(hits[0].document).toHaveProperty("category");
237
- });
238
- it("filters results", async () => {
239
- const index = tpuf.index(testIndexId);
240
- const hits = await index.query({
241
- query: [{ vector: new Array(384).fill(0.3) }],
242
- topK: 10,
243
- filter: { category: "test" },
244
- include: ["category"],
245
- });
246
- expect(hits.length).toBeGreaterThan(0);
247
- for (const hit of hits) {
248
- expect(hit.document?.category).toBe("test");
249
- }
250
- });
251
- it("supports AND filters", async () => {
252
- const index = tpuf.index(testIndexId);
253
- const hits = await index.query({
254
- query: [{ vector: new Array(384).fill(0.3) }],
255
- topK: 10,
256
- filter: {
257
- $and: [
258
- { category: "test" },
259
- { id: { $in: ["doc-2", "doc-3"] } },
260
- ],
261
- },
262
- include: ["category"],
263
- });
264
- expect(hits.length).toBeGreaterThanOrEqual(0);
265
- for (const hit of hits) {
266
- expect(hit.document?.category).toBe("test");
267
- }
268
- });
269
- });
270
- describe("delete", () => {
271
- it("deletes a document by id", async () => {
272
- const vec = new Array(384).fill(0.5);
273
- const index = tpuf.index(testIndexId);
274
- // Insert a document to delete
275
- await index.upsert({
276
- id: "doc-to-delete",
277
- fields: {
278
- content: "Delete me",
279
- vector: { kind: "vector", values: vec },
280
- category: "deletable",
281
- },
282
- });
283
- // Verify it exists
284
- let hits = await index.query({
285
- query: [{ vector: vec }],
286
- topK: 10,
287
- filter: { id: "doc-to-delete" },
288
- });
289
- expect(hits.some((h) => h.id === "doc-to-delete")).toBe(true);
290
- // Delete it
291
- await index.delete("doc-to-delete");
292
- // Verify it's gone
293
- hits = await index.query({
294
- query: [{ vector: vec }],
295
- topK: 10,
296
- filter: { id: "doc-to-delete" },
297
- });
298
- expect(hits.some((h) => h.id === "doc-to-delete")).toBe(false);
299
- });
300
- });
301
- describe("delete (multiple)", () => {
302
- it("deletes multiple documents by ids", async () => {
303
- const vec = new Array(384).fill(0.6);
304
- const index = tpuf.index(testIndexId);
305
- // Insert documents to delete
306
- await index.upsert([
307
- {
308
- id: "bulk-del-1",
309
- fields: {
310
- content: "Bulk delete 1",
311
- vector: { kind: "vector", values: vec },
312
- category: "bulk-delete",
313
- },
314
- },
315
- {
316
- id: "bulk-del-2",
317
- fields: {
318
- content: "Bulk delete 2",
319
- vector: { kind: "vector", values: vec },
320
- category: "bulk-delete",
321
- },
322
- },
323
- ]);
324
- // Verify they exist
325
- let hits = await index.query({
326
- query: [{ vector: vec }],
327
- topK: 10,
328
- filter: { category: "bulk-delete" },
329
- });
330
- expect(hits.length).toBeGreaterThanOrEqual(2);
331
- // Delete by ids
332
- await index.delete(["bulk-del-1", "bulk-del-2"]);
333
- // Verify they're gone
334
- hits = await index.query({
335
- query: [{ vector: vec }],
336
- topK: 10,
337
- filter: { category: "bulk-delete" },
338
- });
339
- expect(hits.some((h) => h.id === "bulk-del-1")).toBe(false);
340
- expect(hits.some((h) => h.id === "bulk-del-2")).toBe(false);
341
- });
342
- });
343
- });
@@ -1,8 +0,0 @@
1
- /**
2
- * Index and handle lifecycle edge case integration tests.
3
- *
4
- * Tests edge cases for index lifecycle operations and document handling
5
- * against real Turbopuffer API.
6
- */
7
- export {};
8
- //# sourceMappingURL=lifecycle.integration.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"lifecycle.integration.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/lifecycle.integration.test.ts"],"names":[],"mappings":"AAAA;;;;;GAKG"}