crw-sdk 0.22.0 → 0.23.0

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 CHANGED
@@ -61,11 +61,13 @@ CRW_LOCAL=1 node app.js
61
61
  ¹ Local search needs a SearXNG URL configured on the engine.
62
62
 
63
63
  ```ts
64
- // Structured extraction:
65
- const data = await crw.extract({
64
+ // Structured extraction (async job → per-URL results array):
65
+ const results = await crw.extract({
66
66
  urls: ["https://example.com"],
67
67
  schema: { type: "object", properties: { title: { type: "string" } } },
68
68
  });
69
+ // results: [{ url, status, data, error, llmUsage }]
70
+ for (const r of results) if (r.status === "completed") console.log(r.url, r.data);
69
71
 
70
72
  // Parse a PDF:
71
73
  import { readFileSync } from "node:fs";
@@ -170,19 +170,27 @@ class CrwClient {
170
170
  Object.assign(args, rest);
171
171
  return this.localTransport().toolCall("crw_parse_file", args);
172
172
  }
173
- /** Structured LLM extraction across URLs (HTTP mode only). */
173
+ /**
174
+ * Native multi-URL structured extraction (HTTP mode only). Starts an async
175
+ * `/v1/extract` job and polls until complete, returning a per-URL results
176
+ * array (`[{ url, status, data, error, llmUsage }]`) in request order.
177
+ */
174
178
  async extract(opts) {
175
179
  if (!this.apiUrl)
176
180
  throw new errors_js_1.CrwError(httpOnlyHint("extract", "LLM extract job endpoint"));
177
- const { urls, prompt, schema, systemPrompt, pollInterval = 2, timeout = 120 } = opts;
181
+ const { urls, prompt, schema, llmApiKey, llmProvider, llmModel, pollInterval = 2, timeout = 120 } = opts;
178
182
  const body = { urls: [...urls] };
179
183
  if (prompt !== undefined)
180
184
  body.prompt = prompt;
181
185
  if (schema !== undefined)
182
186
  body.schema = schema;
183
- if (systemPrompt !== undefined)
184
- body.systemPrompt = systemPrompt;
185
- const start = await this.httpRequest("POST", "/v2/extract", body, { raw: true });
187
+ if (llmApiKey !== undefined)
188
+ body.llmApiKey = llmApiKey;
189
+ if (llmProvider !== undefined)
190
+ body.llmProvider = llmProvider;
191
+ if (llmModel !== undefined)
192
+ body.llmModel = llmModel;
193
+ const start = await this.httpRequest("POST", "/v1/extract", body, { raw: true });
186
194
  const jobId = start.id;
187
195
  if (!jobId)
188
196
  throw new errors_js_1.CrwError(`extract did not return job ID: ${JSON.stringify(start)}`);
@@ -190,9 +198,9 @@ class CrwClient {
190
198
  for (;;) {
191
199
  if (Date.now() > deadline)
192
200
  throw new errors_js_1.CrwTimeoutError(`Extract ${jobId} timed out after ${timeout}s`);
193
- const status = await this.httpRequest("GET", `/v2/extract/${jobId}`, undefined, { raw: true, checkSuccess: false });
201
+ const status = await this.httpRequest("GET", `/v1/extract/${jobId}`, undefined, { raw: true, checkSuccess: false });
194
202
  if (status.status === "completed")
195
- return status.data ?? {};
203
+ return status.results ?? [];
196
204
  if (status.status === "failed")
197
205
  throw new errors_js_1.CrwError(`Extract failed: ${status.error ?? "unknown"}`);
198
206
  await sleep(pollInterval * 1000);
@@ -37,7 +37,11 @@ export declare class CrwClient {
37
37
  * Parse a document (PDF) into markdown / structured JSON. Works in both modes.
38
38
  */
39
39
  parseFile(content: Uint8Array, opts?: ParseFileOptions): Promise<ParseResult>;
40
- /** Structured LLM extraction across URLs (HTTP mode only). */
40
+ /**
41
+ * Native multi-URL structured extraction (HTTP mode only). Starts an async
42
+ * `/v1/extract` job and polls until complete, returning a per-URL results
43
+ * array (`[{ url, status, data, error, llmUsage }]`) in request order.
44
+ */
41
45
  extract(opts: ExtractOptions): Promise<ExtractResult>;
42
46
  /** Scrape many URLs in one async batch job (HTTP mode only). */
43
47
  batchScrape(urls: string[], opts?: BatchScrapeOptions): Promise<BatchResult>;
@@ -167,19 +167,27 @@ export class CrwClient {
167
167
  Object.assign(args, rest);
168
168
  return this.localTransport().toolCall("crw_parse_file", args);
169
169
  }
170
- /** Structured LLM extraction across URLs (HTTP mode only). */
170
+ /**
171
+ * Native multi-URL structured extraction (HTTP mode only). Starts an async
172
+ * `/v1/extract` job and polls until complete, returning a per-URL results
173
+ * array (`[{ url, status, data, error, llmUsage }]`) in request order.
174
+ */
171
175
  async extract(opts) {
172
176
  if (!this.apiUrl)
173
177
  throw new CrwError(httpOnlyHint("extract", "LLM extract job endpoint"));
174
- const { urls, prompt, schema, systemPrompt, pollInterval = 2, timeout = 120 } = opts;
178
+ const { urls, prompt, schema, llmApiKey, llmProvider, llmModel, pollInterval = 2, timeout = 120 } = opts;
175
179
  const body = { urls: [...urls] };
176
180
  if (prompt !== undefined)
177
181
  body.prompt = prompt;
178
182
  if (schema !== undefined)
179
183
  body.schema = schema;
180
- if (systemPrompt !== undefined)
181
- body.systemPrompt = systemPrompt;
182
- const start = await this.httpRequest("POST", "/v2/extract", body, { raw: true });
184
+ if (llmApiKey !== undefined)
185
+ body.llmApiKey = llmApiKey;
186
+ if (llmProvider !== undefined)
187
+ body.llmProvider = llmProvider;
188
+ if (llmModel !== undefined)
189
+ body.llmModel = llmModel;
190
+ const start = await this.httpRequest("POST", "/v1/extract", body, { raw: true });
183
191
  const jobId = start.id;
184
192
  if (!jobId)
185
193
  throw new CrwError(`extract did not return job ID: ${JSON.stringify(start)}`);
@@ -187,9 +195,9 @@ export class CrwClient {
187
195
  for (;;) {
188
196
  if (Date.now() > deadline)
189
197
  throw new CrwTimeoutError(`Extract ${jobId} timed out after ${timeout}s`);
190
- const status = await this.httpRequest("GET", `/v2/extract/${jobId}`, undefined, { raw: true, checkSuccess: false });
198
+ const status = await this.httpRequest("GET", `/v1/extract/${jobId}`, undefined, { raw: true, checkSuccess: false });
191
199
  if (status.status === "completed")
192
- return status.data ?? {};
200
+ return status.results ?? [];
193
201
  if (status.status === "failed")
194
202
  throw new CrwError(`Extract failed: ${status.error ?? "unknown"}`);
195
203
  await sleep(pollInterval * 1000);
@@ -60,7 +60,10 @@ export interface ExtractOptions {
60
60
  urls: string[];
61
61
  prompt?: string;
62
62
  schema?: Json;
63
- systemPrompt?: string;
63
+ /** BYOK: use your own LLM key/provider/model instead of the server's. */
64
+ llmApiKey?: string;
65
+ llmProvider?: string;
66
+ llmModel?: string;
64
67
  pollInterval?: number;
65
68
  timeout?: number;
66
69
  }
@@ -80,7 +83,8 @@ export type ScrapeResult = Json;
80
83
  export type CrawlResult = Json[];
81
84
  export type SearchResult = Json | Json[];
82
85
  export type ParseResult = Json;
83
- export type ExtractResult = Json;
86
+ /** Native `/v1/extract` returns one result object per URL, in request order. */
87
+ export type ExtractResult = Json[];
84
88
  export type BatchResult = Json[];
85
89
  export type Capabilities = Json;
86
90
  export type DiffResult = Json;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "crw-sdk",
3
- "version": "0.22.0",
3
+ "version": "0.23.0",
4
4
  "description": "TypeScript/JavaScript SDK for CRW — scrape, crawl, map, search, parse, and extract any website",
5
5
  "license": "MIT",
6
6
  "homepage": "https://github.com/us/crw",