scoutline 0.22.0 → 0.24.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 +108 -26
- package/dist/capabilities/investigation.d.ts +134 -0
- package/dist/capabilities/investigation.d.ts.map +1 -0
- package/dist/capabilities/investigation.js +278 -0
- package/dist/capabilities/investigation.js.map +1 -0
- package/dist/capabilities/search.d.ts +18 -4
- package/dist/capabilities/search.d.ts.map +1 -1
- package/dist/commands/config.d.ts.map +1 -1
- package/dist/commands/config.js +14 -5
- package/dist/commands/config.js.map +1 -1
- package/dist/commands/crawl.d.ts.map +1 -1
- package/dist/commands/crawl.js +2 -1
- package/dist/commands/crawl.js.map +1 -1
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +2 -1
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/init.d.ts +42 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +42 -5
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/investigate.d.ts +232 -0
- package/dist/commands/investigate.d.ts.map +1 -0
- package/dist/commands/investigate.js +838 -0
- package/dist/commands/investigate.js.map +1 -0
- package/dist/commands/map.d.ts.map +1 -1
- package/dist/commands/map.js +2 -1
- package/dist/commands/map.js.map +1 -1
- package/dist/commands/quota.d.ts.map +1 -1
- package/dist/commands/quota.js +2 -2
- package/dist/commands/quota.js.map +1 -1
- package/dist/commands/read.d.ts.map +1 -1
- package/dist/commands/read.js +2 -1
- package/dist/commands/read.js.map +1 -1
- package/dist/commands/repo.js +1 -1
- package/dist/commands/research.d.ts.map +1 -1
- package/dist/commands/research.js +2 -1
- package/dist/commands/research.js.map +1 -1
- package/dist/commands/search.d.ts +54 -6
- package/dist/commands/search.d.ts.map +1 -1
- package/dist/commands/search.js +273 -25
- package/dist/commands/search.js.map +1 -1
- package/dist/commands/vision.d.ts.map +1 -1
- package/dist/commands/vision.js +15 -2
- package/dist/commands/vision.js.map +1 -1
- package/dist/index.d.ts +93 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +737 -14
- package/dist/index.js.map +1 -1
- package/dist/lib/code-mode.d.ts +12 -0
- package/dist/lib/code-mode.d.ts.map +1 -1
- package/dist/lib/code-mode.js +18 -10
- package/dist/lib/code-mode.js.map +1 -1
- package/dist/lib/config-store.d.ts +45 -1
- package/dist/lib/config-store.d.ts.map +1 -1
- package/dist/lib/config-store.js +70 -1
- package/dist/lib/config-store.js.map +1 -1
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +5 -1
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/errors.d.ts +7 -1
- package/dist/lib/errors.d.ts.map +1 -1
- package/dist/lib/errors.js +8 -2
- package/dist/lib/errors.js.map +1 -1
- package/dist/lib/execution.d.ts +14 -5
- package/dist/lib/execution.d.ts.map +1 -1
- package/dist/lib/execution.js +25 -6
- package/dist/lib/execution.js.map +1 -1
- package/dist/lib/investigate-claims.d.ts +90 -0
- package/dist/lib/investigate-claims.d.ts.map +1 -0
- package/dist/lib/investigate-claims.js +188 -0
- package/dist/lib/investigate-claims.js.map +1 -0
- package/dist/lib/investigate-extract.d.ts +35 -0
- package/dist/lib/investigate-extract.d.ts.map +1 -0
- package/dist/lib/investigate-extract.js +101 -0
- package/dist/lib/investigate-extract.js.map +1 -0
- package/dist/lib/investigate-planner.d.ts +58 -0
- package/dist/lib/investigate-planner.d.ts.map +1 -0
- package/dist/lib/investigate-planner.js +141 -0
- package/dist/lib/investigate-planner.js.map +1 -0
- package/dist/lib/mcp-client.d.ts +7 -0
- package/dist/lib/mcp-client.d.ts.map +1 -1
- package/dist/lib/mcp-client.js +11 -1
- package/dist/lib/mcp-client.js.map +1 -1
- package/dist/lib/parse-zoned-instant.d.ts +13 -0
- package/dist/lib/parse-zoned-instant.d.ts.map +1 -0
- package/dist/lib/parse-zoned-instant.js +17 -0
- package/dist/lib/parse-zoned-instant.js.map +1 -0
- package/dist/lib/quota-mapping.d.ts +4 -2
- package/dist/lib/quota-mapping.d.ts.map +1 -1
- package/dist/lib/quota-mapping.js +25 -2
- package/dist/lib/quota-mapping.js.map +1 -1
- package/dist/lib/redact.d.ts +3 -2
- package/dist/lib/redact.d.ts.map +1 -1
- package/dist/lib/redact.js +90 -24
- package/dist/lib/redact.js.map +1 -1
- package/dist/lib/timeout.d.ts +28 -0
- package/dist/lib/timeout.d.ts.map +1 -0
- package/dist/lib/timeout.js +30 -0
- package/dist/lib/timeout.js.map +1 -0
- package/dist/lib/url.d.ts +10 -4
- package/dist/lib/url.d.ts.map +1 -1
- package/dist/lib/url.js +21 -6
- package/dist/lib/url.js.map +1 -1
- package/dist/providers/arxiv/client.d.ts +4 -1
- package/dist/providers/arxiv/client.d.ts.map +1 -1
- package/dist/providers/arxiv/client.js +11 -3
- package/dist/providers/arxiv/client.js.map +1 -1
- package/dist/providers/bocha/adapter.d.ts +43 -0
- package/dist/providers/bocha/adapter.d.ts.map +1 -0
- package/dist/providers/bocha/adapter.js +197 -0
- package/dist/providers/bocha/adapter.js.map +1 -0
- package/dist/providers/bocha/client.d.ts +51 -0
- package/dist/providers/bocha/client.d.ts.map +1 -0
- package/dist/providers/bocha/client.js +104 -0
- package/dist/providers/bocha/client.js.map +1 -0
- package/dist/providers/bocha/credentials.d.ts +12 -0
- package/dist/providers/bocha/credentials.d.ts.map +1 -0
- package/dist/providers/bocha/credentials.js +29 -0
- package/dist/providers/bocha/credentials.js.map +1 -0
- package/dist/providers/bocha/diagnostics.d.ts +17 -0
- package/dist/providers/bocha/diagnostics.d.ts.map +1 -0
- package/dist/providers/bocha/diagnostics.js +33 -0
- package/dist/providers/bocha/diagnostics.js.map +1 -0
- package/dist/providers/brave/adapter.d.ts.map +1 -1
- package/dist/providers/brave/adapter.js +4 -3
- package/dist/providers/brave/adapter.js.map +1 -1
- package/dist/providers/brave/client.d.ts +1 -0
- package/dist/providers/brave/client.d.ts.map +1 -1
- package/dist/providers/brave/client.js +4 -6
- package/dist/providers/brave/client.js.map +1 -1
- package/dist/providers/brave/credentials.d.ts +2 -0
- package/dist/providers/brave/credentials.d.ts.map +1 -1
- package/dist/providers/brave/credentials.js +2 -0
- package/dist/providers/brave/credentials.js.map +1 -1
- package/dist/providers/catalog.d.ts +34 -0
- package/dist/providers/catalog.d.ts.map +1 -0
- package/dist/providers/catalog.js +57 -0
- package/dist/providers/catalog.js.map +1 -0
- package/dist/providers/crossref/adapter.js +2 -2
- package/dist/providers/crossref/adapter.js.map +1 -1
- package/dist/providers/crossref/client.d.ts +4 -1
- package/dist/providers/crossref/client.d.ts.map +1 -1
- package/dist/providers/crossref/client.js +11 -3
- package/dist/providers/crossref/client.js.map +1 -1
- package/dist/providers/crossref/diagnostics.d.ts +1 -1
- package/dist/providers/crossref/diagnostics.js +1 -1
- package/dist/providers/crossref/diagnostics.js.map +1 -1
- package/dist/providers/europepmc/adapter.js +2 -2
- package/dist/providers/europepmc/adapter.js.map +1 -1
- package/dist/providers/europepmc/client.d.ts +4 -1
- package/dist/providers/europepmc/client.d.ts.map +1 -1
- package/dist/providers/europepmc/client.js +11 -3
- package/dist/providers/europepmc/client.js.map +1 -1
- package/dist/providers/exa/client.d.ts +1 -0
- package/dist/providers/exa/client.d.ts.map +1 -1
- package/dist/providers/exa/client.js +3 -2
- package/dist/providers/exa/client.js.map +1 -1
- package/dist/providers/exa/credentials.d.ts +2 -0
- package/dist/providers/exa/credentials.d.ts.map +1 -1
- package/dist/providers/exa/credentials.js +2 -0
- package/dist/providers/exa/credentials.js.map +1 -1
- package/dist/providers/firecrawl/adapter.d.ts.map +1 -1
- package/dist/providers/firecrawl/adapter.js +2 -1
- package/dist/providers/firecrawl/adapter.js.map +1 -1
- package/dist/providers/firecrawl/client.d.ts +1 -0
- package/dist/providers/firecrawl/client.d.ts.map +1 -1
- package/dist/providers/firecrawl/client.js +3 -2
- package/dist/providers/firecrawl/client.js.map +1 -1
- package/dist/providers/firecrawl/credentials.d.ts +2 -0
- package/dist/providers/firecrawl/credentials.d.ts.map +1 -1
- package/dist/providers/firecrawl/credentials.js +2 -0
- package/dist/providers/firecrawl/credentials.js.map +1 -1
- package/dist/providers/firecrawl/quota.d.ts.map +1 -1
- package/dist/providers/firecrawl/quota.js +5 -2
- package/dist/providers/firecrawl/quota.js.map +1 -1
- package/dist/providers/jina/adapter.d.ts.map +1 -1
- package/dist/providers/jina/adapter.js +6 -4
- package/dist/providers/jina/adapter.js.map +1 -1
- package/dist/providers/jina/client.d.ts +2 -0
- package/dist/providers/jina/client.d.ts.map +1 -1
- package/dist/providers/jina/client.js +6 -5
- package/dist/providers/jina/client.js.map +1 -1
- package/dist/providers/jina/credentials.d.ts +2 -0
- package/dist/providers/jina/credentials.d.ts.map +1 -1
- package/dist/providers/jina/credentials.js +2 -0
- package/dist/providers/jina/credentials.js.map +1 -1
- package/dist/providers/kagi/adapter.d.ts +44 -0
- package/dist/providers/kagi/adapter.d.ts.map +1 -0
- package/dist/providers/kagi/adapter.js +188 -0
- package/dist/providers/kagi/adapter.js.map +1 -0
- package/dist/providers/kagi/client.d.ts +41 -0
- package/dist/providers/kagi/client.d.ts.map +1 -0
- package/dist/providers/kagi/client.js +100 -0
- package/dist/providers/kagi/client.js.map +1 -0
- package/dist/providers/kagi/credentials.d.ts +15 -0
- package/dist/providers/kagi/credentials.d.ts.map +1 -0
- package/dist/providers/kagi/credentials.js +35 -0
- package/dist/providers/kagi/credentials.js.map +1 -0
- package/dist/providers/kagi/diagnostics.d.ts +17 -0
- package/dist/providers/kagi/diagnostics.d.ts.map +1 -0
- package/dist/providers/kagi/diagnostics.js +33 -0
- package/dist/providers/kagi/diagnostics.js.map +1 -0
- package/dist/providers/linkup/client.d.ts +1 -0
- package/dist/providers/linkup/client.d.ts.map +1 -1
- package/dist/providers/linkup/client.js +3 -2
- package/dist/providers/linkup/client.js.map +1 -1
- package/dist/providers/linkup/credentials.d.ts +2 -0
- package/dist/providers/linkup/credentials.d.ts.map +1 -1
- package/dist/providers/linkup/credentials.js +2 -0
- package/dist/providers/linkup/credentials.js.map +1 -1
- package/dist/providers/minimax/adapter.d.ts.map +1 -1
- package/dist/providers/minimax/adapter.js +2 -2
- package/dist/providers/minimax/adapter.js.map +1 -1
- package/dist/providers/minimax/coding-plan-client.d.ts +1 -0
- package/dist/providers/minimax/coding-plan-client.d.ts.map +1 -1
- package/dist/providers/minimax/coding-plan-client.js +3 -2
- package/dist/providers/minimax/coding-plan-client.js.map +1 -1
- package/dist/providers/minimax/quota-client.d.ts +1 -0
- package/dist/providers/minimax/quota-client.d.ts.map +1 -1
- package/dist/providers/minimax/quota-client.js +3 -2
- package/dist/providers/minimax/quota-client.js.map +1 -1
- package/dist/providers/openalex/client.d.ts +2 -0
- package/dist/providers/openalex/client.d.ts.map +1 -1
- package/dist/providers/openalex/client.js +10 -3
- package/dist/providers/openalex/client.js.map +1 -1
- package/dist/providers/openalex/diagnostics.d.ts +1 -1
- package/dist/providers/openalex/diagnostics.js +1 -1
- package/dist/providers/openalex/diagnostics.js.map +1 -1
- package/dist/providers/parallel/client.d.ts +1 -0
- package/dist/providers/parallel/client.d.ts.map +1 -1
- package/dist/providers/parallel/client.js +3 -2
- package/dist/providers/parallel/client.js.map +1 -1
- package/dist/providers/parallel/credentials.d.ts +2 -0
- package/dist/providers/parallel/credentials.d.ts.map +1 -1
- package/dist/providers/parallel/credentials.js +2 -0
- package/dist/providers/parallel/credentials.js.map +1 -1
- package/dist/providers/perplexity/client.d.ts +2 -0
- package/dist/providers/perplexity/client.d.ts.map +1 -1
- package/dist/providers/perplexity/client.js +5 -4
- package/dist/providers/perplexity/client.js.map +1 -1
- package/dist/providers/perplexity/credentials.d.ts +2 -0
- package/dist/providers/perplexity/credentials.d.ts.map +1 -1
- package/dist/providers/perplexity/credentials.js +2 -0
- package/dist/providers/perplexity/credentials.js.map +1 -1
- package/dist/providers/pubmed/client.d.ts +2 -0
- package/dist/providers/pubmed/client.d.ts.map +1 -1
- package/dist/providers/pubmed/client.js +10 -3
- package/dist/providers/pubmed/client.js.map +1 -1
- package/dist/providers/registry.d.ts.map +1 -1
- package/dist/providers/registry.js +10 -1
- package/dist/providers/registry.js.map +1 -1
- package/dist/providers/searchapi/adapter.d.ts +54 -0
- package/dist/providers/searchapi/adapter.d.ts.map +1 -0
- package/dist/providers/searchapi/adapter.js +310 -0
- package/dist/providers/searchapi/adapter.js.map +1 -0
- package/dist/providers/searchapi/client.d.ts +73 -0
- package/dist/providers/searchapi/client.d.ts.map +1 -0
- package/dist/providers/searchapi/client.js +196 -0
- package/dist/providers/searchapi/client.js.map +1 -0
- package/dist/providers/searchapi/credentials.d.ts +46 -0
- package/dist/providers/searchapi/credentials.d.ts.map +1 -0
- package/dist/providers/searchapi/credentials.js +71 -0
- package/dist/providers/searchapi/credentials.js.map +1 -0
- package/dist/providers/searchapi/diagnostics.d.ts +48 -0
- package/dist/providers/searchapi/diagnostics.d.ts.map +1 -0
- package/dist/providers/searchapi/diagnostics.js +70 -0
- package/dist/providers/searchapi/diagnostics.js.map +1 -0
- package/dist/providers/searchapi/quota.d.ts +60 -0
- package/dist/providers/searchapi/quota.d.ts.map +1 -0
- package/dist/providers/searchapi/quota.js +125 -0
- package/dist/providers/searchapi/quota.js.map +1 -0
- package/dist/providers/spider/client.d.ts +2 -0
- package/dist/providers/spider/client.d.ts.map +1 -1
- package/dist/providers/spider/client.js +16 -6
- package/dist/providers/spider/client.js.map +1 -1
- package/dist/providers/spider/credentials.d.ts +2 -0
- package/dist/providers/spider/credentials.d.ts.map +1 -1
- package/dist/providers/spider/credentials.js +2 -0
- package/dist/providers/spider/credentials.js.map +1 -1
- package/dist/providers/tavily/client.d.ts +1 -0
- package/dist/providers/tavily/client.d.ts.map +1 -1
- package/dist/providers/tavily/client.js +3 -2
- package/dist/providers/tavily/client.js.map +1 -1
- package/dist/providers/tavily/credentials.d.ts +2 -0
- package/dist/providers/tavily/credentials.d.ts.map +1 -1
- package/dist/providers/tavily/credentials.js +2 -0
- package/dist/providers/tavily/credentials.js.map +1 -1
- package/dist/providers/types.d.ts +31 -2
- package/dist/providers/types.d.ts.map +1 -1
- package/dist/providers/types.js +3 -0
- package/dist/providers/types.js.map +1 -1
- package/dist/providers/you/client.d.ts +4 -0
- package/dist/providers/you/client.d.ts.map +1 -1
- package/dist/providers/you/client.js +4 -5
- package/dist/providers/you/client.js.map +1 -1
- package/dist/providers/you/credentials.d.ts +2 -0
- package/dist/providers/you/credentials.d.ts.map +1 -1
- package/dist/providers/you/credentials.js +3 -3
- package/dist/providers/you/credentials.js.map +1 -1
- package/dist/providers/zai/adapter.d.ts.map +1 -1
- package/dist/providers/zai/adapter.js +219 -4
- package/dist/providers/zai/adapter.js.map +1 -1
- package/dist/providers/zai/credentials.d.ts +2 -0
- package/dist/providers/zai/credentials.d.ts.map +1 -1
- package/dist/providers/zai/credentials.js +2 -0
- package/dist/providers/zai/credentials.js.map +1 -1
- package/dist/providers/zai/layout-parsing.d.ts +76 -0
- package/dist/providers/zai/layout-parsing.d.ts.map +1 -0
- package/dist/providers/zai/layout-parsing.js +151 -0
- package/dist/providers/zai/layout-parsing.js.map +1 -0
- package/dist/providers/zai/media.d.ts +19 -0
- package/dist/providers/zai/media.d.ts.map +1 -1
- package/dist/providers/zai/media.js +61 -0
- package/dist/providers/zai/media.js.map +1 -1
- package/dist/providers/zai/monitor-client.d.ts +1 -0
- package/dist/providers/zai/monitor-client.d.ts.map +1 -1
- package/dist/providers/zai/monitor-client.js +3 -2
- package/dist/providers/zai/monitor-client.js.map +1 -1
- package/dist/providers/zai/quota.d.ts +4 -0
- package/dist/providers/zai/quota.d.ts.map +1 -1
- package/dist/providers/zai/quota.js +16 -1
- package/dist/providers/zai/quota.js.map +1 -1
- package/package.json +1 -1
- package/skills/scoutline/SKILL.md +163 -45
- package/skills/scoutline/references/advanced.md +12 -10
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SearchApi Provider Adapter.
|
|
3
|
+
*
|
|
4
|
+
* T2 wires the Search Capability; T3 adds the Quota and Diagnostics
|
|
5
|
+
* Capabilities (both backed by the non-destructive `GET /api/v1/me`
|
|
6
|
+
* probe). The descriptor advertises `"search"`, `"diagnostics"`, and
|
|
7
|
+
* `"quota"`, and `create()` returns an Adapter whose slots own
|
|
8
|
+
* credentials, transport, Provider field mapping, and failure
|
|
9
|
+
* normalization.
|
|
10
|
+
*
|
|
11
|
+
* Engine routing (SPEC, locked): `topic:"news"` → `engine=google_news`;
|
|
12
|
+
* every other topic (and no topic) → `engine=google`. Unlike the Z.AI/
|
|
13
|
+
* MiniMax/Parallel/Jina adapters there is NO topic keyword appendage —
|
|
14
|
+
* SearchApi routing is engine-only.
|
|
15
|
+
*
|
|
16
|
+
* Boundary rules (ARCHITECTURE.md §2):
|
|
17
|
+
* - May import capability types, normalized errors, Provider identity
|
|
18
|
+
* types, and the Adapter-local credential and transport Modules.
|
|
19
|
+
* - Must NOT import command presentation, output mode, or another
|
|
20
|
+
* Provider's Adapter.
|
|
21
|
+
*/
|
|
22
|
+
import { ApiError, AuthError, ConfigurationError, NetworkError, QuotaError, TimeoutError, UnsupportedOptionError, ValidationError, } from "../../lib/errors.js";
|
|
23
|
+
import { hashSearchApiKey, isSearchApiConfigured, requireSearchApiKey } from "./credentials.js";
|
|
24
|
+
import { fetchSearchApiSearch, } from "./client.js";
|
|
25
|
+
import { createSearchApiQuotaCapability } from "./quota.js";
|
|
26
|
+
import { createSearchApiDiagnosticsCapability } from "./diagnostics.js";
|
|
27
|
+
const TIMEOUT_HELP_TEXT = "Try again or increase timeout with SEARCHAPI_TIMEOUT env var";
|
|
28
|
+
// ---------------------------------------------------------------------------
|
|
29
|
+
// Helpers
|
|
30
|
+
// ---------------------------------------------------------------------------
|
|
31
|
+
function isPlainObject(value) {
|
|
32
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
33
|
+
}
|
|
34
|
+
// ---------------------------------------------------------------------------
|
|
35
|
+
// Validation (FR-012): reject unsupported controls before any API access
|
|
36
|
+
// ---------------------------------------------------------------------------
|
|
37
|
+
/**
|
|
38
|
+
* Controls the SearchApi Search Adapter does NOT accept. `contentSize`
|
|
39
|
+
* (SearchApi returns organic results, not sized extracts) and `type`
|
|
40
|
+
* (`video` is Brave-only) are rejected individually before any
|
|
41
|
+
* transport call. `domain`, `recency`, `location`, and `topic` are
|
|
42
|
+
* honored.
|
|
43
|
+
*/
|
|
44
|
+
function assertNoUnsupportedControls(request) {
|
|
45
|
+
const controls = request.controls;
|
|
46
|
+
if (!controls)
|
|
47
|
+
return;
|
|
48
|
+
if (controls.contentSize !== undefined) {
|
|
49
|
+
throw new UnsupportedOptionError("searchapi", "search", "contentSize");
|
|
50
|
+
}
|
|
51
|
+
if (controls.type !== undefined) {
|
|
52
|
+
throw new UnsupportedOptionError("searchapi", "search", "type");
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
// ---------------------------------------------------------------------------
|
|
56
|
+
// Control mapping (SearchControls → SearchApi-native API params)
|
|
57
|
+
// ---------------------------------------------------------------------------
|
|
58
|
+
function mapRecencyToTimePeriod(recency) {
|
|
59
|
+
switch (recency) {
|
|
60
|
+
case "oneDay":
|
|
61
|
+
return "last_day";
|
|
62
|
+
case "oneWeek":
|
|
63
|
+
return "last_week";
|
|
64
|
+
case "oneMonth":
|
|
65
|
+
return "last_month";
|
|
66
|
+
case "oneYear":
|
|
67
|
+
return "last_year";
|
|
68
|
+
case "noLimit":
|
|
69
|
+
return undefined;
|
|
70
|
+
default:
|
|
71
|
+
return undefined;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Map the param-bearing controls into SearchApi-native API fields.
|
|
76
|
+
* Engine routing is topic-only: `news` → `google_news`, everything else
|
|
77
|
+
* (general/finance/absent) → `google`. Query-mutating `domain` is
|
|
78
|
+
* handled separately in `invoke`.
|
|
79
|
+
*/
|
|
80
|
+
function mapSearchControls(controls) {
|
|
81
|
+
const params = {
|
|
82
|
+
engine: controls?.topic === "news" ? "google_news" : "google",
|
|
83
|
+
};
|
|
84
|
+
if (controls?.recency) {
|
|
85
|
+
const timePeriod = mapRecencyToTimePeriod(controls.recency);
|
|
86
|
+
if (timePeriod)
|
|
87
|
+
params.time_period = timePeriod;
|
|
88
|
+
}
|
|
89
|
+
if (controls?.location) {
|
|
90
|
+
params.gl = controls.location.toLowerCase();
|
|
91
|
+
}
|
|
92
|
+
return params;
|
|
93
|
+
}
|
|
94
|
+
// ---------------------------------------------------------------------------
|
|
95
|
+
// Response normalization
|
|
96
|
+
// ---------------------------------------------------------------------------
|
|
97
|
+
/**
|
|
98
|
+
* Normalize a raw SearchApi.io search response into `SearchSource[]`.
|
|
99
|
+
* Reads `raw.organic_results[]`:
|
|
100
|
+
*
|
|
101
|
+
* title -> title
|
|
102
|
+
* link -> url
|
|
103
|
+
* snippet -> summary ("" when absent)
|
|
104
|
+
* date -> date (only when present and string)
|
|
105
|
+
*
|
|
106
|
+
* A malformed shape (non-object root, `organic_results` not an array,
|
|
107
|
+
* non-string title/link) is a retryable `ApiError` 500.
|
|
108
|
+
*/
|
|
109
|
+
export function normalizeSearchApiResults(raw) {
|
|
110
|
+
if (!isPlainObject(raw)) {
|
|
111
|
+
throw new ApiError("SearchApi.io returned a malformed response", 500);
|
|
112
|
+
}
|
|
113
|
+
const results = raw.organic_results;
|
|
114
|
+
// The `google_news` engine (topic:"news") legitimately returns only a
|
|
115
|
+
// `top_stories` block with `organic_results` ABSENT — a valid engine
|
|
116
|
+
// response, not a malformed payload. An absent array normalizes to an
|
|
117
|
+
// empty list; only a present-but-non-array value is malformed.
|
|
118
|
+
if (results === undefined)
|
|
119
|
+
return [];
|
|
120
|
+
if (!Array.isArray(results)) {
|
|
121
|
+
throw new ApiError("SearchApi.io returned a malformed response", 500);
|
|
122
|
+
}
|
|
123
|
+
const out = [];
|
|
124
|
+
for (const entry of results) {
|
|
125
|
+
if (!isPlainObject(entry)) {
|
|
126
|
+
throw new ApiError("SearchApi.io returned a malformed response", 500);
|
|
127
|
+
}
|
|
128
|
+
const title = entry.title;
|
|
129
|
+
const link = entry.link;
|
|
130
|
+
if (typeof title !== "string" || typeof link !== "string") {
|
|
131
|
+
throw new ApiError("SearchApi.io returned a malformed response", 500);
|
|
132
|
+
}
|
|
133
|
+
const source = {
|
|
134
|
+
title,
|
|
135
|
+
url: link,
|
|
136
|
+
summary: typeof entry.snippet === "string" ? entry.snippet : "",
|
|
137
|
+
};
|
|
138
|
+
// Publisher attribution (e.g. "Forbes" on google_news) — carried
|
|
139
|
+
// only when the wire supplies a string, mirroring Brave's
|
|
140
|
+
// meta_url.netloc discipline. Absent on the plain google engine.
|
|
141
|
+
if (typeof entry.source === "string") {
|
|
142
|
+
source.source = entry.source;
|
|
143
|
+
}
|
|
144
|
+
if (typeof entry.date === "string") {
|
|
145
|
+
source.date = entry.date;
|
|
146
|
+
}
|
|
147
|
+
out.push(source);
|
|
148
|
+
}
|
|
149
|
+
return out;
|
|
150
|
+
}
|
|
151
|
+
// ---------------------------------------------------------------------------
|
|
152
|
+
// Failure normalization: stable public codes, no raw payloads (NFR-006)
|
|
153
|
+
// ---------------------------------------------------------------------------
|
|
154
|
+
/**
|
|
155
|
+
* Status-keyed outward message for rewrapped SearchApi ApiErrors. The
|
|
156
|
+
* rewrap does not echo upstream `error.message` — a future change
|
|
157
|
+
* embedding a raw Provider body in an ApiError message would leak
|
|
158
|
+
* through normalization, the cache, and stdout. Curated constants only.
|
|
159
|
+
*/
|
|
160
|
+
function searchApiErrorMessage(statusCode) {
|
|
161
|
+
if (statusCode === 429)
|
|
162
|
+
return "SearchApi.io rate limit exceeded";
|
|
163
|
+
return "SearchApi.io request failed";
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Normalize a Provider failure with sanitized messages. Raw response
|
|
167
|
+
* bodies never cross the adapter boundary. Same pattern as
|
|
168
|
+
* `normalizeBraveError`.
|
|
169
|
+
*/
|
|
170
|
+
function normalizeSearchApiError(error) {
|
|
171
|
+
// QuotaError pass-through — terminal retry guarantee preserved.
|
|
172
|
+
if (error instanceof QuotaError)
|
|
173
|
+
return error;
|
|
174
|
+
// Configuration/option/validation errors carry clean, human-authored
|
|
175
|
+
// messages and are safe to surface verbatim.
|
|
176
|
+
if (error instanceof ValidationError ||
|
|
177
|
+
error instanceof UnsupportedOptionError ||
|
|
178
|
+
error instanceof ConfigurationError) {
|
|
179
|
+
return error;
|
|
180
|
+
}
|
|
181
|
+
// Re-wrap typed transport errors with sanitized messages so a raw
|
|
182
|
+
// Provider response body embedded upstream never survives.
|
|
183
|
+
if (error instanceof AuthError) {
|
|
184
|
+
return new AuthError("SearchApi.io authentication failed", "SEARCHAPI_API_KEY");
|
|
185
|
+
}
|
|
186
|
+
if (error instanceof NetworkError) {
|
|
187
|
+
return new NetworkError("SearchApi.io network error");
|
|
188
|
+
}
|
|
189
|
+
if (error instanceof TimeoutError) {
|
|
190
|
+
return new TimeoutError(error.durationMs, TIMEOUT_HELP_TEXT);
|
|
191
|
+
}
|
|
192
|
+
if (error instanceof ApiError) {
|
|
193
|
+
const statusCode = typeof error.statusCode === "number" && Number.isFinite(error.statusCode)
|
|
194
|
+
? error.statusCode
|
|
195
|
+
: 500;
|
|
196
|
+
return new ApiError(searchApiErrorMessage(statusCode), statusCode);
|
|
197
|
+
}
|
|
198
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
199
|
+
const lower = message.toLowerCase();
|
|
200
|
+
if (lower.includes("401") ||
|
|
201
|
+
lower.includes("403") ||
|
|
202
|
+
lower.includes("unauthorized") ||
|
|
203
|
+
lower.includes("forbidden")) {
|
|
204
|
+
return new AuthError("SearchApi.io authentication failed", "SEARCHAPI_API_KEY");
|
|
205
|
+
}
|
|
206
|
+
if (lower.includes("timeout") || lower.includes("timed out") || lower.includes("etimedout")) {
|
|
207
|
+
// Fallback branch: the transport wraps real timeouts into a typed
|
|
208
|
+
// TimeoutError (which carries the configured duration) before they
|
|
209
|
+
// reach this point. This untyped-message heuristic is rarely hit, so
|
|
210
|
+
// a constant default is fine and keeps process.env out of the
|
|
211
|
+
// normalization path (test isolation).
|
|
212
|
+
return new TimeoutError(30000, TIMEOUT_HELP_TEXT);
|
|
213
|
+
}
|
|
214
|
+
if (lower.includes("econnrefused") ||
|
|
215
|
+
lower.includes("econnreset") ||
|
|
216
|
+
lower.includes("network") ||
|
|
217
|
+
lower.includes("enotfound") ||
|
|
218
|
+
lower.includes("fetch failed")) {
|
|
219
|
+
return new NetworkError("SearchApi.io network error");
|
|
220
|
+
}
|
|
221
|
+
if (lower.includes("429") || lower.includes("rate limit")) {
|
|
222
|
+
return new ApiError("SearchApi.io rate limit exceeded", 429);
|
|
223
|
+
}
|
|
224
|
+
return new ApiError("SearchApi.io request failed", 500);
|
|
225
|
+
}
|
|
226
|
+
function createSearchApiSearchCapability(options) {
|
|
227
|
+
const { env, transport } = options;
|
|
228
|
+
const capability = {
|
|
229
|
+
validate(request) {
|
|
230
|
+
if (!request || typeof request.query !== "string" || request.query.trim() === "") {
|
|
231
|
+
throw new ValidationError("Search query must contain at least one non-whitespace character");
|
|
232
|
+
}
|
|
233
|
+
// SearchApi supports domain, recency, location, and topic.
|
|
234
|
+
// contentSize and type are rejected before any transport call.
|
|
235
|
+
assertNoUnsupportedControls(request);
|
|
236
|
+
},
|
|
237
|
+
cacheIdentity(request) {
|
|
238
|
+
const apiKey = requireSearchApiKey(env);
|
|
239
|
+
const identityRequest = {
|
|
240
|
+
query: request.query,
|
|
241
|
+
};
|
|
242
|
+
if (request.controls) {
|
|
243
|
+
identityRequest.controls = request.controls;
|
|
244
|
+
}
|
|
245
|
+
return {
|
|
246
|
+
provider: "searchapi",
|
|
247
|
+
capability: "search",
|
|
248
|
+
credentialFingerprint: hashSearchApiKey(apiKey),
|
|
249
|
+
request: identityRequest,
|
|
250
|
+
};
|
|
251
|
+
},
|
|
252
|
+
async invoke(request) {
|
|
253
|
+
// Validate before any credential access or transport call.
|
|
254
|
+
capability.validate(request);
|
|
255
|
+
const apiKey = requireSearchApiKey(env);
|
|
256
|
+
try {
|
|
257
|
+
const controls = request.controls;
|
|
258
|
+
// `domain` appends a `site:<domain>` operator to the query
|
|
259
|
+
// (SearchApi has no dedicated domain param). Topic routing is
|
|
260
|
+
// engine-only — no keyword appendage.
|
|
261
|
+
const q = controls?.domain !== undefined
|
|
262
|
+
? `${request.query} site:${controls.domain}`
|
|
263
|
+
: request.query;
|
|
264
|
+
const params = mapSearchControls(controls);
|
|
265
|
+
const raw = await fetchSearchApiSearch(apiKey, { engine: params.engine, q, gl: params.gl, time_period: params.time_period }, transport);
|
|
266
|
+
return normalizeSearchApiResults(raw);
|
|
267
|
+
}
|
|
268
|
+
catch (error) {
|
|
269
|
+
throw normalizeSearchApiError(error);
|
|
270
|
+
}
|
|
271
|
+
},
|
|
272
|
+
};
|
|
273
|
+
return capability;
|
|
274
|
+
}
|
|
275
|
+
// ---------------------------------------------------------------------------
|
|
276
|
+
// Descriptor factory
|
|
277
|
+
// ---------------------------------------------------------------------------
|
|
278
|
+
/**
|
|
279
|
+
* Build the SearchApi Provider Descriptor. The descriptor advertises
|
|
280
|
+
* Search, Diagnostics, and Quota; `create()` returns an Adapter whose
|
|
281
|
+
* slots own credentials, transport, Provider field mapping, and failure
|
|
282
|
+
* normalization. Construction is side-effect-free; the transport is
|
|
283
|
+
* invoked per Capability call. Tests pass `transport` (typically a
|
|
284
|
+
* fake-fetch wrapper); production uses the no-argument factory which
|
|
285
|
+
* resolves to the global `fetch` and timers inside the transport
|
|
286
|
+
* Module.
|
|
287
|
+
*/
|
|
288
|
+
export function createSearchApiDescriptor(dependencies) {
|
|
289
|
+
const transport = dependencies?.transport;
|
|
290
|
+
return {
|
|
291
|
+
id: "searchapi",
|
|
292
|
+
isConfigured(env) {
|
|
293
|
+
return isSearchApiConfigured(env);
|
|
294
|
+
},
|
|
295
|
+
capabilities() {
|
|
296
|
+
return new Set(["search", "diagnostics", "quota"]);
|
|
297
|
+
},
|
|
298
|
+
create(context) {
|
|
299
|
+
const search = createSearchApiSearchCapability({ env: context.env, transport });
|
|
300
|
+
const quota = createSearchApiQuotaCapability({ env: context.env, transport });
|
|
301
|
+
const diagnostics = createSearchApiDiagnosticsCapability({
|
|
302
|
+
env: context.env,
|
|
303
|
+
transport,
|
|
304
|
+
});
|
|
305
|
+
return { id: "searchapi", search, diagnostics, quota };
|
|
306
|
+
},
|
|
307
|
+
credentialEnvVars: ["SEARCHAPI_API_KEY", "SERPAPI_API_KEY"],
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
//# sourceMappingURL=adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapter.js","sourceRoot":"","sources":["../../../src/providers/searchapi/adapter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SearchApi.io direct HTTP transport.
|
|
3
|
+
*
|
|
4
|
+
* Performs direct GETs against the SearchApi.io REST API
|
|
5
|
+
* (`https://www.searchapi.io/api/v1`) with an
|
|
6
|
+
* `Authorization: Bearer <apiKey>` header — the key NEVER travels as a
|
|
7
|
+
* query parameter. There is NO internal retry — shared execution owns
|
|
8
|
+
* retry policy. Fetch and timers are injectable for tests.
|
|
9
|
+
*
|
|
10
|
+
* Structurally cloned from `providers/brave/client.ts`, simplified to
|
|
11
|
+
* the Linkup shape (no retry-hint header parsing; SearchApi exposes no
|
|
12
|
+
* rate-limit response headers to read).
|
|
13
|
+
*
|
|
14
|
+
* Failure taxonomy (SearchApi ERROR_HANDLING, locked):
|
|
15
|
+
* 401 / 403 -> AuthError (never retry)
|
|
16
|
+
* 402 -> QuotaError (never retry)
|
|
17
|
+
* 408 / 504 -> TimeoutError (retryable by shared execution)
|
|
18
|
+
* 422 -> ApiError 422 (never retry)
|
|
19
|
+
* 429 -> ApiError 429 (retried by shared execution)
|
|
20
|
+
* >= 500 / default -> ApiError status (retried by shared execution)
|
|
21
|
+
*
|
|
22
|
+
* Raw response bodies NEVER cross this module's error boundary — every
|
|
23
|
+
* thrown message is a curated constant (NFR-006).
|
|
24
|
+
*
|
|
25
|
+
* Boundary rules (ARCHITECTURE.md §2):
|
|
26
|
+
* - May import Adapter-local config and normalized errors.
|
|
27
|
+
* - May import `ProviderQuotaFetch` from `providers/types.js`.
|
|
28
|
+
* - Must NOT import command presentation, capability contracts, or
|
|
29
|
+
* another Provider's Adapter.
|
|
30
|
+
* - Must NOT perform response field normalization — the Adapter owns
|
|
31
|
+
* that. This module declares Provider-native request params only.
|
|
32
|
+
*/
|
|
33
|
+
import type { ProviderQuotaFetch } from "../types.js";
|
|
34
|
+
/** Injectable transport dependencies (fetch, timers, env). */
|
|
35
|
+
export interface SearchApiTransportDeps {
|
|
36
|
+
readonly fetch?: ProviderQuotaFetch;
|
|
37
|
+
readonly setTimeout?: typeof setTimeout;
|
|
38
|
+
readonly clearTimeout?: typeof clearTimeout;
|
|
39
|
+
readonly env?: NodeJS.ProcessEnv;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Provider-native search request query params (SearchApi API field
|
|
43
|
+
* names). The Adapter maps the Provider-neutral `SearchControls` into
|
|
44
|
+
* these before calling {@link fetchSearchApiSearch}; the transport
|
|
45
|
+
* never imports a capability contract. Result-count projection is a
|
|
46
|
+
* client-side concern owned by shared execution, so no count field
|
|
47
|
+
* exists here.
|
|
48
|
+
*/
|
|
49
|
+
export interface SearchApiSearchParams {
|
|
50
|
+
readonly engine?: string;
|
|
51
|
+
readonly q?: string;
|
|
52
|
+
readonly gl?: string;
|
|
53
|
+
readonly time_period?: string;
|
|
54
|
+
}
|
|
55
|
+
export declare function resolveTimeoutMs(env: NodeJS.ProcessEnv): number;
|
|
56
|
+
/**
|
|
57
|
+
* Perform ONE GET against the SearchApi.io `/api/v1/search` endpoint.
|
|
58
|
+
* No retry; no response body in public errors. Returns the parsed JSON
|
|
59
|
+
* body (raw; the Adapter post-processes into normalized search
|
|
60
|
+
* sources).
|
|
61
|
+
*
|
|
62
|
+
* `params` carries SearchApi-native API fields already mapped from
|
|
63
|
+
* `SearchControls` by the Adapter (`engine`/`q`/`gl`/`time_period`).
|
|
64
|
+
*/
|
|
65
|
+
export declare function fetchSearchApiSearch(apiKey: string, params?: SearchApiSearchParams, deps?: SearchApiTransportDeps): Promise<unknown>;
|
|
66
|
+
/**
|
|
67
|
+
* Perform ONE GET against the SearchApi.io `/api/v1/me` endpoint — the
|
|
68
|
+
* account/subscription metadata probe used by the Quota and Diagnostics
|
|
69
|
+
* Capabilities. Non-destructive: `/me` is not a search, so it consumes
|
|
70
|
+
* no search credits. No retry; no response body in public errors.
|
|
71
|
+
*/
|
|
72
|
+
export declare function fetchSearchApiMe(apiKey: string, deps?: SearchApiTransportDeps): Promise<unknown>;
|
|
73
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../src/providers/searchapi/client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAKH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AActD,8DAA8D;AAC9D,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,KAAK,CAAC,EAAE,kBAAkB,CAAC;IACpC,QAAQ,CAAC,UAAU,CAAC,EAAE,OAAO,UAAU,CAAC;IACxC,QAAQ,CAAC,YAAY,CAAC,EAAE,OAAO,YAAY,CAAC;IAC5C,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;CAClC;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;CAC/B;AAED,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,CAAC,UAAU,GAAG,MAAM,CAG/D;AA0ID;;;;;;;;GAQG;AACH,wBAAsB,oBAAoB,CACxC,MAAM,EAAE,MAAM,EACd,MAAM,GAAE,qBAA0B,EAClC,IAAI,GAAE,sBAA2B,GAChC,OAAO,CAAC,OAAO,CAAC,CAElB;AAED;;;;;GAKG;AACH,wBAAsB,gBAAgB,CACpC,MAAM,EAAE,MAAM,EACd,IAAI,GAAE,sBAA2B,GAChC,OAAO,CAAC,OAAO,CAAC,CAElB"}
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SearchApi.io direct HTTP transport.
|
|
3
|
+
*
|
|
4
|
+
* Performs direct GETs against the SearchApi.io REST API
|
|
5
|
+
* (`https://www.searchapi.io/api/v1`) with an
|
|
6
|
+
* `Authorization: Bearer <apiKey>` header — the key NEVER travels as a
|
|
7
|
+
* query parameter. There is NO internal retry — shared execution owns
|
|
8
|
+
* retry policy. Fetch and timers are injectable for tests.
|
|
9
|
+
*
|
|
10
|
+
* Structurally cloned from `providers/brave/client.ts`, simplified to
|
|
11
|
+
* the Linkup shape (no retry-hint header parsing; SearchApi exposes no
|
|
12
|
+
* rate-limit response headers to read).
|
|
13
|
+
*
|
|
14
|
+
* Failure taxonomy (SearchApi ERROR_HANDLING, locked):
|
|
15
|
+
* 401 / 403 -> AuthError (never retry)
|
|
16
|
+
* 402 -> QuotaError (never retry)
|
|
17
|
+
* 408 / 504 -> TimeoutError (retryable by shared execution)
|
|
18
|
+
* 422 -> ApiError 422 (never retry)
|
|
19
|
+
* 429 -> ApiError 429 (retried by shared execution)
|
|
20
|
+
* >= 500 / default -> ApiError status (retried by shared execution)
|
|
21
|
+
*
|
|
22
|
+
* Raw response bodies NEVER cross this module's error boundary — every
|
|
23
|
+
* thrown message is a curated constant (NFR-006).
|
|
24
|
+
*
|
|
25
|
+
* Boundary rules (ARCHITECTURE.md §2):
|
|
26
|
+
* - May import Adapter-local config and normalized errors.
|
|
27
|
+
* - May import `ProviderQuotaFetch` from `providers/types.js`.
|
|
28
|
+
* - Must NOT import command presentation, capability contracts, or
|
|
29
|
+
* another Provider's Adapter.
|
|
30
|
+
* - Must NOT perform response field normalization — the Adapter owns
|
|
31
|
+
* that. This module declares Provider-native request params only.
|
|
32
|
+
*/
|
|
33
|
+
import pkg from "../../../package.json" with { type: "json" };
|
|
34
|
+
import { ApiError, AuthError, NetworkError, QuotaError, TimeoutError } from "../../lib/errors.js";
|
|
35
|
+
import { getGlobalFetch } from "../types.js";
|
|
36
|
+
import { clampTimeoutMs } from "../../lib/timeout.js";
|
|
37
|
+
const { version: VERSION } = pkg;
|
|
38
|
+
const BASE_URL = "https://www.searchapi.io";
|
|
39
|
+
const SEARCH_PATH = "/api/v1/search";
|
|
40
|
+
const ME_PATH = "/api/v1/me";
|
|
41
|
+
const DEFAULT_TIMEOUT_MS = 30000;
|
|
42
|
+
const USER_AGENT = `scoutline/${VERSION}`;
|
|
43
|
+
const TIMEOUT_HELP_TEXT = "Try again or increase timeout with SEARCHAPI_TIMEOUT env var";
|
|
44
|
+
export function resolveTimeoutMs(env) {
|
|
45
|
+
const raw = parseInt(env.SEARCHAPI_TIMEOUT || String(DEFAULT_TIMEOUT_MS), 10);
|
|
46
|
+
return clampTimeoutMs(raw, DEFAULT_TIMEOUT_MS);
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Layer 1 — HTTP-status mapping. Runs BEFORE the body is parsed; on a
|
|
50
|
+
* non-2xx response we discard the body and throw a typed error with a
|
|
51
|
+
* curated message (no raw Provider body in any public error).
|
|
52
|
+
*/
|
|
53
|
+
function mapStatusError(status, timeoutMs) {
|
|
54
|
+
if (status === 401 || status === 403) {
|
|
55
|
+
return new AuthError("SearchApi.io authentication failed", "SEARCHAPI_API_KEY");
|
|
56
|
+
}
|
|
57
|
+
if (status === 402) {
|
|
58
|
+
return new QuotaError("SearchApi.io credits exhausted");
|
|
59
|
+
}
|
|
60
|
+
if (status === 408 || status === 504) {
|
|
61
|
+
return new TimeoutError(timeoutMs, TIMEOUT_HELP_TEXT);
|
|
62
|
+
}
|
|
63
|
+
if (status === 422) {
|
|
64
|
+
return new ApiError("SearchApi.io request failed", 422);
|
|
65
|
+
}
|
|
66
|
+
if (status === 429) {
|
|
67
|
+
return new ApiError("SearchApi.io rate limit exceeded", 429);
|
|
68
|
+
}
|
|
69
|
+
return new ApiError("SearchApi.io request failed", status);
|
|
70
|
+
}
|
|
71
|
+
function normalizeTransportError(err, timeoutMs) {
|
|
72
|
+
if (err instanceof AuthError ||
|
|
73
|
+
err instanceof ApiError ||
|
|
74
|
+
err instanceof NetworkError ||
|
|
75
|
+
err instanceof QuotaError ||
|
|
76
|
+
err instanceof TimeoutError) {
|
|
77
|
+
return err;
|
|
78
|
+
}
|
|
79
|
+
if (err instanceof Error) {
|
|
80
|
+
if (err.name === "AbortError") {
|
|
81
|
+
return new TimeoutError(timeoutMs, TIMEOUT_HELP_TEXT);
|
|
82
|
+
}
|
|
83
|
+
const lower = err.message.toLowerCase();
|
|
84
|
+
if (lower.includes("fetch") ||
|
|
85
|
+
lower.includes("econnrefused") ||
|
|
86
|
+
lower.includes("econnreset") ||
|
|
87
|
+
lower.includes("enotfound") ||
|
|
88
|
+
lower.includes("network")) {
|
|
89
|
+
return new NetworkError("SearchApi.io network error");
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return new ApiError("SearchApi.io request failed", 500);
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Build the query string for a GET. Skips `undefined`/`null` values.
|
|
96
|
+
* Uses `encodeURIComponent` so callers can pass raw strings without
|
|
97
|
+
* pre-encoding. The API key is NEVER a query parameter — it travels
|
|
98
|
+
* only in the `Authorization: Bearer` header.
|
|
99
|
+
*/
|
|
100
|
+
function buildQueryString(params) {
|
|
101
|
+
if (!params)
|
|
102
|
+
return "";
|
|
103
|
+
const parts = [];
|
|
104
|
+
for (const [key, value] of Object.entries(params)) {
|
|
105
|
+
if (value === undefined || value === null)
|
|
106
|
+
continue;
|
|
107
|
+
parts.push(`${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`);
|
|
108
|
+
}
|
|
109
|
+
return parts.length === 0 ? "" : `?${parts.join("&")}`;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Shared GET plumbing for every SearchApi.io JSON endpoint. Performs
|
|
113
|
+
* ONE GET against `path` with the canonical Bearer/Accept/User-Agent
|
|
114
|
+
* headers, the injected timeout, the status map, and JSON parsing. No
|
|
115
|
+
* retry; no response body in public errors. Returns the parsed JSON
|
|
116
|
+
* body (raw; the Adapter post-processes into normalized shapes).
|
|
117
|
+
*
|
|
118
|
+
* `params` carries SearchApi-native API fields already mapped by the
|
|
119
|
+
* Adapter (`engine`/`q`/`gl`/`time_period` for search). The API key is
|
|
120
|
+
* NEVER a query parameter — it travels only in the `Authorization:
|
|
121
|
+
* Bearer` header.
|
|
122
|
+
*/
|
|
123
|
+
async function getSearchApiJson(apiKey, path, params, deps) {
|
|
124
|
+
const f = deps.fetch ?? getGlobalFetch();
|
|
125
|
+
const setT = deps.setTimeout ?? setTimeout;
|
|
126
|
+
const clearT = deps.clearTimeout ?? clearTimeout;
|
|
127
|
+
const env = deps.env ?? process.env;
|
|
128
|
+
const timeoutMs = resolveTimeoutMs(env);
|
|
129
|
+
const url = `${BASE_URL}${path}${buildQueryString(params)}`;
|
|
130
|
+
const controller = new AbortController();
|
|
131
|
+
const timeoutId = setT(() => controller.abort(), timeoutMs);
|
|
132
|
+
try {
|
|
133
|
+
const res = await f(url, {
|
|
134
|
+
method: "GET",
|
|
135
|
+
headers: {
|
|
136
|
+
Authorization: `Bearer ${apiKey}`,
|
|
137
|
+
Accept: "application/json",
|
|
138
|
+
"User-Agent": USER_AGENT,
|
|
139
|
+
},
|
|
140
|
+
signal: controller.signal,
|
|
141
|
+
});
|
|
142
|
+
if (!res.ok) {
|
|
143
|
+
// Drain the body to free the socket, then drop it. The body must
|
|
144
|
+
// NEVER reach the error message (NFR-006).
|
|
145
|
+
await res.text().catch(() => { });
|
|
146
|
+
throw mapStatusError(res.status, timeoutMs);
|
|
147
|
+
}
|
|
148
|
+
let parsed;
|
|
149
|
+
try {
|
|
150
|
+
parsed = await res.json();
|
|
151
|
+
}
|
|
152
|
+
catch (err) {
|
|
153
|
+
// Only a genuine parse failure (non-JSON body → SyntaxError) is
|
|
154
|
+
// the malformed-response case. Anything else — notably the
|
|
155
|
+
// AbortError thrown when the transport timeout fires mid-read —
|
|
156
|
+
// must flow to the outer catch so normalizeTransportError keeps
|
|
157
|
+
// its AbortError → TimeoutError classification.
|
|
158
|
+
if (err instanceof SyntaxError) {
|
|
159
|
+
throw new ApiError("SearchApi.io returned a malformed response", 500);
|
|
160
|
+
}
|
|
161
|
+
throw err;
|
|
162
|
+
}
|
|
163
|
+
return parsed;
|
|
164
|
+
}
|
|
165
|
+
catch (err) {
|
|
166
|
+
throw normalizeTransportError(err, timeoutMs);
|
|
167
|
+
}
|
|
168
|
+
finally {
|
|
169
|
+
// Clear the timeout only after body consumption so the AbortController
|
|
170
|
+
// timeout still covers a stalled/slow response body read.
|
|
171
|
+
clearT(timeoutId);
|
|
172
|
+
controller.abort();
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Perform ONE GET against the SearchApi.io `/api/v1/search` endpoint.
|
|
177
|
+
* No retry; no response body in public errors. Returns the parsed JSON
|
|
178
|
+
* body (raw; the Adapter post-processes into normalized search
|
|
179
|
+
* sources).
|
|
180
|
+
*
|
|
181
|
+
* `params` carries SearchApi-native API fields already mapped from
|
|
182
|
+
* `SearchControls` by the Adapter (`engine`/`q`/`gl`/`time_period`).
|
|
183
|
+
*/
|
|
184
|
+
export async function fetchSearchApiSearch(apiKey, params = {}, deps = {}) {
|
|
185
|
+
return getSearchApiJson(apiKey, SEARCH_PATH, { ...(params ?? {}) }, deps);
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Perform ONE GET against the SearchApi.io `/api/v1/me` endpoint — the
|
|
189
|
+
* account/subscription metadata probe used by the Quota and Diagnostics
|
|
190
|
+
* Capabilities. Non-destructive: `/me` is not a search, so it consumes
|
|
191
|
+
* no search credits. No retry; no response body in public errors.
|
|
192
|
+
*/
|
|
193
|
+
export async function fetchSearchApiMe(apiKey, deps = {}) {
|
|
194
|
+
return getSearchApiJson(apiKey, ME_PATH, undefined, deps);
|
|
195
|
+
}
|
|
196
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../../src/providers/searchapi/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SearchApi credential resolution.
|
|
3
|
+
*
|
|
4
|
+
* Single source of truth for the SearchApi.io API key
|
|
5
|
+
* (`SEARCHAPI_API_KEY`, with the legacy `SERPAPI_API_KEY` accepted as a
|
|
6
|
+
* lower-precedence fallback). Whitespace-only values are treated as
|
|
7
|
+
* absent, matching the descriptor's `isConfigured` contract. Resolved
|
|
8
|
+
* keys are returned trimmed so wire headers never carry stray
|
|
9
|
+
* whitespace.
|
|
10
|
+
*
|
|
11
|
+
* Boundary rules (ARCHITECTURE.md §2):
|
|
12
|
+
* - May import the normalized-error contract only.
|
|
13
|
+
* - Must NOT import transport, command presentation, or another
|
|
14
|
+
* Provider's Adapter.
|
|
15
|
+
*
|
|
16
|
+
* Missing credentials are surfaced as {@link ConfigurationError}
|
|
17
|
+
* (exit 3), distinct from {@link AuthError} (exit 1) which means the
|
|
18
|
+
* Provider REJECTED a presented credential.
|
|
19
|
+
*/
|
|
20
|
+
/** Credential environment names read by this module (#232 derivation pin). */
|
|
21
|
+
export declare const ENV_NAMES: readonly ["SEARCHAPI_API_KEY", "SERPAPI_API_KEY"];
|
|
22
|
+
/**
|
|
23
|
+
* Resolve the SearchApi API key without throwing. Returns the trimmed
|
|
24
|
+
* key or `undefined` when no non-blank value is present.
|
|
25
|
+
* `SEARCHAPI_API_KEY` wins over the legacy `SERPAPI_API_KEY`.
|
|
26
|
+
*/
|
|
27
|
+
export declare function getSearchApiKey(env: NodeJS.ProcessEnv): string | undefined;
|
|
28
|
+
/**
|
|
29
|
+
* Resolve the SearchApi API key or throw {@link ConfigurationError}
|
|
30
|
+
* (exit 3) when it is missing. Call this at every capability
|
|
31
|
+
* invocation gate.
|
|
32
|
+
*/
|
|
33
|
+
export declare function requireSearchApiKey(env: NodeJS.ProcessEnv): string;
|
|
34
|
+
/**
|
|
35
|
+
* True when a non-blank SearchApi API key is configured. Metadata-only:
|
|
36
|
+
* performs no transport construction and reads no other Provider's
|
|
37
|
+
* credentials.
|
|
38
|
+
*/
|
|
39
|
+
export declare function isSearchApiConfigured(env: NodeJS.ProcessEnv): boolean;
|
|
40
|
+
/**
|
|
41
|
+
* Lowercase hex SHA-256 fingerprint of the SearchApi API key. Used for
|
|
42
|
+
* partitioned cache identity; the raw key must never appear in cache
|
|
43
|
+
* filenames, errors, or logs.
|
|
44
|
+
*/
|
|
45
|
+
export declare function hashSearchApiKey(key: string): string;
|
|
46
|
+
//# sourceMappingURL=credentials.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"credentials.d.ts","sourceRoot":"","sources":["../../../src/providers/searchapi/credentials.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAMH,8EAA8E;AAC9E,eAAO,MAAM,SAAS,YAAI,mBAAmB,EAAE,iBAAiB,CAAU,CAAC;AAc3E;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,CAAC,UAAU,GAAG,MAAM,GAAG,SAAS,CAE1E;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,CAAC,UAAU,GAAG,MAAM,CASlE;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,CAAC,UAAU,GAAG,OAAO,CAErE;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAEpD"}
|