Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@turbopuffer/turbopuffer

Package Overview
Dependencies
Maintainers
3
Versions
23
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@turbopuffer/turbopuffer - npm Package Compare versions

Comparing version 0.4.2 to 0.5.0

dist/httpClient.d.ts

75

dist/turbopuffer.d.ts

@@ -7,3 +7,4 @@ /**

*/
import "isomorphic-fetch";
import type { HTTPClient } from "./httpClient";
export { TurbopufferError } from "./httpClient";
/**

@@ -16,10 +17,8 @@ * Utility Types

export type AttributeType = null | string | number | string[] | number[];
export type Attributes = {
[key: string]: AttributeType;
};
export type Vector = {
export type Attributes = Record<string, AttributeType>;
export interface Vector {
id: Id;
vector?: number[];
attributes?: Attributes;
};
}
export type DistanceMetric = "cosine_distance" | "euclidean_squared";

@@ -37,3 +36,10 @@ export type FilterOperator = "Eq" | "NotEq" | "In" | "NotIn" | "Lt" | "Lte" | "Gt" | "Gte" | "Glob" | "NotGlob" | "IGlob" | "NotIGlob" | "And" | "Or";

}[];
export type NamespaceDesc = {
export type QueryMetrics = {
approx_namespace_size: number;
cache_hit_ratio: number;
cache_temperature: string;
processing_time: number;
exhaustive_search_count: number;
};
export interface NamespaceDesc {
id: string;

@@ -43,41 +49,23 @@ approx_count: number;

created_at: string;
};
export type NamespacesListResult = {
}
export interface NamespacesListResult {
namespaces: NamespaceDesc[];
next_cursor?: string;
};
export type RecallMeasurement = {
}
export interface RecallMeasurement {
avg_recall: number;
avg_exhaustive_count: number;
avg_ann_count: number;
};
export declare class TurbopufferError extends Error {
error: string;
status?: number;
constructor(error: string, { status }: {
status?: number;
});
}
export declare class Turbopuffer {
private baseUrl;
apiKey: string;
constructor({ apiKey, baseUrl, }: {
http: HTTPClient;
constructor({ apiKey, baseUrl, connectTimeout, // timeout to establish a connection
connectionIdleTimeout, // socket idle timeout in ms, default 1 minute
warmConnections, }: {
apiKey: string;
baseUrl?: string;
connectTimeout?: number;
connectionIdleTimeout?: number;
warmConnections?: number;
});
statusCodeShouldRetry(statusCode: number): boolean;
delay(ms: number): Promise<unknown>;
doRequest<T>({ method, path, query, body, compress, retryable, }: {
method: string;
path: string;
query?: {
[key: string]: string | undefined;
};
body?: any;
compress?: boolean;
retryable?: boolean;
}): Promise<{
body?: T;
headers: Headers;
}>;
/**

@@ -131,2 +119,17 @@ * List all your namespaces.

/**
* Queries vectors and returns performance metrics along with the results.
* See: https://turbopuffer.com/docs/reference/query
*/
queryWithMetrics({ ...params }: {
vector?: number[];
distance_metric?: DistanceMetric;
top_k?: number;
include_vectors?: boolean;
include_attributes?: boolean | string[];
filters?: Filters;
}): Promise<{
results: QueryResults;
metrics: QueryMetrics;
}>;
/**
* Export all vectors at full precision.

@@ -133,0 +136,0 @@ * See: https://turbopuffer.com/docs/reference/list

@@ -19,121 +19,36 @@ "use strict";

};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Namespace = exports.Turbopuffer = exports.TurbopufferError = void 0;
const pako_1 = __importDefault(require("pako"));
require("isomorphic-fetch");
const package_json_1 = require("../package.json");
/* Error type */
class TurbopufferError extends Error {
constructor(error, { status }) {
super(error);
this.error = error;
this.status = status;
const httpClient_1 = require("./httpClient");
var httpClient_2 = require("./httpClient");
Object.defineProperty(exports, "TurbopufferError", { enumerable: true, get: function () { return httpClient_2.TurbopufferError; } });
function parseServerTiming(value) {
let output = {};
const sections = value.split(", ");
for (let section of sections) {
let tokens = section.split(";");
let base_key = tokens.shift();
for (let token of tokens) {
let components = token.split("=");
let key = base_key + "." + components[0];
let value = components[1];
output[key] = value;
}
}
return output;
}
exports.TurbopufferError = TurbopufferError;
function parseIntMetric(value) {
return value ? parseInt(value) : 0;
}
function parseFloatMetric(value) {
return value ? parseFloat(value) : 0;
}
/* Base Client */
class Turbopuffer {
constructor({ apiKey, baseUrl = "https://api.turbopuffer.com", }) {
this.baseUrl = baseUrl;
this.apiKey = apiKey;
constructor({ apiKey, baseUrl = "https://api.turbopuffer.com", connectTimeout = 10 * 1000, // timeout to establish a connection
connectionIdleTimeout = 60 * 1000, // socket idle timeout in ms, default 1 minute
warmConnections = 0, // number of connections to open initially when creating a new client
}) {
this.http = (0, httpClient_1.createHTTPClient)(baseUrl, apiKey, connectTimeout, connectionIdleTimeout, warmConnections);
}
statusCodeShouldRetry(statusCode) {
return statusCode >= 500;
}
delay(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
async doRequest({ method, path, query, body, compress, retryable, }) {
const url = new URL(`${this.baseUrl}${path}`);
if (query) {
Object.keys(query).forEach((key) => {
let value = query[key];
if (value) {
url.searchParams.append(key, value);
}
});
}
let headers = {
// eslint-disable-next-line @typescript-eslint/naming-convention
"Accept-Encoding": "gzip",
// eslint-disable-next-line @typescript-eslint/naming-convention
Authorization: `Bearer ${this.apiKey}`,
// eslint-disable-next-line @typescript-eslint/naming-convention
"User-Agent": `tpuf-typescript/${package_json_1.version}`,
};
if (body) {
headers["Content-Type"] = "application/json";
}
let requestBody = null;
if (body && compress) {
headers["Content-Encoding"] = "gzip";
requestBody = pako_1.default.gzip(JSON.stringify(body));
}
else if (body) {
requestBody = JSON.stringify(body);
}
const maxAttempts = retryable ? 3 : 1;
var response;
var error = null;
for (let attempt = 0; attempt < maxAttempts; attempt++) {
response = await fetch(url.toString(), {
method,
headers,
body: requestBody,
});
if (response.status >= 400) {
let message = undefined;
if (response.headers.get("Content-Type") === "application/json") {
try {
let body = await response.json();
if (body && body.status === "error") {
message = body.error;
}
else {
message = JSON.stringify(body);
}
}
catch (_) { }
}
else {
try {
let body = await response.text();
if (body) {
message = body;
}
}
catch (_) { }
}
error = new TurbopufferError(message || response.statusText, { status: response.status });
}
if (error &&
this.statusCodeShouldRetry(response.status) &&
attempt + 1 != maxAttempts) {
await this.delay(150 * (attempt + 1)); // 150ms, 300ms, 450ms
continue;
}
break;
}
if (error) {
throw error;
}
if (!response.body) {
return {
headers: response.headers,
};
}
const json = await response.json();
if (json.status && json.status === "error") {
throw new TurbopufferError(json.error || json, {
status: response.status,
});
}
return {
body: json,
headers: response.headers,
};
}
/**

@@ -144,3 +59,3 @@ * List all your namespaces.

async namespaces({ cursor, page_size, }) {
return (await this.doRequest({
return (await this.http.doRequest({
method: "GET",

@@ -178,3 +93,3 @@ path: "/v1/vectors",

const batch = vectors.slice(i, i + batchSize);
await this.client.doRequest({
await this.client.http.doRequest({
method: "POST",

@@ -195,3 +110,3 @@ path: `/v1/vectors/${this.id}`,

async delete({ ids }) {
await this.client.doRequest({
await this.client.http.doRequest({
method: "POST",

@@ -213,3 +128,12 @@ path: `/v1/vectors/${this.id}`,

var params = __rest(_a, []);
return (await this.client.doRequest({
let resultsWithMetrics = await this.queryWithMetrics(params);
return resultsWithMetrics.results;
}
/**
* Queries vectors and returns performance metrics along with the results.
* See: https://turbopuffer.com/docs/reference/query
*/
async queryWithMetrics(_a) {
var params = __rest(_a, []);
let response = await this.client.http.doRequest({
method: "POST",

@@ -219,3 +143,17 @@ path: `/v1/vectors/${this.id}/query`,

retryable: true,
})).body;
});
const serverTimingStr = response.headers.get("Server-Timing");
const serverTiming = serverTimingStr
? parseServerTiming(serverTimingStr)
: {};
return {
results: response.body,
metrics: {
approx_namespace_size: parseIntMetric(response.headers.get("X-turbopuffer-Approx-Namespace-Size")),
cache_hit_ratio: parseFloatMetric(serverTiming["cache.hit_ratio"]),
cache_temperature: serverTiming["cache.temperature"],
processing_time: parseIntMetric(serverTiming["processing_time.dur"]),
exhaustive_search_count: parseIntMetric(serverTiming["exhaustive_search.count"]),
},
};
}

@@ -227,3 +165,3 @@ /**

async export(params) {
let response = await this.client.doRequest({
const response = await this.client.http.doRequest({
method: "GET",

@@ -244,3 +182,3 @@ path: `/v1/vectors/${this.id}`,

async approxNumVectors() {
let response = await this.client.doRequest({
const response = await this.client.http.doRequest({
method: "HEAD",

@@ -250,3 +188,3 @@ path: `/v1/vectors/${this.id}`,

});
let num = response.headers.get("X-turbopuffer-Approx-Num-Vectors");
const num = response.headers.get("X-turbopuffer-Approx-Num-Vectors");
return num ? parseInt(num) : 0;

@@ -259,3 +197,3 @@ }

async deleteAll() {
await this.client.doRequest({
await this.client.http.doRequest({
method: "DELETE",

@@ -271,3 +209,3 @@ path: `/v1/vectors/${this.id}`,

async recall({ num, top_k, filters, queries, }) {
return (await this.client.doRequest({
return (await this.client.http.doRequest({
method: "POST",

@@ -298,5 +236,6 @@ path: `/v1/vectors/${this.id}/_debug/recall`,

}
let attributes = {};
const attributes = {};
vectors.forEach((vec, i) => {
for (let [key, val] of Object.entries(vec.attributes || {})) {
var _a;
for (const [key, val] of Object.entries((_a = vec.attributes) !== null && _a !== void 0 ? _a : {})) {
if (!attributes[key]) {

@@ -315,4 +254,5 @@ attributes[key] = new Array(vectors.length).fill(null);

function fromColumnar(cv) {
let res = new Array(cv.ids.length);
const attributeEntries = Object.entries(cv.attributes || {});
var _a;
const res = new Array(cv.ids.length);
const attributeEntries = Object.entries((_a = cv.attributes) !== null && _a !== void 0 ? _a : {});
for (let i = 0; i < cv.ids.length; i++) {

@@ -319,0 +259,0 @@ res[i] = {

{
"name": "@turbopuffer/turbopuffer",
"version": "0.4.2",
"version": "0.5.0",
"description": "Official Typescript API client library for turbopuffer.com",

@@ -9,3 +9,3 @@ "scripts": {

"postinstall:workspaces": "npm run build",
"test": "jest --config jest_node.config.js && jest --config jest_jsdom.config.js",
"test": "jest --config jest_node.config.js",
"format": "prettier --check . --ignore-path ./.gitignore",

@@ -36,3 +36,2 @@ "format:fix": "prettier --check . --ignore-path ./.gitignore --write",

"devDependencies": {
"@types/isomorphic-fetch": "^0.0.39",
"@types/jest": "^29.5.12",

@@ -45,3 +44,2 @@ "@types/pako": "^2.0.3",

"jest": "^29.7.0",
"jest-environment-jsdom": "^29.7.0",
"prettier": "^3.2.5",

@@ -52,5 +50,5 @@ "ts-jest": "^29.1.2",

"dependencies": {
"isomorphic-fetch": "^3.0.0",
"pako": "^2.1.0"
"pako": "^2.1.0",
"undici": "^6.13.0"
}
}

@@ -13,2 +13,4 @@ The **official TypeScript SDK** for Turbopuffer.

// Make a new client
// Connections are pooled for the lifetime of the client
// We recommend creating a single instance and reusing it for all calls
const tpuf = new Turbopuffer({

@@ -15,0 +17,0 @@ apiKey: process.env.TURBOPUFFER_API_KEY as string,

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc