exa-js
Version:
Exa SDK for Node.js and the browser
1,722 lines (1,704 loc) • 77.3 kB
JavaScript
// src/index.ts
import fetch2, { Headers } from "cross-fetch";
// package.json
var package_default = {
name: "exa-js",
version: "2.16.0",
description: "Exa SDK for Node.js and the browser",
publishConfig: {
access: "public"
},
files: [
"dist"
],
main: "./dist/index.js",
module: "./dist/index.mjs",
exports: {
".": {
types: "./dist/index.d.ts",
require: "./dist/index.js",
module: "./dist/index.mjs",
import: "./dist/index.mjs"
},
"./package.json": "./package.json"
},
types: "./dist/index.d.ts",
scripts: {
"build-fast": "tsup src/index.ts --format cjs,esm",
build: "tsup",
test: "vitest run",
"test:unit": "vitest run --config vitest.unit.config.ts",
"test:integration": "vitest run --config vitest.integration.config.ts",
typecheck: "tsc --noEmit",
"typecheck:examples": "tsc -p examples/tsconfig.json --noEmit",
"generate:types:websets": "openapi-typescript https://raw.githubusercontent.com/exa-labs/openapi-spec/refs/heads/master/exa-websets-spec.yaml --enum --root-types --alphabetize --root-types-no-schema-prefix --output ./src/websets/openapi.ts && npm run format:websets",
format: 'prettier --write "src/**/*.ts" "examples/**/*.ts"',
"format:websets": "prettier --write src/websets/openapi.ts",
"generate-docs": "npx tsx scripts/generate-docs.ts",
"build:beta": "cross-env NPM_CONFIG_TAG=beta npm run build",
"version:beta": "npm version prerelease --preid=beta",
"version:stable": "npm version patch",
"publish:beta": "npm run version:beta && npm run build:beta && npm publish --tag beta",
"publish:stable": "npm run version:stable && npm run build && npm publish",
prepublishOnly: "npm run build"
},
license: "MIT",
devDependencies: {
"@types/node": "~22.14.0",
"cross-env": "~7.0.3",
"openapi-typescript": "~7.6.1",
prettier: "~3.5.3",
"ts-morph": "^27.0.2",
"ts-node": "~10.9.2",
tsup: "~8.4.0",
tsx: "^4.21.0",
typescript: "~5.8.3",
vitest: "~3.1.1"
},
dependencies: {
"cross-fetch": "~4.1.0",
dotenv: "~16.4.7",
openai: "^5.0.1",
zod: "^3.22.0",
"zod-to-json-schema": "^3.20.0"
},
directories: {
test: "test"
},
repository: {
type: "git",
url: "git+https://github.com/exa-labs/exa-js.git"
},
keywords: [
"exa",
"metaphor",
"search",
"AI",
"LLMs",
"RAG",
"retrieval",
"augmented",
"generation"
],
author: "jeffzwang",
bugs: {
url: "https://github.com/exa-labs/exa-js/issues"
},
homepage: "https://github.com/exa-labs/exa-js#readme"
};
// src/errors.ts
var HttpStatusCode = /* @__PURE__ */ ((HttpStatusCode2) => {
HttpStatusCode2[HttpStatusCode2["BadRequest"] = 400] = "BadRequest";
HttpStatusCode2[HttpStatusCode2["NotFound"] = 404] = "NotFound";
HttpStatusCode2[HttpStatusCode2["Unauthorized"] = 401] = "Unauthorized";
HttpStatusCode2[HttpStatusCode2["Forbidden"] = 403] = "Forbidden";
HttpStatusCode2[HttpStatusCode2["TooManyRequests"] = 429] = "TooManyRequests";
HttpStatusCode2[HttpStatusCode2["RequestTimeout"] = 408] = "RequestTimeout";
HttpStatusCode2[HttpStatusCode2["InternalServerError"] = 500] = "InternalServerError";
HttpStatusCode2[HttpStatusCode2["ServiceUnavailable"] = 503] = "ServiceUnavailable";
return HttpStatusCode2;
})(HttpStatusCode || {});
var ExaError = class extends Error {
/**
* Create a new ExaError
* @param message Error message
* @param statusCode HTTP status code
* @param timestamp ISO timestamp from API
* @param path Path that caused the error
*/
constructor(message, statusCode, timestamp, path) {
super(message);
this.name = "ExaError";
this.statusCode = statusCode;
this.timestamp = timestamp ?? (/* @__PURE__ */ new Date()).toISOString();
this.path = path;
}
};
// src/zod-utils.ts
import { ZodType } from "zod";
import { zodToJsonSchema as convertZodToJsonSchema } from "zod-to-json-schema";
function isZodSchema(obj) {
return obj instanceof ZodType;
}
function zodToJsonSchema(schema) {
return convertZodToJsonSchema(schema, {
$refStrategy: "none"
});
}
// src/agent/base.ts
var AgentBaseClient = class {
constructor(client) {
this.client = client;
}
async request(endpoint, method = "POST", data, params, headers) {
return this.client.request(
`/agent/runs${endpoint}`,
method,
data,
params,
headers
);
}
async rawRequest(endpoint, method = "POST", data, params, headers) {
return this.client.rawRequest(
`/agent/runs${endpoint}`,
method,
data,
params,
headers
);
}
buildPaginationParams(pagination) {
const params = {};
if (!pagination) return params;
if (pagination.cursor) params.cursor = pagination.cursor;
if (pagination.limit) params.limit = pagination.limit;
return params;
}
};
// src/agent/client.ts
var DEFAULT_AGENT_POLL_INTERVAL_MS = 1e3;
var DEFAULT_AGENT_POLL_TIMEOUT_MS = 60 * 60 * 1e3;
var DEFAULT_AGENT_CREATE_AND_WAIT_TIMEOUT_MS = 2 * 60 * 1e3;
var TERMINAL_AGENT_RUN_STATUSES = /* @__PURE__ */ new Set([
"completed",
"failed",
"cancelled"
]);
var AgentRunFailedError = class extends Error {
constructor(run) {
super(run.error?.message ?? `Agent run ${run.id} failed`);
this.name = "AgentRunFailedError";
this.run = run;
}
};
var AgentRunCancelledError = class extends Error {
constructor(run) {
super(`Agent run ${run.id} was cancelled`);
this.name = "AgentRunCancelledError";
this.run = run;
}
};
function headersForBetas(betas) {
const betaValues = betas?.filter(Boolean);
if (!betaValues?.length) return void 0;
return { "Exa-Beta": betaValues.join(",") };
}
function isTerminalAgentRunStatus(status) {
return TERMINAL_AGENT_RUN_STATUSES.has(status);
}
function ensureCompletedRun(run) {
if (run.status === "failed") {
throw new AgentRunFailedError(run);
}
if (run.status === "cancelled") {
throw new AgentRunCancelledError(run);
}
return run;
}
function createAndWaitPollOptions(options) {
return {
pollInterval: options?.pollInterval ?? DEFAULT_AGENT_POLL_INTERVAL_MS,
timeoutMs: options?.timeoutMs ?? DEFAULT_AGENT_CREATE_AND_WAIT_TIMEOUT_MS
};
}
function buildAgentRunPayload(params) {
const { stream, outputSchema, ...rest } = params;
let schema = outputSchema;
if (schema && isZodSchema(schema)) {
schema = zodToJsonSchema(schema);
}
const payload = { ...rest };
if (schema) {
payload.outputSchema = schema;
}
return { stream, payload };
}
async function* streamAgentEvents(response) {
if (!response.body) {
throw new Error("No response body for SSE stream");
}
const reader = response.body.getReader();
const decoder = new TextDecoder();
let buffer = "";
let doneReading = false;
const processPart = (part) => {
const event = {};
const dataLines = [];
for (const line of part.split("\n")) {
if (!line || !line.includes(":")) continue;
const [field, ...rest] = line.split(":");
const value = rest.join(":").replace(/^ /, "");
if (field === "id") event.id = value;
if (field === "event") event.event = value;
if (field === "data") dataLines.push(value);
}
if (!event.event || dataLines.length === 0) return null;
try {
event.data = JSON.parse(dataLines.join("\n"));
} catch {
event.data = { value: dataLines.join("\n") };
}
return event;
};
try {
while (true) {
const { done, value } = await reader.read();
if (done) {
doneReading = true;
break;
}
buffer += decoder.decode(value, { stream: true });
const parts = buffer.split("\n\n");
buffer = parts.pop() ?? "";
for (const part of parts) {
const event = processPart(part);
if (event) yield event;
}
}
if (buffer.trim()) {
const event = processPart(buffer.trim());
if (event) yield event;
}
} finally {
if (!doneReading) {
await reader.cancel();
}
reader.releaseLock();
}
}
var AgentRunEventsClient = class extends AgentBaseClient {
/**
* List stored events for an Agent run.
*/
async list(runId, options) {
const params = this.buildPaginationParams(options);
return this.request(
`/${runId}/events`,
"GET",
void 0,
params
);
}
};
var AgentRunsClient = class extends AgentBaseClient {
constructor(client) {
super(client);
this.events = new AgentRunEventsClient(client);
}
async create(params) {
const { stream, payload } = buildAgentRunPayload(params);
if (stream) {
const response = await this.rawRequest("", "POST", payload, void 0, {
Accept: "text/event-stream"
});
if (!response.ok) {
const message = await response.text();
throw new ExaError(
message || `Request failed with status code ${response.status}`,
response.status,
(/* @__PURE__ */ new Date()).toISOString(),
"/agent/runs"
);
}
return streamAgentEvents(response);
}
return this.request("", "POST", payload);
}
/**
* Get an Agent run by ID.
*/
async get(runId) {
return this.request(`/${runId}`, "GET");
}
/**
* List Agent runs.
*/
async list(options) {
const params = this.buildPaginationParams(options);
return this.request("", "GET", void 0, params);
}
/**
* Iterate through all Agent runs, handling pagination automatically.
*/
async *listAll(options) {
let cursor = void 0;
const pageOptions = options ? { ...options } : {};
while (true) {
pageOptions.cursor = cursor;
const response = await this.list(pageOptions);
for (const run of response.data) {
yield run;
}
if (!response.hasMore || !response.nextCursor) {
break;
}
cursor = response.nextCursor;
}
}
/**
* Collect all Agent runs into an array.
*/
async getAll(options) {
const runs = [];
for await (const run of this.listAll(options)) {
runs.push(run);
}
return runs;
}
/**
* Cancel a queued or running Agent run.
*/
async cancel(runId) {
return this.request(`/${runId}/cancel`, "POST");
}
/**
* Delete a stored Agent run.
*/
async delete(runId) {
return this.request(`/${runId}`, "DELETE");
}
/**
* Poll an Agent run until it reaches a terminal status.
*/
async pollUntilFinished(runId, options) {
const pollInterval = options?.pollInterval ?? DEFAULT_AGENT_POLL_INTERVAL_MS;
const timeoutMs = options?.timeoutMs ?? DEFAULT_AGENT_POLL_TIMEOUT_MS;
const startTime = Date.now();
while (true) {
const run = await this.get(runId);
if (isTerminalAgentRunStatus(run.status)) {
return run;
}
if (Date.now() - startTime > timeoutMs) {
throw new Error(
`Polling timeout: Agent run ${runId} did not complete within ${timeoutMs}ms`
);
}
await new Promise((resolve) => setTimeout(resolve, pollInterval));
}
}
async createAndWait(params, options) {
const { stream: _stream, ...createParams } = params;
const run = await this.create(
createParams
);
const runId = run.id;
const terminalRun = await this.pollUntilFinished(
runId,
createAndWaitPollOptions(options)
);
return ensureCompletedRun(terminalRun);
}
};
var AgentClient = class {
constructor(client) {
this.client = client;
this.runs = new AgentRunsClient(client);
}
};
var AgentBetaRunEventsClient = class extends AgentRunEventsClient {
/**
* List stored events for an Agent run.
*
* @deprecated Use exa.agent.runs.events instead.
*/
async list(runId, options) {
const { betas, ...pagination } = options ?? {};
const params = this.buildPaginationParams(pagination);
return this.request(
`/${runId}/events`,
"GET",
void 0,
params,
headersForBetas(betas)
);
}
};
var AgentBetaRunsClient = class extends AgentRunsClient {
constructor(client) {
super(client);
this.events = new AgentBetaRunEventsClient(client);
}
async create(params) {
const { betas, ...createParams } = params;
const { stream, payload } = buildAgentRunPayload(
createParams
);
const headers = headersForBetas(betas);
if (stream) {
const response = await this.rawRequest("", "POST", payload, void 0, {
...headers,
Accept: "text/event-stream"
});
if (!response.ok) {
const message = await response.text();
throw new ExaError(
message || `Request failed with status code ${response.status}`,
response.status,
(/* @__PURE__ */ new Date()).toISOString(),
"/agent/runs"
);
}
return streamAgentEvents(response);
}
return this.request(
"",
"POST",
payload,
void 0,
headers
);
}
async get(runId, options) {
return this.request(
`/${runId}`,
"GET",
void 0,
void 0,
headersForBetas(options?.betas)
);
}
async list(options) {
const { betas, ...pagination } = options ?? {};
const params = this.buildPaginationParams(pagination);
return this.request(
"",
"GET",
void 0,
params,
headersForBetas(betas)
);
}
async *listAll(options) {
let cursor = void 0;
const { betas, ...pagination } = options ?? {};
const pageOptions = { ...pagination };
while (true) {
pageOptions.cursor = cursor;
const response = await this.list({ ...pageOptions, betas });
for (const run of response.data) {
yield run;
}
if (!response.hasMore || !response.nextCursor) {
break;
}
cursor = response.nextCursor;
}
}
async getAll(options) {
const runs = [];
for await (const run of this.listAll(options)) {
runs.push(run);
}
return runs;
}
async cancel(runId, options) {
return this.request(
`/${runId}/cancel`,
"POST",
void 0,
void 0,
headersForBetas(options?.betas)
);
}
async delete(runId, options) {
return this.request(
`/${runId}`,
"DELETE",
void 0,
void 0,
headersForBetas(options?.betas)
);
}
async pollUntilFinished(runId, options) {
const pollInterval = options?.pollInterval ?? DEFAULT_AGENT_POLL_INTERVAL_MS;
const timeoutMs = options?.timeoutMs ?? DEFAULT_AGENT_POLL_TIMEOUT_MS;
const startTime = Date.now();
const headers = headersForBetas(options?.betas);
while (true) {
const run = await this.request(
`/${runId}`,
"GET",
void 0,
void 0,
headers
);
if (isTerminalAgentRunStatus(run.status)) {
return run;
}
if (Date.now() - startTime > timeoutMs) {
throw new Error(
`Polling timeout: Agent run ${runId} did not complete within ${timeoutMs}ms`
);
}
await new Promise((resolve) => setTimeout(resolve, pollInterval));
}
}
async createAndWait(params, options) {
const {
betas,
stream: _stream,
...createParams
} = params;
const run = await this.create({
...createParams,
betas
});
const runId = run.id;
const terminalRun = await this.pollUntilFinished(runId, {
...createAndWaitPollOptions(options),
betas
});
return ensureCompletedRun(terminalRun);
}
};
var AgentBetaClient = class extends AgentClient {
constructor(clientOrAgent) {
const client = clientOrAgent instanceof AgentClient ? clientOrAgent.client : clientOrAgent;
super(client);
this.runs = new AgentBetaRunsClient(client);
}
};
var BetaClient = class {
constructor(clientOrAgent) {
this.agent = new AgentBetaClient(clientOrAgent);
}
};
// src/monitors/base.ts
var SearchMonitorsBaseClient = class {
constructor(client) {
this.client = client;
}
async request(endpoint, method = "POST", data, params) {
return this.client.request(
`/monitors${endpoint}`,
method,
data,
params
);
}
buildPaginationParams(pagination) {
const params = {};
if (!pagination) return params;
if (pagination.cursor) params.cursor = pagination.cursor;
if (pagination.limit) params.limit = pagination.limit;
if ("status" in pagination && pagination.status)
params.status = pagination.status;
return params;
}
};
// src/monitors/client.ts
var SearchMonitorRunsClient = class extends SearchMonitorsBaseClient {
/**
* List all runs for a Search Monitor
* @param monitorId The ID of the Search Monitor
* @param options Pagination options
* @returns The list of Search Monitor runs
*/
async list(monitorId, options) {
const params = this.buildPaginationParams(options);
return this.request(
`/${monitorId}/runs`,
"GET",
void 0,
params
);
}
/**
* Get a specific Search Monitor run
* @param monitorId The ID of the Search Monitor
* @param runId The ID of the run
* @returns The Search Monitor run
*/
async get(monitorId, runId) {
return this.request(
`/${monitorId}/runs/${runId}`,
"GET"
);
}
/**
* Iterate through all runs for a Search Monitor, handling pagination automatically
* @param monitorId The ID of the Search Monitor
* @param options Pagination options
* @returns Async generator of Search Monitor runs
*/
async *listAll(monitorId, options) {
let cursor = void 0;
const pageOptions = options ? { ...options } : {};
while (true) {
pageOptions.cursor = cursor;
const response = await this.list(monitorId, pageOptions);
for (const run of response.data) {
yield run;
}
if (!response.hasMore || !response.nextCursor) {
break;
}
cursor = response.nextCursor;
}
}
/**
* Collect all runs for a Search Monitor into an array
* @param monitorId The ID of the Search Monitor
* @param options Pagination options
* @returns Promise resolving to an array of all Search Monitor runs
*/
async getAll(monitorId, options) {
const runs = [];
for await (const run of this.listAll(monitorId, options)) {
runs.push(run);
}
return runs;
}
};
var SearchMonitorsClient = class extends SearchMonitorsBaseClient {
constructor(client) {
super(client);
this.runs = new SearchMonitorRunsClient(client);
}
/**
* Create a Search Monitor
* @param params The monitor creation parameters
* @returns The created Search Monitor with webhookSecret
*/
async create(params) {
return this.request("", "POST", params);
}
/**
* Get a Search Monitor by ID
* @param id The ID of the Search Monitor
* @returns The Search Monitor
*/
async get(id) {
return this.request(`/${id}`, "GET");
}
/**
* List Search Monitors
* @param options Pagination and filtering options
* @returns The list of Search Monitors
*/
async list(options) {
const params = this.buildPaginationParams(options);
return this.request(
"",
"GET",
void 0,
params
);
}
/**
* Update a Search Monitor
* @param id The ID of the Search Monitor
* @param params The update parameters
* @returns The updated Search Monitor
*/
async update(id, params) {
return this.request(`/${id}`, "PATCH", params);
}
/**
* Delete a Search Monitor
* @param id The ID of the Search Monitor
* @returns The deleted Search Monitor
*/
async delete(id) {
return this.request(`/${id}`, "DELETE");
}
/**
* Trigger a Search Monitor run immediately
* @param id The ID of the Search Monitor
* @returns Whether the monitor was triggered
*/
async trigger(id) {
return this.request(
`/${id}/trigger`,
"POST"
);
}
/**
* Iterate through all Search Monitors, handling pagination automatically
* @param options Pagination and filtering options
* @returns Async generator of Search Monitors
*/
async *listAll(options) {
let cursor = void 0;
const pageOptions = options ? { ...options } : {};
while (true) {
pageOptions.cursor = cursor;
const response = await this.list(pageOptions);
for (const monitor of response.data) {
yield monitor;
}
if (!response.hasMore || !response.nextCursor) {
break;
}
cursor = response.nextCursor;
}
}
/**
* Collect all Search Monitors into an array
* @param options Pagination and filtering options
* @returns Promise resolving to an array of all Search Monitors
*/
async getAll(options) {
const monitors = [];
for await (const monitor of this.listAll(options)) {
monitors.push(monitor);
}
return monitors;
}
};
// src/research/base.ts
var ResearchBaseClient = class {
constructor(client) {
this.client = client;
}
async request(endpoint, method = "POST", data, params) {
return this.client.request(
`/research/v1${endpoint}`,
method,
data,
params
);
}
async rawRequest(endpoint, method = "POST", data, params) {
return this.client.rawRequest(
`/research/v1${endpoint}`,
method,
data,
params
);
}
buildPaginationParams(pagination) {
const params = {};
if (!pagination) return params;
if (pagination.cursor) params.cursor = pagination.cursor;
if (pagination.limit) params.limit = pagination.limit;
return params;
}
};
// src/research/client.ts
var ResearchClient = class extends ResearchBaseClient {
constructor(client) {
super(client);
}
async create(params) {
const { instructions, model, outputSchema } = params;
let schema = outputSchema;
if (schema && isZodSchema(schema)) {
schema = zodToJsonSchema(schema);
}
const payload = {
instructions,
model: model ?? "exa-research-fast"
};
if (schema) {
payload.outputSchema = schema;
}
return this.request("", "POST", payload);
}
get(researchId, options) {
if (options?.stream) {
const promise = async () => {
const params = { stream: "true" };
if (options.events !== void 0) {
params.events = options.events.toString();
}
const resp = await this.rawRequest(
`/${researchId}`,
"GET",
void 0,
params
);
if (!resp.body) {
throw new Error("No response body for SSE stream");
}
const reader = resp.body.getReader();
const decoder = new TextDecoder();
let buffer = "";
function processPart(part) {
const lines = part.split("\n");
let data = lines.slice(1).join("\n");
if (data.startsWith("data:")) {
data = data.slice(5).trimStart();
}
try {
return JSON.parse(data);
} catch (e) {
return null;
}
}
async function* streamEvents() {
while (true) {
const { done, value } = await reader.read();
if (done) break;
buffer += decoder.decode(value, { stream: true });
let parts = buffer.split("\n\n");
buffer = parts.pop() ?? "";
for (const part of parts) {
const processed = processPart(part);
if (processed) {
yield processed;
}
}
}
if (buffer.trim()) {
const processed = processPart(buffer.trim());
if (processed) {
yield processed;
}
}
}
return streamEvents();
};
return promise();
} else {
const params = { stream: "false" };
if (options?.events !== void 0) {
params.events = options.events.toString();
}
return this.request(
`/${researchId}`,
"GET",
void 0,
params
);
}
}
async list(options) {
const params = this.buildPaginationParams(options);
return this.request("", "GET", void 0, params);
}
async pollUntilFinished(researchId, options) {
const pollInterval = options?.pollInterval ?? 1e3;
const timeoutMs = options?.timeoutMs ?? 10 * 60 * 1e3;
const maxConsecutiveFailures = 5;
const startTime = Date.now();
let consecutiveFailures = 0;
while (true) {
try {
const research = await this.get(researchId, {
events: options?.events
});
consecutiveFailures = 0;
if (research.status === "completed" || research.status === "failed" || research.status === "canceled") {
return research;
}
} catch (err) {
consecutiveFailures += 1;
if (consecutiveFailures >= maxConsecutiveFailures) {
throw new Error(
`Polling failed ${maxConsecutiveFailures} times in a row for research ${researchId}: ${err}`
);
}
}
if (Date.now() - startTime > timeoutMs) {
throw new Error(
`Polling timeout: Research ${researchId} did not complete within ${timeoutMs}ms`
);
}
await new Promise((resolve) => setTimeout(resolve, pollInterval));
}
}
};
// src/websets/base.ts
var WebsetsBaseClient = class {
/**
* Initialize a new Websets base client
* @param client The Exa client instance
*/
constructor(client) {
this.client = client;
}
/**
* Make a request to the Websets API
* @param endpoint The endpoint path
* @param method The HTTP method
* @param data Optional request body data
* @param params Optional query parameters
* @returns The response JSON
* @throws ExaError with API error details if the request fails
*/
async request(endpoint, method = "POST", data, params, headers) {
return this.client.request(
`/websets${endpoint}`,
method,
data,
params,
headers
);
}
/**
* Helper to build pagination parameters
* @param pagination The pagination parameters
* @returns QueryParams object with pagination parameters
*/
buildPaginationParams(pagination) {
const params = {};
if (!pagination) return params;
if (pagination.cursor) params.cursor = pagination.cursor;
if (pagination.limit) params.limit = pagination.limit;
return params;
}
};
// src/websets/enrichments.ts
var WebsetEnrichmentsClient = class extends WebsetsBaseClient {
/**
* Create an Enrichment for a Webset
* @param websetId The ID of the Webset
* @param params The enrichment parameters
* @returns The created Webset Enrichment
*/
async create(websetId, params) {
return this.request(
`/v0/websets/${websetId}/enrichments`,
"POST",
params
);
}
/**
* Get an Enrichment by ID
* @param websetId The ID of the Webset
* @param id The ID of the Enrichment
* @returns The Webset Enrichment
*/
async get(websetId, id) {
return this.request(
`/v0/websets/${websetId}/enrichments/${id}`,
"GET"
);
}
/**
* Delete an Enrichment
* @param websetId The ID of the Webset
* @param id The ID of the Enrichment
* @returns The deleted Webset Enrichment
*/
async delete(websetId, id) {
return this.request(
`/v0/websets/${websetId}/enrichments/${id}`,
"DELETE"
);
}
/**
* Update an Enrichment
* @param websetId The ID of the Webset
* @param id The ID of the Enrichment
* @param params The enrichment update parameters
* @returns Promise that resolves when the update is complete
*/
async update(websetId, id, params) {
return this.request(
`/v0/websets/${websetId}/enrichments/${id}`,
"PATCH",
params
);
}
/**
* Cancel a running Enrichment
* @param websetId The ID of the Webset
* @param id The ID of the Enrichment
* @returns The canceled Webset Enrichment
*/
async cancel(websetId, id) {
return this.request(
`/v0/websets/${websetId}/enrichments/${id}/cancel`,
"POST"
);
}
};
// src/websets/events.ts
var EventsClient = class extends WebsetsBaseClient {
/**
* Initialize a new Events client
* @param client The Exa client instance
*/
constructor(client) {
super(client);
}
/**
* List all Events
* @param options Optional filtering and pagination options
* @returns The list of Events
*/
async list(options) {
const params = {
cursor: options?.cursor,
limit: options?.limit,
types: options?.types
};
return this.request(
"/v0/events",
"GET",
void 0,
params
);
}
/**
* Get an Event by ID
* @param id The ID of the Event
* @returns The Event
*/
async get(id) {
return this.request(`/v0/events/${id}`, "GET");
}
/**
* Iterate through all Events, handling pagination automatically
* @param options Filtering and pagination options
* @returns Async generator of Events
*/
async *listAll(options) {
let cursor = void 0;
const pageOptions = options ? { ...options } : {};
while (true) {
pageOptions.cursor = cursor;
const response = await this.list(pageOptions);
for (const event of response.data) {
yield event;
}
if (!response.hasMore || !response.nextCursor) {
break;
}
cursor = response.nextCursor;
}
}
/**
* Collect all Events into an array
* @param options Filtering and pagination options
* @returns Promise resolving to an array of all Events
*/
async getAll(options) {
const events = [];
for await (const event of this.listAll(options)) {
events.push(event);
}
return events;
}
};
// src/websets/openapi.ts
var CreateEnrichmentParametersFormat = /* @__PURE__ */ ((CreateEnrichmentParametersFormat2) => {
CreateEnrichmentParametersFormat2["text"] = "text";
CreateEnrichmentParametersFormat2["date"] = "date";
CreateEnrichmentParametersFormat2["number"] = "number";
CreateEnrichmentParametersFormat2["options"] = "options";
CreateEnrichmentParametersFormat2["email"] = "email";
CreateEnrichmentParametersFormat2["phone"] = "phone";
CreateEnrichmentParametersFormat2["url"] = "url";
return CreateEnrichmentParametersFormat2;
})(CreateEnrichmentParametersFormat || {});
var CreateImportParametersFormat = /* @__PURE__ */ ((CreateImportParametersFormat2) => {
CreateImportParametersFormat2["csv"] = "csv";
return CreateImportParametersFormat2;
})(CreateImportParametersFormat || {});
var WebsetImportSource = /* @__PURE__ */ ((WebsetImportSource2) => {
WebsetImportSource2["import"] = "import";
WebsetImportSource2["webset"] = "webset";
return WebsetImportSource2;
})(WebsetImportSource || {});
var EventType = /* @__PURE__ */ ((EventType2) => {
EventType2["webset_created"] = "webset.created";
EventType2["webset_deleted"] = "webset.deleted";
EventType2["webset_paused"] = "webset.paused";
EventType2["webset_idle"] = "webset.idle";
EventType2["webset_search_created"] = "webset.search.created";
EventType2["webset_search_canceled"] = "webset.search.canceled";
EventType2["webset_search_completed"] = "webset.search.completed";
EventType2["webset_search_updated"] = "webset.search.updated";
EventType2["import_created"] = "import.created";
EventType2["import_completed"] = "import.completed";
EventType2["webset_item_created"] = "webset.item.created";
EventType2["webset_item_enriched"] = "webset.item.enriched";
EventType2["monitor_created"] = "monitor.created";
EventType2["monitor_updated"] = "monitor.updated";
EventType2["monitor_deleted"] = "monitor.deleted";
EventType2["monitor_run_created"] = "monitor.run.created";
EventType2["monitor_run_completed"] = "monitor.run.completed";
EventType2["webset_export_created"] = "webset.export.created";
EventType2["webset_export_completed"] = "webset.export.completed";
return EventType2;
})(EventType || {});
var ImportFailedReason = /* @__PURE__ */ ((ImportFailedReason2) => {
ImportFailedReason2["invalid_format"] = "invalid_format";
ImportFailedReason2["invalid_file_content"] = "invalid_file_content";
ImportFailedReason2["missing_identifier"] = "missing_identifier";
return ImportFailedReason2;
})(ImportFailedReason || {});
var ImportFormat = /* @__PURE__ */ ((ImportFormat2) => {
ImportFormat2["csv"] = "csv";
ImportFormat2["webset"] = "webset";
return ImportFormat2;
})(ImportFormat || {});
var ImportObject = /* @__PURE__ */ ((ImportObject2) => {
ImportObject2["import"] = "import";
return ImportObject2;
})(ImportObject || {});
var ImportStatus = /* @__PURE__ */ ((ImportStatus2) => {
ImportStatus2["pending"] = "pending";
ImportStatus2["processing"] = "processing";
ImportStatus2["completed"] = "completed";
ImportStatus2["failed"] = "failed";
return ImportStatus2;
})(ImportStatus || {});
var MonitorObject = /* @__PURE__ */ ((MonitorObject2) => {
MonitorObject2["monitor"] = "monitor";
return MonitorObject2;
})(MonitorObject || {});
var MonitorStatus = /* @__PURE__ */ ((MonitorStatus2) => {
MonitorStatus2["enabled"] = "enabled";
MonitorStatus2["disabled"] = "disabled";
return MonitorStatus2;
})(MonitorStatus || {});
var MonitorRunObject = /* @__PURE__ */ ((MonitorRunObject2) => {
MonitorRunObject2["monitor_run"] = "monitor_run";
return MonitorRunObject2;
})(MonitorRunObject || {});
var MonitorRunStatus = /* @__PURE__ */ ((MonitorRunStatus2) => {
MonitorRunStatus2["created"] = "created";
MonitorRunStatus2["running"] = "running";
MonitorRunStatus2["completed"] = "completed";
MonitorRunStatus2["canceled"] = "canceled";
MonitorRunStatus2["failed"] = "failed";
return MonitorRunStatus2;
})(MonitorRunStatus || {});
var MonitorRunType = /* @__PURE__ */ ((MonitorRunType2) => {
MonitorRunType2["search"] = "search";
MonitorRunType2["refresh"] = "refresh";
return MonitorRunType2;
})(MonitorRunType || {});
var UpdateMonitorStatus = /* @__PURE__ */ ((UpdateMonitorStatus2) => {
UpdateMonitorStatus2["enabled"] = "enabled";
UpdateMonitorStatus2["disabled"] = "disabled";
return UpdateMonitorStatus2;
})(UpdateMonitorStatus || {});
var WebhookStatus = /* @__PURE__ */ ((WebhookStatus2) => {
WebhookStatus2["active"] = "active";
WebhookStatus2["inactive"] = "inactive";
return WebhookStatus2;
})(WebhookStatus || {});
var WebsetStatus = /* @__PURE__ */ ((WebsetStatus2) => {
WebsetStatus2["idle"] = "idle";
WebsetStatus2["pending"] = "pending";
WebsetStatus2["running"] = "running";
WebsetStatus2["paused"] = "paused";
return WebsetStatus2;
})(WebsetStatus || {});
var WebsetEnrichmentStatus = /* @__PURE__ */ ((WebsetEnrichmentStatus2) => {
WebsetEnrichmentStatus2["pending"] = "pending";
WebsetEnrichmentStatus2["canceled"] = "canceled";
WebsetEnrichmentStatus2["completed"] = "completed";
return WebsetEnrichmentStatus2;
})(WebsetEnrichmentStatus || {});
var WebsetEnrichmentFormat = /* @__PURE__ */ ((WebsetEnrichmentFormat2) => {
WebsetEnrichmentFormat2["text"] = "text";
WebsetEnrichmentFormat2["date"] = "date";
WebsetEnrichmentFormat2["number"] = "number";
WebsetEnrichmentFormat2["options"] = "options";
WebsetEnrichmentFormat2["email"] = "email";
WebsetEnrichmentFormat2["phone"] = "phone";
WebsetEnrichmentFormat2["url"] = "url";
return WebsetEnrichmentFormat2;
})(WebsetEnrichmentFormat || {});
var WebsetItemSource = /* @__PURE__ */ ((WebsetItemSource2) => {
WebsetItemSource2["search"] = "search";
WebsetItemSource2["import"] = "import";
return WebsetItemSource2;
})(WebsetItemSource || {});
var WebsetItemEvaluationSatisfied = /* @__PURE__ */ ((WebsetItemEvaluationSatisfied2) => {
WebsetItemEvaluationSatisfied2["yes"] = "yes";
WebsetItemEvaluationSatisfied2["no"] = "no";
WebsetItemEvaluationSatisfied2["unclear"] = "unclear";
return WebsetItemEvaluationSatisfied2;
})(WebsetItemEvaluationSatisfied || {});
var WebsetExcludeSource = /* @__PURE__ */ ((WebsetExcludeSource2) => {
WebsetExcludeSource2["import"] = "import";
WebsetExcludeSource2["webset"] = "webset";
return WebsetExcludeSource2;
})(WebsetExcludeSource || {});
var WebsetSearchScopeSource = /* @__PURE__ */ ((WebsetSearchScopeSource2) => {
WebsetSearchScopeSource2["import"] = "import";
WebsetSearchScopeSource2["webset"] = "webset";
return WebsetSearchScopeSource2;
})(WebsetSearchScopeSource || {});
var WebsetSearchStatus = /* @__PURE__ */ ((WebsetSearchStatus2) => {
WebsetSearchStatus2["created"] = "created";
WebsetSearchStatus2["pending"] = "pending";
WebsetSearchStatus2["running"] = "running";
WebsetSearchStatus2["completed"] = "completed";
WebsetSearchStatus2["canceled"] = "canceled";
return WebsetSearchStatus2;
})(WebsetSearchStatus || {});
var WebsetSearchBehavior = /* @__PURE__ */ ((WebsetSearchBehavior2) => {
WebsetSearchBehavior2["override"] = "override";
WebsetSearchBehavior2["append"] = "append";
return WebsetSearchBehavior2;
})(WebsetSearchBehavior || {});
var WebsetSearchCanceledReason = /* @__PURE__ */ ((WebsetSearchCanceledReason2) => {
WebsetSearchCanceledReason2["webset_deleted"] = "webset_deleted";
WebsetSearchCanceledReason2["webset_canceled"] = "webset_canceled";
return WebsetSearchCanceledReason2;
})(WebsetSearchCanceledReason || {});
// src/websets/imports.ts
var ImportsClient = class extends WebsetsBaseClient {
async create(params, csv) {
if (csv === void 0) {
return this.request(
"/v0/imports",
"POST",
params
);
}
let csvBuffer;
if (typeof csv === "string") {
csvBuffer = Buffer.from(csv, "utf8");
} else if (Buffer.isBuffer(csv)) {
csvBuffer = csv;
} else {
throw new ExaError(
"Invalid CSV data input. Must be string or Buffer",
400 /* BadRequest */
);
}
const sizeInBytes = csvBuffer.length;
const sizeInMB = Math.max(1, Math.ceil(sizeInBytes / (1024 * 1024)));
const csvText = csvBuffer.toString("utf8");
const lines = csvText.split("\n").filter((line) => line.trim().length > 0);
const recordCount = Math.max(0, lines.length - 1);
if (sizeInMB > 50) {
throw new ExaError(
`CSV file too large: ${sizeInMB}MB. Maximum size is 50MB.`,
400 /* BadRequest */
);
}
if (recordCount === 0) {
throw new ExaError(
"CSV file appears to have no data records (only header or empty)",
400 /* BadRequest */
);
}
const createParams = {
title: params.title,
format: "csv" /* csv */,
entity: params.entity,
size: sizeInBytes,
count: recordCount,
metadata: params.metadata,
csv: params.csv
};
const importResponse = await this.request(
"/v0/imports",
"POST",
createParams
);
try {
const uploadResponse = await fetch(importResponse.uploadUrl, {
method: "PUT",
body: csvBuffer
});
if (!uploadResponse.ok) {
const errorText = await uploadResponse.text();
throw new ExaError(
`Upload failed: ${uploadResponse.status} ${uploadResponse.statusText}. ${errorText}`,
400 /* BadRequest */
);
}
} catch (error) {
if (error instanceof ExaError) {
throw error;
}
throw new ExaError(
`Failed to upload CSV data: ${error.message}`,
400 /* BadRequest */
);
}
return importResponse;
}
/**
* Get an Import by ID
* @param id The ID of the Import
* @returns The Import
*/
async get(id) {
return this.request(`/v0/imports/${id}`, "GET");
}
/**
* List all Imports
* @param options Pagination options
* @returns The list of Imports
*/
async list(options) {
const params = this.buildPaginationParams(options);
return this.request(
"/v0/imports",
"GET",
void 0,
params
);
}
/**
* Update an Import
* @param id The ID of the Import
* @param params The import update parameters
* @returns The updated Import
*/
async update(id, params) {
return this.request(`/v0/imports/${id}`, "PATCH", params);
}
/**
* Delete an Import
* @param id The ID of the Import
* @returns The deleted Import
*/
async delete(id) {
return this.request(`/v0/imports/${id}`, "DELETE");
}
/**
* Wait until an Import is completed or failed
* @param id The ID of the Import
* @param options Configuration options for timeout and polling
* @returns The Import once it reaches a final state (completed or failed)
* @throws Error if the Import does not complete within the timeout or fails
*/
async waitUntilCompleted(id, options) {
const timeout = options?.timeout ?? 30 * 60 * 1e3;
const pollInterval = options?.pollInterval ?? 2e3;
const onPoll = options?.onPoll;
const startTime = Date.now();
while (true) {
const importItem = await this.get(id);
if (onPoll) {
onPoll(importItem.status);
}
if (importItem.status === "completed" /* completed */) {
return importItem;
}
if (importItem.status === "failed" /* failed */) {
throw new ExaError(
`Import ${id} failed: ${importItem.failedMessage || "Unknown error"}`,
400 /* BadRequest */
);
}
if (Date.now() - startTime > timeout) {
throw new ExaError(
`Import ${id} did not complete within ${timeout}ms. Current status: ${importItem.status}`,
408 /* RequestTimeout */
);
}
await new Promise((resolve) => setTimeout(resolve, pollInterval));
}
}
/**
* Iterate through all Imports, handling pagination automatically
* @param options Pagination options
* @returns Async generator of Imports
*/
async *listAll(options) {
let cursor = void 0;
const pageOptions = options ? { ...options } : {};
while (true) {
pageOptions.cursor = cursor;
const response = await this.list(pageOptions);
for (const importItem of response.data) {
yield importItem;
}
if (!response.hasMore || !response.nextCursor) {
break;
}
cursor = response.nextCursor;
}
}
/**
* Collect all Imports into an array
* @param options Pagination options
* @returns Promise resolving to an array of all Imports
*/
async getAll(options) {
const imports = [];
for await (const importItem of this.listAll(options)) {
imports.push(importItem);
}
return imports;
}
};
// src/websets/items.ts
var WebsetItemsClient = class extends WebsetsBaseClient {
/**
* List all Items for a Webset
* @param websetId The ID of the Webset
* @param params - Optional pagination and filtering parameters
* @returns A promise that resolves with the list of Items
*/
list(websetId, params) {
const queryParams = {
...this.buildPaginationParams(params),
sourceId: params?.sourceId
};
return this.request(
`/v0/websets/${websetId}/items`,
"GET",
void 0,
queryParams
);
}
/**
* Iterate through all Items in a Webset, handling pagination automatically
* @param websetId The ID of the Webset
* @param options Pagination options
* @returns Async generator of Webset Items
*/
async *listAll(websetId, options) {
let cursor = void 0;
const pageOptions = options ? { ...options } : {};
while (true) {
pageOptions.cursor = cursor;
const response = await this.list(websetId, pageOptions);
for (const item of response.data) {
yield item;
}
if (!response.hasMore || !response.nextCursor) {
break;
}
cursor = response.nextCursor;
}
}
/**
* Collect all items from a Webset into an array
* @param websetId The ID of the Webset
* @param options Pagination options
* @returns Promise resolving to an array of all Webset Items
*/
async getAll(websetId, options) {
const items = [];
for await (const item of this.listAll(websetId, options)) {
items.push(item);
}
return items;
}
/**
* Get an Item by ID
* @param websetId The ID of the Webset
* @param id The ID of the Item
* @returns The Webset Item
*/
async get(websetId, id) {
return this.request(
`/v0/websets/${websetId}/items/${id}`,
"GET"
);
}
/**
* Delete an Item
* @param websetId The ID of the Webset
* @param id The ID of the Item
* @returns The deleted Webset Item
*/
async delete(websetId, id) {
return this.request(
`/v0/websets/${websetId}/items/${id}`,
"DELETE"
);
}
};
// src/websets/monitors.ts
var WebsetMonitorRunsClient = class extends WebsetsBaseClient {
/**
* List all runs for a Monitor
* @param monitorId The ID of the Monitor
* @param options Pagination options
* @returns The list of Monitor runs
*/
async list(monitorId, options) {
const params = this.buildPaginationParams(options);
return this.request(
`/v0/monitors/${monitorId}/runs`,
"GET",
void 0,
params
);
}
/**
* Get a specific Monitor run
* @param monitorId The ID of the Monitor
* @param runId The ID of the Monitor run
* @returns The Monitor run
*/
async get(monitorId, runId) {
return this.request(
`/v0/monitors/${monitorId}/runs/${runId}`,
"GET"
);
}
};
var WebsetMonitorsClient = class extends WebsetsBaseClient {
constructor(client) {
super(client);
this.runs = new WebsetMonitorRunsClient(client);
}
/**
* Create a Monitor
* @param params The monitor parameters
* @returns The created Monitor
*/
async create(params) {
return this.request("/v0/monitors", "POST", params);
}
/**
* Get a Monitor by ID
* @param id The ID of the Monitor
* @returns The Monitor
*/
async get(id) {
return this.request(`/v0/monitors/${id}`, "GET");
}
/**
* List all Monitors
* @param options Pagination and filtering options
* @returns The list of Monitors
*/
async list(options) {
const params = {
cursor: options?.cursor,
limit: options?.limit,
websetId: options?.websetId
};
return this.request(
"/v0/monitors",
"GET",
void 0,
params
);
}
/**
* Update a Monitor
* @param id The ID of the Monitor
* @param params The monitor update parameters (status, metadata)
* @returns The updated Monitor
*/
async update(id, params) {
return this.request(`/v0/monitors/${id}`, "PATCH", params);
}
/**
* Delete a Monitor
* @param id The ID of the Monitor
* @returns The deleted Monitor
*/
async delete(id) {
return this.request(`/v0/monitors/${id}`, "DELETE");
}
/**
* Iterate through all Monitors, handling pagination automatically
* @param options Pagination and filtering options
* @returns Async generator of Monitors
*/
async *listAll(options) {
let cursor = void 0;
const pageOptions = options ? { ...options } : {};
while (true) {
pageOptions.cursor = cursor;
const response = await this.list(pageOptions);
for (const monitor of response.data) {
yield monitor;
}
if (!response.hasMore || !response.nextCursor) {
break;
}
cursor = response.nextCursor;
}
}
/**
* Collect all Monitors into an array
* @param options Pagination and filtering options
* @returns Promise resolving to an array of all Monitors
*/
async getAll(options) {
const monitors = [];
for await (const monitor of this.listAll(options)) {
monitors.push(monitor);
}
return monitors;
}
};
// src/websets/searches.ts
var WebsetSearchesClient = class extends WebsetsBaseClient {
/**
* Create a new Search for the Webset
* @param websetId The ID of the Webset
* @param params The search parameters
* @returns The created Webset Search
*/
async create(websetId, params, options) {
return this.request(
`/v0/websets/${websetId}/searches`,
"POST",
params,
void 0,
options?.headers
);
}
/**
* Get a Search by ID
* @param websetId The ID of the Webset
* @param id The ID of the Search
* @returns The Webset Search
*/
async get(websetId, id) {
return this.request(
`/v0/websets/${websetId}/searches/${id}`,
"GET"
);
}
/**
* Cancel a running Search
* @param websetId The ID of the Webset
* @param id The ID of the Search
* @returns The canceled Webset Search
*/
async cancel(websetId, id) {
return this.request(
`/v0/websets/${websetId}/searches/${id}/cancel`,
"POST"
);
}
};
// src/websets/webhooks.ts
var WebsetWebhooksClient = class extends WebsetsBaseClient {
/**
* Create a Webhook
* @param params The webhook parameters
* @returns The created Webhook
*/
async create(params) {
return this.request("/v0/webhooks", "POST", params);
}
/**
* Get a Webhook by ID
* @param id The ID of the Webhook
* @returns The Webhook
*/
async get(id) {
return this.request(`/v0/webhooks/${id}`, "GET");
}
/**
* List all Webhooks
* @param options Pagination options
* @returns The list of Webhooks
*/
async list(options) {
const params = this.buildPaginationParams(options);
return this.request(
"/v0/webhooks",
"GET",
void 0,
params
);
}
/**
* Iterate through all Webhooks, handling pagination automatically
* @param options Pagination options
* @returns Async generator of Webhooks
*/
async *listAll(options) {
let cursor = void 0;
const pageOptions = options ? { ...options } : {};
while (true) {
pageOptions.cursor = cursor;
const response = await