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.
Files changed (325) hide show
  1. package/README.md +108 -26
  2. package/dist/capabilities/investigation.d.ts +134 -0
  3. package/dist/capabilities/investigation.d.ts.map +1 -0
  4. package/dist/capabilities/investigation.js +278 -0
  5. package/dist/capabilities/investigation.js.map +1 -0
  6. package/dist/capabilities/search.d.ts +18 -4
  7. package/dist/capabilities/search.d.ts.map +1 -1
  8. package/dist/commands/config.d.ts.map +1 -1
  9. package/dist/commands/config.js +14 -5
  10. package/dist/commands/config.js.map +1 -1
  11. package/dist/commands/crawl.d.ts.map +1 -1
  12. package/dist/commands/crawl.js +2 -1
  13. package/dist/commands/crawl.js.map +1 -1
  14. package/dist/commands/doctor.d.ts.map +1 -1
  15. package/dist/commands/doctor.js +2 -1
  16. package/dist/commands/doctor.js.map +1 -1
  17. package/dist/commands/init.d.ts +42 -1
  18. package/dist/commands/init.d.ts.map +1 -1
  19. package/dist/commands/init.js +42 -5
  20. package/dist/commands/init.js.map +1 -1
  21. package/dist/commands/investigate.d.ts +232 -0
  22. package/dist/commands/investigate.d.ts.map +1 -0
  23. package/dist/commands/investigate.js +838 -0
  24. package/dist/commands/investigate.js.map +1 -0
  25. package/dist/commands/map.d.ts.map +1 -1
  26. package/dist/commands/map.js +2 -1
  27. package/dist/commands/map.js.map +1 -1
  28. package/dist/commands/quota.d.ts.map +1 -1
  29. package/dist/commands/quota.js +2 -2
  30. package/dist/commands/quota.js.map +1 -1
  31. package/dist/commands/read.d.ts.map +1 -1
  32. package/dist/commands/read.js +2 -1
  33. package/dist/commands/read.js.map +1 -1
  34. package/dist/commands/repo.js +1 -1
  35. package/dist/commands/research.d.ts.map +1 -1
  36. package/dist/commands/research.js +2 -1
  37. package/dist/commands/research.js.map +1 -1
  38. package/dist/commands/search.d.ts +54 -6
  39. package/dist/commands/search.d.ts.map +1 -1
  40. package/dist/commands/search.js +273 -25
  41. package/dist/commands/search.js.map +1 -1
  42. package/dist/commands/vision.d.ts.map +1 -1
  43. package/dist/commands/vision.js +15 -2
  44. package/dist/commands/vision.js.map +1 -1
  45. package/dist/index.d.ts +93 -1
  46. package/dist/index.d.ts.map +1 -1
  47. package/dist/index.js +737 -14
  48. package/dist/index.js.map +1 -1
  49. package/dist/lib/code-mode.d.ts +12 -0
  50. package/dist/lib/code-mode.d.ts.map +1 -1
  51. package/dist/lib/code-mode.js +18 -10
  52. package/dist/lib/code-mode.js.map +1 -1
  53. package/dist/lib/config-store.d.ts +45 -1
  54. package/dist/lib/config-store.d.ts.map +1 -1
  55. package/dist/lib/config-store.js +70 -1
  56. package/dist/lib/config-store.js.map +1 -1
  57. package/dist/lib/config.d.ts.map +1 -1
  58. package/dist/lib/config.js +5 -1
  59. package/dist/lib/config.js.map +1 -1
  60. package/dist/lib/errors.d.ts +7 -1
  61. package/dist/lib/errors.d.ts.map +1 -1
  62. package/dist/lib/errors.js +8 -2
  63. package/dist/lib/errors.js.map +1 -1
  64. package/dist/lib/execution.d.ts +14 -5
  65. package/dist/lib/execution.d.ts.map +1 -1
  66. package/dist/lib/execution.js +25 -6
  67. package/dist/lib/execution.js.map +1 -1
  68. package/dist/lib/investigate-claims.d.ts +90 -0
  69. package/dist/lib/investigate-claims.d.ts.map +1 -0
  70. package/dist/lib/investigate-claims.js +188 -0
  71. package/dist/lib/investigate-claims.js.map +1 -0
  72. package/dist/lib/investigate-extract.d.ts +35 -0
  73. package/dist/lib/investigate-extract.d.ts.map +1 -0
  74. package/dist/lib/investigate-extract.js +101 -0
  75. package/dist/lib/investigate-extract.js.map +1 -0
  76. package/dist/lib/investigate-planner.d.ts +58 -0
  77. package/dist/lib/investigate-planner.d.ts.map +1 -0
  78. package/dist/lib/investigate-planner.js +141 -0
  79. package/dist/lib/investigate-planner.js.map +1 -0
  80. package/dist/lib/mcp-client.d.ts +7 -0
  81. package/dist/lib/mcp-client.d.ts.map +1 -1
  82. package/dist/lib/mcp-client.js +11 -1
  83. package/dist/lib/mcp-client.js.map +1 -1
  84. package/dist/lib/parse-zoned-instant.d.ts +13 -0
  85. package/dist/lib/parse-zoned-instant.d.ts.map +1 -0
  86. package/dist/lib/parse-zoned-instant.js +17 -0
  87. package/dist/lib/parse-zoned-instant.js.map +1 -0
  88. package/dist/lib/quota-mapping.d.ts +4 -2
  89. package/dist/lib/quota-mapping.d.ts.map +1 -1
  90. package/dist/lib/quota-mapping.js +25 -2
  91. package/dist/lib/quota-mapping.js.map +1 -1
  92. package/dist/lib/redact.d.ts +3 -2
  93. package/dist/lib/redact.d.ts.map +1 -1
  94. package/dist/lib/redact.js +90 -24
  95. package/dist/lib/redact.js.map +1 -1
  96. package/dist/lib/timeout.d.ts +28 -0
  97. package/dist/lib/timeout.d.ts.map +1 -0
  98. package/dist/lib/timeout.js +30 -0
  99. package/dist/lib/timeout.js.map +1 -0
  100. package/dist/lib/url.d.ts +10 -4
  101. package/dist/lib/url.d.ts.map +1 -1
  102. package/dist/lib/url.js +21 -6
  103. package/dist/lib/url.js.map +1 -1
  104. package/dist/providers/arxiv/client.d.ts +4 -1
  105. package/dist/providers/arxiv/client.d.ts.map +1 -1
  106. package/dist/providers/arxiv/client.js +11 -3
  107. package/dist/providers/arxiv/client.js.map +1 -1
  108. package/dist/providers/bocha/adapter.d.ts +43 -0
  109. package/dist/providers/bocha/adapter.d.ts.map +1 -0
  110. package/dist/providers/bocha/adapter.js +197 -0
  111. package/dist/providers/bocha/adapter.js.map +1 -0
  112. package/dist/providers/bocha/client.d.ts +51 -0
  113. package/dist/providers/bocha/client.d.ts.map +1 -0
  114. package/dist/providers/bocha/client.js +104 -0
  115. package/dist/providers/bocha/client.js.map +1 -0
  116. package/dist/providers/bocha/credentials.d.ts +12 -0
  117. package/dist/providers/bocha/credentials.d.ts.map +1 -0
  118. package/dist/providers/bocha/credentials.js +29 -0
  119. package/dist/providers/bocha/credentials.js.map +1 -0
  120. package/dist/providers/bocha/diagnostics.d.ts +17 -0
  121. package/dist/providers/bocha/diagnostics.d.ts.map +1 -0
  122. package/dist/providers/bocha/diagnostics.js +33 -0
  123. package/dist/providers/bocha/diagnostics.js.map +1 -0
  124. package/dist/providers/brave/adapter.d.ts.map +1 -1
  125. package/dist/providers/brave/adapter.js +4 -3
  126. package/dist/providers/brave/adapter.js.map +1 -1
  127. package/dist/providers/brave/client.d.ts +1 -0
  128. package/dist/providers/brave/client.d.ts.map +1 -1
  129. package/dist/providers/brave/client.js +4 -6
  130. package/dist/providers/brave/client.js.map +1 -1
  131. package/dist/providers/brave/credentials.d.ts +2 -0
  132. package/dist/providers/brave/credentials.d.ts.map +1 -1
  133. package/dist/providers/brave/credentials.js +2 -0
  134. package/dist/providers/brave/credentials.js.map +1 -1
  135. package/dist/providers/catalog.d.ts +34 -0
  136. package/dist/providers/catalog.d.ts.map +1 -0
  137. package/dist/providers/catalog.js +57 -0
  138. package/dist/providers/catalog.js.map +1 -0
  139. package/dist/providers/crossref/adapter.js +2 -2
  140. package/dist/providers/crossref/adapter.js.map +1 -1
  141. package/dist/providers/crossref/client.d.ts +4 -1
  142. package/dist/providers/crossref/client.d.ts.map +1 -1
  143. package/dist/providers/crossref/client.js +11 -3
  144. package/dist/providers/crossref/client.js.map +1 -1
  145. package/dist/providers/crossref/diagnostics.d.ts +1 -1
  146. package/dist/providers/crossref/diagnostics.js +1 -1
  147. package/dist/providers/crossref/diagnostics.js.map +1 -1
  148. package/dist/providers/europepmc/adapter.js +2 -2
  149. package/dist/providers/europepmc/adapter.js.map +1 -1
  150. package/dist/providers/europepmc/client.d.ts +4 -1
  151. package/dist/providers/europepmc/client.d.ts.map +1 -1
  152. package/dist/providers/europepmc/client.js +11 -3
  153. package/dist/providers/europepmc/client.js.map +1 -1
  154. package/dist/providers/exa/client.d.ts +1 -0
  155. package/dist/providers/exa/client.d.ts.map +1 -1
  156. package/dist/providers/exa/client.js +3 -2
  157. package/dist/providers/exa/client.js.map +1 -1
  158. package/dist/providers/exa/credentials.d.ts +2 -0
  159. package/dist/providers/exa/credentials.d.ts.map +1 -1
  160. package/dist/providers/exa/credentials.js +2 -0
  161. package/dist/providers/exa/credentials.js.map +1 -1
  162. package/dist/providers/firecrawl/adapter.d.ts.map +1 -1
  163. package/dist/providers/firecrawl/adapter.js +2 -1
  164. package/dist/providers/firecrawl/adapter.js.map +1 -1
  165. package/dist/providers/firecrawl/client.d.ts +1 -0
  166. package/dist/providers/firecrawl/client.d.ts.map +1 -1
  167. package/dist/providers/firecrawl/client.js +3 -2
  168. package/dist/providers/firecrawl/client.js.map +1 -1
  169. package/dist/providers/firecrawl/credentials.d.ts +2 -0
  170. package/dist/providers/firecrawl/credentials.d.ts.map +1 -1
  171. package/dist/providers/firecrawl/credentials.js +2 -0
  172. package/dist/providers/firecrawl/credentials.js.map +1 -1
  173. package/dist/providers/firecrawl/quota.d.ts.map +1 -1
  174. package/dist/providers/firecrawl/quota.js +5 -2
  175. package/dist/providers/firecrawl/quota.js.map +1 -1
  176. package/dist/providers/jina/adapter.d.ts.map +1 -1
  177. package/dist/providers/jina/adapter.js +6 -4
  178. package/dist/providers/jina/adapter.js.map +1 -1
  179. package/dist/providers/jina/client.d.ts +2 -0
  180. package/dist/providers/jina/client.d.ts.map +1 -1
  181. package/dist/providers/jina/client.js +6 -5
  182. package/dist/providers/jina/client.js.map +1 -1
  183. package/dist/providers/jina/credentials.d.ts +2 -0
  184. package/dist/providers/jina/credentials.d.ts.map +1 -1
  185. package/dist/providers/jina/credentials.js +2 -0
  186. package/dist/providers/jina/credentials.js.map +1 -1
  187. package/dist/providers/kagi/adapter.d.ts +44 -0
  188. package/dist/providers/kagi/adapter.d.ts.map +1 -0
  189. package/dist/providers/kagi/adapter.js +188 -0
  190. package/dist/providers/kagi/adapter.js.map +1 -0
  191. package/dist/providers/kagi/client.d.ts +41 -0
  192. package/dist/providers/kagi/client.d.ts.map +1 -0
  193. package/dist/providers/kagi/client.js +100 -0
  194. package/dist/providers/kagi/client.js.map +1 -0
  195. package/dist/providers/kagi/credentials.d.ts +15 -0
  196. package/dist/providers/kagi/credentials.d.ts.map +1 -0
  197. package/dist/providers/kagi/credentials.js +35 -0
  198. package/dist/providers/kagi/credentials.js.map +1 -0
  199. package/dist/providers/kagi/diagnostics.d.ts +17 -0
  200. package/dist/providers/kagi/diagnostics.d.ts.map +1 -0
  201. package/dist/providers/kagi/diagnostics.js +33 -0
  202. package/dist/providers/kagi/diagnostics.js.map +1 -0
  203. package/dist/providers/linkup/client.d.ts +1 -0
  204. package/dist/providers/linkup/client.d.ts.map +1 -1
  205. package/dist/providers/linkup/client.js +3 -2
  206. package/dist/providers/linkup/client.js.map +1 -1
  207. package/dist/providers/linkup/credentials.d.ts +2 -0
  208. package/dist/providers/linkup/credentials.d.ts.map +1 -1
  209. package/dist/providers/linkup/credentials.js +2 -0
  210. package/dist/providers/linkup/credentials.js.map +1 -1
  211. package/dist/providers/minimax/adapter.d.ts.map +1 -1
  212. package/dist/providers/minimax/adapter.js +2 -2
  213. package/dist/providers/minimax/adapter.js.map +1 -1
  214. package/dist/providers/minimax/coding-plan-client.d.ts +1 -0
  215. package/dist/providers/minimax/coding-plan-client.d.ts.map +1 -1
  216. package/dist/providers/minimax/coding-plan-client.js +3 -2
  217. package/dist/providers/minimax/coding-plan-client.js.map +1 -1
  218. package/dist/providers/minimax/quota-client.d.ts +1 -0
  219. package/dist/providers/minimax/quota-client.d.ts.map +1 -1
  220. package/dist/providers/minimax/quota-client.js +3 -2
  221. package/dist/providers/minimax/quota-client.js.map +1 -1
  222. package/dist/providers/openalex/client.d.ts +2 -0
  223. package/dist/providers/openalex/client.d.ts.map +1 -1
  224. package/dist/providers/openalex/client.js +10 -3
  225. package/dist/providers/openalex/client.js.map +1 -1
  226. package/dist/providers/openalex/diagnostics.d.ts +1 -1
  227. package/dist/providers/openalex/diagnostics.js +1 -1
  228. package/dist/providers/openalex/diagnostics.js.map +1 -1
  229. package/dist/providers/parallel/client.d.ts +1 -0
  230. package/dist/providers/parallel/client.d.ts.map +1 -1
  231. package/dist/providers/parallel/client.js +3 -2
  232. package/dist/providers/parallel/client.js.map +1 -1
  233. package/dist/providers/parallel/credentials.d.ts +2 -0
  234. package/dist/providers/parallel/credentials.d.ts.map +1 -1
  235. package/dist/providers/parallel/credentials.js +2 -0
  236. package/dist/providers/parallel/credentials.js.map +1 -1
  237. package/dist/providers/perplexity/client.d.ts +2 -0
  238. package/dist/providers/perplexity/client.d.ts.map +1 -1
  239. package/dist/providers/perplexity/client.js +5 -4
  240. package/dist/providers/perplexity/client.js.map +1 -1
  241. package/dist/providers/perplexity/credentials.d.ts +2 -0
  242. package/dist/providers/perplexity/credentials.d.ts.map +1 -1
  243. package/dist/providers/perplexity/credentials.js +2 -0
  244. package/dist/providers/perplexity/credentials.js.map +1 -1
  245. package/dist/providers/pubmed/client.d.ts +2 -0
  246. package/dist/providers/pubmed/client.d.ts.map +1 -1
  247. package/dist/providers/pubmed/client.js +10 -3
  248. package/dist/providers/pubmed/client.js.map +1 -1
  249. package/dist/providers/registry.d.ts.map +1 -1
  250. package/dist/providers/registry.js +10 -1
  251. package/dist/providers/registry.js.map +1 -1
  252. package/dist/providers/searchapi/adapter.d.ts +54 -0
  253. package/dist/providers/searchapi/adapter.d.ts.map +1 -0
  254. package/dist/providers/searchapi/adapter.js +310 -0
  255. package/dist/providers/searchapi/adapter.js.map +1 -0
  256. package/dist/providers/searchapi/client.d.ts +73 -0
  257. package/dist/providers/searchapi/client.d.ts.map +1 -0
  258. package/dist/providers/searchapi/client.js +196 -0
  259. package/dist/providers/searchapi/client.js.map +1 -0
  260. package/dist/providers/searchapi/credentials.d.ts +46 -0
  261. package/dist/providers/searchapi/credentials.d.ts.map +1 -0
  262. package/dist/providers/searchapi/credentials.js +71 -0
  263. package/dist/providers/searchapi/credentials.js.map +1 -0
  264. package/dist/providers/searchapi/diagnostics.d.ts +48 -0
  265. package/dist/providers/searchapi/diagnostics.d.ts.map +1 -0
  266. package/dist/providers/searchapi/diagnostics.js +70 -0
  267. package/dist/providers/searchapi/diagnostics.js.map +1 -0
  268. package/dist/providers/searchapi/quota.d.ts +60 -0
  269. package/dist/providers/searchapi/quota.d.ts.map +1 -0
  270. package/dist/providers/searchapi/quota.js +125 -0
  271. package/dist/providers/searchapi/quota.js.map +1 -0
  272. package/dist/providers/spider/client.d.ts +2 -0
  273. package/dist/providers/spider/client.d.ts.map +1 -1
  274. package/dist/providers/spider/client.js +16 -6
  275. package/dist/providers/spider/client.js.map +1 -1
  276. package/dist/providers/spider/credentials.d.ts +2 -0
  277. package/dist/providers/spider/credentials.d.ts.map +1 -1
  278. package/dist/providers/spider/credentials.js +2 -0
  279. package/dist/providers/spider/credentials.js.map +1 -1
  280. package/dist/providers/tavily/client.d.ts +1 -0
  281. package/dist/providers/tavily/client.d.ts.map +1 -1
  282. package/dist/providers/tavily/client.js +3 -2
  283. package/dist/providers/tavily/client.js.map +1 -1
  284. package/dist/providers/tavily/credentials.d.ts +2 -0
  285. package/dist/providers/tavily/credentials.d.ts.map +1 -1
  286. package/dist/providers/tavily/credentials.js +2 -0
  287. package/dist/providers/tavily/credentials.js.map +1 -1
  288. package/dist/providers/types.d.ts +31 -2
  289. package/dist/providers/types.d.ts.map +1 -1
  290. package/dist/providers/types.js +3 -0
  291. package/dist/providers/types.js.map +1 -1
  292. package/dist/providers/you/client.d.ts +4 -0
  293. package/dist/providers/you/client.d.ts.map +1 -1
  294. package/dist/providers/you/client.js +4 -5
  295. package/dist/providers/you/client.js.map +1 -1
  296. package/dist/providers/you/credentials.d.ts +2 -0
  297. package/dist/providers/you/credentials.d.ts.map +1 -1
  298. package/dist/providers/you/credentials.js +3 -3
  299. package/dist/providers/you/credentials.js.map +1 -1
  300. package/dist/providers/zai/adapter.d.ts.map +1 -1
  301. package/dist/providers/zai/adapter.js +219 -4
  302. package/dist/providers/zai/adapter.js.map +1 -1
  303. package/dist/providers/zai/credentials.d.ts +2 -0
  304. package/dist/providers/zai/credentials.d.ts.map +1 -1
  305. package/dist/providers/zai/credentials.js +2 -0
  306. package/dist/providers/zai/credentials.js.map +1 -1
  307. package/dist/providers/zai/layout-parsing.d.ts +76 -0
  308. package/dist/providers/zai/layout-parsing.d.ts.map +1 -0
  309. package/dist/providers/zai/layout-parsing.js +151 -0
  310. package/dist/providers/zai/layout-parsing.js.map +1 -0
  311. package/dist/providers/zai/media.d.ts +19 -0
  312. package/dist/providers/zai/media.d.ts.map +1 -1
  313. package/dist/providers/zai/media.js +61 -0
  314. package/dist/providers/zai/media.js.map +1 -1
  315. package/dist/providers/zai/monitor-client.d.ts +1 -0
  316. package/dist/providers/zai/monitor-client.d.ts.map +1 -1
  317. package/dist/providers/zai/monitor-client.js +3 -2
  318. package/dist/providers/zai/monitor-client.js.map +1 -1
  319. package/dist/providers/zai/quota.d.ts +4 -0
  320. package/dist/providers/zai/quota.d.ts.map +1 -1
  321. package/dist/providers/zai/quota.js +16 -1
  322. package/dist/providers/zai/quota.js.map +1 -1
  323. package/package.json +1 -1
  324. package/skills/scoutline/SKILL.md +163 -45
  325. 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"}