exa-js 1.4.8 → 1.4.10
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.
- package/README.md +31 -25
- package/dist/index.d.ts +57 -17
- package/dist/index.js +122 -47
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +122 -47
- package/dist/index.mjs.map +1 -1
- package/package.json +5 -3
package/README.md
CHANGED
|
@@ -74,21 +74,23 @@ const customContentsResults = await exa.getContents(["urls"], {
|
|
|
74
74
|
});
|
|
75
75
|
|
|
76
76
|
// Get an answer to a question
|
|
77
|
-
const answerResult = await exa.answer("What is the population of New York City?"
|
|
78
|
-
expandedQueriesLimit: 2,
|
|
79
|
-
includeText: false
|
|
80
|
-
});
|
|
77
|
+
const answerResult = await exa.answer("What is the population of New York City?");
|
|
81
78
|
|
|
82
|
-
// Get answer with
|
|
79
|
+
// Get answer with citation contents and use the exa-pro model, which passes 2 extra queries to exa to increase coverage of the search space.
|
|
83
80
|
const answerWithTextResults = await exa.answer("What is the population of New York City?", {
|
|
84
|
-
|
|
85
|
-
|
|
81
|
+
text: true,
|
|
82
|
+
model: "exa-pro"
|
|
86
83
|
});
|
|
87
84
|
|
|
88
|
-
//
|
|
89
|
-
const
|
|
90
|
-
|
|
91
|
-
|
|
85
|
+
// Get an answer with streaming
|
|
86
|
+
for await (const chunk of exa.streamAnswer("What is the population of New York City?")) {
|
|
87
|
+
if (chunk.content) {
|
|
88
|
+
process.stdout.write(chunk.content);
|
|
89
|
+
}
|
|
90
|
+
if (chunk.citations) {
|
|
91
|
+
console.log("\nCitations:", chunk.citations);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
92
94
|
```
|
|
93
95
|
|
|
94
96
|
### `exa.search(query: string, options?: SearchOptions): Promise<SearchResponse>`
|
|
@@ -123,27 +125,31 @@ Generates an answer to a query using search results as context.
|
|
|
123
125
|
|
|
124
126
|
```javascript
|
|
125
127
|
const response = await exa.answer('What is the population of New York City?', {
|
|
126
|
-
|
|
128
|
+
text: true
|
|
127
129
|
});
|
|
128
130
|
```
|
|
129
131
|
|
|
130
|
-
###
|
|
131
|
-
|
|
132
|
+
### `exa.streamAnswer(query: string, options?: { text?: boolean }): AsyncGenerator<AnswerStreamChunk>`
|
|
133
|
+
Streams an answer as it's being generated, yielding chunks of text and citations. This is useful for providing real-time updates in chat interfaces or displaying partial results as they become available.
|
|
132
134
|
|
|
133
135
|
```javascript
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
{
|
|
137
|
-
|
|
138
|
-
stream: true,
|
|
139
|
-
includeText: false
|
|
140
|
-
},
|
|
141
|
-
(chunk) => {
|
|
142
|
-
// Process each chunk as it arrives
|
|
143
|
-
console.log(chunk.answer);
|
|
136
|
+
// Basic streaming example
|
|
137
|
+
for await (const chunk of exa.streamAnswer("What is quantum computing?")) {
|
|
138
|
+
if (chunk.content) {
|
|
139
|
+
process.stdout.write(chunk.content);
|
|
144
140
|
}
|
|
145
|
-
)
|
|
141
|
+
if (chunk.citations) {
|
|
142
|
+
console.log("\nCitations:", chunk.citations);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
for await (const chunk of exa.streamAnswer("What is quantum computing?", { text: true })) {
|
|
147
|
+
}
|
|
146
148
|
```
|
|
147
149
|
|
|
150
|
+
Each chunk contains:
|
|
151
|
+
- `content`: A string containing the next piece of generated text
|
|
152
|
+
- `citations`: An array of citation objects containing source information
|
|
153
|
+
|
|
148
154
|
# Contributing
|
|
149
155
|
Pull requests are welcome! For major changes, please open an issue first to discuss what you would like to change.
|
package/dist/index.d.ts
CHANGED
|
@@ -198,38 +198,53 @@ type SearchResponse<T extends ContentsOptions> = {
|
|
|
198
198
|
/**
|
|
199
199
|
* Options for the answer endpoint
|
|
200
200
|
* @typedef {Object} AnswerOptions
|
|
201
|
-
* @property {number} [expandedQueriesLimit] - Maximum number of query variations (0-4). Default 1.
|
|
202
201
|
* @property {boolean} [stream] - Whether to stream the response. Default false.
|
|
203
|
-
* @property {boolean} [
|
|
202
|
+
* @property {boolean} [text] - Whether to include text in the source results. Default false.
|
|
203
|
+
* @property {"exa" | "exa-pro"} [model] - The model to use for generating the answer. Default "exa".
|
|
204
204
|
*/
|
|
205
205
|
type AnswerOptions = {
|
|
206
|
-
expandedQueriesLimit?: number;
|
|
207
206
|
stream?: boolean;
|
|
208
|
-
|
|
207
|
+
text?: boolean;
|
|
208
|
+
model?: "exa" | "exa-pro";
|
|
209
209
|
};
|
|
210
210
|
/**
|
|
211
211
|
* Represents an answer response object from the /answer endpoint.
|
|
212
212
|
* @typedef {Object} AnswerResponse
|
|
213
213
|
* @property {string} answer - The generated answer text.
|
|
214
|
-
* @property {SearchResult<{}>[]}
|
|
214
|
+
* @property {SearchResult<{}>[]} citations - The sources used to generate the answer.
|
|
215
215
|
* @property {string} [requestId] - Optional request ID for the answer.
|
|
216
216
|
*/
|
|
217
217
|
type AnswerResponse = {
|
|
218
218
|
answer: string;
|
|
219
|
-
|
|
219
|
+
citations: SearchResult<{}>[];
|
|
220
220
|
requestId?: string;
|
|
221
221
|
};
|
|
222
|
+
type AnswerStreamChunk = {
|
|
223
|
+
/**
|
|
224
|
+
* The partial text content of the answer (if present in this chunk).
|
|
225
|
+
*/
|
|
226
|
+
content?: string;
|
|
227
|
+
/**
|
|
228
|
+
* Citations associated with the current chunk of text (if present).
|
|
229
|
+
*/
|
|
230
|
+
citations?: Array<{
|
|
231
|
+
id: string;
|
|
232
|
+
url: string;
|
|
233
|
+
title?: string;
|
|
234
|
+
publishedDate?: string;
|
|
235
|
+
author?: string;
|
|
236
|
+
text?: string;
|
|
237
|
+
}>;
|
|
238
|
+
};
|
|
222
239
|
/**
|
|
223
240
|
* Represents a streaming answer response chunk from the /answer endpoint.
|
|
224
241
|
* @typedef {Object} AnswerStreamResponse
|
|
225
242
|
* @property {string} [answer] - A chunk of the generated answer text.
|
|
226
|
-
* @property {SearchResult<{}>[]]} [
|
|
227
|
-
* @property {string} [error] - Error message if something went wrong.
|
|
243
|
+
* @property {SearchResult<{}>[]]} [citations] - The sources used to generate the answer.
|
|
228
244
|
*/
|
|
229
245
|
type AnswerStreamResponse = {
|
|
230
246
|
answer?: string;
|
|
231
|
-
|
|
232
|
-
error?: string;
|
|
247
|
+
citations?: SearchResult<{}>[];
|
|
233
248
|
};
|
|
234
249
|
/**
|
|
235
250
|
* The Exa class encapsulates the API's endpoints.
|
|
@@ -252,8 +267,6 @@ declare class Exa {
|
|
|
252
267
|
* @param {string} endpoint - The API endpoint to call.
|
|
253
268
|
* @param {string} method - The HTTP method to use.
|
|
254
269
|
* @param {any} [body] - The request body for POST requests.
|
|
255
|
-
* @param {boolean} [stream] - Whether to stream the response.
|
|
256
|
-
* @param {(chunk: AnswerStreamResponse) => void} [onChunk] - Callback for handling stream chunks.
|
|
257
270
|
* @returns {Promise<any>} The response from the API.
|
|
258
271
|
*/
|
|
259
272
|
private request;
|
|
@@ -295,13 +308,40 @@ declare class Exa {
|
|
|
295
308
|
*/
|
|
296
309
|
getContents<T extends ContentsOptions>(urls: string | string[] | SearchResult<T>[], options?: T): Promise<SearchResponse<T>>;
|
|
297
310
|
/**
|
|
298
|
-
*
|
|
311
|
+
* Generate an answer to a query.
|
|
299
312
|
* @param {string} query - The question or query to answer.
|
|
300
313
|
* @param {AnswerOptions} [options] - Additional options for answer generation.
|
|
301
|
-
* @
|
|
302
|
-
*
|
|
314
|
+
* @returns {Promise<AnswerResponse>} The generated answer and source references.
|
|
315
|
+
*
|
|
316
|
+
* Note: For streaming responses, use the `streamAnswer` method:
|
|
317
|
+
* ```ts
|
|
318
|
+
* for await (const chunk of exa.streamAnswer(query)) {
|
|
319
|
+
* // Handle chunks
|
|
320
|
+
* }
|
|
321
|
+
* ```
|
|
322
|
+
*/
|
|
323
|
+
answer(query: string, options?: AnswerOptions): Promise<AnswerResponse>;
|
|
324
|
+
/**
|
|
325
|
+
* Stream an answer as an async generator
|
|
326
|
+
*
|
|
327
|
+
* Each iteration yields a chunk with partial text (`content`) or new citations.
|
|
328
|
+
* Use this if you'd like to read the answer incrementally, e.g. in a chat UI.
|
|
329
|
+
*
|
|
330
|
+
* Example usage:
|
|
331
|
+
* ```ts
|
|
332
|
+
* for await (const chunk of exa.streamAnswer("What is quantum computing?", { text: false })) {
|
|
333
|
+
* if (chunk.content) process.stdout.write(chunk.content);
|
|
334
|
+
* if (chunk.citations) {
|
|
335
|
+
* console.log("\nCitations: ", chunk.citations);
|
|
336
|
+
* }
|
|
337
|
+
* }
|
|
338
|
+
* ```
|
|
303
339
|
*/
|
|
304
|
-
|
|
340
|
+
streamAnswer(query: string, options?: {
|
|
341
|
+
text?: boolean;
|
|
342
|
+
model?: "exa" | "exa-pro";
|
|
343
|
+
}): AsyncGenerator<AnswerStreamChunk>;
|
|
344
|
+
private processChunk;
|
|
305
345
|
}
|
|
306
346
|
|
|
307
|
-
export { AnswerOptions, AnswerResponse, AnswerStreamResponse, BaseSearchOptions, ContentsOptions, ContentsResultComponent, Default, ExtrasOptions, ExtrasResponse, FindSimilarOptions, HighlightsContentsOptions, HighlightsResponse, LivecrawlOptions, RegularSearchOptions, SearchResponse, SearchResult, SubpagesResponse, SummaryContentsOptions, SummaryResponse, TextContentsOptions, TextResponse, Exa as default };
|
|
347
|
+
export { AnswerOptions, AnswerResponse, AnswerStreamChunk, AnswerStreamResponse, BaseSearchOptions, ContentsOptions, ContentsResultComponent, Default, ExtrasOptions, ExtrasResponse, FindSimilarOptions, HighlightsContentsOptions, HighlightsResponse, LivecrawlOptions, RegularSearchOptions, SearchResponse, SearchResult, SubpagesResponse, SummaryContentsOptions, SummaryResponse, TextContentsOptions, TextResponse, Exa as default };
|
package/dist/index.js
CHANGED
|
@@ -103,11 +103,9 @@ var Exa = class {
|
|
|
103
103
|
* @param {string} endpoint - The API endpoint to call.
|
|
104
104
|
* @param {string} method - The HTTP method to use.
|
|
105
105
|
* @param {any} [body] - The request body for POST requests.
|
|
106
|
-
* @param {boolean} [stream] - Whether to stream the response.
|
|
107
|
-
* @param {(chunk: AnswerStreamResponse) => void} [onChunk] - Callback for handling stream chunks.
|
|
108
106
|
* @returns {Promise<any>} The response from the API.
|
|
109
107
|
*/
|
|
110
|
-
async request(endpoint, method, body
|
|
108
|
+
async request(endpoint, method, body) {
|
|
111
109
|
const response = await fetchImpl(this.baseURL + endpoint, {
|
|
112
110
|
method,
|
|
113
111
|
headers: this.headers,
|
|
@@ -119,42 +117,6 @@ var Exa = class {
|
|
|
119
117
|
`Request failed with status ${response.status}. ${message}`
|
|
120
118
|
);
|
|
121
119
|
}
|
|
122
|
-
if (stream && response.body) {
|
|
123
|
-
const reader = response.body.getReader();
|
|
124
|
-
const decoder = new TextDecoder();
|
|
125
|
-
let buffer = "";
|
|
126
|
-
try {
|
|
127
|
-
while (true) {
|
|
128
|
-
const { done, value } = await reader.read();
|
|
129
|
-
if (done)
|
|
130
|
-
break;
|
|
131
|
-
buffer += decoder.decode(value, { stream: true });
|
|
132
|
-
const lines = buffer.split("\n");
|
|
133
|
-
buffer = lines.pop() || "";
|
|
134
|
-
for (const line of lines) {
|
|
135
|
-
if (line.startsWith("data: ")) {
|
|
136
|
-
try {
|
|
137
|
-
const data = JSON.parse(line.slice(6));
|
|
138
|
-
onChunk?.(data);
|
|
139
|
-
} catch (e) {
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
if (buffer && buffer.startsWith("data: ")) {
|
|
145
|
-
try {
|
|
146
|
-
const data = JSON.parse(buffer.slice(6));
|
|
147
|
-
onChunk?.(data);
|
|
148
|
-
} catch (e) {
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
} catch (error) {
|
|
152
|
-
throw new Error(`Streaming error: ${error?.message || "Unknown error"}`);
|
|
153
|
-
} finally {
|
|
154
|
-
reader.releaseLock();
|
|
155
|
-
}
|
|
156
|
-
return null;
|
|
157
|
-
}
|
|
158
120
|
return await response.json();
|
|
159
121
|
}
|
|
160
122
|
/**
|
|
@@ -230,20 +192,133 @@ var Exa = class {
|
|
|
230
192
|
return await this.request("/contents", "POST", payload);
|
|
231
193
|
}
|
|
232
194
|
/**
|
|
233
|
-
*
|
|
195
|
+
* Generate an answer to a query.
|
|
234
196
|
* @param {string} query - The question or query to answer.
|
|
235
197
|
* @param {AnswerOptions} [options] - Additional options for answer generation.
|
|
236
|
-
* @
|
|
237
|
-
*
|
|
198
|
+
* @returns {Promise<AnswerResponse>} The generated answer and source references.
|
|
199
|
+
*
|
|
200
|
+
* Note: For streaming responses, use the `streamAnswer` method:
|
|
201
|
+
* ```ts
|
|
202
|
+
* for await (const chunk of exa.streamAnswer(query)) {
|
|
203
|
+
* // Handle chunks
|
|
204
|
+
* }
|
|
205
|
+
* ```
|
|
238
206
|
*/
|
|
239
|
-
async answer(query, options
|
|
207
|
+
async answer(query, options) {
|
|
208
|
+
if (options?.stream) {
|
|
209
|
+
throw new Error(
|
|
210
|
+
"For streaming responses, please use streamAnswer() instead:\n\nfor await (const chunk of exa.streamAnswer(query)) {\n // Handle chunks\n}"
|
|
211
|
+
);
|
|
212
|
+
}
|
|
240
213
|
const requestBody = {
|
|
241
214
|
query,
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
215
|
+
stream: false,
|
|
216
|
+
text: options?.text ?? false,
|
|
217
|
+
model: options?.model ?? "exa"
|
|
218
|
+
};
|
|
219
|
+
return await this.request("/answer", "POST", requestBody);
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Stream an answer as an async generator
|
|
223
|
+
*
|
|
224
|
+
* Each iteration yields a chunk with partial text (`content`) or new citations.
|
|
225
|
+
* Use this if you'd like to read the answer incrementally, e.g. in a chat UI.
|
|
226
|
+
*
|
|
227
|
+
* Example usage:
|
|
228
|
+
* ```ts
|
|
229
|
+
* for await (const chunk of exa.streamAnswer("What is quantum computing?", { text: false })) {
|
|
230
|
+
* if (chunk.content) process.stdout.write(chunk.content);
|
|
231
|
+
* if (chunk.citations) {
|
|
232
|
+
* console.log("\nCitations: ", chunk.citations);
|
|
233
|
+
* }
|
|
234
|
+
* }
|
|
235
|
+
* ```
|
|
236
|
+
*/
|
|
237
|
+
async *streamAnswer(query, options) {
|
|
238
|
+
const body = {
|
|
239
|
+
query,
|
|
240
|
+
text: options?.text ?? false,
|
|
241
|
+
stream: true,
|
|
242
|
+
model: options?.model ?? "exa"
|
|
245
243
|
};
|
|
246
|
-
|
|
244
|
+
const response = await fetchImpl(this.baseURL + "/answer", {
|
|
245
|
+
method: "POST",
|
|
246
|
+
headers: this.headers,
|
|
247
|
+
body: JSON.stringify(body)
|
|
248
|
+
});
|
|
249
|
+
if (!response.ok) {
|
|
250
|
+
const message = await response.text();
|
|
251
|
+
throw new Error(
|
|
252
|
+
`Request failed with status ${response.status}. ${message}`
|
|
253
|
+
);
|
|
254
|
+
}
|
|
255
|
+
const reader = response.body?.getReader();
|
|
256
|
+
if (!reader) {
|
|
257
|
+
throw new Error("No response body available for streaming.");
|
|
258
|
+
}
|
|
259
|
+
const decoder = new TextDecoder();
|
|
260
|
+
let buffer = "";
|
|
261
|
+
try {
|
|
262
|
+
while (true) {
|
|
263
|
+
const { done, value } = await reader.read();
|
|
264
|
+
if (done)
|
|
265
|
+
break;
|
|
266
|
+
buffer += decoder.decode(value, { stream: true });
|
|
267
|
+
const lines = buffer.split("\n");
|
|
268
|
+
buffer = lines.pop() || "";
|
|
269
|
+
for (const line of lines) {
|
|
270
|
+
if (!line.startsWith("data: "))
|
|
271
|
+
continue;
|
|
272
|
+
const jsonStr = line.replace(/^data:\s*/, "").trim();
|
|
273
|
+
if (!jsonStr || jsonStr === "[DONE]") {
|
|
274
|
+
continue;
|
|
275
|
+
}
|
|
276
|
+
let chunkData;
|
|
277
|
+
try {
|
|
278
|
+
chunkData = JSON.parse(jsonStr);
|
|
279
|
+
} catch (err) {
|
|
280
|
+
continue;
|
|
281
|
+
}
|
|
282
|
+
const chunk = this.processChunk(chunkData);
|
|
283
|
+
if (chunk.content || chunk.citations) {
|
|
284
|
+
yield chunk;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
if (buffer.startsWith("data: ")) {
|
|
289
|
+
const leftover = buffer.replace(/^data:\s*/, "").trim();
|
|
290
|
+
if (leftover && leftover !== "[DONE]") {
|
|
291
|
+
try {
|
|
292
|
+
const chunkData = JSON.parse(leftover);
|
|
293
|
+
const chunk = this.processChunk(chunkData);
|
|
294
|
+
if (chunk.content || chunk.citations) {
|
|
295
|
+
yield chunk;
|
|
296
|
+
}
|
|
297
|
+
} catch (e) {
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
} finally {
|
|
302
|
+
reader.releaseLock();
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
processChunk(chunkData) {
|
|
306
|
+
let content;
|
|
307
|
+
let citations;
|
|
308
|
+
if (chunkData.choices && chunkData.choices[0] && chunkData.choices[0].delta) {
|
|
309
|
+
content = chunkData.choices[0].delta.content;
|
|
310
|
+
}
|
|
311
|
+
if (chunkData.citations && chunkData.citations !== "null") {
|
|
312
|
+
citations = chunkData.citations.map((c) => ({
|
|
313
|
+
id: c.id,
|
|
314
|
+
url: c.url,
|
|
315
|
+
title: c.title,
|
|
316
|
+
publishedDate: c.publishedDate,
|
|
317
|
+
author: c.author,
|
|
318
|
+
text: c.text
|
|
319
|
+
}));
|
|
320
|
+
}
|
|
321
|
+
return { content, citations };
|
|
247
322
|
}
|
|
248
323
|
};
|
|
249
324
|
var src_default = Exa;
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import fetch, { Headers } from \"cross-fetch\";\n\n// Use native fetch in Node.js environments\nconst fetchImpl = typeof global !== \"undefined\" && global.fetch ? global.fetch : fetch;\nconst HeadersImpl = typeof global !== \"undefined\" && global.Headers ? global.Headers : Headers;\n\nconst isBeta = false;\n\n/**\n * Search options for performing a search query.\n * @typedef {Object} SearchOptions\n * @property {number} [numResults] - Number of search results to return. Default 10. Max 10 for basic plans.\n * @property {string[]} [includeDomains] - List of domains to include in the search.\n * @property {string[]} [excludeDomains] - List of domains to exclude in the search.\n * @property {string} [startCrawlDate] - Start date for results based on crawl date.\n * @property {string} [endCrawlDate] - End date for results based on crawl date.\n * @property {string} [startPublishedDate] - Start date for results based on published date.\n * @property {string} [endPublishedDate] - End date for results based on published date.\n * @property {string} [category] - A data category to focus on, with higher comprehensivity and data cleanliness. Currently, the only category is company.\n * @property {string[]} [includeText] - List of strings that must be present in webpage text of results. Currently only supports 1 string of up to 5 words.\n * @property {string[]} [excludeText] - List of strings that must not be present in webpage text of results. Currently only supports 1 string of up to 5 words.\n * @property {string[]} [flags] - Experimental flags\n */\nexport type BaseSearchOptions = {\n numResults?: number;\n includeDomains?: string[];\n excludeDomains?: string[];\n startCrawlDate?: string;\n endCrawlDate?: string;\n startPublishedDate?: string;\n endPublishedDate?: string;\n category?:\n | \"company\"\n | \"research paper\"\n | \"news\"\n | \"pdf\"\n | \"github\"\n | \"tweet\"\n | \"personal site\"\n | \"linkedin profile\"\n | \"financial report\";\n includeText?: string[];\n excludeText?: string[];\n flags?: string[];\n};\n\n/**\n * Search options for performing a search query.\n * @typedef {Object} RegularSearchOptions\n */\nexport type RegularSearchOptions = BaseSearchOptions & {\n /**\n * If true, the search results are moderated for safety.\n */\n moderation?: boolean;\n\n useAutoprompt?: boolean;\n type?: \"keyword\" | \"neural\" | \"auto\";\n};\n\n/**\n * Options for finding similar links.\n * @typedef {Object} FindSimilarOptions\n * @property {boolean} [excludeSourceDomain] - If true, excludes links from the base domain of the input.\n */\nexport type FindSimilarOptions = BaseSearchOptions & {\n excludeSourceDomain?: boolean;\n};\n\nexport type ExtrasOptions = { links?: number; imageLinks?: number };\n\n/**\n * Search options for performing a search query.\n * @typedef {Object} ContentsOptions\n * @property {TextContentsOptions | boolean} [text] - Options for retrieving text contents.\n * @property {HighlightsContentsOptions | boolean} [highlights] - Options for retrieving highlights.\n * @property {SummaryContentsOptions | boolean} [summary] - Options for retrieving summary.\n * @property {LivecrawlOptions} [livecrawl] - Options for livecrawling contents. Default is \"never\" for neural/auto search, \"fallback\" for keyword search.\n * @property {number} [livecrawlTimeout] - The timeout for livecrawling. Max and default is 10000ms.\n * @property {boolean} [filterEmptyResults] - If true, filters out results with no contents. Default is true.\n * @property {number} [subpages] - The number of subpages to return for each result, where each subpage is derived from an internal link for the result.\n * @property {string | string[]} [subpageTarget] - Text used to match/rank subpages in the returned subpage list. You could use \"about\" to get *about* page for websites. Note that this is a fuzzy matcher.\n * @property {ExtrasOptions} [extras] - Miscelleneous data derived from results\n */\nexport type ContentsOptions = {\n text?: TextContentsOptions | true;\n highlights?: HighlightsContentsOptions | true;\n summary?: SummaryContentsOptions | true;\n livecrawl?: LivecrawlOptions;\n livecrawlTimeout?: number;\n filterEmptyResults?: boolean;\n subpages?: number;\n subpageTarget?: string | string[];\n extras?: ExtrasOptions;\n} & (typeof isBeta extends true ? {} : {});\n\n/**\n * Options for livecrawling contents\n * @typedef {string} LivecrawlOptions\n */\nexport type LivecrawlOptions = \"never\" | \"fallback\" | \"always\" | \"auto\";\n\n/**\n * Options for retrieving text from page.\n * @typedef {Object} TextContentsOptions\n * @property {number} [maxCharacters] - The maximum number of characters to return.\n * @property {boolean} [includeHtmlTags] - If true, includes HTML tags in the returned text. Default: false\n */\nexport type TextContentsOptions = {\n maxCharacters?: number;\n includeHtmlTags?: boolean;\n};\n\n/**\n * Options for retrieving highlights from page.\n * @typedef {Object} HighlightsContentsOptions\n * @property {string} [query] - The query string to use for highlights search.\n * @property {number} [numSentences] - The number of sentences to return for each highlight.\n * @property {number} [highlightsPerUrl] - The number of highlights to return for each URL.\n */\nexport type HighlightsContentsOptions = {\n query?: string;\n numSentences?: number;\n highlightsPerUrl?: number;\n};\n\n/**\n * Options for retrieving summary from page.\n * @typedef {Object} SummaryContentsOptions\n * @property {string} [query] - The query string to use for summary generation.\n */\nexport type SummaryContentsOptions = {\n query?: string;\n};\n\n/**\n * @typedef {Object} TextResponse\n * @property {string} text - Text from page\n */\nexport type TextResponse = { text: string };\n\n/**\n * @typedef {Object} HighlightsResponse\n * @property {string[]} highlights - The highlights as an array of strings.\n * @property {number[]} highlightScores - The corresponding scores as an array of floats, 0 to 1\n */\nexport type HighlightsResponse = {\n highlights: string[];\n highlightScores: number[];\n};\n\n/**\n * @typedef {Object} SummaryResponse\n * @property {string} summary - The generated summary of the page content.\n */\nexport type SummaryResponse = { summary: string };\n\n/**\n * @typedef {Object} ExtrasResponse\n * @property {string[]} links - The links on the page of a result\n * @property {string[]} imageLinks - The image links on the page of a result\n */\nexport type ExtrasResponse = { extras: { links?: string[]; imageLinks?: string[] } };\n\n/**\n * @typedef {Object} SubpagesResponse\n * @property {ContentsResultComponent<T extends ContentsOptions>} subpages - The subpages for a result\n */\nexport type SubpagesResponse<T extends ContentsOptions> = {\n subpages: ContentsResultComponent<T>[];\n};\n\nexport type Default<T extends {}, U> = [keyof T] extends [never] ? U : T;\n\n/**\n * @typedef {Object} ContentsResultComponent\n * Depending on 'ContentsOptions', this yields a combination of 'TextResponse', 'HighlightsResponse', 'SummaryResponse', or an empty object.\n *\n * @template T - A type extending from 'ContentsOptions'.\n */\nexport type ContentsResultComponent<T extends ContentsOptions> = Default<\n (T[\"text\"] extends object | true ? TextResponse : {}) &\n (T[\"highlights\"] extends object | true ? HighlightsResponse : {}) &\n (T[\"summary\"] extends object | true ? SummaryResponse : {}) &\n (T[\"subpages\"] extends number ? SubpagesResponse<T> : {}) &\n (T[\"extras\"] extends object ? ExtrasResponse : {}),\n TextResponse\n>;\n\n/**\n * Represents a search result object.\n * @typedef {Object} SearchResult\n * @property {string} title - The title of the search result.\n * @property {string} url - The URL of the search result.\n * @property {string} [publishedDate] - The estimated creation date of the content.\n * @property {string} [author] - The author of the content, if available.\n * @property {number} [score] - Similarity score between the query/url and the result.\n * @property {string} id - The temporary ID for the document.\n * @property {string} [image] - A representative image for the content, if any.\n * @property {string} [favicon] - A favicon for the site, if any.\n */\nexport type SearchResult<T extends ContentsOptions> = {\n title: string | null;\n url: string;\n publishedDate?: string;\n author?: string;\n score?: number;\n id: string;\n image?: string;\n favicon?: string;\n} & ContentsResultComponent<T>;\n\n/**\n * Represents a search response object.\n * @typedef {Object} SearchResponse\n * @property {Result[]} results - The list of search results.\n * @property {string} [autopromptString] - The autoprompt string, if applicable.\n * @property {string} [autoDate] - The autoprompt date, if applicable.\n * @property {string} requestId - The request ID for the search.\n */\nexport type SearchResponse<T extends ContentsOptions> = {\n results: SearchResult<T>[];\n autopromptString?: string;\n autoDate?: string;\n requestId: string;\n};\n\n/**\n * Options for the answer endpoint\n * @typedef {Object} AnswerOptions\n * @property {number} [expandedQueriesLimit] - Maximum number of query variations (0-4). Default 1.\n * @property {boolean} [stream] - Whether to stream the response. Default false.\n * @property {boolean} [includeText] - Whether to include text in the source results. Default false.\n */\nexport type AnswerOptions = {\n expandedQueriesLimit?: number;\n stream?: boolean;\n includeText?: boolean;\n};\n\n/**\n * Represents an answer response object from the /answer endpoint.\n * @typedef {Object} AnswerResponse\n * @property {string} answer - The generated answer text.\n * @property {SearchResult<{}>[]} sources - The sources used to generate the answer.\n * @property {string} [requestId] - Optional request ID for the answer.\n */\nexport type AnswerResponse = {\n answer: string;\n sources: SearchResult<{}>[];\n requestId?: string;\n};\n\n/**\n * Represents a streaming answer response chunk from the /answer endpoint.\n * @typedef {Object} AnswerStreamResponse\n * @property {string} [answer] - A chunk of the generated answer text.\n * @property {SearchResult<{}>[]]} [sources] - The sources used to generate the answer.\n * @property {string} [error] - Error message if something went wrong.\n */\nexport type AnswerStreamResponse = {\n answer?: string;\n sources?: SearchResult<{}>[];\n error?: string;\n};\n\n/**\n * The Exa class encapsulates the API's endpoints.\n */\nclass Exa {\n private baseURL: string;\n private headers: Headers;\n\n /**\n * Helper method to separate out the contents-specific options from the rest.\n */\n private extractContentsOptions<T extends ContentsOptions>(options: T): {\n contentsOptions: ContentsOptions;\n restOptions: Omit<T, keyof ContentsOptions>;\n } {\n const {\n text,\n highlights,\n summary,\n subpages,\n subpageTarget,\n extras,\n livecrawl,\n livecrawlTimeout,\n ...rest\n } = options;\n\n const contentsOptions: ContentsOptions = {};\n\n // Default: if none of text, summary, or highlights is provided, we retrieve text\n if (\n text === undefined &&\n summary === undefined &&\n highlights === undefined &&\n extras === undefined\n ) {\n contentsOptions.text = true;\n }\n\n if (text !== undefined) contentsOptions.text = text;\n if (summary !== undefined) contentsOptions.summary = summary;\n if (highlights !== undefined) contentsOptions.highlights = highlights;\n if (subpages !== undefined) contentsOptions.subpages = subpages;\n if (subpageTarget !== undefined) contentsOptions.subpageTarget = subpageTarget;\n if (extras !== undefined) contentsOptions.extras = extras;\n if (livecrawl !== undefined) contentsOptions.livecrawl = livecrawl;\n if (livecrawlTimeout !== undefined) contentsOptions.livecrawlTimeout = livecrawlTimeout;\n\n return {\n contentsOptions,\n restOptions: rest as Omit<T, keyof ContentsOptions>,\n };\n }\n\n /**\n * Constructs the Exa API client.\n * @param {string} apiKey - The API key for authentication.\n * @param {string} [baseURL] - The base URL of the Exa API.\n */\n constructor(apiKey?: string, baseURL: string = \"https://api.exa.ai\") {\n this.baseURL = baseURL;\n if (!apiKey) {\n apiKey = process.env.EXASEARCH_API_KEY;\n if (!apiKey) {\n throw new Error(\n \"API key must be provided as an argument or as an environment variable (EXASEARCH_API_KEY)\",\n );\n }\n }\n this.headers = new HeadersImpl({\n \"x-api-key\": apiKey,\n \"Content-Type\": \"application/json\",\n \"User-Agent\": \"exa-node 1.4.0\",\n });\n }\n\n /**\n * Makes a request to the Exa API.\n * @param {string} endpoint - The API endpoint to call.\n * @param {string} method - The HTTP method to use.\n * @param {any} [body] - The request body for POST requests.\n * @param {boolean} [stream] - Whether to stream the response.\n * @param {(chunk: AnswerStreamResponse) => void} [onChunk] - Callback for handling stream chunks.\n * @returns {Promise<any>} The response from the API.\n */\n private async request(\n endpoint: string,\n method: string,\n body?: any,\n stream?: boolean,\n onChunk?: (chunk: AnswerStreamResponse) => void,\n ): Promise<any> {\n const response = await fetchImpl(this.baseURL + endpoint, {\n method,\n headers: this.headers,\n body: body ? JSON.stringify(body) : undefined,\n });\n\n if (!response.ok) {\n const message = (await response.json()).error;\n throw new Error(\n `Request failed with status ${response.status}. ${message}`,\n );\n }\n\n // Streaming logic if `stream` is true\n if (stream && response.body) {\n const reader = response.body.getReader();\n const decoder = new TextDecoder();\n let buffer = '';\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split('\\n');\n buffer = lines.pop() || '';\n\n for (const line of lines) {\n if (line.startsWith('data: ')) {\n try {\n const data = JSON.parse(line.slice(6));\n onChunk?.(data);\n } catch (e) {\n // Could not parse JSON, ignore\n }\n }\n }\n }\n\n if (buffer && buffer.startsWith('data: ')) {\n try {\n const data = JSON.parse(buffer.slice(6));\n onChunk?.(data);\n } catch (e) {\n // Could not parse JSON, ignore\n }\n }\n } catch (error: any) {\n throw new Error(`Streaming error: ${error?.message || 'Unknown error'}`);\n } finally {\n reader.releaseLock();\n }\n\n return null;\n }\n\n return await response.json();\n }\n\n /**\n * Performs a search with an Exa prompt-engineered query.\n * \n * @param {string} query - The query string.\n * @param {RegularSearchOptions} [options] - Additional search options\n * @returns {Promise<SearchResponse<{}>>} A list of relevant search results.\n */\n async search(\n query: string,\n options?: RegularSearchOptions,\n ): Promise<SearchResponse<{}>> {\n return await this.request(\"/search\", \"POST\", { query, ...options });\n }\n\n /**\n * Performs a search with an Exa prompt-engineered query and returns the contents of the documents.\n * \n * @param {string} query - The query string.\n * @param {RegularSearchOptions & T} [options] - Additional search + contents options\n * @returns {Promise<SearchResponse<T>>} A list of relevant search results with requested contents.\n */\n async searchAndContents<T extends ContentsOptions>(\n query: string,\n options?: RegularSearchOptions & T,\n ): Promise<SearchResponse<T>> {\n const { contentsOptions, restOptions } =\n options === undefined\n ? { contentsOptions: { text: true }, restOptions: {} }\n : this.extractContentsOptions(options);\n\n return await this.request(\"/search\", \"POST\", {\n query,\n contents: contentsOptions,\n ...restOptions,\n });\n }\n\n /**\n * Finds similar links to the provided URL.\n * @param {string} url - The URL for which to find similar links.\n * @param {FindSimilarOptions} [options] - Additional options for finding similar links.\n * @returns {Promise<SearchResponse<{}>>} A list of similar search results.\n */\n async findSimilar(\n url: string,\n options?: FindSimilarOptions,\n ): Promise<SearchResponse<{}>> {\n return await this.request(\"/findSimilar\", \"POST\", { url, ...options });\n }\n\n /**\n * Finds similar links to the provided URL and returns the contents of the documents.\n * @param {string} url - The URL for which to find similar links.\n * @param {FindSimilarOptions & T} [options] - Additional options for finding similar links + contents.\n * @returns {Promise<SearchResponse<T>>} A list of similar search results, including requested contents.\n */\n async findSimilarAndContents<T extends ContentsOptions>(\n url: string,\n options?: FindSimilarOptions & T,\n ): Promise<SearchResponse<T>> {\n const { contentsOptions, restOptions } =\n options === undefined\n ? { contentsOptions: { text: true }, restOptions: {} }\n : this.extractContentsOptions(options);\n\n return await this.request(\"/findSimilar\", \"POST\", {\n url,\n contents: contentsOptions,\n ...restOptions,\n });\n }\n\n /**\n * Retrieves contents of documents based on URLs.\n * @param {string | string[] | SearchResult[]} urls - A URL or array of URLs, or an array of SearchResult objects.\n * @param {ContentsOptions} [options] - Additional options for retrieving document contents.\n * @returns {Promise<SearchResponse<T>>} A list of document contents for the requested URLs.\n */\n async getContents<T extends ContentsOptions>(\n urls: string | string[] | SearchResult<T>[],\n options?: T,\n ): Promise<SearchResponse<T>> {\n if (!urls || (Array.isArray(urls) && urls.length === 0)) {\n throw new Error(\"Must provide at least one URL\");\n }\n\n let requestUrls: string[];\n\n if (typeof urls === \"string\") {\n requestUrls = [urls];\n } else if (typeof urls[0] === \"string\") {\n requestUrls = urls as string[];\n } else {\n requestUrls = (urls as SearchResult<T>[]).map((result) => result.url);\n }\n\n const payload = {\n urls: requestUrls,\n ...options,\n };\n\n return await this.request(\"/contents\", \"POST\", payload);\n }\n\n /**\n * Generates an answer to a query using search results as context.\n * @param {string} query - The question or query to answer.\n * @param {AnswerOptions} [options] - Additional options for answer generation.\n * @param {(chunk: AnswerStreamResponse) => void} [onChunk] - Callback for handling stream chunks (if streaming).\n * @returns {Promise<AnswerResponse | null>} The generated answer and source references, or null if streaming.\n */\n async answer(\n query: string,\n options?: AnswerOptions,\n onChunk?: (chunk: AnswerStreamResponse) => void,\n ): Promise<AnswerResponse | null> {\n const requestBody = {\n query,\n expandedQueriesLimit: options?.expandedQueriesLimit ?? 1,\n stream: options?.stream ?? false,\n includeText: options?.includeText ?? false\n };\n\n return await this.request(\"/answer\", \"POST\", requestBody, options?.stream, onChunk);\n }\n}\n\nexport default Exa;\n"],"mappings":"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","names":["fetch"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import fetch, { Headers } from \"cross-fetch\";\n\n// Use native fetch in Node.js environments\nconst fetchImpl = typeof global !== \"undefined\" && global.fetch ? global.fetch : fetch;\nconst HeadersImpl = typeof global !== \"undefined\" && global.Headers ? global.Headers : Headers;\n\nconst isBeta = false;\n\n/**\n * Search options for performing a search query.\n * @typedef {Object} SearchOptions\n * @property {number} [numResults] - Number of search results to return. Default 10. Max 10 for basic plans.\n * @property {string[]} [includeDomains] - List of domains to include in the search.\n * @property {string[]} [excludeDomains] - List of domains to exclude in the search.\n * @property {string} [startCrawlDate] - Start date for results based on crawl date.\n * @property {string} [endCrawlDate] - End date for results based on crawl date.\n * @property {string} [startPublishedDate] - Start date for results based on published date.\n * @property {string} [endPublishedDate] - End date for results based on published date.\n * @property {string} [category] - A data category to focus on, with higher comprehensivity and data cleanliness. Currently, the only category is company.\n * @property {string[]} [includeText] - List of strings that must be present in webpage text of results. Currently only supports 1 string of up to 5 words.\n * @property {string[]} [excludeText] - List of strings that must not be present in webpage text of results. Currently only supports 1 string of up to 5 words.\n * @property {string[]} [flags] - Experimental flags\n */\nexport type BaseSearchOptions = {\n numResults?: number;\n includeDomains?: string[];\n excludeDomains?: string[];\n startCrawlDate?: string;\n endCrawlDate?: string;\n startPublishedDate?: string;\n endPublishedDate?: string;\n category?:\n | \"company\"\n | \"research paper\"\n | \"news\"\n | \"pdf\"\n | \"github\"\n | \"tweet\"\n | \"personal site\"\n | \"linkedin profile\"\n | \"financial report\";\n includeText?: string[];\n excludeText?: string[];\n flags?: string[];\n};\n\n/**\n * Search options for performing a search query.\n * @typedef {Object} RegularSearchOptions\n */\nexport type RegularSearchOptions = BaseSearchOptions & {\n /**\n * If true, the search results are moderated for safety.\n */\n moderation?: boolean;\n\n useAutoprompt?: boolean;\n type?: \"keyword\" | \"neural\" | \"auto\";\n};\n\n/**\n * Options for finding similar links.\n * @typedef {Object} FindSimilarOptions\n * @property {boolean} [excludeSourceDomain] - If true, excludes links from the base domain of the input.\n */\nexport type FindSimilarOptions = BaseSearchOptions & {\n excludeSourceDomain?: boolean;\n};\n\nexport type ExtrasOptions = { links?: number; imageLinks?: number };\n\n/**\n * Search options for performing a search query.\n * @typedef {Object} ContentsOptions\n * @property {TextContentsOptions | boolean} [text] - Options for retrieving text contents.\n * @property {HighlightsContentsOptions | boolean} [highlights] - Options for retrieving highlights.\n * @property {SummaryContentsOptions | boolean} [summary] - Options for retrieving summary.\n * @property {LivecrawlOptions} [livecrawl] - Options for livecrawling contents. Default is \"never\" for neural/auto search, \"fallback\" for keyword search.\n * @property {number} [livecrawlTimeout] - The timeout for livecrawling. Max and default is 10000ms.\n * @property {boolean} [filterEmptyResults] - If true, filters out results with no contents. Default is true.\n * @property {number} [subpages] - The number of subpages to return for each result, where each subpage is derived from an internal link for the result.\n * @property {string | string[]} [subpageTarget] - Text used to match/rank subpages in the returned subpage list. You could use \"about\" to get *about* page for websites. Note that this is a fuzzy matcher.\n * @property {ExtrasOptions} [extras] - Miscelleneous data derived from results\n */\nexport type ContentsOptions = {\n text?: TextContentsOptions | true;\n highlights?: HighlightsContentsOptions | true;\n summary?: SummaryContentsOptions | true;\n livecrawl?: LivecrawlOptions;\n livecrawlTimeout?: number;\n filterEmptyResults?: boolean;\n subpages?: number;\n subpageTarget?: string | string[];\n extras?: ExtrasOptions;\n} & (typeof isBeta extends true ? {} : {});\n\n/**\n * Options for livecrawling contents\n * @typedef {string} LivecrawlOptions\n */\nexport type LivecrawlOptions = \"never\" | \"fallback\" | \"always\" | \"auto\";\n\n/**\n * Options for retrieving text from page.\n * @typedef {Object} TextContentsOptions\n * @property {number} [maxCharacters] - The maximum number of characters to return.\n * @property {boolean} [includeHtmlTags] - If true, includes HTML tags in the returned text. Default: false\n */\nexport type TextContentsOptions = {\n maxCharacters?: number;\n includeHtmlTags?: boolean;\n};\n\n/**\n * Options for retrieving highlights from page.\n * @typedef {Object} HighlightsContentsOptions\n * @property {string} [query] - The query string to use for highlights search.\n * @property {number} [numSentences] - The number of sentences to return for each highlight.\n * @property {number} [highlightsPerUrl] - The number of highlights to return for each URL.\n */\nexport type HighlightsContentsOptions = {\n query?: string;\n numSentences?: number;\n highlightsPerUrl?: number;\n};\n\n/**\n * Options for retrieving summary from page.\n * @typedef {Object} SummaryContentsOptions\n * @property {string} [query] - The query string to use for summary generation.\n */\nexport type SummaryContentsOptions = {\n query?: string;\n};\n\n/**\n * @typedef {Object} TextResponse\n * @property {string} text - Text from page\n */\nexport type TextResponse = { text: string };\n\n/**\n * @typedef {Object} HighlightsResponse\n * @property {string[]} highlights - The highlights as an array of strings.\n * @property {number[]} highlightScores - The corresponding scores as an array of floats, 0 to 1\n */\nexport type HighlightsResponse = {\n highlights: string[];\n highlightScores: number[];\n};\n\n/**\n * @typedef {Object} SummaryResponse\n * @property {string} summary - The generated summary of the page content.\n */\nexport type SummaryResponse = { summary: string };\n\n/**\n * @typedef {Object} ExtrasResponse\n * @property {string[]} links - The links on the page of a result\n * @property {string[]} imageLinks - The image links on the page of a result\n */\nexport type ExtrasResponse = { extras: { links?: string[]; imageLinks?: string[] } };\n\n/**\n * @typedef {Object} SubpagesResponse\n * @property {ContentsResultComponent<T extends ContentsOptions>} subpages - The subpages for a result\n */\nexport type SubpagesResponse<T extends ContentsOptions> = {\n subpages: ContentsResultComponent<T>[];\n};\n\nexport type Default<T extends {}, U> = [keyof T] extends [never] ? U : T;\n\n/**\n * @typedef {Object} ContentsResultComponent\n * Depending on 'ContentsOptions', this yields a combination of 'TextResponse', 'HighlightsResponse', 'SummaryResponse', or an empty object.\n *\n * @template T - A type extending from 'ContentsOptions'.\n */\nexport type ContentsResultComponent<T extends ContentsOptions> = Default<\n (T[\"text\"] extends object | true ? TextResponse : {}) &\n (T[\"highlights\"] extends object | true ? HighlightsResponse : {}) &\n (T[\"summary\"] extends object | true ? SummaryResponse : {}) &\n (T[\"subpages\"] extends number ? SubpagesResponse<T> : {}) &\n (T[\"extras\"] extends object ? ExtrasResponse : {}),\n TextResponse\n>;\n\n/**\n * Represents a search result object.\n * @typedef {Object} SearchResult\n * @property {string} title - The title of the search result.\n * @property {string} url - The URL of the search result.\n * @property {string} [publishedDate] - The estimated creation date of the content.\n * @property {string} [author] - The author of the content, if available.\n * @property {number} [score] - Similarity score between the query/url and the result.\n * @property {string} id - The temporary ID for the document.\n * @property {string} [image] - A representative image for the content, if any.\n * @property {string} [favicon] - A favicon for the site, if any.\n */\nexport type SearchResult<T extends ContentsOptions> = {\n title: string | null;\n url: string;\n publishedDate?: string;\n author?: string;\n score?: number;\n id: string;\n image?: string;\n favicon?: string;\n} & ContentsResultComponent<T>;\n\n/**\n * Represents a search response object.\n * @typedef {Object} SearchResponse\n * @property {Result[]} results - The list of search results.\n * @property {string} [autopromptString] - The autoprompt string, if applicable.\n * @property {string} [autoDate] - The autoprompt date, if applicable.\n * @property {string} requestId - The request ID for the search.\n */\nexport type SearchResponse<T extends ContentsOptions> = {\n results: SearchResult<T>[];\n autopromptString?: string;\n autoDate?: string;\n requestId: string;\n};\n\n/**\n * Options for the answer endpoint\n * @typedef {Object} AnswerOptions\n * @property {boolean} [stream] - Whether to stream the response. Default false.\n * @property {boolean} [text] - Whether to include text in the source results. Default false.\n * @property {\"exa\" | \"exa-pro\"} [model] - The model to use for generating the answer. Default \"exa\".\n */\nexport type AnswerOptions = {\n stream?: boolean;\n text?: boolean;\n model?: \"exa\" | \"exa-pro\";\n};\n\n/**\n * Represents an answer response object from the /answer endpoint.\n * @typedef {Object} AnswerResponse\n * @property {string} answer - The generated answer text.\n * @property {SearchResult<{}>[]} citations - The sources used to generate the answer.\n * @property {string} [requestId] - Optional request ID for the answer.\n */\nexport type AnswerResponse = {\n answer: string;\n citations: SearchResult<{}>[];\n requestId?: string;\n};\n\nexport type AnswerStreamChunk = {\n /**\n * The partial text content of the answer (if present in this chunk).\n */\n content?: string;\n /**\n * Citations associated with the current chunk of text (if present).\n */\n citations?: Array<{\n id: string;\n url: string;\n title?: string;\n publishedDate?: string;\n author?: string;\n text?: string;\n }>;\n};\n\n/**\n * Represents a streaming answer response chunk from the /answer endpoint.\n * @typedef {Object} AnswerStreamResponse\n * @property {string} [answer] - A chunk of the generated answer text.\n * @property {SearchResult<{}>[]]} [citations] - The sources used to generate the answer.\n */\nexport type AnswerStreamResponse = {\n answer?: string;\n citations?: SearchResult<{}>[];\n};\n\n/**\n * The Exa class encapsulates the API's endpoints.\n */\nclass Exa {\n private baseURL: string;\n private headers: Headers;\n\n /**\n * Helper method to separate out the contents-specific options from the rest.\n */\n private extractContentsOptions<T extends ContentsOptions>(options: T): {\n contentsOptions: ContentsOptions;\n restOptions: Omit<T, keyof ContentsOptions>;\n } {\n const {\n text,\n highlights,\n summary,\n subpages,\n subpageTarget,\n extras,\n livecrawl,\n livecrawlTimeout,\n ...rest\n } = options;\n\n const contentsOptions: ContentsOptions = {};\n\n // Default: if none of text, summary, or highlights is provided, we retrieve text\n if (\n text === undefined &&\n summary === undefined &&\n highlights === undefined &&\n extras === undefined\n ) {\n contentsOptions.text = true;\n }\n\n if (text !== undefined) contentsOptions.text = text;\n if (summary !== undefined) contentsOptions.summary = summary;\n if (highlights !== undefined) contentsOptions.highlights = highlights;\n if (subpages !== undefined) contentsOptions.subpages = subpages;\n if (subpageTarget !== undefined) contentsOptions.subpageTarget = subpageTarget;\n if (extras !== undefined) contentsOptions.extras = extras;\n if (livecrawl !== undefined) contentsOptions.livecrawl = livecrawl;\n if (livecrawlTimeout !== undefined) contentsOptions.livecrawlTimeout = livecrawlTimeout;\n\n return {\n contentsOptions,\n restOptions: rest as Omit<T, keyof ContentsOptions>,\n };\n }\n\n /**\n * Constructs the Exa API client.\n * @param {string} apiKey - The API key for authentication.\n * @param {string} [baseURL] - The base URL of the Exa API.\n */\n constructor(apiKey?: string, baseURL: string = \"https://api.exa.ai\") {\n this.baseURL = baseURL;\n if (!apiKey) {\n apiKey = process.env.EXASEARCH_API_KEY;\n if (!apiKey) {\n throw new Error(\n \"API key must be provided as an argument or as an environment variable (EXASEARCH_API_KEY)\",\n );\n }\n }\n this.headers = new HeadersImpl({\n \"x-api-key\": apiKey,\n \"Content-Type\": \"application/json\",\n \"User-Agent\": \"exa-node 1.4.0\",\n });\n }\n\n /**\n * Makes a request to the Exa API.\n * @param {string} endpoint - The API endpoint to call.\n * @param {string} method - The HTTP method to use.\n * @param {any} [body] - The request body for POST requests.\n * @returns {Promise<any>} The response from the API.\n */\n private async request(\n endpoint: string,\n method: string,\n body?: any,\n ): Promise<any> {\n const response = await fetchImpl(this.baseURL + endpoint, {\n method,\n headers: this.headers,\n body: body ? JSON.stringify(body) : undefined,\n });\n\n if (!response.ok) {\n const message = (await response.json()).error;\n throw new Error(\n `Request failed with status ${response.status}. ${message}`,\n );\n }\n\n return await response.json();\n }\n\n /**\n * Performs a search with an Exa prompt-engineered query.\n * \n * @param {string} query - The query string.\n * @param {RegularSearchOptions} [options] - Additional search options\n * @returns {Promise<SearchResponse<{}>>} A list of relevant search results.\n */\n async search(\n query: string,\n options?: RegularSearchOptions,\n ): Promise<SearchResponse<{}>> {\n return await this.request(\"/search\", \"POST\", { query, ...options });\n }\n\n /**\n * Performs a search with an Exa prompt-engineered query and returns the contents of the documents.\n * \n * @param {string} query - The query string.\n * @param {RegularSearchOptions & T} [options] - Additional search + contents options\n * @returns {Promise<SearchResponse<T>>} A list of relevant search results with requested contents.\n */\n async searchAndContents<T extends ContentsOptions>(\n query: string,\n options?: RegularSearchOptions & T,\n ): Promise<SearchResponse<T>> {\n const { contentsOptions, restOptions } =\n options === undefined\n ? { contentsOptions: { text: true }, restOptions: {} }\n : this.extractContentsOptions(options);\n\n return await this.request(\"/search\", \"POST\", {\n query,\n contents: contentsOptions,\n ...restOptions,\n });\n }\n\n /**\n * Finds similar links to the provided URL.\n * @param {string} url - The URL for which to find similar links.\n * @param {FindSimilarOptions} [options] - Additional options for finding similar links.\n * @returns {Promise<SearchResponse<{}>>} A list of similar search results.\n */\n async findSimilar(\n url: string,\n options?: FindSimilarOptions,\n ): Promise<SearchResponse<{}>> {\n return await this.request(\"/findSimilar\", \"POST\", { url, ...options });\n }\n\n /**\n * Finds similar links to the provided URL and returns the contents of the documents.\n * @param {string} url - The URL for which to find similar links.\n * @param {FindSimilarOptions & T} [options] - Additional options for finding similar links + contents.\n * @returns {Promise<SearchResponse<T>>} A list of similar search results, including requested contents.\n */\n async findSimilarAndContents<T extends ContentsOptions>(\n url: string,\n options?: FindSimilarOptions & T,\n ): Promise<SearchResponse<T>> {\n const { contentsOptions, restOptions } =\n options === undefined\n ? { contentsOptions: { text: true }, restOptions: {} }\n : this.extractContentsOptions(options);\n\n return await this.request(\"/findSimilar\", \"POST\", {\n url,\n contents: contentsOptions,\n ...restOptions,\n });\n }\n\n /**\n * Retrieves contents of documents based on URLs.\n * @param {string | string[] | SearchResult[]} urls - A URL or array of URLs, or an array of SearchResult objects.\n * @param {ContentsOptions} [options] - Additional options for retrieving document contents.\n * @returns {Promise<SearchResponse<T>>} A list of document contents for the requested URLs.\n */\n async getContents<T extends ContentsOptions>(\n urls: string | string[] | SearchResult<T>[],\n options?: T,\n ): Promise<SearchResponse<T>> {\n if (!urls || (Array.isArray(urls) && urls.length === 0)) {\n throw new Error(\"Must provide at least one URL\");\n }\n\n let requestUrls: string[];\n\n if (typeof urls === \"string\") {\n requestUrls = [urls];\n } else if (typeof urls[0] === \"string\") {\n requestUrls = urls as string[];\n } else {\n requestUrls = (urls as SearchResult<T>[]).map((result) => result.url);\n }\n\n const payload = {\n urls: requestUrls,\n ...options,\n };\n\n return await this.request(\"/contents\", \"POST\", payload);\n }\n\n /**\n * Generate an answer to a query.\n * @param {string} query - The question or query to answer.\n * @param {AnswerOptions} [options] - Additional options for answer generation.\n * @returns {Promise<AnswerResponse>} The generated answer and source references.\n * \n * Note: For streaming responses, use the `streamAnswer` method:\n * ```ts\n * for await (const chunk of exa.streamAnswer(query)) {\n * // Handle chunks\n * }\n * ```\n */\n async answer(\n query: string,\n options?: AnswerOptions,\n ): Promise<AnswerResponse> {\n if (options?.stream) {\n throw new Error(\n \"For streaming responses, please use streamAnswer() instead:\\n\\n\" +\n \"for await (const chunk of exa.streamAnswer(query)) {\\n\" +\n \" // Handle chunks\\n\" +\n \"}\"\n );\n }\n\n // For non-streaming requests, make a regular API call\n const requestBody = {\n query,\n stream: false,\n text: options?.text ?? false,\n model: options?.model ?? \"exa\"\n };\n\n return await this.request(\"/answer\", \"POST\", requestBody);\n }\n\n /**\n * Stream an answer as an async generator\n *\n * Each iteration yields a chunk with partial text (`content`) or new citations.\n * Use this if you'd like to read the answer incrementally, e.g. in a chat UI.\n *\n * Example usage:\n * ```ts\n * for await (const chunk of exa.streamAnswer(\"What is quantum computing?\", { text: false })) {\n * if (chunk.content) process.stdout.write(chunk.content);\n * if (chunk.citations) {\n * console.log(\"\\nCitations: \", chunk.citations);\n * }\n * }\n * ```\n */\n async *streamAnswer(\n query: string,\n options?: { text?: boolean; model?: \"exa\" | \"exa-pro\" }\n ): AsyncGenerator<AnswerStreamChunk> {\n // Build the POST body and fetch the streaming response.\n const body = {\n query,\n text: options?.text ?? false,\n stream: true,\n model: options?.model ?? \"exa\"\n };\n\n const response = await fetchImpl(this.baseURL + \"/answer\", {\n method: \"POST\",\n headers: this.headers,\n body: JSON.stringify(body),\n });\n\n if (!response.ok) {\n const message = await response.text();\n throw new Error(\n `Request failed with status ${response.status}. ${message}`,\n );\n }\n\n const reader = response.body?.getReader();\n if (!reader) {\n throw new Error(\"No response body available for streaming.\");\n }\n\n const decoder = new TextDecoder();\n let buffer = \"\";\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split(\"\\n\");\n buffer = lines.pop() || \"\";\n\n for (const line of lines) {\n if (!line.startsWith(\"data: \")) continue;\n\n const jsonStr = line.replace(/^data:\\s*/, \"\").trim();\n if (!jsonStr || jsonStr === \"[DONE]\") {\n continue;\n }\n\n let chunkData: any;\n try {\n chunkData = JSON.parse(jsonStr);\n } catch (err) {\n continue;\n }\n\n const chunk = this.processChunk(chunkData);\n if (chunk.content || chunk.citations) {\n yield chunk;\n }\n }\n }\n\n if (buffer.startsWith(\"data: \")) {\n const leftover = buffer.replace(/^data:\\s*/, \"\").trim();\n if (leftover && leftover !== \"[DONE]\") {\n try {\n const chunkData = JSON.parse(leftover);\n const chunk = this.processChunk(chunkData);\n if (chunk.content || chunk.citations) {\n yield chunk;\n }\n } catch (e) {\n }\n }\n }\n } finally {\n reader.releaseLock();\n }\n }\n\n private processChunk(chunkData: any): AnswerStreamChunk {\n let content: string | undefined;\n let citations:\n | Array<{\n id: string;\n url: string;\n title?: string;\n publishedDate?: string;\n author?: string;\n text?: string;\n }>\n | undefined;\n\n if (chunkData.choices && chunkData.choices[0] && chunkData.choices[0].delta) {\n content = chunkData.choices[0].delta.content;\n }\n\n if (chunkData.citations && chunkData.citations !== \"null\") {\n citations = chunkData.citations.map((c: any) => ({\n id: c.id,\n url: c.url,\n title: c.title,\n publishedDate: c.publishedDate,\n author: c.author,\n text: c.text,\n }));\n }\n\n return { content, citations };\n }\n}\n\nexport default Exa;\n"],"mappings":"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","names":["fetch"]}
|
package/dist/index.mjs
CHANGED
|
@@ -69,11 +69,9 @@ var Exa = class {
|
|
|
69
69
|
* @param {string} endpoint - The API endpoint to call.
|
|
70
70
|
* @param {string} method - The HTTP method to use.
|
|
71
71
|
* @param {any} [body] - The request body for POST requests.
|
|
72
|
-
* @param {boolean} [stream] - Whether to stream the response.
|
|
73
|
-
* @param {(chunk: AnswerStreamResponse) => void} [onChunk] - Callback for handling stream chunks.
|
|
74
72
|
* @returns {Promise<any>} The response from the API.
|
|
75
73
|
*/
|
|
76
|
-
async request(endpoint, method, body
|
|
74
|
+
async request(endpoint, method, body) {
|
|
77
75
|
const response = await fetchImpl(this.baseURL + endpoint, {
|
|
78
76
|
method,
|
|
79
77
|
headers: this.headers,
|
|
@@ -85,42 +83,6 @@ var Exa = class {
|
|
|
85
83
|
`Request failed with status ${response.status}. ${message}`
|
|
86
84
|
);
|
|
87
85
|
}
|
|
88
|
-
if (stream && response.body) {
|
|
89
|
-
const reader = response.body.getReader();
|
|
90
|
-
const decoder = new TextDecoder();
|
|
91
|
-
let buffer = "";
|
|
92
|
-
try {
|
|
93
|
-
while (true) {
|
|
94
|
-
const { done, value } = await reader.read();
|
|
95
|
-
if (done)
|
|
96
|
-
break;
|
|
97
|
-
buffer += decoder.decode(value, { stream: true });
|
|
98
|
-
const lines = buffer.split("\n");
|
|
99
|
-
buffer = lines.pop() || "";
|
|
100
|
-
for (const line of lines) {
|
|
101
|
-
if (line.startsWith("data: ")) {
|
|
102
|
-
try {
|
|
103
|
-
const data = JSON.parse(line.slice(6));
|
|
104
|
-
onChunk?.(data);
|
|
105
|
-
} catch (e) {
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
if (buffer && buffer.startsWith("data: ")) {
|
|
111
|
-
try {
|
|
112
|
-
const data = JSON.parse(buffer.slice(6));
|
|
113
|
-
onChunk?.(data);
|
|
114
|
-
} catch (e) {
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
} catch (error) {
|
|
118
|
-
throw new Error(`Streaming error: ${error?.message || "Unknown error"}`);
|
|
119
|
-
} finally {
|
|
120
|
-
reader.releaseLock();
|
|
121
|
-
}
|
|
122
|
-
return null;
|
|
123
|
-
}
|
|
124
86
|
return await response.json();
|
|
125
87
|
}
|
|
126
88
|
/**
|
|
@@ -196,20 +158,133 @@ var Exa = class {
|
|
|
196
158
|
return await this.request("/contents", "POST", payload);
|
|
197
159
|
}
|
|
198
160
|
/**
|
|
199
|
-
*
|
|
161
|
+
* Generate an answer to a query.
|
|
200
162
|
* @param {string} query - The question or query to answer.
|
|
201
163
|
* @param {AnswerOptions} [options] - Additional options for answer generation.
|
|
202
|
-
* @
|
|
203
|
-
*
|
|
164
|
+
* @returns {Promise<AnswerResponse>} The generated answer and source references.
|
|
165
|
+
*
|
|
166
|
+
* Note: For streaming responses, use the `streamAnswer` method:
|
|
167
|
+
* ```ts
|
|
168
|
+
* for await (const chunk of exa.streamAnswer(query)) {
|
|
169
|
+
* // Handle chunks
|
|
170
|
+
* }
|
|
171
|
+
* ```
|
|
204
172
|
*/
|
|
205
|
-
async answer(query, options
|
|
173
|
+
async answer(query, options) {
|
|
174
|
+
if (options?.stream) {
|
|
175
|
+
throw new Error(
|
|
176
|
+
"For streaming responses, please use streamAnswer() instead:\n\nfor await (const chunk of exa.streamAnswer(query)) {\n // Handle chunks\n}"
|
|
177
|
+
);
|
|
178
|
+
}
|
|
206
179
|
const requestBody = {
|
|
207
180
|
query,
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
181
|
+
stream: false,
|
|
182
|
+
text: options?.text ?? false,
|
|
183
|
+
model: options?.model ?? "exa"
|
|
184
|
+
};
|
|
185
|
+
return await this.request("/answer", "POST", requestBody);
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Stream an answer as an async generator
|
|
189
|
+
*
|
|
190
|
+
* Each iteration yields a chunk with partial text (`content`) or new citations.
|
|
191
|
+
* Use this if you'd like to read the answer incrementally, e.g. in a chat UI.
|
|
192
|
+
*
|
|
193
|
+
* Example usage:
|
|
194
|
+
* ```ts
|
|
195
|
+
* for await (const chunk of exa.streamAnswer("What is quantum computing?", { text: false })) {
|
|
196
|
+
* if (chunk.content) process.stdout.write(chunk.content);
|
|
197
|
+
* if (chunk.citations) {
|
|
198
|
+
* console.log("\nCitations: ", chunk.citations);
|
|
199
|
+
* }
|
|
200
|
+
* }
|
|
201
|
+
* ```
|
|
202
|
+
*/
|
|
203
|
+
async *streamAnswer(query, options) {
|
|
204
|
+
const body = {
|
|
205
|
+
query,
|
|
206
|
+
text: options?.text ?? false,
|
|
207
|
+
stream: true,
|
|
208
|
+
model: options?.model ?? "exa"
|
|
211
209
|
};
|
|
212
|
-
|
|
210
|
+
const response = await fetchImpl(this.baseURL + "/answer", {
|
|
211
|
+
method: "POST",
|
|
212
|
+
headers: this.headers,
|
|
213
|
+
body: JSON.stringify(body)
|
|
214
|
+
});
|
|
215
|
+
if (!response.ok) {
|
|
216
|
+
const message = await response.text();
|
|
217
|
+
throw new Error(
|
|
218
|
+
`Request failed with status ${response.status}. ${message}`
|
|
219
|
+
);
|
|
220
|
+
}
|
|
221
|
+
const reader = response.body?.getReader();
|
|
222
|
+
if (!reader) {
|
|
223
|
+
throw new Error("No response body available for streaming.");
|
|
224
|
+
}
|
|
225
|
+
const decoder = new TextDecoder();
|
|
226
|
+
let buffer = "";
|
|
227
|
+
try {
|
|
228
|
+
while (true) {
|
|
229
|
+
const { done, value } = await reader.read();
|
|
230
|
+
if (done)
|
|
231
|
+
break;
|
|
232
|
+
buffer += decoder.decode(value, { stream: true });
|
|
233
|
+
const lines = buffer.split("\n");
|
|
234
|
+
buffer = lines.pop() || "";
|
|
235
|
+
for (const line of lines) {
|
|
236
|
+
if (!line.startsWith("data: "))
|
|
237
|
+
continue;
|
|
238
|
+
const jsonStr = line.replace(/^data:\s*/, "").trim();
|
|
239
|
+
if (!jsonStr || jsonStr === "[DONE]") {
|
|
240
|
+
continue;
|
|
241
|
+
}
|
|
242
|
+
let chunkData;
|
|
243
|
+
try {
|
|
244
|
+
chunkData = JSON.parse(jsonStr);
|
|
245
|
+
} catch (err) {
|
|
246
|
+
continue;
|
|
247
|
+
}
|
|
248
|
+
const chunk = this.processChunk(chunkData);
|
|
249
|
+
if (chunk.content || chunk.citations) {
|
|
250
|
+
yield chunk;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
if (buffer.startsWith("data: ")) {
|
|
255
|
+
const leftover = buffer.replace(/^data:\s*/, "").trim();
|
|
256
|
+
if (leftover && leftover !== "[DONE]") {
|
|
257
|
+
try {
|
|
258
|
+
const chunkData = JSON.parse(leftover);
|
|
259
|
+
const chunk = this.processChunk(chunkData);
|
|
260
|
+
if (chunk.content || chunk.citations) {
|
|
261
|
+
yield chunk;
|
|
262
|
+
}
|
|
263
|
+
} catch (e) {
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
} finally {
|
|
268
|
+
reader.releaseLock();
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
processChunk(chunkData) {
|
|
272
|
+
let content;
|
|
273
|
+
let citations;
|
|
274
|
+
if (chunkData.choices && chunkData.choices[0] && chunkData.choices[0].delta) {
|
|
275
|
+
content = chunkData.choices[0].delta.content;
|
|
276
|
+
}
|
|
277
|
+
if (chunkData.citations && chunkData.citations !== "null") {
|
|
278
|
+
citations = chunkData.citations.map((c) => ({
|
|
279
|
+
id: c.id,
|
|
280
|
+
url: c.url,
|
|
281
|
+
title: c.title,
|
|
282
|
+
publishedDate: c.publishedDate,
|
|
283
|
+
author: c.author,
|
|
284
|
+
text: c.text
|
|
285
|
+
}));
|
|
286
|
+
}
|
|
287
|
+
return { content, citations };
|
|
213
288
|
}
|
|
214
289
|
};
|
|
215
290
|
var src_default = Exa;
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import fetch, { Headers } from \"cross-fetch\";\n\n// Use native fetch in Node.js environments\nconst fetchImpl = typeof global !== \"undefined\" && global.fetch ? global.fetch : fetch;\nconst HeadersImpl = typeof global !== \"undefined\" && global.Headers ? global.Headers : Headers;\n\nconst isBeta = false;\n\n/**\n * Search options for performing a search query.\n * @typedef {Object} SearchOptions\n * @property {number} [numResults] - Number of search results to return. Default 10. Max 10 for basic plans.\n * @property {string[]} [includeDomains] - List of domains to include in the search.\n * @property {string[]} [excludeDomains] - List of domains to exclude in the search.\n * @property {string} [startCrawlDate] - Start date for results based on crawl date.\n * @property {string} [endCrawlDate] - End date for results based on crawl date.\n * @property {string} [startPublishedDate] - Start date for results based on published date.\n * @property {string} [endPublishedDate] - End date for results based on published date.\n * @property {string} [category] - A data category to focus on, with higher comprehensivity and data cleanliness. Currently, the only category is company.\n * @property {string[]} [includeText] - List of strings that must be present in webpage text of results. Currently only supports 1 string of up to 5 words.\n * @property {string[]} [excludeText] - List of strings that must not be present in webpage text of results. Currently only supports 1 string of up to 5 words.\n * @property {string[]} [flags] - Experimental flags\n */\nexport type BaseSearchOptions = {\n numResults?: number;\n includeDomains?: string[];\n excludeDomains?: string[];\n startCrawlDate?: string;\n endCrawlDate?: string;\n startPublishedDate?: string;\n endPublishedDate?: string;\n category?:\n | \"company\"\n | \"research paper\"\n | \"news\"\n | \"pdf\"\n | \"github\"\n | \"tweet\"\n | \"personal site\"\n | \"linkedin profile\"\n | \"financial report\";\n includeText?: string[];\n excludeText?: string[];\n flags?: string[];\n};\n\n/**\n * Search options for performing a search query.\n * @typedef {Object} RegularSearchOptions\n */\nexport type RegularSearchOptions = BaseSearchOptions & {\n /**\n * If true, the search results are moderated for safety.\n */\n moderation?: boolean;\n\n useAutoprompt?: boolean;\n type?: \"keyword\" | \"neural\" | \"auto\";\n};\n\n/**\n * Options for finding similar links.\n * @typedef {Object} FindSimilarOptions\n * @property {boolean} [excludeSourceDomain] - If true, excludes links from the base domain of the input.\n */\nexport type FindSimilarOptions = BaseSearchOptions & {\n excludeSourceDomain?: boolean;\n};\n\nexport type ExtrasOptions = { links?: number; imageLinks?: number };\n\n/**\n * Search options for performing a search query.\n * @typedef {Object} ContentsOptions\n * @property {TextContentsOptions | boolean} [text] - Options for retrieving text contents.\n * @property {HighlightsContentsOptions | boolean} [highlights] - Options for retrieving highlights.\n * @property {SummaryContentsOptions | boolean} [summary] - Options for retrieving summary.\n * @property {LivecrawlOptions} [livecrawl] - Options for livecrawling contents. Default is \"never\" for neural/auto search, \"fallback\" for keyword search.\n * @property {number} [livecrawlTimeout] - The timeout for livecrawling. Max and default is 10000ms.\n * @property {boolean} [filterEmptyResults] - If true, filters out results with no contents. Default is true.\n * @property {number} [subpages] - The number of subpages to return for each result, where each subpage is derived from an internal link for the result.\n * @property {string | string[]} [subpageTarget] - Text used to match/rank subpages in the returned subpage list. You could use \"about\" to get *about* page for websites. Note that this is a fuzzy matcher.\n * @property {ExtrasOptions} [extras] - Miscelleneous data derived from results\n */\nexport type ContentsOptions = {\n text?: TextContentsOptions | true;\n highlights?: HighlightsContentsOptions | true;\n summary?: SummaryContentsOptions | true;\n livecrawl?: LivecrawlOptions;\n livecrawlTimeout?: number;\n filterEmptyResults?: boolean;\n subpages?: number;\n subpageTarget?: string | string[];\n extras?: ExtrasOptions;\n} & (typeof isBeta extends true ? {} : {});\n\n/**\n * Options for livecrawling contents\n * @typedef {string} LivecrawlOptions\n */\nexport type LivecrawlOptions = \"never\" | \"fallback\" | \"always\" | \"auto\";\n\n/**\n * Options for retrieving text from page.\n * @typedef {Object} TextContentsOptions\n * @property {number} [maxCharacters] - The maximum number of characters to return.\n * @property {boolean} [includeHtmlTags] - If true, includes HTML tags in the returned text. Default: false\n */\nexport type TextContentsOptions = {\n maxCharacters?: number;\n includeHtmlTags?: boolean;\n};\n\n/**\n * Options for retrieving highlights from page.\n * @typedef {Object} HighlightsContentsOptions\n * @property {string} [query] - The query string to use for highlights search.\n * @property {number} [numSentences] - The number of sentences to return for each highlight.\n * @property {number} [highlightsPerUrl] - The number of highlights to return for each URL.\n */\nexport type HighlightsContentsOptions = {\n query?: string;\n numSentences?: number;\n highlightsPerUrl?: number;\n};\n\n/**\n * Options for retrieving summary from page.\n * @typedef {Object} SummaryContentsOptions\n * @property {string} [query] - The query string to use for summary generation.\n */\nexport type SummaryContentsOptions = {\n query?: string;\n};\n\n/**\n * @typedef {Object} TextResponse\n * @property {string} text - Text from page\n */\nexport type TextResponse = { text: string };\n\n/**\n * @typedef {Object} HighlightsResponse\n * @property {string[]} highlights - The highlights as an array of strings.\n * @property {number[]} highlightScores - The corresponding scores as an array of floats, 0 to 1\n */\nexport type HighlightsResponse = {\n highlights: string[];\n highlightScores: number[];\n};\n\n/**\n * @typedef {Object} SummaryResponse\n * @property {string} summary - The generated summary of the page content.\n */\nexport type SummaryResponse = { summary: string };\n\n/**\n * @typedef {Object} ExtrasResponse\n * @property {string[]} links - The links on the page of a result\n * @property {string[]} imageLinks - The image links on the page of a result\n */\nexport type ExtrasResponse = { extras: { links?: string[]; imageLinks?: string[] } };\n\n/**\n * @typedef {Object} SubpagesResponse\n * @property {ContentsResultComponent<T extends ContentsOptions>} subpages - The subpages for a result\n */\nexport type SubpagesResponse<T extends ContentsOptions> = {\n subpages: ContentsResultComponent<T>[];\n};\n\nexport type Default<T extends {}, U> = [keyof T] extends [never] ? U : T;\n\n/**\n * @typedef {Object} ContentsResultComponent\n * Depending on 'ContentsOptions', this yields a combination of 'TextResponse', 'HighlightsResponse', 'SummaryResponse', or an empty object.\n *\n * @template T - A type extending from 'ContentsOptions'.\n */\nexport type ContentsResultComponent<T extends ContentsOptions> = Default<\n (T[\"text\"] extends object | true ? TextResponse : {}) &\n (T[\"highlights\"] extends object | true ? HighlightsResponse : {}) &\n (T[\"summary\"] extends object | true ? SummaryResponse : {}) &\n (T[\"subpages\"] extends number ? SubpagesResponse<T> : {}) &\n (T[\"extras\"] extends object ? ExtrasResponse : {}),\n TextResponse\n>;\n\n/**\n * Represents a search result object.\n * @typedef {Object} SearchResult\n * @property {string} title - The title of the search result.\n * @property {string} url - The URL of the search result.\n * @property {string} [publishedDate] - The estimated creation date of the content.\n * @property {string} [author] - The author of the content, if available.\n * @property {number} [score] - Similarity score between the query/url and the result.\n * @property {string} id - The temporary ID for the document.\n * @property {string} [image] - A representative image for the content, if any.\n * @property {string} [favicon] - A favicon for the site, if any.\n */\nexport type SearchResult<T extends ContentsOptions> = {\n title: string | null;\n url: string;\n publishedDate?: string;\n author?: string;\n score?: number;\n id: string;\n image?: string;\n favicon?: string;\n} & ContentsResultComponent<T>;\n\n/**\n * Represents a search response object.\n * @typedef {Object} SearchResponse\n * @property {Result[]} results - The list of search results.\n * @property {string} [autopromptString] - The autoprompt string, if applicable.\n * @property {string} [autoDate] - The autoprompt date, if applicable.\n * @property {string} requestId - The request ID for the search.\n */\nexport type SearchResponse<T extends ContentsOptions> = {\n results: SearchResult<T>[];\n autopromptString?: string;\n autoDate?: string;\n requestId: string;\n};\n\n/**\n * Options for the answer endpoint\n * @typedef {Object} AnswerOptions\n * @property {number} [expandedQueriesLimit] - Maximum number of query variations (0-4). Default 1.\n * @property {boolean} [stream] - Whether to stream the response. Default false.\n * @property {boolean} [includeText] - Whether to include text in the source results. Default false.\n */\nexport type AnswerOptions = {\n expandedQueriesLimit?: number;\n stream?: boolean;\n includeText?: boolean;\n};\n\n/**\n * Represents an answer response object from the /answer endpoint.\n * @typedef {Object} AnswerResponse\n * @property {string} answer - The generated answer text.\n * @property {SearchResult<{}>[]} sources - The sources used to generate the answer.\n * @property {string} [requestId] - Optional request ID for the answer.\n */\nexport type AnswerResponse = {\n answer: string;\n sources: SearchResult<{}>[];\n requestId?: string;\n};\n\n/**\n * Represents a streaming answer response chunk from the /answer endpoint.\n * @typedef {Object} AnswerStreamResponse\n * @property {string} [answer] - A chunk of the generated answer text.\n * @property {SearchResult<{}>[]]} [sources] - The sources used to generate the answer.\n * @property {string} [error] - Error message if something went wrong.\n */\nexport type AnswerStreamResponse = {\n answer?: string;\n sources?: SearchResult<{}>[];\n error?: string;\n};\n\n/**\n * The Exa class encapsulates the API's endpoints.\n */\nclass Exa {\n private baseURL: string;\n private headers: Headers;\n\n /**\n * Helper method to separate out the contents-specific options from the rest.\n */\n private extractContentsOptions<T extends ContentsOptions>(options: T): {\n contentsOptions: ContentsOptions;\n restOptions: Omit<T, keyof ContentsOptions>;\n } {\n const {\n text,\n highlights,\n summary,\n subpages,\n subpageTarget,\n extras,\n livecrawl,\n livecrawlTimeout,\n ...rest\n } = options;\n\n const contentsOptions: ContentsOptions = {};\n\n // Default: if none of text, summary, or highlights is provided, we retrieve text\n if (\n text === undefined &&\n summary === undefined &&\n highlights === undefined &&\n extras === undefined\n ) {\n contentsOptions.text = true;\n }\n\n if (text !== undefined) contentsOptions.text = text;\n if (summary !== undefined) contentsOptions.summary = summary;\n if (highlights !== undefined) contentsOptions.highlights = highlights;\n if (subpages !== undefined) contentsOptions.subpages = subpages;\n if (subpageTarget !== undefined) contentsOptions.subpageTarget = subpageTarget;\n if (extras !== undefined) contentsOptions.extras = extras;\n if (livecrawl !== undefined) contentsOptions.livecrawl = livecrawl;\n if (livecrawlTimeout !== undefined) contentsOptions.livecrawlTimeout = livecrawlTimeout;\n\n return {\n contentsOptions,\n restOptions: rest as Omit<T, keyof ContentsOptions>,\n };\n }\n\n /**\n * Constructs the Exa API client.\n * @param {string} apiKey - The API key for authentication.\n * @param {string} [baseURL] - The base URL of the Exa API.\n */\n constructor(apiKey?: string, baseURL: string = \"https://api.exa.ai\") {\n this.baseURL = baseURL;\n if (!apiKey) {\n apiKey = process.env.EXASEARCH_API_KEY;\n if (!apiKey) {\n throw new Error(\n \"API key must be provided as an argument or as an environment variable (EXASEARCH_API_KEY)\",\n );\n }\n }\n this.headers = new HeadersImpl({\n \"x-api-key\": apiKey,\n \"Content-Type\": \"application/json\",\n \"User-Agent\": \"exa-node 1.4.0\",\n });\n }\n\n /**\n * Makes a request to the Exa API.\n * @param {string} endpoint - The API endpoint to call.\n * @param {string} method - The HTTP method to use.\n * @param {any} [body] - The request body for POST requests.\n * @param {boolean} [stream] - Whether to stream the response.\n * @param {(chunk: AnswerStreamResponse) => void} [onChunk] - Callback for handling stream chunks.\n * @returns {Promise<any>} The response from the API.\n */\n private async request(\n endpoint: string,\n method: string,\n body?: any,\n stream?: boolean,\n onChunk?: (chunk: AnswerStreamResponse) => void,\n ): Promise<any> {\n const response = await fetchImpl(this.baseURL + endpoint, {\n method,\n headers: this.headers,\n body: body ? JSON.stringify(body) : undefined,\n });\n\n if (!response.ok) {\n const message = (await response.json()).error;\n throw new Error(\n `Request failed with status ${response.status}. ${message}`,\n );\n }\n\n // Streaming logic if `stream` is true\n if (stream && response.body) {\n const reader = response.body.getReader();\n const decoder = new TextDecoder();\n let buffer = '';\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split('\\n');\n buffer = lines.pop() || '';\n\n for (const line of lines) {\n if (line.startsWith('data: ')) {\n try {\n const data = JSON.parse(line.slice(6));\n onChunk?.(data);\n } catch (e) {\n // Could not parse JSON, ignore\n }\n }\n }\n }\n\n if (buffer && buffer.startsWith('data: ')) {\n try {\n const data = JSON.parse(buffer.slice(6));\n onChunk?.(data);\n } catch (e) {\n // Could not parse JSON, ignore\n }\n }\n } catch (error: any) {\n throw new Error(`Streaming error: ${error?.message || 'Unknown error'}`);\n } finally {\n reader.releaseLock();\n }\n\n return null;\n }\n\n return await response.json();\n }\n\n /**\n * Performs a search with an Exa prompt-engineered query.\n * \n * @param {string} query - The query string.\n * @param {RegularSearchOptions} [options] - Additional search options\n * @returns {Promise<SearchResponse<{}>>} A list of relevant search results.\n */\n async search(\n query: string,\n options?: RegularSearchOptions,\n ): Promise<SearchResponse<{}>> {\n return await this.request(\"/search\", \"POST\", { query, ...options });\n }\n\n /**\n * Performs a search with an Exa prompt-engineered query and returns the contents of the documents.\n * \n * @param {string} query - The query string.\n * @param {RegularSearchOptions & T} [options] - Additional search + contents options\n * @returns {Promise<SearchResponse<T>>} A list of relevant search results with requested contents.\n */\n async searchAndContents<T extends ContentsOptions>(\n query: string,\n options?: RegularSearchOptions & T,\n ): Promise<SearchResponse<T>> {\n const { contentsOptions, restOptions } =\n options === undefined\n ? { contentsOptions: { text: true }, restOptions: {} }\n : this.extractContentsOptions(options);\n\n return await this.request(\"/search\", \"POST\", {\n query,\n contents: contentsOptions,\n ...restOptions,\n });\n }\n\n /**\n * Finds similar links to the provided URL.\n * @param {string} url - The URL for which to find similar links.\n * @param {FindSimilarOptions} [options] - Additional options for finding similar links.\n * @returns {Promise<SearchResponse<{}>>} A list of similar search results.\n */\n async findSimilar(\n url: string,\n options?: FindSimilarOptions,\n ): Promise<SearchResponse<{}>> {\n return await this.request(\"/findSimilar\", \"POST\", { url, ...options });\n }\n\n /**\n * Finds similar links to the provided URL and returns the contents of the documents.\n * @param {string} url - The URL for which to find similar links.\n * @param {FindSimilarOptions & T} [options] - Additional options for finding similar links + contents.\n * @returns {Promise<SearchResponse<T>>} A list of similar search results, including requested contents.\n */\n async findSimilarAndContents<T extends ContentsOptions>(\n url: string,\n options?: FindSimilarOptions & T,\n ): Promise<SearchResponse<T>> {\n const { contentsOptions, restOptions } =\n options === undefined\n ? { contentsOptions: { text: true }, restOptions: {} }\n : this.extractContentsOptions(options);\n\n return await this.request(\"/findSimilar\", \"POST\", {\n url,\n contents: contentsOptions,\n ...restOptions,\n });\n }\n\n /**\n * Retrieves contents of documents based on URLs.\n * @param {string | string[] | SearchResult[]} urls - A URL or array of URLs, or an array of SearchResult objects.\n * @param {ContentsOptions} [options] - Additional options for retrieving document contents.\n * @returns {Promise<SearchResponse<T>>} A list of document contents for the requested URLs.\n */\n async getContents<T extends ContentsOptions>(\n urls: string | string[] | SearchResult<T>[],\n options?: T,\n ): Promise<SearchResponse<T>> {\n if (!urls || (Array.isArray(urls) && urls.length === 0)) {\n throw new Error(\"Must provide at least one URL\");\n }\n\n let requestUrls: string[];\n\n if (typeof urls === \"string\") {\n requestUrls = [urls];\n } else if (typeof urls[0] === \"string\") {\n requestUrls = urls as string[];\n } else {\n requestUrls = (urls as SearchResult<T>[]).map((result) => result.url);\n }\n\n const payload = {\n urls: requestUrls,\n ...options,\n };\n\n return await this.request(\"/contents\", \"POST\", payload);\n }\n\n /**\n * Generates an answer to a query using search results as context.\n * @param {string} query - The question or query to answer.\n * @param {AnswerOptions} [options] - Additional options for answer generation.\n * @param {(chunk: AnswerStreamResponse) => void} [onChunk] - Callback for handling stream chunks (if streaming).\n * @returns {Promise<AnswerResponse | null>} The generated answer and source references, or null if streaming.\n */\n async answer(\n query: string,\n options?: AnswerOptions,\n onChunk?: (chunk: AnswerStreamResponse) => void,\n ): Promise<AnswerResponse | null> {\n const requestBody = {\n query,\n expandedQueriesLimit: options?.expandedQueriesLimit ?? 1,\n stream: options?.stream ?? false,\n includeText: options?.includeText ?? false\n };\n\n return await this.request(\"/answer\", \"POST\", requestBody, options?.stream, onChunk);\n }\n}\n\nexport default Exa;\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import fetch, { Headers } from \"cross-fetch\";\n\n// Use native fetch in Node.js environments\nconst fetchImpl = typeof global !== \"undefined\" && global.fetch ? global.fetch : fetch;\nconst HeadersImpl = typeof global !== \"undefined\" && global.Headers ? global.Headers : Headers;\n\nconst isBeta = false;\n\n/**\n * Search options for performing a search query.\n * @typedef {Object} SearchOptions\n * @property {number} [numResults] - Number of search results to return. Default 10. Max 10 for basic plans.\n * @property {string[]} [includeDomains] - List of domains to include in the search.\n * @property {string[]} [excludeDomains] - List of domains to exclude in the search.\n * @property {string} [startCrawlDate] - Start date for results based on crawl date.\n * @property {string} [endCrawlDate] - End date for results based on crawl date.\n * @property {string} [startPublishedDate] - Start date for results based on published date.\n * @property {string} [endPublishedDate] - End date for results based on published date.\n * @property {string} [category] - A data category to focus on, with higher comprehensivity and data cleanliness. Currently, the only category is company.\n * @property {string[]} [includeText] - List of strings that must be present in webpage text of results. Currently only supports 1 string of up to 5 words.\n * @property {string[]} [excludeText] - List of strings that must not be present in webpage text of results. Currently only supports 1 string of up to 5 words.\n * @property {string[]} [flags] - Experimental flags\n */\nexport type BaseSearchOptions = {\n numResults?: number;\n includeDomains?: string[];\n excludeDomains?: string[];\n startCrawlDate?: string;\n endCrawlDate?: string;\n startPublishedDate?: string;\n endPublishedDate?: string;\n category?:\n | \"company\"\n | \"research paper\"\n | \"news\"\n | \"pdf\"\n | \"github\"\n | \"tweet\"\n | \"personal site\"\n | \"linkedin profile\"\n | \"financial report\";\n includeText?: string[];\n excludeText?: string[];\n flags?: string[];\n};\n\n/**\n * Search options for performing a search query.\n * @typedef {Object} RegularSearchOptions\n */\nexport type RegularSearchOptions = BaseSearchOptions & {\n /**\n * If true, the search results are moderated for safety.\n */\n moderation?: boolean;\n\n useAutoprompt?: boolean;\n type?: \"keyword\" | \"neural\" | \"auto\";\n};\n\n/**\n * Options for finding similar links.\n * @typedef {Object} FindSimilarOptions\n * @property {boolean} [excludeSourceDomain] - If true, excludes links from the base domain of the input.\n */\nexport type FindSimilarOptions = BaseSearchOptions & {\n excludeSourceDomain?: boolean;\n};\n\nexport type ExtrasOptions = { links?: number; imageLinks?: number };\n\n/**\n * Search options for performing a search query.\n * @typedef {Object} ContentsOptions\n * @property {TextContentsOptions | boolean} [text] - Options for retrieving text contents.\n * @property {HighlightsContentsOptions | boolean} [highlights] - Options for retrieving highlights.\n * @property {SummaryContentsOptions | boolean} [summary] - Options for retrieving summary.\n * @property {LivecrawlOptions} [livecrawl] - Options for livecrawling contents. Default is \"never\" for neural/auto search, \"fallback\" for keyword search.\n * @property {number} [livecrawlTimeout] - The timeout for livecrawling. Max and default is 10000ms.\n * @property {boolean} [filterEmptyResults] - If true, filters out results with no contents. Default is true.\n * @property {number} [subpages] - The number of subpages to return for each result, where each subpage is derived from an internal link for the result.\n * @property {string | string[]} [subpageTarget] - Text used to match/rank subpages in the returned subpage list. You could use \"about\" to get *about* page for websites. Note that this is a fuzzy matcher.\n * @property {ExtrasOptions} [extras] - Miscelleneous data derived from results\n */\nexport type ContentsOptions = {\n text?: TextContentsOptions | true;\n highlights?: HighlightsContentsOptions | true;\n summary?: SummaryContentsOptions | true;\n livecrawl?: LivecrawlOptions;\n livecrawlTimeout?: number;\n filterEmptyResults?: boolean;\n subpages?: number;\n subpageTarget?: string | string[];\n extras?: ExtrasOptions;\n} & (typeof isBeta extends true ? {} : {});\n\n/**\n * Options for livecrawling contents\n * @typedef {string} LivecrawlOptions\n */\nexport type LivecrawlOptions = \"never\" | \"fallback\" | \"always\" | \"auto\";\n\n/**\n * Options for retrieving text from page.\n * @typedef {Object} TextContentsOptions\n * @property {number} [maxCharacters] - The maximum number of characters to return.\n * @property {boolean} [includeHtmlTags] - If true, includes HTML tags in the returned text. Default: false\n */\nexport type TextContentsOptions = {\n maxCharacters?: number;\n includeHtmlTags?: boolean;\n};\n\n/**\n * Options for retrieving highlights from page.\n * @typedef {Object} HighlightsContentsOptions\n * @property {string} [query] - The query string to use for highlights search.\n * @property {number} [numSentences] - The number of sentences to return for each highlight.\n * @property {number} [highlightsPerUrl] - The number of highlights to return for each URL.\n */\nexport type HighlightsContentsOptions = {\n query?: string;\n numSentences?: number;\n highlightsPerUrl?: number;\n};\n\n/**\n * Options for retrieving summary from page.\n * @typedef {Object} SummaryContentsOptions\n * @property {string} [query] - The query string to use for summary generation.\n */\nexport type SummaryContentsOptions = {\n query?: string;\n};\n\n/**\n * @typedef {Object} TextResponse\n * @property {string} text - Text from page\n */\nexport type TextResponse = { text: string };\n\n/**\n * @typedef {Object} HighlightsResponse\n * @property {string[]} highlights - The highlights as an array of strings.\n * @property {number[]} highlightScores - The corresponding scores as an array of floats, 0 to 1\n */\nexport type HighlightsResponse = {\n highlights: string[];\n highlightScores: number[];\n};\n\n/**\n * @typedef {Object} SummaryResponse\n * @property {string} summary - The generated summary of the page content.\n */\nexport type SummaryResponse = { summary: string };\n\n/**\n * @typedef {Object} ExtrasResponse\n * @property {string[]} links - The links on the page of a result\n * @property {string[]} imageLinks - The image links on the page of a result\n */\nexport type ExtrasResponse = { extras: { links?: string[]; imageLinks?: string[] } };\n\n/**\n * @typedef {Object} SubpagesResponse\n * @property {ContentsResultComponent<T extends ContentsOptions>} subpages - The subpages for a result\n */\nexport type SubpagesResponse<T extends ContentsOptions> = {\n subpages: ContentsResultComponent<T>[];\n};\n\nexport type Default<T extends {}, U> = [keyof T] extends [never] ? U : T;\n\n/**\n * @typedef {Object} ContentsResultComponent\n * Depending on 'ContentsOptions', this yields a combination of 'TextResponse', 'HighlightsResponse', 'SummaryResponse', or an empty object.\n *\n * @template T - A type extending from 'ContentsOptions'.\n */\nexport type ContentsResultComponent<T extends ContentsOptions> = Default<\n (T[\"text\"] extends object | true ? TextResponse : {}) &\n (T[\"highlights\"] extends object | true ? HighlightsResponse : {}) &\n (T[\"summary\"] extends object | true ? SummaryResponse : {}) &\n (T[\"subpages\"] extends number ? SubpagesResponse<T> : {}) &\n (T[\"extras\"] extends object ? ExtrasResponse : {}),\n TextResponse\n>;\n\n/**\n * Represents a search result object.\n * @typedef {Object} SearchResult\n * @property {string} title - The title of the search result.\n * @property {string} url - The URL of the search result.\n * @property {string} [publishedDate] - The estimated creation date of the content.\n * @property {string} [author] - The author of the content, if available.\n * @property {number} [score] - Similarity score between the query/url and the result.\n * @property {string} id - The temporary ID for the document.\n * @property {string} [image] - A representative image for the content, if any.\n * @property {string} [favicon] - A favicon for the site, if any.\n */\nexport type SearchResult<T extends ContentsOptions> = {\n title: string | null;\n url: string;\n publishedDate?: string;\n author?: string;\n score?: number;\n id: string;\n image?: string;\n favicon?: string;\n} & ContentsResultComponent<T>;\n\n/**\n * Represents a search response object.\n * @typedef {Object} SearchResponse\n * @property {Result[]} results - The list of search results.\n * @property {string} [autopromptString] - The autoprompt string, if applicable.\n * @property {string} [autoDate] - The autoprompt date, if applicable.\n * @property {string} requestId - The request ID for the search.\n */\nexport type SearchResponse<T extends ContentsOptions> = {\n results: SearchResult<T>[];\n autopromptString?: string;\n autoDate?: string;\n requestId: string;\n};\n\n/**\n * Options for the answer endpoint\n * @typedef {Object} AnswerOptions\n * @property {boolean} [stream] - Whether to stream the response. Default false.\n * @property {boolean} [text] - Whether to include text in the source results. Default false.\n * @property {\"exa\" | \"exa-pro\"} [model] - The model to use for generating the answer. Default \"exa\".\n */\nexport type AnswerOptions = {\n stream?: boolean;\n text?: boolean;\n model?: \"exa\" | \"exa-pro\";\n};\n\n/**\n * Represents an answer response object from the /answer endpoint.\n * @typedef {Object} AnswerResponse\n * @property {string} answer - The generated answer text.\n * @property {SearchResult<{}>[]} citations - The sources used to generate the answer.\n * @property {string} [requestId] - Optional request ID for the answer.\n */\nexport type AnswerResponse = {\n answer: string;\n citations: SearchResult<{}>[];\n requestId?: string;\n};\n\nexport type AnswerStreamChunk = {\n /**\n * The partial text content of the answer (if present in this chunk).\n */\n content?: string;\n /**\n * Citations associated with the current chunk of text (if present).\n */\n citations?: Array<{\n id: string;\n url: string;\n title?: string;\n publishedDate?: string;\n author?: string;\n text?: string;\n }>;\n};\n\n/**\n * Represents a streaming answer response chunk from the /answer endpoint.\n * @typedef {Object} AnswerStreamResponse\n * @property {string} [answer] - A chunk of the generated answer text.\n * @property {SearchResult<{}>[]]} [citations] - The sources used to generate the answer.\n */\nexport type AnswerStreamResponse = {\n answer?: string;\n citations?: SearchResult<{}>[];\n};\n\n/**\n * The Exa class encapsulates the API's endpoints.\n */\nclass Exa {\n private baseURL: string;\n private headers: Headers;\n\n /**\n * Helper method to separate out the contents-specific options from the rest.\n */\n private extractContentsOptions<T extends ContentsOptions>(options: T): {\n contentsOptions: ContentsOptions;\n restOptions: Omit<T, keyof ContentsOptions>;\n } {\n const {\n text,\n highlights,\n summary,\n subpages,\n subpageTarget,\n extras,\n livecrawl,\n livecrawlTimeout,\n ...rest\n } = options;\n\n const contentsOptions: ContentsOptions = {};\n\n // Default: if none of text, summary, or highlights is provided, we retrieve text\n if (\n text === undefined &&\n summary === undefined &&\n highlights === undefined &&\n extras === undefined\n ) {\n contentsOptions.text = true;\n }\n\n if (text !== undefined) contentsOptions.text = text;\n if (summary !== undefined) contentsOptions.summary = summary;\n if (highlights !== undefined) contentsOptions.highlights = highlights;\n if (subpages !== undefined) contentsOptions.subpages = subpages;\n if (subpageTarget !== undefined) contentsOptions.subpageTarget = subpageTarget;\n if (extras !== undefined) contentsOptions.extras = extras;\n if (livecrawl !== undefined) contentsOptions.livecrawl = livecrawl;\n if (livecrawlTimeout !== undefined) contentsOptions.livecrawlTimeout = livecrawlTimeout;\n\n return {\n contentsOptions,\n restOptions: rest as Omit<T, keyof ContentsOptions>,\n };\n }\n\n /**\n * Constructs the Exa API client.\n * @param {string} apiKey - The API key for authentication.\n * @param {string} [baseURL] - The base URL of the Exa API.\n */\n constructor(apiKey?: string, baseURL: string = \"https://api.exa.ai\") {\n this.baseURL = baseURL;\n if (!apiKey) {\n apiKey = process.env.EXASEARCH_API_KEY;\n if (!apiKey) {\n throw new Error(\n \"API key must be provided as an argument or as an environment variable (EXASEARCH_API_KEY)\",\n );\n }\n }\n this.headers = new HeadersImpl({\n \"x-api-key\": apiKey,\n \"Content-Type\": \"application/json\",\n \"User-Agent\": \"exa-node 1.4.0\",\n });\n }\n\n /**\n * Makes a request to the Exa API.\n * @param {string} endpoint - The API endpoint to call.\n * @param {string} method - The HTTP method to use.\n * @param {any} [body] - The request body for POST requests.\n * @returns {Promise<any>} The response from the API.\n */\n private async request(\n endpoint: string,\n method: string,\n body?: any,\n ): Promise<any> {\n const response = await fetchImpl(this.baseURL + endpoint, {\n method,\n headers: this.headers,\n body: body ? JSON.stringify(body) : undefined,\n });\n\n if (!response.ok) {\n const message = (await response.json()).error;\n throw new Error(\n `Request failed with status ${response.status}. ${message}`,\n );\n }\n\n return await response.json();\n }\n\n /**\n * Performs a search with an Exa prompt-engineered query.\n * \n * @param {string} query - The query string.\n * @param {RegularSearchOptions} [options] - Additional search options\n * @returns {Promise<SearchResponse<{}>>} A list of relevant search results.\n */\n async search(\n query: string,\n options?: RegularSearchOptions,\n ): Promise<SearchResponse<{}>> {\n return await this.request(\"/search\", \"POST\", { query, ...options });\n }\n\n /**\n * Performs a search with an Exa prompt-engineered query and returns the contents of the documents.\n * \n * @param {string} query - The query string.\n * @param {RegularSearchOptions & T} [options] - Additional search + contents options\n * @returns {Promise<SearchResponse<T>>} A list of relevant search results with requested contents.\n */\n async searchAndContents<T extends ContentsOptions>(\n query: string,\n options?: RegularSearchOptions & T,\n ): Promise<SearchResponse<T>> {\n const { contentsOptions, restOptions } =\n options === undefined\n ? { contentsOptions: { text: true }, restOptions: {} }\n : this.extractContentsOptions(options);\n\n return await this.request(\"/search\", \"POST\", {\n query,\n contents: contentsOptions,\n ...restOptions,\n });\n }\n\n /**\n * Finds similar links to the provided URL.\n * @param {string} url - The URL for which to find similar links.\n * @param {FindSimilarOptions} [options] - Additional options for finding similar links.\n * @returns {Promise<SearchResponse<{}>>} A list of similar search results.\n */\n async findSimilar(\n url: string,\n options?: FindSimilarOptions,\n ): Promise<SearchResponse<{}>> {\n return await this.request(\"/findSimilar\", \"POST\", { url, ...options });\n }\n\n /**\n * Finds similar links to the provided URL and returns the contents of the documents.\n * @param {string} url - The URL for which to find similar links.\n * @param {FindSimilarOptions & T} [options] - Additional options for finding similar links + contents.\n * @returns {Promise<SearchResponse<T>>} A list of similar search results, including requested contents.\n */\n async findSimilarAndContents<T extends ContentsOptions>(\n url: string,\n options?: FindSimilarOptions & T,\n ): Promise<SearchResponse<T>> {\n const { contentsOptions, restOptions } =\n options === undefined\n ? { contentsOptions: { text: true }, restOptions: {} }\n : this.extractContentsOptions(options);\n\n return await this.request(\"/findSimilar\", \"POST\", {\n url,\n contents: contentsOptions,\n ...restOptions,\n });\n }\n\n /**\n * Retrieves contents of documents based on URLs.\n * @param {string | string[] | SearchResult[]} urls - A URL or array of URLs, or an array of SearchResult objects.\n * @param {ContentsOptions} [options] - Additional options for retrieving document contents.\n * @returns {Promise<SearchResponse<T>>} A list of document contents for the requested URLs.\n */\n async getContents<T extends ContentsOptions>(\n urls: string | string[] | SearchResult<T>[],\n options?: T,\n ): Promise<SearchResponse<T>> {\n if (!urls || (Array.isArray(urls) && urls.length === 0)) {\n throw new Error(\"Must provide at least one URL\");\n }\n\n let requestUrls: string[];\n\n if (typeof urls === \"string\") {\n requestUrls = [urls];\n } else if (typeof urls[0] === \"string\") {\n requestUrls = urls as string[];\n } else {\n requestUrls = (urls as SearchResult<T>[]).map((result) => result.url);\n }\n\n const payload = {\n urls: requestUrls,\n ...options,\n };\n\n return await this.request(\"/contents\", \"POST\", payload);\n }\n\n /**\n * Generate an answer to a query.\n * @param {string} query - The question or query to answer.\n * @param {AnswerOptions} [options] - Additional options for answer generation.\n * @returns {Promise<AnswerResponse>} The generated answer and source references.\n * \n * Note: For streaming responses, use the `streamAnswer` method:\n * ```ts\n * for await (const chunk of exa.streamAnswer(query)) {\n * // Handle chunks\n * }\n * ```\n */\n async answer(\n query: string,\n options?: AnswerOptions,\n ): Promise<AnswerResponse> {\n if (options?.stream) {\n throw new Error(\n \"For streaming responses, please use streamAnswer() instead:\\n\\n\" +\n \"for await (const chunk of exa.streamAnswer(query)) {\\n\" +\n \" // Handle chunks\\n\" +\n \"}\"\n );\n }\n\n // For non-streaming requests, make a regular API call\n const requestBody = {\n query,\n stream: false,\n text: options?.text ?? false,\n model: options?.model ?? \"exa\"\n };\n\n return await this.request(\"/answer\", \"POST\", requestBody);\n }\n\n /**\n * Stream an answer as an async generator\n *\n * Each iteration yields a chunk with partial text (`content`) or new citations.\n * Use this if you'd like to read the answer incrementally, e.g. in a chat UI.\n *\n * Example usage:\n * ```ts\n * for await (const chunk of exa.streamAnswer(\"What is quantum computing?\", { text: false })) {\n * if (chunk.content) process.stdout.write(chunk.content);\n * if (chunk.citations) {\n * console.log(\"\\nCitations: \", chunk.citations);\n * }\n * }\n * ```\n */\n async *streamAnswer(\n query: string,\n options?: { text?: boolean; model?: \"exa\" | \"exa-pro\" }\n ): AsyncGenerator<AnswerStreamChunk> {\n // Build the POST body and fetch the streaming response.\n const body = {\n query,\n text: options?.text ?? false,\n stream: true,\n model: options?.model ?? \"exa\"\n };\n\n const response = await fetchImpl(this.baseURL + \"/answer\", {\n method: \"POST\",\n headers: this.headers,\n body: JSON.stringify(body),\n });\n\n if (!response.ok) {\n const message = await response.text();\n throw new Error(\n `Request failed with status ${response.status}. ${message}`,\n );\n }\n\n const reader = response.body?.getReader();\n if (!reader) {\n throw new Error(\"No response body available for streaming.\");\n }\n\n const decoder = new TextDecoder();\n let buffer = \"\";\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split(\"\\n\");\n buffer = lines.pop() || \"\";\n\n for (const line of lines) {\n if (!line.startsWith(\"data: \")) continue;\n\n const jsonStr = line.replace(/^data:\\s*/, \"\").trim();\n if (!jsonStr || jsonStr === \"[DONE]\") {\n continue;\n }\n\n let chunkData: any;\n try {\n chunkData = JSON.parse(jsonStr);\n } catch (err) {\n continue;\n }\n\n const chunk = this.processChunk(chunkData);\n if (chunk.content || chunk.citations) {\n yield chunk;\n }\n }\n }\n\n if (buffer.startsWith(\"data: \")) {\n const leftover = buffer.replace(/^data:\\s*/, \"\").trim();\n if (leftover && leftover !== \"[DONE]\") {\n try {\n const chunkData = JSON.parse(leftover);\n const chunk = this.processChunk(chunkData);\n if (chunk.content || chunk.citations) {\n yield chunk;\n }\n } catch (e) {\n }\n }\n }\n } finally {\n reader.releaseLock();\n }\n }\n\n private processChunk(chunkData: any): AnswerStreamChunk {\n let content: string | undefined;\n let citations:\n | Array<{\n id: string;\n url: string;\n title?: string;\n publishedDate?: string;\n author?: string;\n text?: string;\n }>\n | undefined;\n\n if (chunkData.choices && chunkData.choices[0] && chunkData.choices[0].delta) {\n content = chunkData.choices[0].delta.content;\n }\n\n if (chunkData.citations && chunkData.citations !== \"null\") {\n citations = chunkData.citations.map((c: any) => ({\n id: c.id,\n url: c.url,\n title: c.title,\n publishedDate: c.publishedDate,\n author: c.author,\n text: c.text,\n }));\n }\n\n return { content, citations };\n }\n}\n\nexport default Exa;\n"],"mappings":";AAAA,OAAO,SAAS,eAAe;AAG/B,IAAM,YAAY,OAAO,WAAW,eAAe,OAAO,QAAQ,OAAO,QAAQ;AACjF,IAAM,cAAc,OAAO,WAAW,eAAe,OAAO,UAAU,OAAO,UAAU;AAyRvF,IAAM,MAAN,MAAU;AAAA;AAAA;AAAA;AAAA,EAOA,uBAAkD,SAGxD;AACA,UAAM;AAAA,MACJ;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,GAAG;AAAA,IACL,IAAI;AAEJ,UAAM,kBAAmC,CAAC;AAG1C,QACE,SAAS,UACT,YAAY,UACZ,eAAe,UACf,WAAW,QACX;AACA,sBAAgB,OAAO;AAAA,IACzB;AAEA,QAAI,SAAS;AAAW,sBAAgB,OAAO;AAC/C,QAAI,YAAY;AAAW,sBAAgB,UAAU;AACrD,QAAI,eAAe;AAAW,sBAAgB,aAAa;AAC3D,QAAI,aAAa;AAAW,sBAAgB,WAAW;AACvD,QAAI,kBAAkB;AAAW,sBAAgB,gBAAgB;AACjE,QAAI,WAAW;AAAW,sBAAgB,SAAS;AACnD,QAAI,cAAc;AAAW,sBAAgB,YAAY;AACzD,QAAI,qBAAqB;AAAW,sBAAgB,mBAAmB;AAEvE,WAAO;AAAA,MACL;AAAA,MACA,aAAa;AAAA,IACf;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,YAAY,QAAiB,UAAkB,sBAAsB;AACnE,SAAK,UAAU;AACf,QAAI,CAAC,QAAQ;AACX,eAAS,QAAQ,IAAI;AACrB,UAAI,CAAC,QAAQ;AACX,cAAM,IAAI;AAAA,UACR;AAAA,QACF;AAAA,MACF;AAAA,IACF;AACA,SAAK,UAAU,IAAI,YAAY;AAAA,MAC7B,aAAa;AAAA,MACb,gBAAgB;AAAA,MAChB,cAAc;AAAA,IAChB,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAc,QACZ,UACA,QACA,MACc;AACd,UAAM,WAAW,MAAM,UAAU,KAAK,UAAU,UAAU;AAAA,MACxD;AAAA,MACA,SAAS,KAAK;AAAA,MACd,MAAM,OAAO,KAAK,UAAU,IAAI,IAAI;AAAA,IACtC,CAAC;AAED,QAAI,CAAC,SAAS,IAAI;AAChB,YAAM,WAAW,MAAM,SAAS,KAAK,GAAG;AACxC,YAAM,IAAI;AAAA,QACR,8BAA8B,SAAS,WAAW;AAAA,MACpD;AAAA,IACF;AAEA,WAAO,MAAM,SAAS,KAAK;AAAA,EAC7B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,OACJ,OACA,SAC6B;AAC7B,WAAO,MAAM,KAAK,QAAQ,WAAW,QAAQ,EAAE,OAAO,GAAG,QAAQ,CAAC;AAAA,EACpE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,kBACJ,OACA,SAC4B;AAC5B,UAAM,EAAE,iBAAiB,YAAY,IACnC,YAAY,SACR,EAAE,iBAAiB,EAAE,MAAM,KAAK,GAAG,aAAa,CAAC,EAAE,IACnD,KAAK,uBAAuB,OAAO;AAEzC,WAAO,MAAM,KAAK,QAAQ,WAAW,QAAQ;AAAA,MAC3C;AAAA,MACA,UAAU;AAAA,MACV,GAAG;AAAA,IACL,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,YACJ,KACA,SAC6B;AAC7B,WAAO,MAAM,KAAK,QAAQ,gBAAgB,QAAQ,EAAE,KAAK,GAAG,QAAQ,CAAC;AAAA,EACvE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,uBACJ,KACA,SAC4B;AAC5B,UAAM,EAAE,iBAAiB,YAAY,IACnC,YAAY,SACR,EAAE,iBAAiB,EAAE,MAAM,KAAK,GAAG,aAAa,CAAC,EAAE,IACnD,KAAK,uBAAuB,OAAO;AAEzC,WAAO,MAAM,KAAK,QAAQ,gBAAgB,QAAQ;AAAA,MAChD;AAAA,MACA,UAAU;AAAA,MACV,GAAG;AAAA,IACL,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,YACJ,MACA,SAC4B;AAC5B,QAAI,CAAC,QAAS,MAAM,QAAQ,IAAI,KAAK,KAAK,WAAW,GAAI;AACvD,YAAM,IAAI,MAAM,+BAA+B;AAAA,IACjD;AAEA,QAAI;AAEJ,QAAI,OAAO,SAAS,UAAU;AAC5B,oBAAc,CAAC,IAAI;AAAA,IACrB,WAAW,OAAO,KAAK,CAAC,MAAM,UAAU;AACtC,oBAAc;AAAA,IAChB,OAAO;AACL,oBAAe,KAA2B,IAAI,CAAC,WAAW,OAAO,GAAG;AAAA,IACtE;AAEA,UAAM,UAAU;AAAA,MACd,MAAM;AAAA,MACN,GAAG;AAAA,IACL;AAEA,WAAO,MAAM,KAAK,QAAQ,aAAa,QAAQ,OAAO;AAAA,EACxD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAeA,MAAM,OACJ,OACA,SACyB;AACzB,QAAI,SAAS,QAAQ;AACnB,YAAM,IAAI;AAAA,QACR;AAAA,MAIF;AAAA,IACF;AAGA,UAAM,cAAc;AAAA,MAClB;AAAA,MACA,QAAQ;AAAA,MACR,MAAM,SAAS,QAAQ;AAAA,MACvB,OAAO,SAAS,SAAS;AAAA,IAC3B;AAEA,WAAO,MAAM,KAAK,QAAQ,WAAW,QAAQ,WAAW;AAAA,EAC1D;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAkBA,OAAO,aACL,OACA,SACmC;AAEnC,UAAM,OAAO;AAAA,MACX;AAAA,MACA,MAAM,SAAS,QAAQ;AAAA,MACvB,QAAQ;AAAA,MACR,OAAO,SAAS,SAAS;AAAA,IAC3B;AAEA,UAAM,WAAW,MAAM,UAAU,KAAK,UAAU,WAAW;AAAA,MACzD,QAAQ;AAAA,MACR,SAAS,KAAK;AAAA,MACd,MAAM,KAAK,UAAU,IAAI;AAAA,IAC3B,CAAC;AAED,QAAI,CAAC,SAAS,IAAI;AAChB,YAAM,UAAU,MAAM,SAAS,KAAK;AACpC,YAAM,IAAI;AAAA,QACR,8BAA8B,SAAS,WAAW;AAAA,MACpD;AAAA,IACF;AAEA,UAAM,SAAS,SAAS,MAAM,UAAU;AACxC,QAAI,CAAC,QAAQ;AACX,YAAM,IAAI,MAAM,2CAA2C;AAAA,IAC7D;AAEA,UAAM,UAAU,IAAI,YAAY;AAChC,QAAI,SAAS;AAEb,QAAI;AACF,aAAO,MAAM;AACX,cAAM,EAAE,MAAM,MAAM,IAAI,MAAM,OAAO,KAAK;AAC1C,YAAI;AAAM;AAEV,kBAAU,QAAQ,OAAO,OAAO,EAAE,QAAQ,KAAK,CAAC;AAChD,cAAM,QAAQ,OAAO,MAAM,IAAI;AAC/B,iBAAS,MAAM,IAAI,KAAK;AAExB,mBAAW,QAAQ,OAAO;AACxB,cAAI,CAAC,KAAK,WAAW,QAAQ;AAAG;AAEhC,gBAAM,UAAU,KAAK,QAAQ,aAAa,EAAE,EAAE,KAAK;AACnD,cAAI,CAAC,WAAW,YAAY,UAAU;AACpC;AAAA,UACF;AAEA,cAAI;AACJ,cAAI;AACF,wBAAY,KAAK,MAAM,OAAO;AAAA,UAChC,SAAS,KAAP;AACA;AAAA,UACF;AAEA,gBAAM,QAAQ,KAAK,aAAa,SAAS;AACzC,cAAI,MAAM,WAAW,MAAM,WAAW;AACpC,kBAAM;AAAA,UACR;AAAA,QACF;AAAA,MACF;AAEA,UAAI,OAAO,WAAW,QAAQ,GAAG;AAC/B,cAAM,WAAW,OAAO,QAAQ,aAAa,EAAE,EAAE,KAAK;AACtD,YAAI,YAAY,aAAa,UAAU;AACrC,cAAI;AACF,kBAAM,YAAY,KAAK,MAAM,QAAQ;AACrC,kBAAM,QAAQ,KAAK,aAAa,SAAS;AACzC,gBAAI,MAAM,WAAW,MAAM,WAAW;AACpC,oBAAM;AAAA,YACR;AAAA,UACF,SAAS,GAAP;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF,UAAE;AACA,aAAO,YAAY;AAAA,IACrB;AAAA,EACF;AAAA,EAEQ,aAAa,WAAmC;AACtD,QAAI;AACJ,QAAI;AAWJ,QAAI,UAAU,WAAW,UAAU,QAAQ,CAAC,KAAK,UAAU,QAAQ,CAAC,EAAE,OAAO;AAC3E,gBAAU,UAAU,QAAQ,CAAC,EAAE,MAAM;AAAA,IACvC;AAEA,QAAI,UAAU,aAAa,UAAU,cAAc,QAAQ;AACzD,kBAAY,UAAU,UAAU,IAAI,CAAC,OAAY;AAAA,QAC/C,IAAI,EAAE;AAAA,QACN,KAAK,EAAE;AAAA,QACP,OAAO,EAAE;AAAA,QACT,eAAe,EAAE;AAAA,QACjB,QAAQ,EAAE;AAAA,QACV,MAAM,EAAE;AAAA,MACV,EAAE;AAAA,IACJ;AAEA,WAAO,EAAE,SAAS,UAAU;AAAA,EAC9B;AACF;AAEA,IAAO,cAAQ;","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "exa-js",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.10",
|
|
4
4
|
"description": "Exa SDK for Node.js and the browser",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -37,14 +37,16 @@
|
|
|
37
37
|
"@types/node": "^22.10.2",
|
|
38
38
|
"cross-env": "^7.0.3",
|
|
39
39
|
"prettier": "2.8.4",
|
|
40
|
+
"ts-node": "^10.9.2",
|
|
40
41
|
"tsup": "6.6.3",
|
|
41
42
|
"typedoc": "^0.25.4",
|
|
42
43
|
"typedoc-plugin-markdown": "^3.17.1",
|
|
43
|
-
"typescript": "4.9.5",
|
|
44
|
+
"typescript": "^4.9.5",
|
|
44
45
|
"vitest": "0.28.5"
|
|
45
46
|
},
|
|
46
47
|
"dependencies": {
|
|
47
|
-
"cross-fetch": "^4.0.0"
|
|
48
|
+
"cross-fetch": "^4.0.0",
|
|
49
|
+
"dotenv": "^16.4.7"
|
|
48
50
|
},
|
|
49
51
|
"directories": {
|
|
50
52
|
"test": "test"
|