@datafuel/sdk 0.3.0 → 0.4.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 +33 -7
- package/dist/index.cjs +64 -16
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +62 -7
- package/dist/index.d.ts +62 -7
- package/dist/index.js +63 -16
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/client.ts +44 -2
- package/src/core.ts +29 -20
- package/src/errors.ts +12 -1
- package/src/index.ts +4 -0
- package/src/models.ts +33 -3
package/dist/index.d.cts
CHANGED
|
@@ -40,7 +40,9 @@ interface AI {
|
|
|
40
40
|
prompt?: string;
|
|
41
41
|
/** Example JSON object the output must follow. */
|
|
42
42
|
format?: unknown;
|
|
43
|
-
|
|
43
|
+
/** Required. One of the providers `df.aiProviders()` lists; the API answers 400 INVALID_ATTRIBUTES without it. */
|
|
44
|
+
provider?: string;
|
|
45
|
+
/** One of the models `df.aiProviders()` lists for `provider`. Omit for the provider's default. */
|
|
44
46
|
model?: string;
|
|
45
47
|
apiKey?: string;
|
|
46
48
|
}
|
|
@@ -54,9 +56,15 @@ interface ScrapeOptions {
|
|
|
54
56
|
jsRendering?: boolean;
|
|
55
57
|
waitFor?: string;
|
|
56
58
|
waitForTimeoutMs?: number;
|
|
57
|
-
/**
|
|
59
|
+
/**
|
|
60
|
+
* Browser actions run after load: an array of single-action objects, run in
|
|
61
|
+
* order, e.g. `[{ click: "#more" }, { wait_ms: 1000 }, { click: "#more" }]`.
|
|
62
|
+
* An object keyed by action is still accepted, but its order is not
|
|
63
|
+
* guaranteed and an action cannot repeat. `df.jsInstructions()` lists them.
|
|
64
|
+
*/
|
|
58
65
|
jsInstructions?: unknown;
|
|
59
|
-
|
|
66
|
+
/** Resource types the browser must not load: one, e.g. `"Image"`, or several. */
|
|
67
|
+
blockResource?: string | string[];
|
|
60
68
|
/** Markdown only: always render just the `<main>` / `<article>` container. */
|
|
61
69
|
mainContentOnly?: boolean;
|
|
62
70
|
/** Markdown only: `false` drops images and saves tokens. */
|
|
@@ -445,6 +453,28 @@ interface JsInstruction {
|
|
|
445
453
|
iframe: boolean;
|
|
446
454
|
example: unknown;
|
|
447
455
|
}
|
|
456
|
+
/** An LLM provider `ai.provider` accepts, with the models `ai.model` accepts for it. */
|
|
457
|
+
interface AIProvider {
|
|
458
|
+
name: string;
|
|
459
|
+
models: string[];
|
|
460
|
+
}
|
|
461
|
+
/** The anti-bot protection in front of one host and path, from `checkProtection`. */
|
|
462
|
+
interface ProtectionCheck {
|
|
463
|
+
host: string;
|
|
464
|
+
path: string;
|
|
465
|
+
/** cloudflare, cloudflare_5sec, akamai, imperva, perimeterx or unprotected. */
|
|
466
|
+
protection_type: string;
|
|
467
|
+
}
|
|
468
|
+
/** The state of the API. `checks` is filled by a deep check only, keyed by dependency. */
|
|
469
|
+
interface Health {
|
|
470
|
+
status: "ok" | "degraded" | (string & {});
|
|
471
|
+
checks?: Record<string, {
|
|
472
|
+
status: "ok" | "fail" | (string & {});
|
|
473
|
+
latency_ms: number;
|
|
474
|
+
}>;
|
|
475
|
+
/** Whether the API can serve requests. */
|
|
476
|
+
ok: boolean;
|
|
477
|
+
}
|
|
448
478
|
/** A named proxy location: a city, or an ASN. */
|
|
449
479
|
interface ProxyLocation {
|
|
450
480
|
code: string;
|
|
@@ -488,7 +518,7 @@ declare class Capabilities {
|
|
|
488
518
|
|
|
489
519
|
declare const DEFAULT_BASE_URL = "https://scraping-api.datafuel.ai/api/v1";
|
|
490
520
|
/** Kept in step with package.json by a test; see test/hardening.test.ts. */
|
|
491
|
-
declare const VERSION = "0.
|
|
521
|
+
declare const VERSION = "0.4.0";
|
|
492
522
|
/** Options for the llm_scraping module, which reads its proxy country here. */
|
|
493
523
|
interface AskOptions {
|
|
494
524
|
engine: Engine | string;
|
|
@@ -556,7 +586,10 @@ interface SearchOptions {
|
|
|
556
586
|
ludocid?: string;
|
|
557
587
|
lsig?: string;
|
|
558
588
|
ibp?: string;
|
|
559
|
-
/**
|
|
589
|
+
/**
|
|
590
|
+
* Accepted but not used yet: searches leave through DataFuel's own pool.
|
|
591
|
+
* Target a market with `country` and `language`.
|
|
592
|
+
*/
|
|
560
593
|
proxyCountry?: string;
|
|
561
594
|
/** Default json. */
|
|
562
595
|
format?: "json" | "html" | "markdown";
|
|
@@ -739,6 +772,21 @@ declare class DataFuel {
|
|
|
739
772
|
capabilities(options?: CallOptions): Promise<Capabilities>;
|
|
740
773
|
/** The browser actions `jsInstructions` accepts, with their arguments. Needs no key. */
|
|
741
774
|
jsInstructions(options?: CallOptions): Promise<JsInstruction[]>;
|
|
775
|
+
/** The LLM providers and models `ai` accepts. Needs no key. */
|
|
776
|
+
aiProviders(options?: CallOptions): Promise<AIProvider[]>;
|
|
777
|
+
/**
|
|
778
|
+
* Whether the API is up. `deep` also checks the dependencies it needs to
|
|
779
|
+
* serve scrapes. A degraded report is returned, not thrown: read `ok`.
|
|
780
|
+
* Needs no key.
|
|
781
|
+
*/
|
|
782
|
+
health(options?: CallOptions & {
|
|
783
|
+
deep?: boolean;
|
|
784
|
+
}): Promise<Health>;
|
|
785
|
+
/**
|
|
786
|
+
* Which anti-bot protection sits in front of each URL. Nothing is scraped
|
|
787
|
+
* and nothing is charged; invalid URLs are skipped.
|
|
788
|
+
*/
|
|
789
|
+
checkProtection(urls: string[], options?: CallOptions): Promise<ProtectionCheck[]>;
|
|
742
790
|
/** Countries, regions and cities a proxy type can exit from. */
|
|
743
791
|
proxyLocations(options?: CallOptions & {
|
|
744
792
|
proxyType?: string;
|
|
@@ -792,7 +840,7 @@ declare class NoApiKey extends DataFuelError {
|
|
|
792
840
|
declare class TransportError extends DataFuelError {
|
|
793
841
|
}
|
|
794
842
|
/** The `code` of an API error. The API may add codes; unknown ones pass through. */
|
|
795
|
-
type ErrorCode = "UNAUTHORIZED" | "INVALID_API_KEY" | "FORBIDDEN" | "INSUFFICIENT_CREDITS" | "RATE_LIMIT_EXCEEDED" | "CONCURRENCY_LIMIT_REACHED" | "INVALID_REQUEST_BODY" | "INVALID_ATTRIBUTES" | "MISSING_TARGET" | "UNSUPPORTED_TASK_TYPE" | "JOB_REQUIRES_MULTIPLE_TARGETS" | "INVALID_IDEMPOTENCY_KEY" | "IDEMPOTENCY_KEY_REUSED" | "INVALID_TASK_ID" | "INVALID_JOB_ID" | "TASK_NOT_FOUND" | "JOB_NOT_FOUND" | "CRAWL_NOT_FOUND" | "JOB_NOT_CANCELLABLE" | "INVALID_CRAWL_PATTERN" | "CRAWL_UNSUPPORTED_OPTION" | "INVALID_CURSOR" | "INVALID_QUERY_PARAM" | "INVALID_PROXY_TYPE" | "INVALID_COUNTRY" | "INVALID_DATE_FORMAT" | "INVALID_DATE_RANGE" | "INVALID_INTERVAL" | "MODULE_UNAVAILABLE" | "ENGINE_UNAVAILABLE" | "API_KEY_RESET_FAILED" | "TASK_RESULT_TIMEOUT" | "INTERNAL_ERROR" | (string & {});
|
|
843
|
+
type ErrorCode = "UNAUTHORIZED" | "INVALID_API_KEY" | "FORBIDDEN" | "INSUFFICIENT_CREDITS" | "RATE_LIMIT_EXCEEDED" | "CONCURRENCY_LIMIT_REACHED" | "INVALID_REQUEST_BODY" | "INVALID_ATTRIBUTES" | "MISSING_TARGET" | "UNSUPPORTED_TASK_TYPE" | "JOB_REQUIRES_MULTIPLE_TARGETS" | "INVALID_IDEMPOTENCY_KEY" | "IDEMPOTENCY_KEY_REUSED" | "INVALID_TASK_ID" | "INVALID_JOB_ID" | "TASK_NOT_FOUND" | "JOB_NOT_FOUND" | "CRAWL_NOT_FOUND" | "JOB_NOT_CANCELLABLE" | "TASK_ALREADY_EXISTS" | "JOB_ALREADY_EXISTS" | "URL_LENGTH_CANNOT_BE_ZERO" | "ANALYTICS_FETCH_FAILED" | "INVALID_CRAWL_PATTERN" | "CRAWL_UNSUPPORTED_OPTION" | "INVALID_CURSOR" | "INVALID_QUERY_PARAM" | "INVALID_PROXY_TYPE" | "INVALID_COUNTRY" | "INVALID_DATE_FORMAT" | "INVALID_DATE_RANGE" | "INVALID_INTERVAL" | "MODULE_UNAVAILABLE" | "ENGINE_UNAVAILABLE" | "API_KEY_RESET_FAILED" | "TASK_RESULT_TIMEOUT" | "INTERNAL_ERROR" | (string & {});
|
|
796
844
|
/** A non-2xx answer from the API itself. */
|
|
797
845
|
declare class APIError extends DataFuelError {
|
|
798
846
|
readonly status: number;
|
|
@@ -825,6 +873,13 @@ declare class IdempotencyKeyReused extends APIError {
|
|
|
825
873
|
/** 409 JOB_NOT_CANCELLABLE: the job or crawl already finished. */
|
|
826
874
|
declare class JobNotCancellable extends APIError {
|
|
827
875
|
}
|
|
876
|
+
/**
|
|
877
|
+
* 409 TASK_ALREADY_EXISTS / JOB_ALREADY_EXISTS: the create collided with an
|
|
878
|
+
* existing task or job and is not an idempotent replay. Nothing was charged;
|
|
879
|
+
* send the request again.
|
|
880
|
+
*/
|
|
881
|
+
declare class AlreadyExists extends APIError {
|
|
882
|
+
}
|
|
828
883
|
/** 503: an operator switched something off, or a dependency is down. The message carries the reason. */
|
|
829
884
|
declare class Unavailable extends APIError {
|
|
830
885
|
}
|
|
@@ -864,4 +919,4 @@ declare class WaitTimeout extends DataFuelError {
|
|
|
864
919
|
constructor(message: string, id?: string, status?: unknown);
|
|
865
920
|
}
|
|
866
921
|
|
|
867
|
-
export { type AI, APIError, type Analytics, type AnalyticsCounts, type AnalyticsOptions, type AskOptions, type BalanceSplit, Blocked, type CallOptions, type CancelResult, Capabilities, type Capability, type ClientOptions, type CrawlOptions, CrawlPage, type CrawlResult, type CrawlResultsPage, type CrawlStatus, DEFAULT_BASE_URL, DataFuel, DataFuelError, type Engine, EngineUnavailable, type ErrorCode, Forbidden, type Format, IdempotencyKeyReused, InsufficientCredits, InvalidAttributes, JobNotCancellable, type JobResults, type JobStatus, type JobSummary, type JobsPage, type JsInstruction, type JsInstructionArg, type Link, type ListOptions, type ListTasksOptions, type MapOptions, ModuleUnavailable, NoApiKey, NotFound, type Payload, type PreviousPeriod, type Profile, type Proxy, type ProxyCountry, type ProxyLocation, type ProxyType, RateLimited, Result, type ScrapeOptions, type SearchOptions, type SiteMap, type Status, type StatusCodeBreakdown, TaskFailed, type TaskSummary, type TaskType, type TasksPage, type Transaction, type TransactionOperation, type TransactionSum, type TransactionsOptions, type TransactionsPage, TransportError, Unauthorized, Unavailable, VERSION, WaitTimeout, isDone };
|
|
922
|
+
export { type AI, type AIProvider, APIError, AlreadyExists, type Analytics, type AnalyticsCounts, type AnalyticsOptions, type AskOptions, type BalanceSplit, Blocked, type CallOptions, type CancelResult, Capabilities, type Capability, type ClientOptions, type CrawlOptions, CrawlPage, type CrawlResult, type CrawlResultsPage, type CrawlStatus, DEFAULT_BASE_URL, DataFuel, DataFuelError, type Engine, EngineUnavailable, type ErrorCode, Forbidden, type Format, type Health, IdempotencyKeyReused, InsufficientCredits, InvalidAttributes, JobNotCancellable, type JobResults, type JobStatus, type JobSummary, type JobsPage, type JsInstruction, type JsInstructionArg, type Link, type ListOptions, type ListTasksOptions, type MapOptions, ModuleUnavailable, NoApiKey, NotFound, type Payload, type PreviousPeriod, type Profile, type ProtectionCheck, type Proxy, type ProxyCountry, type ProxyLocation, type ProxyType, RateLimited, Result, type ScrapeOptions, type SearchOptions, type SiteMap, type Status, type StatusCodeBreakdown, TaskFailed, type TaskSummary, type TaskType, type TasksPage, type Transaction, type TransactionOperation, type TransactionSum, type TransactionsOptions, type TransactionsPage, TransportError, Unauthorized, Unavailable, VERSION, WaitTimeout, isDone };
|
package/dist/index.d.ts
CHANGED
|
@@ -40,7 +40,9 @@ interface AI {
|
|
|
40
40
|
prompt?: string;
|
|
41
41
|
/** Example JSON object the output must follow. */
|
|
42
42
|
format?: unknown;
|
|
43
|
-
|
|
43
|
+
/** Required. One of the providers `df.aiProviders()` lists; the API answers 400 INVALID_ATTRIBUTES without it. */
|
|
44
|
+
provider?: string;
|
|
45
|
+
/** One of the models `df.aiProviders()` lists for `provider`. Omit for the provider's default. */
|
|
44
46
|
model?: string;
|
|
45
47
|
apiKey?: string;
|
|
46
48
|
}
|
|
@@ -54,9 +56,15 @@ interface ScrapeOptions {
|
|
|
54
56
|
jsRendering?: boolean;
|
|
55
57
|
waitFor?: string;
|
|
56
58
|
waitForTimeoutMs?: number;
|
|
57
|
-
/**
|
|
59
|
+
/**
|
|
60
|
+
* Browser actions run after load: an array of single-action objects, run in
|
|
61
|
+
* order, e.g. `[{ click: "#more" }, { wait_ms: 1000 }, { click: "#more" }]`.
|
|
62
|
+
* An object keyed by action is still accepted, but its order is not
|
|
63
|
+
* guaranteed and an action cannot repeat. `df.jsInstructions()` lists them.
|
|
64
|
+
*/
|
|
58
65
|
jsInstructions?: unknown;
|
|
59
|
-
|
|
66
|
+
/** Resource types the browser must not load: one, e.g. `"Image"`, or several. */
|
|
67
|
+
blockResource?: string | string[];
|
|
60
68
|
/** Markdown only: always render just the `<main>` / `<article>` container. */
|
|
61
69
|
mainContentOnly?: boolean;
|
|
62
70
|
/** Markdown only: `false` drops images and saves tokens. */
|
|
@@ -445,6 +453,28 @@ interface JsInstruction {
|
|
|
445
453
|
iframe: boolean;
|
|
446
454
|
example: unknown;
|
|
447
455
|
}
|
|
456
|
+
/** An LLM provider `ai.provider` accepts, with the models `ai.model` accepts for it. */
|
|
457
|
+
interface AIProvider {
|
|
458
|
+
name: string;
|
|
459
|
+
models: string[];
|
|
460
|
+
}
|
|
461
|
+
/** The anti-bot protection in front of one host and path, from `checkProtection`. */
|
|
462
|
+
interface ProtectionCheck {
|
|
463
|
+
host: string;
|
|
464
|
+
path: string;
|
|
465
|
+
/** cloudflare, cloudflare_5sec, akamai, imperva, perimeterx or unprotected. */
|
|
466
|
+
protection_type: string;
|
|
467
|
+
}
|
|
468
|
+
/** The state of the API. `checks` is filled by a deep check only, keyed by dependency. */
|
|
469
|
+
interface Health {
|
|
470
|
+
status: "ok" | "degraded" | (string & {});
|
|
471
|
+
checks?: Record<string, {
|
|
472
|
+
status: "ok" | "fail" | (string & {});
|
|
473
|
+
latency_ms: number;
|
|
474
|
+
}>;
|
|
475
|
+
/** Whether the API can serve requests. */
|
|
476
|
+
ok: boolean;
|
|
477
|
+
}
|
|
448
478
|
/** A named proxy location: a city, or an ASN. */
|
|
449
479
|
interface ProxyLocation {
|
|
450
480
|
code: string;
|
|
@@ -488,7 +518,7 @@ declare class Capabilities {
|
|
|
488
518
|
|
|
489
519
|
declare const DEFAULT_BASE_URL = "https://scraping-api.datafuel.ai/api/v1";
|
|
490
520
|
/** Kept in step with package.json by a test; see test/hardening.test.ts. */
|
|
491
|
-
declare const VERSION = "0.
|
|
521
|
+
declare const VERSION = "0.4.0";
|
|
492
522
|
/** Options for the llm_scraping module, which reads its proxy country here. */
|
|
493
523
|
interface AskOptions {
|
|
494
524
|
engine: Engine | string;
|
|
@@ -556,7 +586,10 @@ interface SearchOptions {
|
|
|
556
586
|
ludocid?: string;
|
|
557
587
|
lsig?: string;
|
|
558
588
|
ibp?: string;
|
|
559
|
-
/**
|
|
589
|
+
/**
|
|
590
|
+
* Accepted but not used yet: searches leave through DataFuel's own pool.
|
|
591
|
+
* Target a market with `country` and `language`.
|
|
592
|
+
*/
|
|
560
593
|
proxyCountry?: string;
|
|
561
594
|
/** Default json. */
|
|
562
595
|
format?: "json" | "html" | "markdown";
|
|
@@ -739,6 +772,21 @@ declare class DataFuel {
|
|
|
739
772
|
capabilities(options?: CallOptions): Promise<Capabilities>;
|
|
740
773
|
/** The browser actions `jsInstructions` accepts, with their arguments. Needs no key. */
|
|
741
774
|
jsInstructions(options?: CallOptions): Promise<JsInstruction[]>;
|
|
775
|
+
/** The LLM providers and models `ai` accepts. Needs no key. */
|
|
776
|
+
aiProviders(options?: CallOptions): Promise<AIProvider[]>;
|
|
777
|
+
/**
|
|
778
|
+
* Whether the API is up. `deep` also checks the dependencies it needs to
|
|
779
|
+
* serve scrapes. A degraded report is returned, not thrown: read `ok`.
|
|
780
|
+
* Needs no key.
|
|
781
|
+
*/
|
|
782
|
+
health(options?: CallOptions & {
|
|
783
|
+
deep?: boolean;
|
|
784
|
+
}): Promise<Health>;
|
|
785
|
+
/**
|
|
786
|
+
* Which anti-bot protection sits in front of each URL. Nothing is scraped
|
|
787
|
+
* and nothing is charged; invalid URLs are skipped.
|
|
788
|
+
*/
|
|
789
|
+
checkProtection(urls: string[], options?: CallOptions): Promise<ProtectionCheck[]>;
|
|
742
790
|
/** Countries, regions and cities a proxy type can exit from. */
|
|
743
791
|
proxyLocations(options?: CallOptions & {
|
|
744
792
|
proxyType?: string;
|
|
@@ -792,7 +840,7 @@ declare class NoApiKey extends DataFuelError {
|
|
|
792
840
|
declare class TransportError extends DataFuelError {
|
|
793
841
|
}
|
|
794
842
|
/** The `code` of an API error. The API may add codes; unknown ones pass through. */
|
|
795
|
-
type ErrorCode = "UNAUTHORIZED" | "INVALID_API_KEY" | "FORBIDDEN" | "INSUFFICIENT_CREDITS" | "RATE_LIMIT_EXCEEDED" | "CONCURRENCY_LIMIT_REACHED" | "INVALID_REQUEST_BODY" | "INVALID_ATTRIBUTES" | "MISSING_TARGET" | "UNSUPPORTED_TASK_TYPE" | "JOB_REQUIRES_MULTIPLE_TARGETS" | "INVALID_IDEMPOTENCY_KEY" | "IDEMPOTENCY_KEY_REUSED" | "INVALID_TASK_ID" | "INVALID_JOB_ID" | "TASK_NOT_FOUND" | "JOB_NOT_FOUND" | "CRAWL_NOT_FOUND" | "JOB_NOT_CANCELLABLE" | "INVALID_CRAWL_PATTERN" | "CRAWL_UNSUPPORTED_OPTION" | "INVALID_CURSOR" | "INVALID_QUERY_PARAM" | "INVALID_PROXY_TYPE" | "INVALID_COUNTRY" | "INVALID_DATE_FORMAT" | "INVALID_DATE_RANGE" | "INVALID_INTERVAL" | "MODULE_UNAVAILABLE" | "ENGINE_UNAVAILABLE" | "API_KEY_RESET_FAILED" | "TASK_RESULT_TIMEOUT" | "INTERNAL_ERROR" | (string & {});
|
|
843
|
+
type ErrorCode = "UNAUTHORIZED" | "INVALID_API_KEY" | "FORBIDDEN" | "INSUFFICIENT_CREDITS" | "RATE_LIMIT_EXCEEDED" | "CONCURRENCY_LIMIT_REACHED" | "INVALID_REQUEST_BODY" | "INVALID_ATTRIBUTES" | "MISSING_TARGET" | "UNSUPPORTED_TASK_TYPE" | "JOB_REQUIRES_MULTIPLE_TARGETS" | "INVALID_IDEMPOTENCY_KEY" | "IDEMPOTENCY_KEY_REUSED" | "INVALID_TASK_ID" | "INVALID_JOB_ID" | "TASK_NOT_FOUND" | "JOB_NOT_FOUND" | "CRAWL_NOT_FOUND" | "JOB_NOT_CANCELLABLE" | "TASK_ALREADY_EXISTS" | "JOB_ALREADY_EXISTS" | "URL_LENGTH_CANNOT_BE_ZERO" | "ANALYTICS_FETCH_FAILED" | "INVALID_CRAWL_PATTERN" | "CRAWL_UNSUPPORTED_OPTION" | "INVALID_CURSOR" | "INVALID_QUERY_PARAM" | "INVALID_PROXY_TYPE" | "INVALID_COUNTRY" | "INVALID_DATE_FORMAT" | "INVALID_DATE_RANGE" | "INVALID_INTERVAL" | "MODULE_UNAVAILABLE" | "ENGINE_UNAVAILABLE" | "API_KEY_RESET_FAILED" | "TASK_RESULT_TIMEOUT" | "INTERNAL_ERROR" | (string & {});
|
|
796
844
|
/** A non-2xx answer from the API itself. */
|
|
797
845
|
declare class APIError extends DataFuelError {
|
|
798
846
|
readonly status: number;
|
|
@@ -825,6 +873,13 @@ declare class IdempotencyKeyReused extends APIError {
|
|
|
825
873
|
/** 409 JOB_NOT_CANCELLABLE: the job or crawl already finished. */
|
|
826
874
|
declare class JobNotCancellable extends APIError {
|
|
827
875
|
}
|
|
876
|
+
/**
|
|
877
|
+
* 409 TASK_ALREADY_EXISTS / JOB_ALREADY_EXISTS: the create collided with an
|
|
878
|
+
* existing task or job and is not an idempotent replay. Nothing was charged;
|
|
879
|
+
* send the request again.
|
|
880
|
+
*/
|
|
881
|
+
declare class AlreadyExists extends APIError {
|
|
882
|
+
}
|
|
828
883
|
/** 503: an operator switched something off, or a dependency is down. The message carries the reason. */
|
|
829
884
|
declare class Unavailable extends APIError {
|
|
830
885
|
}
|
|
@@ -864,4 +919,4 @@ declare class WaitTimeout extends DataFuelError {
|
|
|
864
919
|
constructor(message: string, id?: string, status?: unknown);
|
|
865
920
|
}
|
|
866
921
|
|
|
867
|
-
export { type AI, APIError, type Analytics, type AnalyticsCounts, type AnalyticsOptions, type AskOptions, type BalanceSplit, Blocked, type CallOptions, type CancelResult, Capabilities, type Capability, type ClientOptions, type CrawlOptions, CrawlPage, type CrawlResult, type CrawlResultsPage, type CrawlStatus, DEFAULT_BASE_URL, DataFuel, DataFuelError, type Engine, EngineUnavailable, type ErrorCode, Forbidden, type Format, IdempotencyKeyReused, InsufficientCredits, InvalidAttributes, JobNotCancellable, type JobResults, type JobStatus, type JobSummary, type JobsPage, type JsInstruction, type JsInstructionArg, type Link, type ListOptions, type ListTasksOptions, type MapOptions, ModuleUnavailable, NoApiKey, NotFound, type Payload, type PreviousPeriod, type Profile, type Proxy, type ProxyCountry, type ProxyLocation, type ProxyType, RateLimited, Result, type ScrapeOptions, type SearchOptions, type SiteMap, type Status, type StatusCodeBreakdown, TaskFailed, type TaskSummary, type TaskType, type TasksPage, type Transaction, type TransactionOperation, type TransactionSum, type TransactionsOptions, type TransactionsPage, TransportError, Unauthorized, Unavailable, VERSION, WaitTimeout, isDone };
|
|
922
|
+
export { type AI, type AIProvider, APIError, AlreadyExists, type Analytics, type AnalyticsCounts, type AnalyticsOptions, type AskOptions, type BalanceSplit, Blocked, type CallOptions, type CancelResult, Capabilities, type Capability, type ClientOptions, type CrawlOptions, CrawlPage, type CrawlResult, type CrawlResultsPage, type CrawlStatus, DEFAULT_BASE_URL, DataFuel, DataFuelError, type Engine, EngineUnavailable, type ErrorCode, Forbidden, type Format, type Health, IdempotencyKeyReused, InsufficientCredits, InvalidAttributes, JobNotCancellable, type JobResults, type JobStatus, type JobSummary, type JobsPage, type JsInstruction, type JsInstructionArg, type Link, type ListOptions, type ListTasksOptions, type MapOptions, ModuleUnavailable, NoApiKey, NotFound, type Payload, type PreviousPeriod, type Profile, type ProtectionCheck, type Proxy, type ProxyCountry, type ProxyLocation, type ProxyType, RateLimited, Result, type ScrapeOptions, type SearchOptions, type SiteMap, type Status, type StatusCodeBreakdown, TaskFailed, type TaskSummary, type TaskType, type TasksPage, type Transaction, type TransactionOperation, type TransactionSum, type TransactionsOptions, type TransactionsPage, TransportError, Unauthorized, Unavailable, VERSION, WaitTimeout, isDone };
|
package/dist/index.js
CHANGED
|
@@ -37,6 +37,8 @@ var IdempotencyKeyReused = class extends APIError {
|
|
|
37
37
|
};
|
|
38
38
|
var JobNotCancellable = class extends APIError {
|
|
39
39
|
};
|
|
40
|
+
var AlreadyExists = class extends APIError {
|
|
41
|
+
};
|
|
40
42
|
var Unavailable = class extends APIError {
|
|
41
43
|
};
|
|
42
44
|
var ModuleUnavailable = class extends Unavailable {
|
|
@@ -74,14 +76,15 @@ var BY_CODE = {
|
|
|
74
76
|
IDEMPOTENCY_KEY_REUSED: IdempotencyKeyReused,
|
|
75
77
|
INVALID_API_KEY: Unauthorized,
|
|
76
78
|
FORBIDDEN: Forbidden,
|
|
77
|
-
JOB_NOT_CANCELLABLE: JobNotCancellable
|
|
79
|
+
JOB_NOT_CANCELLABLE: JobNotCancellable,
|
|
80
|
+
TASK_ALREADY_EXISTS: AlreadyExists,
|
|
81
|
+
JOB_ALREADY_EXISTS: AlreadyExists
|
|
78
82
|
};
|
|
79
83
|
var BY_STATUS = {
|
|
80
84
|
401: Unauthorized,
|
|
81
85
|
402: InsufficientCredits,
|
|
82
86
|
403: Forbidden,
|
|
83
87
|
404: NotFound,
|
|
84
|
-
409: JobNotCancellable,
|
|
85
88
|
422: IdempotencyKeyReused,
|
|
86
89
|
429: RateLimited,
|
|
87
90
|
503: Unavailable
|
|
@@ -102,19 +105,20 @@ function apiError(status, body, retryAfter = 0) {
|
|
|
102
105
|
|
|
103
106
|
// src/core.ts
|
|
104
107
|
var DEFAULT_BASE_URL = "https://scraping-api.datafuel.ai/api/v1";
|
|
105
|
-
var VERSION = "0.
|
|
108
|
+
var VERSION = "0.4.0";
|
|
106
109
|
var DEFAULT_TIMEOUT_MS = 18e4;
|
|
107
110
|
var STILL_PROCESSING_DELAY_MS = 2e3;
|
|
108
111
|
var STILL_PROCESSING = "TASK_STILL_PROCESSING";
|
|
109
112
|
var MAX_IDEMPOTENCY_KEY = 255;
|
|
110
113
|
var Request = class {
|
|
111
|
-
constructor(method, path, params, body, idempotencyKey, auth = true) {
|
|
114
|
+
constructor(method, path, params, body, idempotencyKey, auth = true, degradedOk = false) {
|
|
112
115
|
this.method = method;
|
|
113
116
|
this.path = path;
|
|
114
117
|
this.params = params;
|
|
115
118
|
this.body = body;
|
|
116
119
|
this.idempotencyKey = idempotencyKey;
|
|
117
120
|
this.auth = auth;
|
|
121
|
+
this.degradedOk = degradedOk;
|
|
118
122
|
}
|
|
119
123
|
method;
|
|
120
124
|
path;
|
|
@@ -122,6 +126,7 @@ var Request = class {
|
|
|
122
126
|
body;
|
|
123
127
|
idempotencyKey;
|
|
124
128
|
auth;
|
|
129
|
+
degradedOk;
|
|
125
130
|
/** GETs are safe by nature, writes because they carry an idempotency key. */
|
|
126
131
|
get retryable() {
|
|
127
132
|
return this.method === "GET" || this.idempotencyKey !== void 0;
|
|
@@ -169,15 +174,8 @@ function aiAttributes(ai) {
|
|
|
169
174
|
return out;
|
|
170
175
|
}
|
|
171
176
|
function validateAI(ai) {
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
model: ai.model !== void 0,
|
|
175
|
-
apiKey: ai.apiKey !== void 0
|
|
176
|
-
};
|
|
177
|
-
const present = Object.values(given).filter(Boolean).length;
|
|
178
|
-
if (present > 0 && present < 3) {
|
|
179
|
-
const missing = Object.entries(given).filter(([, ok]) => !ok).map(([name]) => name).join(", ");
|
|
180
|
-
throw new TypeError(`ai needs provider, model and apiKey together; missing: ${missing}`);
|
|
177
|
+
if (!ai.provider) {
|
|
178
|
+
throw new TypeError("ai needs a provider; aiProviders() lists the ones the API supports");
|
|
181
179
|
}
|
|
182
180
|
}
|
|
183
181
|
function scrapeAttributes(options = {}) {
|
|
@@ -187,7 +185,9 @@ function scrapeAttributes(options = {}) {
|
|
|
187
185
|
if (options.waitFor) attrs.wait_for_selector = options.waitFor;
|
|
188
186
|
if (options.waitForTimeoutMs) attrs.wait_for_selector_timeout_ms = options.waitForTimeoutMs;
|
|
189
187
|
if (options.jsInstructions) attrs.js_instructions = options.jsInstructions;
|
|
190
|
-
if (options.blockResource)
|
|
188
|
+
if (options.blockResource?.length) {
|
|
189
|
+
attrs.block_resource = typeof options.blockResource === "string" ? options.blockResource : [...options.blockResource];
|
|
190
|
+
}
|
|
191
191
|
if (options.mainContentOnly) attrs.main_content_only = true;
|
|
192
192
|
if (options.includeImages !== void 0) attrs.include_images = options.includeImages;
|
|
193
193
|
if (options.extract) attrs.extract_selector = selector(options.extract);
|
|
@@ -369,6 +369,17 @@ function crawlResultsRequest(crawlId, cursor, limit) {
|
|
|
369
369
|
Object.keys(params).length > 0 ? params : void 0
|
|
370
370
|
);
|
|
371
371
|
}
|
|
372
|
+
function healthRequest(deep) {
|
|
373
|
+
return new Request(
|
|
374
|
+
"GET",
|
|
375
|
+
"/healthz",
|
|
376
|
+
deep ? { deep: "1" } : void 0,
|
|
377
|
+
void 0,
|
|
378
|
+
void 0,
|
|
379
|
+
false,
|
|
380
|
+
true
|
|
381
|
+
);
|
|
382
|
+
}
|
|
372
383
|
function day(value) {
|
|
373
384
|
return typeof value === "string" ? value : value.toISOString().slice(0, 10);
|
|
374
385
|
}
|
|
@@ -601,7 +612,7 @@ var DataFuel = class {
|
|
|
601
612
|
const signal = this.signalFor(opts);
|
|
602
613
|
const send = this.fetchImpl;
|
|
603
614
|
const response = await send(url, signal ? { ...init, signal } : init);
|
|
604
|
-
return await parse(response);
|
|
615
|
+
return await parse(response, request.degradedOk);
|
|
605
616
|
} catch (caught) {
|
|
606
617
|
if (isAbort(caught)) {
|
|
607
618
|
throw new TransportError("the request was aborted or timed out", { cause: caught });
|
|
@@ -963,6 +974,37 @@ var DataFuel = class {
|
|
|
963
974
|
const body = record(await this.send(request, options));
|
|
964
975
|
return Array.isArray(body.instructions) ? body.instructions : [];
|
|
965
976
|
}
|
|
977
|
+
/** The LLM providers and models `ai` accepts. Needs no key. */
|
|
978
|
+
async aiProviders(options = {}) {
|
|
979
|
+
const request = new Request(
|
|
980
|
+
"GET",
|
|
981
|
+
"/config/ai-providers",
|
|
982
|
+
void 0,
|
|
983
|
+
void 0,
|
|
984
|
+
void 0,
|
|
985
|
+
false
|
|
986
|
+
);
|
|
987
|
+
const body = record(await this.send(request, options));
|
|
988
|
+
return Array.isArray(body.providers) ? body.providers : [];
|
|
989
|
+
}
|
|
990
|
+
/**
|
|
991
|
+
* Whether the API is up. `deep` also checks the dependencies it needs to
|
|
992
|
+
* serve scrapes. A degraded report is returned, not thrown: read `ok`.
|
|
993
|
+
* Needs no key.
|
|
994
|
+
*/
|
|
995
|
+
async health(options = {}) {
|
|
996
|
+
const body = record(await this.send(healthRequest(options.deep ?? false), options));
|
|
997
|
+
return { ...body, ok: body.status === "ok" };
|
|
998
|
+
}
|
|
999
|
+
/**
|
|
1000
|
+
* Which anti-bot protection sits in front of each URL. Nothing is scraped
|
|
1001
|
+
* and nothing is charged; invalid URLs are skipped.
|
|
1002
|
+
*/
|
|
1003
|
+
async checkProtection(urls, options = {}) {
|
|
1004
|
+
return list(
|
|
1005
|
+
await this.send(new Request("POST", "/filter/check", void 0, [...urls]), options)
|
|
1006
|
+
);
|
|
1007
|
+
}
|
|
966
1008
|
/** Countries, regions and cities a proxy type can exit from. */
|
|
967
1009
|
async proxyLocations(options = {}) {
|
|
968
1010
|
const params = options.proxyType ? { proxy_type: options.proxyType } : void 0;
|
|
@@ -1034,7 +1076,7 @@ var DataFuel = class {
|
|
|
1034
1076
|
function envApiKey() {
|
|
1035
1077
|
return typeof process !== "undefined" ? process.env?.DATAFUEL_API_KEY : void 0;
|
|
1036
1078
|
}
|
|
1037
|
-
async function parse(response) {
|
|
1079
|
+
async function parse(response, degradedOk = false) {
|
|
1038
1080
|
const text = await response.text();
|
|
1039
1081
|
let body;
|
|
1040
1082
|
if (text.length > 0) {
|
|
@@ -1044,6 +1086,7 @@ async function parse(response) {
|
|
|
1044
1086
|
body = text;
|
|
1045
1087
|
}
|
|
1046
1088
|
}
|
|
1089
|
+
if (degradedOk && response.status === 503 && isHealthReport(body)) return body;
|
|
1047
1090
|
if (!response.ok) {
|
|
1048
1091
|
const header = response.headers.get("Retry-After");
|
|
1049
1092
|
const retryAfter = header !== null && !Number.isNaN(Number(header)) ? Number(header) : 0;
|
|
@@ -1051,6 +1094,9 @@ async function parse(response) {
|
|
|
1051
1094
|
}
|
|
1052
1095
|
return body;
|
|
1053
1096
|
}
|
|
1097
|
+
function isHealthReport(body) {
|
|
1098
|
+
return body !== null && typeof body === "object" && "status" in body;
|
|
1099
|
+
}
|
|
1054
1100
|
function isAbort(error) {
|
|
1055
1101
|
return error instanceof Error && (error.name === "AbortError" || error.name === "TimeoutError");
|
|
1056
1102
|
}
|
|
@@ -1107,6 +1153,7 @@ function intField(body, name) {
|
|
|
1107
1153
|
}
|
|
1108
1154
|
export {
|
|
1109
1155
|
APIError,
|
|
1156
|
+
AlreadyExists,
|
|
1110
1157
|
Blocked,
|
|
1111
1158
|
Capabilities,
|
|
1112
1159
|
CrawlPage,
|