@hydrafetch/node-sdk 0.3.0 → 0.5.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 +30 -1
- package/dist/index.cjs +9 -1
- package/dist/index.d.cts +25 -1
- package/dist/index.d.ts +25 -1
- package/dist/index.js +9 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -25,7 +25,7 @@ const page = await hf.scrape('https://example.com/article');
|
|
|
25
25
|
console.log(page.markdown);
|
|
26
26
|
```
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
Copy your key from [app.hydrafetch.com](https://app.hydrafetch.com). The constructor reads `HYDRAFETCH_API_KEY` when no key is passed.
|
|
29
29
|
|
|
30
30
|
## Scraping
|
|
31
31
|
|
|
@@ -82,6 +82,16 @@ out.results.forEach((item) => console.log(item.url, item.data?.name));
|
|
|
82
82
|
|
|
83
83
|
Pass `prompt` instead of, or alongside, `schema` to describe the fields in plain language.
|
|
84
84
|
|
|
85
|
+
Sites that price or stock by delivery area serve a different page for each area. Pass `location` to fetch as if from a country and language, and `headers` to send the cookie that picks the store or area, the same options `scrape` takes.
|
|
86
|
+
|
|
87
|
+
```ts
|
|
88
|
+
const out = await hf.extract(['https://shop.example/search?q=ghee'], {
|
|
89
|
+
prompt: 'every product with its size and price',
|
|
90
|
+
location: { country: 'in' },
|
|
91
|
+
headers: { Cookie: 'store_id=42' },
|
|
92
|
+
});
|
|
93
|
+
```
|
|
94
|
+
|
|
85
95
|
### Zod schemas
|
|
86
96
|
|
|
87
97
|
If you already use Zod, pass the schema directly. Zod stays optional and is imported only when you
|
|
@@ -167,6 +177,24 @@ await hf.styleguide('https://stripe.com/pricing', { maxAge: 0 }); // one page, r
|
|
|
167
177
|
|
|
168
178
|
For logos in a browser use [`@hydrafetch/client-sdk`](https://github.com/Hydrafetch/client-sdk) or [`@hydrafetch/react`](https://github.com/Hydrafetch/react-sdk) with a publishable key. Those bill against logo pulls rather than credits.
|
|
169
179
|
|
|
180
|
+
## Rating results
|
|
181
|
+
|
|
182
|
+
Tell us when a result was wrong, so it gets looked at. It is free, and rating the same request again replaces the earlier rating.
|
|
183
|
+
|
|
184
|
+
```ts
|
|
185
|
+
const page = await hf.scrape('https://stripe.com/pricing');
|
|
186
|
+
await hf.rateResult({
|
|
187
|
+
requestId: hf.lastRequestId,
|
|
188
|
+
rating: 'bad',
|
|
189
|
+
reasons: ['missing_content'],
|
|
190
|
+
note: 'The enterprise tier is missing',
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
await hf.rateResult({ url: 'https://stripe.com/pricing', rating: 'good' }); // by URL, last 24 hours
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
Reasons are `missing_content`, `wrong_content`, `blocked`, `slow`, `formatting` and `other`.
|
|
197
|
+
|
|
170
198
|
## Error handling
|
|
171
199
|
|
|
172
200
|
All failures throw `HydrafetchError`, carrying the API's error code, HTTP status and request id.
|
|
@@ -235,6 +263,7 @@ const hf = new Hydrafetch({
|
|
|
235
263
|
| `startCrawl(url, options?)` | `string` | 1 per page |
|
|
236
264
|
| `startBatch(urls, options?)` | `string` | 1 per page |
|
|
237
265
|
| `crawlStatus(id)`, `batchStatus(id)` | `JobResult` | free |
|
|
266
|
+
| `rateResult(input)` | `RateResultResponse` | free |
|
|
238
267
|
|
|
239
268
|
Failed requests are not billed. Pricing does not vary with page difficulty, so there is no render, stealth or proxy option to set.
|
|
240
269
|
|
package/dist/index.cjs
CHANGED
|
@@ -129,6 +129,10 @@ var Hydrafetch = class {
|
|
|
129
129
|
timeoutMs;
|
|
130
130
|
maxRetries;
|
|
131
131
|
fetchImpl;
|
|
132
|
+
latestRequestId;
|
|
133
|
+
get lastRequestId() {
|
|
134
|
+
return this.latestRequestId;
|
|
135
|
+
}
|
|
132
136
|
constructor(options = {}) {
|
|
133
137
|
const opts = typeof options === "string" ? { apiKey: options } : options;
|
|
134
138
|
const env = globalThis.process?.env;
|
|
@@ -136,7 +140,7 @@ var Hydrafetch = class {
|
|
|
136
140
|
if (!apiKey) {
|
|
137
141
|
throw new HydrafetchError({
|
|
138
142
|
code: "MISSING_API_KEY",
|
|
139
|
-
message: "No API key. Pass one to the constructor or set HYDRAFETCH_API_KEY.
|
|
143
|
+
message: "No API key. Pass one to the constructor or set HYDRAFETCH_API_KEY. Copy your key from https://app.hydrafetch.com.",
|
|
140
144
|
status: 401
|
|
141
145
|
});
|
|
142
146
|
}
|
|
@@ -174,6 +178,7 @@ var Hydrafetch = class {
|
|
|
174
178
|
body: body === void 0 ? void 0 : JSON.stringify(body),
|
|
175
179
|
signal: controller.signal
|
|
176
180
|
});
|
|
181
|
+
this.latestRequestId = res.headers.get("x-request-id") ?? this.latestRequestId;
|
|
177
182
|
const text = await res.text();
|
|
178
183
|
let parsed;
|
|
179
184
|
try {
|
|
@@ -221,6 +226,9 @@ var Hydrafetch = class {
|
|
|
221
226
|
const page = await this.scrape(url, { ...options, formats: ["markdown"] });
|
|
222
227
|
return page.markdown;
|
|
223
228
|
}
|
|
229
|
+
rateResult(input) {
|
|
230
|
+
return this.request("POST", "/v1/web/feedback", input);
|
|
231
|
+
}
|
|
224
232
|
map(url, options = {}) {
|
|
225
233
|
return this.request("POST", "/v1/web/map", { url, ...options });
|
|
226
234
|
}
|
package/dist/index.d.cts
CHANGED
|
@@ -34,6 +34,10 @@ interface ScrapeBase {
|
|
|
34
34
|
type ScrapeResult<F extends Format = 'markdown'> = ScrapeBase & {
|
|
35
35
|
[K in F]: ScrapeContent[K];
|
|
36
36
|
} & Partial<Omit<ScrapeContent, F>>;
|
|
37
|
+
interface Location {
|
|
38
|
+
country?: string;
|
|
39
|
+
languages?: string[];
|
|
40
|
+
}
|
|
37
41
|
interface ScrapeOptions<F extends readonly Format[] = readonly Format[]> {
|
|
38
42
|
formats?: F;
|
|
39
43
|
maxAge?: number;
|
|
@@ -48,6 +52,7 @@ interface ScrapeOptions<F extends readonly Format[] = readonly Format[]> {
|
|
|
48
52
|
includeLinks?: boolean;
|
|
49
53
|
waitFor?: number;
|
|
50
54
|
timeout?: number;
|
|
55
|
+
location?: Location;
|
|
51
56
|
headers?: Record<string, string>;
|
|
52
57
|
jsonOptions?: Record<string, unknown>;
|
|
53
58
|
}
|
|
@@ -114,6 +119,8 @@ interface ExtractOptions {
|
|
|
114
119
|
showConfidence?: boolean;
|
|
115
120
|
mergeEntities?: boolean;
|
|
116
121
|
maxAge?: number;
|
|
122
|
+
location?: Location;
|
|
123
|
+
headers?: Record<string, string>;
|
|
117
124
|
}
|
|
118
125
|
interface ExtractItem<T = unknown> {
|
|
119
126
|
url: string;
|
|
@@ -231,6 +238,20 @@ interface WaitOptions {
|
|
|
231
238
|
pollIntervalMs?: number;
|
|
232
239
|
onProgress?: (job: JobResult) => void;
|
|
233
240
|
}
|
|
241
|
+
type ResultRating = 'good' | 'bad';
|
|
242
|
+
type ResultFeedbackReason = 'missing_content' | 'wrong_content' | 'blocked' | 'slow' | 'formatting' | 'other';
|
|
243
|
+
interface RateResultInput {
|
|
244
|
+
requestId?: string;
|
|
245
|
+
url?: string;
|
|
246
|
+
rating: ResultRating;
|
|
247
|
+
reasons?: ResultFeedbackReason[];
|
|
248
|
+
note?: string;
|
|
249
|
+
}
|
|
250
|
+
interface RateResultResponse {
|
|
251
|
+
id: string;
|
|
252
|
+
requestId: string;
|
|
253
|
+
rating: ResultRating;
|
|
254
|
+
}
|
|
234
255
|
|
|
235
256
|
interface HydrafetchOptions {
|
|
236
257
|
apiKey?: string;
|
|
@@ -245,10 +266,13 @@ declare class Hydrafetch {
|
|
|
245
266
|
private readonly timeoutMs;
|
|
246
267
|
private readonly maxRetries;
|
|
247
268
|
private readonly fetchImpl;
|
|
269
|
+
private latestRequestId;
|
|
270
|
+
get lastRequestId(): string | undefined;
|
|
248
271
|
constructor(options?: HydrafetchOptions | string);
|
|
249
272
|
private request;
|
|
250
273
|
scrape<const F extends readonly Format[] = ['markdown']>(url: string, options?: ScrapeOptions<F>): Promise<ScrapeResult<F[number]>>;
|
|
251
274
|
markdown(url: string, options?: Omit<ScrapeOptions, 'formats'>): Promise<string>;
|
|
275
|
+
rateResult(input: RateResultInput): Promise<RateResultResponse>;
|
|
252
276
|
map(url: string, options?: MapOptions): Promise<MapResult>;
|
|
253
277
|
search(query: string, options?: SearchOptions): Promise<SearchResult>;
|
|
254
278
|
extract<T = unknown>(urls: string | string[], options?: ExtractOptions): Promise<ExtractResult<T>>;
|
|
@@ -290,4 +314,4 @@ declare class HydrafetchTimeoutError extends HydrafetchError {
|
|
|
290
314
|
constructor(message: string);
|
|
291
315
|
}
|
|
292
316
|
|
|
293
|
-
export { type BatchOptions, type BrandOptions, type BrandResult, type CrawlOptions, type ExtractItem, type ExtractOptions, type ExtractResult, type ExtractSchema, type Format, Hydrafetch, HydrafetchError, type HydrafetchOptions, HydrafetchTimeoutError, type ImagesResult, type JobPage, type JobResult, type JobStatus, type LogoResult, type MapOptions, type MapResult, type PageImage, type PageMetadata, type ScrapeBase, type ScrapeContent, type ScrapeOptions, type ScrapeResult, type ScreenshotOptions, type ScreenshotResult, type SearchOptions, type SearchResult, type SearchResultItem, type StyleguideOptions, type StyleguideResult, type Usage, type WaitOptions, type ZodLike };
|
|
317
|
+
export { type BatchOptions, type BrandOptions, type BrandResult, type CrawlOptions, type ExtractItem, type ExtractOptions, type ExtractResult, type ExtractSchema, type Format, Hydrafetch, HydrafetchError, type HydrafetchOptions, HydrafetchTimeoutError, type ImagesResult, type JobPage, type JobResult, type JobStatus, type Location, type LogoResult, type MapOptions, type MapResult, type PageImage, type PageMetadata, type RateResultInput, type RateResultResponse, type ResultFeedbackReason, type ResultRating, type ScrapeBase, type ScrapeContent, type ScrapeOptions, type ScrapeResult, type ScreenshotOptions, type ScreenshotResult, type SearchOptions, type SearchResult, type SearchResultItem, type StyleguideOptions, type StyleguideResult, type Usage, type WaitOptions, type ZodLike };
|
package/dist/index.d.ts
CHANGED
|
@@ -34,6 +34,10 @@ interface ScrapeBase {
|
|
|
34
34
|
type ScrapeResult<F extends Format = 'markdown'> = ScrapeBase & {
|
|
35
35
|
[K in F]: ScrapeContent[K];
|
|
36
36
|
} & Partial<Omit<ScrapeContent, F>>;
|
|
37
|
+
interface Location {
|
|
38
|
+
country?: string;
|
|
39
|
+
languages?: string[];
|
|
40
|
+
}
|
|
37
41
|
interface ScrapeOptions<F extends readonly Format[] = readonly Format[]> {
|
|
38
42
|
formats?: F;
|
|
39
43
|
maxAge?: number;
|
|
@@ -48,6 +52,7 @@ interface ScrapeOptions<F extends readonly Format[] = readonly Format[]> {
|
|
|
48
52
|
includeLinks?: boolean;
|
|
49
53
|
waitFor?: number;
|
|
50
54
|
timeout?: number;
|
|
55
|
+
location?: Location;
|
|
51
56
|
headers?: Record<string, string>;
|
|
52
57
|
jsonOptions?: Record<string, unknown>;
|
|
53
58
|
}
|
|
@@ -114,6 +119,8 @@ interface ExtractOptions {
|
|
|
114
119
|
showConfidence?: boolean;
|
|
115
120
|
mergeEntities?: boolean;
|
|
116
121
|
maxAge?: number;
|
|
122
|
+
location?: Location;
|
|
123
|
+
headers?: Record<string, string>;
|
|
117
124
|
}
|
|
118
125
|
interface ExtractItem<T = unknown> {
|
|
119
126
|
url: string;
|
|
@@ -231,6 +238,20 @@ interface WaitOptions {
|
|
|
231
238
|
pollIntervalMs?: number;
|
|
232
239
|
onProgress?: (job: JobResult) => void;
|
|
233
240
|
}
|
|
241
|
+
type ResultRating = 'good' | 'bad';
|
|
242
|
+
type ResultFeedbackReason = 'missing_content' | 'wrong_content' | 'blocked' | 'slow' | 'formatting' | 'other';
|
|
243
|
+
interface RateResultInput {
|
|
244
|
+
requestId?: string;
|
|
245
|
+
url?: string;
|
|
246
|
+
rating: ResultRating;
|
|
247
|
+
reasons?: ResultFeedbackReason[];
|
|
248
|
+
note?: string;
|
|
249
|
+
}
|
|
250
|
+
interface RateResultResponse {
|
|
251
|
+
id: string;
|
|
252
|
+
requestId: string;
|
|
253
|
+
rating: ResultRating;
|
|
254
|
+
}
|
|
234
255
|
|
|
235
256
|
interface HydrafetchOptions {
|
|
236
257
|
apiKey?: string;
|
|
@@ -245,10 +266,13 @@ declare class Hydrafetch {
|
|
|
245
266
|
private readonly timeoutMs;
|
|
246
267
|
private readonly maxRetries;
|
|
247
268
|
private readonly fetchImpl;
|
|
269
|
+
private latestRequestId;
|
|
270
|
+
get lastRequestId(): string | undefined;
|
|
248
271
|
constructor(options?: HydrafetchOptions | string);
|
|
249
272
|
private request;
|
|
250
273
|
scrape<const F extends readonly Format[] = ['markdown']>(url: string, options?: ScrapeOptions<F>): Promise<ScrapeResult<F[number]>>;
|
|
251
274
|
markdown(url: string, options?: Omit<ScrapeOptions, 'formats'>): Promise<string>;
|
|
275
|
+
rateResult(input: RateResultInput): Promise<RateResultResponse>;
|
|
252
276
|
map(url: string, options?: MapOptions): Promise<MapResult>;
|
|
253
277
|
search(query: string, options?: SearchOptions): Promise<SearchResult>;
|
|
254
278
|
extract<T = unknown>(urls: string | string[], options?: ExtractOptions): Promise<ExtractResult<T>>;
|
|
@@ -290,4 +314,4 @@ declare class HydrafetchTimeoutError extends HydrafetchError {
|
|
|
290
314
|
constructor(message: string);
|
|
291
315
|
}
|
|
292
316
|
|
|
293
|
-
export { type BatchOptions, type BrandOptions, type BrandResult, type CrawlOptions, type ExtractItem, type ExtractOptions, type ExtractResult, type ExtractSchema, type Format, Hydrafetch, HydrafetchError, type HydrafetchOptions, HydrafetchTimeoutError, type ImagesResult, type JobPage, type JobResult, type JobStatus, type LogoResult, type MapOptions, type MapResult, type PageImage, type PageMetadata, type ScrapeBase, type ScrapeContent, type ScrapeOptions, type ScrapeResult, type ScreenshotOptions, type ScreenshotResult, type SearchOptions, type SearchResult, type SearchResultItem, type StyleguideOptions, type StyleguideResult, type Usage, type WaitOptions, type ZodLike };
|
|
317
|
+
export { type BatchOptions, type BrandOptions, type BrandResult, type CrawlOptions, type ExtractItem, type ExtractOptions, type ExtractResult, type ExtractSchema, type Format, Hydrafetch, HydrafetchError, type HydrafetchOptions, HydrafetchTimeoutError, type ImagesResult, type JobPage, type JobResult, type JobStatus, type Location, type LogoResult, type MapOptions, type MapResult, type PageImage, type PageMetadata, type RateResultInput, type RateResultResponse, type ResultFeedbackReason, type ResultRating, type ScrapeBase, type ScrapeContent, type ScrapeOptions, type ScrapeResult, type ScreenshotOptions, type ScreenshotResult, type SearchOptions, type SearchResult, type SearchResultItem, type StyleguideOptions, type StyleguideResult, type Usage, type WaitOptions, type ZodLike };
|
package/dist/index.js
CHANGED
|
@@ -101,6 +101,10 @@ var Hydrafetch = class {
|
|
|
101
101
|
timeoutMs;
|
|
102
102
|
maxRetries;
|
|
103
103
|
fetchImpl;
|
|
104
|
+
latestRequestId;
|
|
105
|
+
get lastRequestId() {
|
|
106
|
+
return this.latestRequestId;
|
|
107
|
+
}
|
|
104
108
|
constructor(options = {}) {
|
|
105
109
|
const opts = typeof options === "string" ? { apiKey: options } : options;
|
|
106
110
|
const env = globalThis.process?.env;
|
|
@@ -108,7 +112,7 @@ var Hydrafetch = class {
|
|
|
108
112
|
if (!apiKey) {
|
|
109
113
|
throw new HydrafetchError({
|
|
110
114
|
code: "MISSING_API_KEY",
|
|
111
|
-
message: "No API key. Pass one to the constructor or set HYDRAFETCH_API_KEY.
|
|
115
|
+
message: "No API key. Pass one to the constructor or set HYDRAFETCH_API_KEY. Copy your key from https://app.hydrafetch.com.",
|
|
112
116
|
status: 401
|
|
113
117
|
});
|
|
114
118
|
}
|
|
@@ -146,6 +150,7 @@ var Hydrafetch = class {
|
|
|
146
150
|
body: body === void 0 ? void 0 : JSON.stringify(body),
|
|
147
151
|
signal: controller.signal
|
|
148
152
|
});
|
|
153
|
+
this.latestRequestId = res.headers.get("x-request-id") ?? this.latestRequestId;
|
|
149
154
|
const text = await res.text();
|
|
150
155
|
let parsed;
|
|
151
156
|
try {
|
|
@@ -193,6 +198,9 @@ var Hydrafetch = class {
|
|
|
193
198
|
const page = await this.scrape(url, { ...options, formats: ["markdown"] });
|
|
194
199
|
return page.markdown;
|
|
195
200
|
}
|
|
201
|
+
rateResult(input) {
|
|
202
|
+
return this.request("POST", "/v1/web/feedback", input);
|
|
203
|
+
}
|
|
196
204
|
map(url, options = {}) {
|
|
197
205
|
return this.request("POST", "/v1/web/map", { url, ...options });
|
|
198
206
|
}
|
package/package.json
CHANGED