serpkite 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -92,7 +92,6 @@ vertical-specific extras and `meta` (`request_id`, `credits_used`, `cached`, `la
92
92
  | `scholar(params)` | `POST /v1/scholar` | `SearchParams` | `ScholarResponse` |
93
93
  | `patents(params)` | `POST /v1/patents` | `SearchParams` | `PatentsResponse` |
94
94
  | `autocomplete(params)` | `POST /v1/autocomplete` | `SearchParams` | `AutocompleteResponse` (`results[].value`) |
95
- | `lens(params)` | `POST /v1/lens` | `LensParams` (`url` of an image) | `LensResponse` |
96
95
  | `webpage(params)` | `POST /v1/webpage` | `WebpageParams` (`url`, `include_html`) | `WebpageResponse` (`markdown`, `text`, `metadata`) |
97
96
  | `rank(params)` | `POST /v1/rank` | `RankParams` (`q`, `domain`, `num`: 10\|20\|30\|50\|100) | `RankResponse` (`position` or `null`, `matches`, `checked`) |
98
97
  | `account()` | `GET /v1/account` | none | `Account` (`balance`, `plan`, `rate_limit_rps`, `month`, …) |
@@ -256,7 +255,7 @@ Types are generated from the OpenAPI contract (`backend/api/serp-api.yaml`) with
256
255
  `openapi-typescript`. Friendly aliases are exported: `SearchParams`, `SearchResponse`,
257
256
  `OrganicResult`, `AnswerBox`, `NewsResponse`, `NewsResult`, `ImagesResponse`, `PlacesResponse`,
258
257
  `ReviewsResponse`, `ShoppingResponse`, `ScholarResponse`, `PatentsResponse`,
259
- `AutocompleteResponse`, `LensResponse`, `WebpageResponse`, `RankResponse`,
258
+ `AutocompleteResponse`, `WebpageResponse`, `RankResponse`,
260
259
  `Account`, `Batch`, `BatchCreateParams`, `Meta`, `Engine`, `Provider`, `RouteStep`,
261
260
  `CompactResponse` and more. The raw
262
261
  `paths`, `components` and `operations` types are exported as well.
package/dist/index.cjs CHANGED
@@ -50,7 +50,7 @@ function errorFromResponse(status, headers, body) {
50
50
  }
51
51
 
52
52
  // src/client.ts
53
- var VERSION = "0.2.0";
53
+ var VERSION = "0.3.0";
54
54
  var DEFAULT_BASE_URL = "https://api.serpkite.com";
55
55
  var SerpKite = class {
56
56
  baseUrl;
@@ -113,10 +113,6 @@ var SerpKite = class {
113
113
  autocomplete = this.#vertical("/v1/autocomplete");
114
114
  /** Fetch any public URL as clean Markdown plus metadata. */
115
115
  webpage = this.#vertical("/v1/webpage");
116
- /** Google Lens visual matches for an image URL. */
117
- lens(params, options) {
118
- return this.request({ method: "POST", path: "/v1/lens", body: params, options });
119
- }
120
116
  /** Position of `domain` for keyword `q` in the top `num` results (default 100). */
121
117
  rank(params, options) {
122
118
  return this.request({ method: "POST", path: "/v1/rank", body: params, options });
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/errors.ts","../src/client.ts","../src/util.ts","../src/webhooks.ts"],"names":[],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Every failure thrown by the SDK. API errors carry the fields of the\n * `{\"error\":{\"code\",\"message\",\"request_id\"}}` envelope; network failures and\n * timeouts use `status: 0` with code `connection_error` or `timeout`.\n */\nexport class SerpKiteError extends Error {\n /** HTTP status, or 0 when no response was received. */\n readonly status: number;\n /** Machine-readable code, e.g. `unauthorized`, `insufficient_credits`, `rate_limited`. */\n readonly code: string;\n /** `X-Request-Id` of the failed request, when the API returned one. */\n readonly requestId: string | undefined;\n /** Response headers, when the API responded. */\n readonly headers: Headers | undefined;\n\n constructor(\n status: number,\n code: string,\n message: string,\n requestId?: string,\n headers?: Headers,\n options?: { cause?: unknown },\n ) {\n super(message, options);\n this.name = \"SerpKiteError\";\n this.status = status;\n this.code = code;\n this.requestId = requestId || undefined;\n this.headers = headers;\n }\n}\n\nconst fallbackCodes: Record<number, string> = {\n 400: \"invalid_request\",\n 401: \"unauthorized\",\n 402: \"insufficient_credits\",\n 403: \"forbidden\",\n 404: \"not_found\",\n 429: \"rate_limited\",\n // The API sends upstream failures as 503 with a JSON body; a bare 502/504\n // comes from a proxy (Cloudflare replaces origin 502/504 bodies).\n 502: \"upstream_error\",\n 503: \"unavailable\",\n 504: \"upstream_timeout\",\n};\n\n/** Builds a SerpKiteError from a non-2xx response body (JSON envelope or anything else). */\nexport function errorFromResponse(status: number, headers: Headers, body: string): SerpKiteError {\n let code = fallbackCodes[status] ?? (status >= 500 ? \"server_error\" : \"http_error\");\n let message = body.trim().slice(0, 500) || `HTTP ${status}`;\n let requestId = headers.get(\"x-request-id\") ?? undefined;\n try {\n const parsed = JSON.parse(body) as {\n error?: { code?: unknown; message?: unknown; request_id?: unknown };\n };\n const e = parsed?.error;\n if (e && typeof e === \"object\") {\n if (typeof e.code === \"string\" && e.code) code = e.code;\n if (typeof e.message === \"string\" && e.message) message = e.message;\n if (typeof e.request_id === \"string\" && e.request_id) requestId = e.request_id;\n }\n } catch {\n // Not JSON: keep the text body as the message.\n }\n return new SerpKiteError(status, code, message, requestId, headers);\n}\n","import { errorFromResponse, SerpKiteError } from \"./errors\";\nimport type {\n Account,\n AutocompleteResponse,\n Batch,\n BatchCreateEntry,\n BatchCreateParams,\n BatchCreateResponse,\n CompactResponse,\n ImagesResponse,\n LensParams,\n LensResponse,\n NewsResponse,\n PatentsResponse,\n PlacesResponse,\n RankParams,\n RankResponse,\n ReviewsParams,\n ReviewsResponse,\n ScholarResponse,\n SearchParams,\n SearchResponse,\n ShoppingResponse,\n VideosResponse,\n WebpageParams,\n WebpageResponse,\n} from \"./types\";\n\nexport const VERSION = \"0.2.0\";\nexport const DEFAULT_BASE_URL = \"https://api.serpkite.com\";\n\nexport interface SerpKiteOptions {\n /** API key (`skt_live_…`). Defaults to the `SERPKITE_API_KEY` environment variable. */\n apiKey?: string;\n /** Defaults to `SERPKITE_BASE_URL` or https://api.serpkite.com. */\n baseUrl?: string;\n /** Per-attempt timeout in milliseconds. Default 60000. */\n timeoutMs?: number;\n /** Retries after the first attempt on 429, 5xx and network errors. Default 2. */\n maxRetries?: number;\n /** Base delay of the exponential backoff in milliseconds. Default 500. */\n retryDelayMs?: number;\n /** Custom fetch implementation. Defaults to the global `fetch`. */\n fetch?: typeof fetch;\n /** Extra headers sent with every request. */\n headers?: Record<string, string>;\n}\n\n/** Billing and tracing details from the response headers. */\nexport interface ResponseInfo {\n status: number;\n headers: Headers;\n requestId: string | undefined;\n creditsUsed: number | undefined;\n creditsRemaining: number | undefined;\n costUsd: number | undefined;\n /** `HIT` when served from cache (`max_age`), else `MISS`. */\n cache: \"HIT\" | \"MISS\" | undefined;\n latencyMs: number | undefined;\n tokensEstimate: number | undefined;\n}\n\nexport interface RequestOptions {\n signal?: AbortSignal;\n /** Overrides the client's per-attempt timeout. */\n timeoutMs?: number;\n /** Overrides the client's retry count. */\n maxRetries?: number;\n headers?: Record<string, string>;\n /** Called with the final response's headers (credits used/remaining, cache, request id). */\n onResponse?: (info: ResponseInfo) => void;\n}\n\nexport interface BatchCreateOptions extends RequestOptions {\n /**\n * Sent as `Idempotency-Key` (1-255 printable ASCII characters, e.g. a UUID).\n * For 24 hours a retry with the same key and body returns the first response\n * instead of queueing and billing the jobs again.\n */\n idempotencyKey?: string;\n}\n\nexport interface WaitOptions {\n /** Give up after this many milliseconds. Default 600000 (10 minutes). */\n timeoutMs?: number;\n /** First delay between polls. Default 1000. Grows 1.5× per poll. */\n pollIntervalMs?: number;\n /** Upper bound of the delay between polls. Default 10000. */\n maxPollIntervalMs?: number;\n signal?: AbortSignal;\n}\n\n/** A vertical whose return type follows `format`: `\"markdown\"` → string, `\"compact\"` → CompactResponse. */\nexport interface VerticalMethod<P, R> {\n (params: P & { format: \"markdown\" }, options?: RequestOptions): Promise<string>;\n (params: P & { format: \"compact\" }, options?: RequestOptions): Promise<CompactResponse>;\n (params: P & { format?: \"json\" }, options?: RequestOptions): Promise<R>;\n (params: P, options?: RequestOptions): Promise<R | CompactResponse | string>;\n}\n\ntype Method = \"GET\" | \"POST\";\n\ninterface Call {\n method: Method;\n path: string;\n body?: unknown;\n options?: RequestOptions;\n /** Which failures are safe to retry. `all` = 429, 5xx and network errors. */\n retry?: \"all\" | \"rate_limit\";\n}\n\nexport class SerpKite {\n readonly baseUrl: string;\n readonly timeoutMs: number;\n readonly maxRetries: number;\n readonly retryDelayMs: number;\n readonly #apiKey: string;\n readonly #fetch: typeof fetch;\n readonly #headers: Record<string, string>;\n\n constructor(options: SerpKiteOptions = {}) {\n const apiKey = options.apiKey ?? env(\"SERPKITE_API_KEY\");\n if (!apiKey) {\n throw new SerpKiteError(\n 0,\n \"missing_api_key\",\n \"No API key: pass { apiKey } or set the SERPKITE_API_KEY environment variable\",\n );\n }\n this.#apiKey = apiKey;\n this.baseUrl = (options.baseUrl ?? env(\"SERPKITE_BASE_URL\") ?? DEFAULT_BASE_URL).replace(\n /\\/+$/,\n \"\",\n );\n this.timeoutMs = options.timeoutMs ?? 60_000;\n this.maxRetries = Math.max(0, options.maxRetries ?? 2);\n this.retryDelayMs = options.retryDelayMs ?? 500;\n const f = options.fetch ?? globalThis.fetch;\n if (typeof f !== \"function\") {\n throw new SerpKiteError(\n 0,\n \"missing_fetch\",\n \"No global fetch: pass { fetch } (Node 18+ has one)\",\n );\n }\n this.#fetch = f;\n this.#headers = { ...options.headers };\n }\n\n // ── Verticals ─────────────────────────────────────────────────────────\n\n /** Google web search: organic results, answer box, knowledge graph, people also ask… */\n readonly search = this.#vertical<SearchParams, SearchResponse>(\"/v1/search\");\n /** Google Images. */\n readonly images = this.#vertical<SearchParams, ImagesResponse>(\"/v1/images\");\n /** Google Videos. */\n readonly videos = this.#vertical<SearchParams, VideosResponse>(\"/v1/videos\");\n /** Google News. */\n readonly news = this.#vertical<SearchParams, NewsResponse>(\"/v1/news\");\n /** Google Maps search (places with coordinates). Accepts `ll` (\"@lat,lng,14z\"). */\n readonly maps = this.#vertical<SearchParams, PlacesResponse>(\"/v1/maps\");\n /** Google local results. */\n readonly places = this.#vertical<SearchParams, PlacesResponse>(\"/v1/places\");\n /** Reviews of a place by `place_id`, `cid` or `fid`. Page with `page_token` = `next_page_token`. */\n readonly reviews = this.#vertical<ReviewsParams, ReviewsResponse>(\"/v1/reviews\");\n /** Google Shopping. */\n readonly shopping = this.#vertical<SearchParams, ShoppingResponse>(\"/v1/shopping\");\n /** Google Scholar. */\n readonly scholar = this.#vertical<SearchParams, ScholarResponse>(\"/v1/scholar\");\n /** Google Patents. */\n readonly patents = this.#vertical<SearchParams, PatentsResponse>(\"/v1/patents\");\n /** Google autocomplete suggestions. */\n readonly autocomplete = this.#vertical<SearchParams, AutocompleteResponse>(\"/v1/autocomplete\");\n /** Fetch any public URL as clean Markdown plus metadata. */\n readonly webpage = this.#vertical<WebpageParams, WebpageResponse>(\"/v1/webpage\");\n\n /** Google Lens visual matches for an image URL. */\n lens(params: LensParams, options?: RequestOptions): Promise<LensResponse> {\n return this.request({ method: \"POST\", path: \"/v1/lens\", body: params, options });\n }\n\n /** Position of `domain` for keyword `q` in the top `num` results (default 100). */\n rank(params: RankParams, options?: RequestOptions): Promise<RankResponse> {\n return this.request({ method: \"POST\", path: \"/v1/rank\", body: params, options });\n }\n\n /** Balance, limits and this month's usage for the key's account. */\n account(options?: RequestOptions): Promise<Account> {\n return this.request({ method: \"GET\", path: \"/v1/account\", options });\n }\n\n // ── Batches ───────────────────────────────────────────────────────────\n\n readonly batches = {\n /**\n * Queue 1-100 requests for one endpoint at half price. Returns one entry per\n * request, in order: a queued `Batch` or an error object. Without an\n * `idempotencyKey` it is only retried on 429, so a lost response never queues\n * (and bills) the same requests twice. With one, 5xx and network errors are\n * retried too: the server replays the first response for the same key and body.\n */\n create: (\n params: BatchCreateParams,\n options: BatchCreateOptions = {},\n ): Promise<BatchCreateResponse> => {\n const { idempotencyKey, ...rest } = options;\n return this.request({\n method: \"POST\",\n path: \"/v1/batches\",\n body: params,\n options: idempotencyKey\n ? { ...rest, headers: { ...rest.headers, \"Idempotency-Key\": idempotencyKey } }\n : rest,\n retry: idempotencyKey ? \"all\" : \"rate_limit\",\n });\n },\n\n /** Poll one batch job. */\n get: (id: string, options?: RequestOptions): Promise<Batch> =>\n this.request({ method: \"GET\", path: `/v1/batches/${encodeURIComponent(id)}`, options }),\n\n /**\n * Poll until the job is `done` or `failed` and return it (a failed job is\n * returned, not thrown; check `status` and `error`). Accepts an id or an\n * entry from `create`; an entry that failed to queue throws its error.\n */\n wait: (idOrEntry: string | BatchCreateEntry | undefined, options: WaitOptions = {}) =>\n this.#wait(idOrEntry, options),\n };\n\n // ── Plumbing ──────────────────────────────────────────────────────────\n\n #vertical<P, R>(path: string): VerticalMethod<P, R> {\n return ((params: P, options?: RequestOptions) =>\n this.request({ method: \"POST\", path, body: params, options })) as VerticalMethod<P, R>;\n }\n\n async #wait(idOrEntry: string | BatchCreateEntry | undefined, o: WaitOptions): Promise<Batch> {\n let id: string | undefined;\n if (typeof idOrEntry === \"string\") {\n id = idOrEntry;\n } else if (idOrEntry && \"id\" in idOrEntry && typeof idOrEntry.id === \"string\") {\n id = idOrEntry.id;\n } else if (idOrEntry && \"error\" in idOrEntry && idOrEntry.error && !(\"id\" in idOrEntry)) {\n const e = idOrEntry.error as { code?: string; message?: string; request_id?: string };\n throw new SerpKiteError(\n 400,\n e.code ?? \"invalid_request\",\n e.message ?? \"batch entry was not queued\",\n e.request_id,\n );\n }\n if (!id) {\n throw new SerpKiteError(0, \"invalid_request\", \"batches.wait needs a batch id\");\n }\n const timeoutMs = o.timeoutMs ?? 600_000;\n const maxInterval = o.maxPollIntervalMs ?? 10_000;\n let interval = o.pollIntervalMs ?? 1_000;\n const deadline = Date.now() + timeoutMs;\n for (;;) {\n const batch = await this.batches.get(id, { signal: o.signal });\n if (batch.status === \"done\" || batch.status === \"failed\") return batch;\n const left = deadline - Date.now();\n if (left <= 0) {\n throw new SerpKiteError(\n 0,\n \"timeout\",\n `batch ${id} still ${batch.status} after ${timeoutMs} ms`,\n );\n }\n await sleep(Math.min(interval, left), o.signal);\n interval = Math.min(interval * 1.5, maxInterval);\n }\n }\n\n /** Low-level request: JSON body in, parsed JSON (or text for non-JSON responses) out. */\n async request<T>(call: Call): Promise<T> {\n const { method, path, body, options = {} } = call;\n const maxRetries = Math.max(0, options.maxRetries ?? this.maxRetries);\n const timeoutMs = options.timeoutMs ?? this.timeoutMs;\n const headers: Record<string, string> = {\n Accept: \"application/json, text/markdown;q=0.9\",\n Authorization: `Bearer ${this.#apiKey}`,\n ...this.#headers,\n ...options.headers,\n };\n if (body !== undefined) headers[\"Content-Type\"] = \"application/json\";\n // Browsers would turn a custom User-Agent into a CORS preflight header.\n if (!isBrowser()) headers[\"User-Agent\"] = `serpkite-typescript/${VERSION}`;\n const init: RequestInit = {\n method,\n headers,\n body: body === undefined ? undefined : JSON.stringify(body),\n };\n\n for (let attempt = 0; ; attempt++) {\n const canRetry = attempt < maxRetries;\n let res: Response;\n const { signal, cleanup, timedOut } = withTimeout(options.signal, timeoutMs);\n try {\n res = await this.#fetch(this.baseUrl + path, { ...init, signal });\n } catch (err) {\n cleanup();\n if (options.signal?.aborted) throw err;\n const code = timedOut() ? \"timeout\" : \"connection_error\";\n if (canRetry && call.retry !== \"rate_limit\") {\n await sleep(this.#backoff(attempt), options.signal);\n continue;\n }\n const msg = timedOut()\n ? `request timed out after ${timeoutMs} ms`\n : `request failed: ${err instanceof Error ? err.message : String(err)}`;\n throw new SerpKiteError(0, code, msg, undefined, undefined, { cause: err });\n }\n\n let text: string;\n try {\n text = await res.text();\n } catch (err) {\n cleanup();\n if (options.signal?.aborted) throw err;\n if (canRetry && call.retry !== \"rate_limit\") {\n await sleep(this.#backoff(attempt), options.signal);\n continue;\n }\n const code = timedOut() ? \"timeout\" : \"connection_error\";\n throw new SerpKiteError(\n 0,\n code,\n \"failed to read the response body\",\n undefined,\n res.headers,\n {\n cause: err,\n },\n );\n }\n cleanup();\n\n if (!res.ok) {\n const retryable = res.status === 429 || (res.status >= 500 && call.retry !== \"rate_limit\");\n if (canRetry && retryable) {\n await sleep(this.#retryDelay(attempt, res.headers), options.signal);\n continue;\n }\n throw errorFromResponse(res.status, res.headers, text);\n }\n\n options.onResponse?.(responseInfo(res));\n const type = res.headers.get(\"content-type\") ?? \"\";\n if (type.includes(\"json\")) {\n try {\n return JSON.parse(text) as T;\n } catch (err) {\n throw new SerpKiteError(\n res.status,\n \"invalid_response\",\n \"response is not valid JSON\",\n res.headers.get(\"x-request-id\") ?? undefined,\n res.headers,\n { cause: err },\n );\n }\n }\n return text as T;\n }\n }\n\n #backoff(attempt: number): number {\n const base = Math.min(this.retryDelayMs * 2 ** attempt, 8_000);\n return base / 2 + Math.random() * (base / 2);\n }\n\n #retryDelay(attempt: number, headers: Headers): number {\n const after = parseRetryAfter(headers.get(\"retry-after\"));\n return after === undefined ? this.#backoff(attempt) : Math.min(after, 60_000);\n }\n}\n\n// ── helpers ─────────────────────────────────────────────────────────────\n\n/** Parses Retry-After (seconds or an HTTP date) into milliseconds. */\nexport function parseRetryAfter(v: string | null): number | undefined {\n if (!v) return undefined;\n const secs = Number(v);\n if (Number.isFinite(secs)) return Math.max(0, secs * 1000);\n const at = Date.parse(v);\n return Number.isNaN(at) ? undefined : Math.max(0, at - Date.now());\n}\n\nfunction responseInfo(res: Response): ResponseInfo {\n const h = res.headers;\n const num = (name: string) => {\n const v = h.get(name);\n if (v === null || v === \"\") return undefined;\n const n = Number(v);\n return Number.isFinite(n) ? n : undefined;\n };\n const cache = h.get(\"x-cache\")?.toUpperCase();\n return {\n status: res.status,\n headers: h,\n requestId: h.get(\"x-request-id\") ?? undefined,\n creditsUsed: num(\"x-credits-used\"),\n creditsRemaining: num(\"x-credits-remaining\"),\n costUsd: num(\"x-cost-usd\"),\n cache: cache === \"HIT\" || cache === \"MISS\" ? cache : undefined,\n latencyMs: num(\"x-latency-ms\"),\n tokensEstimate: num(\"x-tokens-estimate\"),\n };\n}\n\nfunction withTimeout(outer: AbortSignal | undefined, ms: number) {\n const ctrl = new AbortController();\n let timedOut = false;\n const onAbort = () => ctrl.abort(outer?.reason);\n if (outer?.aborted) ctrl.abort(outer.reason);\n else outer?.addEventListener(\"abort\", onAbort, { once: true });\n const timer =\n ms > 0 && Number.isFinite(ms)\n ? setTimeout(() => {\n timedOut = true;\n ctrl.abort(new SerpKiteError(0, \"timeout\", `request timed out after ${ms} ms`));\n }, ms)\n : undefined;\n return {\n signal: ctrl.signal,\n timedOut: () => timedOut,\n cleanup: () => {\n if (timer !== undefined) clearTimeout(timer);\n outer?.removeEventListener(\"abort\", onAbort);\n },\n };\n}\n\nfunction sleep(ms: number, signal?: AbortSignal): Promise<void> {\n return new Promise((resolve, reject) => {\n if (signal?.aborted) return reject(signal.reason);\n const t = setTimeout(() => {\n signal?.removeEventListener(\"abort\", onAbort);\n resolve();\n }, ms);\n const onAbort = () => {\n clearTimeout(t);\n reject(signal?.reason);\n };\n signal?.addEventListener(\"abort\", onAbort, { once: true });\n });\n}\n\ntype EnvHost = {\n process?: { env?: Record<string, string | undefined> };\n Deno?: { env?: { get?: (name: string) => string | undefined } };\n document?: unknown;\n};\n\nfunction env(name: string): string | undefined {\n const g = globalThis as EnvHost;\n try {\n const v = g.process?.env?.[name];\n if (v) return v;\n } catch {\n // process.env may be a throwing proxy on some edge runtimes.\n }\n try {\n return g.Deno?.env?.get?.(name) || undefined;\n } catch {\n // Deno without --allow-env.\n return undefined;\n }\n}\n\nfunction isBrowser(): boolean {\n return typeof (globalThis as EnvHost).document !== \"undefined\";\n}\n","import type { BatchCreateEntry, BatchCreateError } from \"./types\";\n\n/** True when a `batches.create` entry was rejected instead of queued. */\nexport function isBatchError(entry: BatchCreateEntry): entry is BatchCreateError {\n return !(\"id\" in entry && typeof entry.id === \"string\") && \"error\" in entry && !!entry.error;\n}\n","/** Options for {@link verifyWebhook}. */\nexport interface VerifyWebhookOptions {\n /** Reject deliveries whose timestamp is further than this from now. Default 300. */\n toleranceSeconds?: number;\n /** Current time in Unix seconds (tests). */\n now?: number;\n}\n\ntype HeaderSource = Headers | Record<string, string | string[] | undefined>;\n\nfunction header(headers: HeaderSource, name: string): string | undefined {\n if (typeof (headers as Headers).get === \"function\") {\n return (headers as Headers).get(name) ?? undefined;\n }\n const rec = headers as Record<string, string | string[] | undefined>;\n const key = Object.keys(rec).find((k) => k.toLowerCase() === name.toLowerCase());\n const v = key === undefined ? undefined : rec[key];\n return Array.isArray(v) ? v[0] : v;\n}\n\n/**\n * Checks a batch webhook delivery: `X-SerpKite-Signature` must be\n * `v1=<hex HMAC-SHA256(secret, \"<X-SerpKite-Timestamp>.<raw body>\")>` and the\n * timestamp recent. Pass the raw request body exactly as received (not\n * re-serialised JSON). Uses Web Crypto (Node 18+, Deno, Bun, browsers).\n *\n * ```ts\n * const ok = await verifyWebhook(process.env.SERPKITE_WEBHOOK_SECRET!, rawBody, req.headers);\n * ```\n */\nexport async function verifyWebhook(\n secret: string,\n payload: string | Uint8Array,\n headers: HeaderSource,\n options: VerifyWebhookOptions = {},\n): Promise<boolean> {\n const signature = header(headers, \"x-serpkite-signature\");\n const ts = header(headers, \"x-serpkite-timestamp\");\n if (!secret || !signature?.startsWith(\"v1=\") || !ts || !/^\\d+$/.test(ts)) return false;\n const now = options.now ?? Math.floor(Date.now() / 1000);\n if (Math.abs(now - Number(ts)) > (options.toleranceSeconds ?? 300)) return false;\n\n const enc = new TextEncoder();\n const body = typeof payload === \"string\" ? enc.encode(payload) : payload;\n const prefix = enc.encode(`${ts}.`);\n const msg = new Uint8Array(prefix.length + body.length);\n msg.set(prefix);\n msg.set(body, prefix.length);\n const key = await crypto.subtle.importKey(\n \"raw\",\n enc.encode(secret),\n { name: \"HMAC\", hash: \"SHA-256\" },\n false,\n [\"sign\"],\n );\n const mac = new Uint8Array(await crypto.subtle.sign(\"HMAC\", key, msg));\n const want = Array.from(mac, (b) => b.toString(16).padStart(2, \"0\")).join(\"\");\n const got = signature.slice(3).toLowerCase();\n if (got.length !== want.length) return false;\n let diff = 0;\n for (let i = 0; i < want.length; i++) diff |= want.charCodeAt(i) ^ got.charCodeAt(i);\n return diff === 0;\n}\n"]}
1
+ {"version":3,"sources":["../src/errors.ts","../src/client.ts","../src/util.ts","../src/webhooks.ts"],"names":[],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Every failure thrown by the SDK. API errors carry the fields of the\n * `{\"error\":{\"code\",\"message\",\"request_id\"}}` envelope; network failures and\n * timeouts use `status: 0` with code `connection_error` or `timeout`.\n */\nexport class SerpKiteError extends Error {\n /** HTTP status, or 0 when no response was received. */\n readonly status: number;\n /** Machine-readable code, e.g. `unauthorized`, `insufficient_credits`, `rate_limited`. */\n readonly code: string;\n /** `X-Request-Id` of the failed request, when the API returned one. */\n readonly requestId: string | undefined;\n /** Response headers, when the API responded. */\n readonly headers: Headers | undefined;\n\n constructor(\n status: number,\n code: string,\n message: string,\n requestId?: string,\n headers?: Headers,\n options?: { cause?: unknown },\n ) {\n super(message, options);\n this.name = \"SerpKiteError\";\n this.status = status;\n this.code = code;\n this.requestId = requestId || undefined;\n this.headers = headers;\n }\n}\n\nconst fallbackCodes: Record<number, string> = {\n 400: \"invalid_request\",\n 401: \"unauthorized\",\n 402: \"insufficient_credits\",\n 403: \"forbidden\",\n 404: \"not_found\",\n 429: \"rate_limited\",\n // The API sends upstream failures as 503 with a JSON body; a bare 502/504\n // comes from a proxy (Cloudflare replaces origin 502/504 bodies).\n 502: \"upstream_error\",\n 503: \"unavailable\",\n 504: \"upstream_timeout\",\n};\n\n/** Builds a SerpKiteError from a non-2xx response body (JSON envelope or anything else). */\nexport function errorFromResponse(status: number, headers: Headers, body: string): SerpKiteError {\n let code = fallbackCodes[status] ?? (status >= 500 ? \"server_error\" : \"http_error\");\n let message = body.trim().slice(0, 500) || `HTTP ${status}`;\n let requestId = headers.get(\"x-request-id\") ?? undefined;\n try {\n const parsed = JSON.parse(body) as {\n error?: { code?: unknown; message?: unknown; request_id?: unknown };\n };\n const e = parsed?.error;\n if (e && typeof e === \"object\") {\n if (typeof e.code === \"string\" && e.code) code = e.code;\n if (typeof e.message === \"string\" && e.message) message = e.message;\n if (typeof e.request_id === \"string\" && e.request_id) requestId = e.request_id;\n }\n } catch {\n // Not JSON: keep the text body as the message.\n }\n return new SerpKiteError(status, code, message, requestId, headers);\n}\n","import { errorFromResponse, SerpKiteError } from \"./errors\";\nimport type {\n Account,\n AutocompleteResponse,\n Batch,\n BatchCreateEntry,\n BatchCreateParams,\n BatchCreateResponse,\n CompactResponse,\n ImagesResponse,\n NewsResponse,\n PatentsResponse,\n PlacesResponse,\n RankParams,\n RankResponse,\n ReviewsParams,\n ReviewsResponse,\n ScholarResponse,\n SearchParams,\n SearchResponse,\n ShoppingResponse,\n VideosResponse,\n WebpageParams,\n WebpageResponse,\n} from \"./types\";\n\nexport const VERSION = \"0.3.0\";\nexport const DEFAULT_BASE_URL = \"https://api.serpkite.com\";\n\nexport interface SerpKiteOptions {\n /** API key (`skt_live_…`). Defaults to the `SERPKITE_API_KEY` environment variable. */\n apiKey?: string;\n /** Defaults to `SERPKITE_BASE_URL` or https://api.serpkite.com. */\n baseUrl?: string;\n /** Per-attempt timeout in milliseconds. Default 60000. */\n timeoutMs?: number;\n /** Retries after the first attempt on 429, 5xx and network errors. Default 2. */\n maxRetries?: number;\n /** Base delay of the exponential backoff in milliseconds. Default 500. */\n retryDelayMs?: number;\n /** Custom fetch implementation. Defaults to the global `fetch`. */\n fetch?: typeof fetch;\n /** Extra headers sent with every request. */\n headers?: Record<string, string>;\n}\n\n/** Billing and tracing details from the response headers. */\nexport interface ResponseInfo {\n status: number;\n headers: Headers;\n requestId: string | undefined;\n creditsUsed: number | undefined;\n creditsRemaining: number | undefined;\n costUsd: number | undefined;\n /** `HIT` when served from cache (`max_age`), else `MISS`. */\n cache: \"HIT\" | \"MISS\" | undefined;\n latencyMs: number | undefined;\n tokensEstimate: number | undefined;\n}\n\nexport interface RequestOptions {\n signal?: AbortSignal;\n /** Overrides the client's per-attempt timeout. */\n timeoutMs?: number;\n /** Overrides the client's retry count. */\n maxRetries?: number;\n headers?: Record<string, string>;\n /** Called with the final response's headers (credits used/remaining, cache, request id). */\n onResponse?: (info: ResponseInfo) => void;\n}\n\nexport interface BatchCreateOptions extends RequestOptions {\n /**\n * Sent as `Idempotency-Key` (1-255 printable ASCII characters, e.g. a UUID).\n * For 24 hours a retry with the same key and body returns the first response\n * instead of queueing and billing the jobs again.\n */\n idempotencyKey?: string;\n}\n\nexport interface WaitOptions {\n /** Give up after this many milliseconds. Default 600000 (10 minutes). */\n timeoutMs?: number;\n /** First delay between polls. Default 1000. Grows 1.5× per poll. */\n pollIntervalMs?: number;\n /** Upper bound of the delay between polls. Default 10000. */\n maxPollIntervalMs?: number;\n signal?: AbortSignal;\n}\n\n/** A vertical whose return type follows `format`: `\"markdown\"` → string, `\"compact\"` → CompactResponse. */\nexport interface VerticalMethod<P, R> {\n (params: P & { format: \"markdown\" }, options?: RequestOptions): Promise<string>;\n (params: P & { format: \"compact\" }, options?: RequestOptions): Promise<CompactResponse>;\n (params: P & { format?: \"json\" }, options?: RequestOptions): Promise<R>;\n (params: P, options?: RequestOptions): Promise<R | CompactResponse | string>;\n}\n\ntype Method = \"GET\" | \"POST\";\n\ninterface Call {\n method: Method;\n path: string;\n body?: unknown;\n options?: RequestOptions;\n /** Which failures are safe to retry. `all` = 429, 5xx and network errors. */\n retry?: \"all\" | \"rate_limit\";\n}\n\nexport class SerpKite {\n readonly baseUrl: string;\n readonly timeoutMs: number;\n readonly maxRetries: number;\n readonly retryDelayMs: number;\n readonly #apiKey: string;\n readonly #fetch: typeof fetch;\n readonly #headers: Record<string, string>;\n\n constructor(options: SerpKiteOptions = {}) {\n const apiKey = options.apiKey ?? env(\"SERPKITE_API_KEY\");\n if (!apiKey) {\n throw new SerpKiteError(\n 0,\n \"missing_api_key\",\n \"No API key: pass { apiKey } or set the SERPKITE_API_KEY environment variable\",\n );\n }\n this.#apiKey = apiKey;\n this.baseUrl = (options.baseUrl ?? env(\"SERPKITE_BASE_URL\") ?? DEFAULT_BASE_URL).replace(\n /\\/+$/,\n \"\",\n );\n this.timeoutMs = options.timeoutMs ?? 60_000;\n this.maxRetries = Math.max(0, options.maxRetries ?? 2);\n this.retryDelayMs = options.retryDelayMs ?? 500;\n const f = options.fetch ?? globalThis.fetch;\n if (typeof f !== \"function\") {\n throw new SerpKiteError(\n 0,\n \"missing_fetch\",\n \"No global fetch: pass { fetch } (Node 18+ has one)\",\n );\n }\n this.#fetch = f;\n this.#headers = { ...options.headers };\n }\n\n // ── Verticals ─────────────────────────────────────────────────────────\n\n /** Google web search: organic results, answer box, knowledge graph, people also ask… */\n readonly search = this.#vertical<SearchParams, SearchResponse>(\"/v1/search\");\n /** Google Images. */\n readonly images = this.#vertical<SearchParams, ImagesResponse>(\"/v1/images\");\n /** Google Videos. */\n readonly videos = this.#vertical<SearchParams, VideosResponse>(\"/v1/videos\");\n /** Google News. */\n readonly news = this.#vertical<SearchParams, NewsResponse>(\"/v1/news\");\n /** Google Maps search (places with coordinates). Accepts `ll` (\"@lat,lng,14z\"). */\n readonly maps = this.#vertical<SearchParams, PlacesResponse>(\"/v1/maps\");\n /** Google local results. */\n readonly places = this.#vertical<SearchParams, PlacesResponse>(\"/v1/places\");\n /** Reviews of a place by `place_id`, `cid` or `fid`. Page with `page_token` = `next_page_token`. */\n readonly reviews = this.#vertical<ReviewsParams, ReviewsResponse>(\"/v1/reviews\");\n /** Google Shopping. */\n readonly shopping = this.#vertical<SearchParams, ShoppingResponse>(\"/v1/shopping\");\n /** Google Scholar. */\n readonly scholar = this.#vertical<SearchParams, ScholarResponse>(\"/v1/scholar\");\n /** Google Patents. */\n readonly patents = this.#vertical<SearchParams, PatentsResponse>(\"/v1/patents\");\n /** Google autocomplete suggestions. */\n readonly autocomplete = this.#vertical<SearchParams, AutocompleteResponse>(\"/v1/autocomplete\");\n /** Fetch any public URL as clean Markdown plus metadata. */\n readonly webpage = this.#vertical<WebpageParams, WebpageResponse>(\"/v1/webpage\");\n\n /** Position of `domain` for keyword `q` in the top `num` results (default 100). */\n rank(params: RankParams, options?: RequestOptions): Promise<RankResponse> {\n return this.request({ method: \"POST\", path: \"/v1/rank\", body: params, options });\n }\n\n /** Balance, limits and this month's usage for the key's account. */\n account(options?: RequestOptions): Promise<Account> {\n return this.request({ method: \"GET\", path: \"/v1/account\", options });\n }\n\n // ── Batches ───────────────────────────────────────────────────────────\n\n readonly batches = {\n /**\n * Queue 1-100 requests for one endpoint at half price. Returns one entry per\n * request, in order: a queued `Batch` or an error object. Without an\n * `idempotencyKey` it is only retried on 429, so a lost response never queues\n * (and bills) the same requests twice. With one, 5xx and network errors are\n * retried too: the server replays the first response for the same key and body.\n */\n create: (\n params: BatchCreateParams,\n options: BatchCreateOptions = {},\n ): Promise<BatchCreateResponse> => {\n const { idempotencyKey, ...rest } = options;\n return this.request({\n method: \"POST\",\n path: \"/v1/batches\",\n body: params,\n options: idempotencyKey\n ? { ...rest, headers: { ...rest.headers, \"Idempotency-Key\": idempotencyKey } }\n : rest,\n retry: idempotencyKey ? \"all\" : \"rate_limit\",\n });\n },\n\n /** Poll one batch job. */\n get: (id: string, options?: RequestOptions): Promise<Batch> =>\n this.request({ method: \"GET\", path: `/v1/batches/${encodeURIComponent(id)}`, options }),\n\n /**\n * Poll until the job is `done` or `failed` and return it (a failed job is\n * returned, not thrown; check `status` and `error`). Accepts an id or an\n * entry from `create`; an entry that failed to queue throws its error.\n */\n wait: (idOrEntry: string | BatchCreateEntry | undefined, options: WaitOptions = {}) =>\n this.#wait(idOrEntry, options),\n };\n\n // ── Plumbing ──────────────────────────────────────────────────────────\n\n #vertical<P, R>(path: string): VerticalMethod<P, R> {\n return ((params: P, options?: RequestOptions) =>\n this.request({ method: \"POST\", path, body: params, options })) as VerticalMethod<P, R>;\n }\n\n async #wait(idOrEntry: string | BatchCreateEntry | undefined, o: WaitOptions): Promise<Batch> {\n let id: string | undefined;\n if (typeof idOrEntry === \"string\") {\n id = idOrEntry;\n } else if (idOrEntry && \"id\" in idOrEntry && typeof idOrEntry.id === \"string\") {\n id = idOrEntry.id;\n } else if (idOrEntry && \"error\" in idOrEntry && idOrEntry.error && !(\"id\" in idOrEntry)) {\n const e = idOrEntry.error as { code?: string; message?: string; request_id?: string };\n throw new SerpKiteError(\n 400,\n e.code ?? \"invalid_request\",\n e.message ?? \"batch entry was not queued\",\n e.request_id,\n );\n }\n if (!id) {\n throw new SerpKiteError(0, \"invalid_request\", \"batches.wait needs a batch id\");\n }\n const timeoutMs = o.timeoutMs ?? 600_000;\n const maxInterval = o.maxPollIntervalMs ?? 10_000;\n let interval = o.pollIntervalMs ?? 1_000;\n const deadline = Date.now() + timeoutMs;\n for (;;) {\n const batch = await this.batches.get(id, { signal: o.signal });\n if (batch.status === \"done\" || batch.status === \"failed\") return batch;\n const left = deadline - Date.now();\n if (left <= 0) {\n throw new SerpKiteError(\n 0,\n \"timeout\",\n `batch ${id} still ${batch.status} after ${timeoutMs} ms`,\n );\n }\n await sleep(Math.min(interval, left), o.signal);\n interval = Math.min(interval * 1.5, maxInterval);\n }\n }\n\n /** Low-level request: JSON body in, parsed JSON (or text for non-JSON responses) out. */\n async request<T>(call: Call): Promise<T> {\n const { method, path, body, options = {} } = call;\n const maxRetries = Math.max(0, options.maxRetries ?? this.maxRetries);\n const timeoutMs = options.timeoutMs ?? this.timeoutMs;\n const headers: Record<string, string> = {\n Accept: \"application/json, text/markdown;q=0.9\",\n Authorization: `Bearer ${this.#apiKey}`,\n ...this.#headers,\n ...options.headers,\n };\n if (body !== undefined) headers[\"Content-Type\"] = \"application/json\";\n // Browsers would turn a custom User-Agent into a CORS preflight header.\n if (!isBrowser()) headers[\"User-Agent\"] = `serpkite-typescript/${VERSION}`;\n const init: RequestInit = {\n method,\n headers,\n body: body === undefined ? undefined : JSON.stringify(body),\n };\n\n for (let attempt = 0; ; attempt++) {\n const canRetry = attempt < maxRetries;\n let res: Response;\n const { signal, cleanup, timedOut } = withTimeout(options.signal, timeoutMs);\n try {\n res = await this.#fetch(this.baseUrl + path, { ...init, signal });\n } catch (err) {\n cleanup();\n if (options.signal?.aborted) throw err;\n const code = timedOut() ? \"timeout\" : \"connection_error\";\n if (canRetry && call.retry !== \"rate_limit\") {\n await sleep(this.#backoff(attempt), options.signal);\n continue;\n }\n const msg = timedOut()\n ? `request timed out after ${timeoutMs} ms`\n : `request failed: ${err instanceof Error ? err.message : String(err)}`;\n throw new SerpKiteError(0, code, msg, undefined, undefined, { cause: err });\n }\n\n let text: string;\n try {\n text = await res.text();\n } catch (err) {\n cleanup();\n if (options.signal?.aborted) throw err;\n if (canRetry && call.retry !== \"rate_limit\") {\n await sleep(this.#backoff(attempt), options.signal);\n continue;\n }\n const code = timedOut() ? \"timeout\" : \"connection_error\";\n throw new SerpKiteError(\n 0,\n code,\n \"failed to read the response body\",\n undefined,\n res.headers,\n {\n cause: err,\n },\n );\n }\n cleanup();\n\n if (!res.ok) {\n const retryable = res.status === 429 || (res.status >= 500 && call.retry !== \"rate_limit\");\n if (canRetry && retryable) {\n await sleep(this.#retryDelay(attempt, res.headers), options.signal);\n continue;\n }\n throw errorFromResponse(res.status, res.headers, text);\n }\n\n options.onResponse?.(responseInfo(res));\n const type = res.headers.get(\"content-type\") ?? \"\";\n if (type.includes(\"json\")) {\n try {\n return JSON.parse(text) as T;\n } catch (err) {\n throw new SerpKiteError(\n res.status,\n \"invalid_response\",\n \"response is not valid JSON\",\n res.headers.get(\"x-request-id\") ?? undefined,\n res.headers,\n { cause: err },\n );\n }\n }\n return text as T;\n }\n }\n\n #backoff(attempt: number): number {\n const base = Math.min(this.retryDelayMs * 2 ** attempt, 8_000);\n return base / 2 + Math.random() * (base / 2);\n }\n\n #retryDelay(attempt: number, headers: Headers): number {\n const after = parseRetryAfter(headers.get(\"retry-after\"));\n return after === undefined ? this.#backoff(attempt) : Math.min(after, 60_000);\n }\n}\n\n// ── helpers ─────────────────────────────────────────────────────────────\n\n/** Parses Retry-After (seconds or an HTTP date) into milliseconds. */\nexport function parseRetryAfter(v: string | null): number | undefined {\n if (!v) return undefined;\n const secs = Number(v);\n if (Number.isFinite(secs)) return Math.max(0, secs * 1000);\n const at = Date.parse(v);\n return Number.isNaN(at) ? undefined : Math.max(0, at - Date.now());\n}\n\nfunction responseInfo(res: Response): ResponseInfo {\n const h = res.headers;\n const num = (name: string) => {\n const v = h.get(name);\n if (v === null || v === \"\") return undefined;\n const n = Number(v);\n return Number.isFinite(n) ? n : undefined;\n };\n const cache = h.get(\"x-cache\")?.toUpperCase();\n return {\n status: res.status,\n headers: h,\n requestId: h.get(\"x-request-id\") ?? undefined,\n creditsUsed: num(\"x-credits-used\"),\n creditsRemaining: num(\"x-credits-remaining\"),\n costUsd: num(\"x-cost-usd\"),\n cache: cache === \"HIT\" || cache === \"MISS\" ? cache : undefined,\n latencyMs: num(\"x-latency-ms\"),\n tokensEstimate: num(\"x-tokens-estimate\"),\n };\n}\n\nfunction withTimeout(outer: AbortSignal | undefined, ms: number) {\n const ctrl = new AbortController();\n let timedOut = false;\n const onAbort = () => ctrl.abort(outer?.reason);\n if (outer?.aborted) ctrl.abort(outer.reason);\n else outer?.addEventListener(\"abort\", onAbort, { once: true });\n const timer =\n ms > 0 && Number.isFinite(ms)\n ? setTimeout(() => {\n timedOut = true;\n ctrl.abort(new SerpKiteError(0, \"timeout\", `request timed out after ${ms} ms`));\n }, ms)\n : undefined;\n return {\n signal: ctrl.signal,\n timedOut: () => timedOut,\n cleanup: () => {\n if (timer !== undefined) clearTimeout(timer);\n outer?.removeEventListener(\"abort\", onAbort);\n },\n };\n}\n\nfunction sleep(ms: number, signal?: AbortSignal): Promise<void> {\n return new Promise((resolve, reject) => {\n if (signal?.aborted) return reject(signal.reason);\n const t = setTimeout(() => {\n signal?.removeEventListener(\"abort\", onAbort);\n resolve();\n }, ms);\n const onAbort = () => {\n clearTimeout(t);\n reject(signal?.reason);\n };\n signal?.addEventListener(\"abort\", onAbort, { once: true });\n });\n}\n\ntype EnvHost = {\n process?: { env?: Record<string, string | undefined> };\n Deno?: { env?: { get?: (name: string) => string | undefined } };\n document?: unknown;\n};\n\nfunction env(name: string): string | undefined {\n const g = globalThis as EnvHost;\n try {\n const v = g.process?.env?.[name];\n if (v) return v;\n } catch {\n // process.env may be a throwing proxy on some edge runtimes.\n }\n try {\n return g.Deno?.env?.get?.(name) || undefined;\n } catch {\n // Deno without --allow-env.\n return undefined;\n }\n}\n\nfunction isBrowser(): boolean {\n return typeof (globalThis as EnvHost).document !== \"undefined\";\n}\n","import type { BatchCreateEntry, BatchCreateError } from \"./types\";\n\n/** True when a `batches.create` entry was rejected instead of queued. */\nexport function isBatchError(entry: BatchCreateEntry): entry is BatchCreateError {\n return !(\"id\" in entry && typeof entry.id === \"string\") && \"error\" in entry && !!entry.error;\n}\n","/** Options for {@link verifyWebhook}. */\nexport interface VerifyWebhookOptions {\n /** Reject deliveries whose timestamp is further than this from now. Default 300. */\n toleranceSeconds?: number;\n /** Current time in Unix seconds (tests). */\n now?: number;\n}\n\ntype HeaderSource = Headers | Record<string, string | string[] | undefined>;\n\nfunction header(headers: HeaderSource, name: string): string | undefined {\n if (typeof (headers as Headers).get === \"function\") {\n return (headers as Headers).get(name) ?? undefined;\n }\n const rec = headers as Record<string, string | string[] | undefined>;\n const key = Object.keys(rec).find((k) => k.toLowerCase() === name.toLowerCase());\n const v = key === undefined ? undefined : rec[key];\n return Array.isArray(v) ? v[0] : v;\n}\n\n/**\n * Checks a batch webhook delivery: `X-SerpKite-Signature` must be\n * `v1=<hex HMAC-SHA256(secret, \"<X-SerpKite-Timestamp>.<raw body>\")>` and the\n * timestamp recent. Pass the raw request body exactly as received (not\n * re-serialised JSON). Uses Web Crypto (Node 18+, Deno, Bun, browsers).\n *\n * ```ts\n * const ok = await verifyWebhook(process.env.SERPKITE_WEBHOOK_SECRET!, rawBody, req.headers);\n * ```\n */\nexport async function verifyWebhook(\n secret: string,\n payload: string | Uint8Array,\n headers: HeaderSource,\n options: VerifyWebhookOptions = {},\n): Promise<boolean> {\n const signature = header(headers, \"x-serpkite-signature\");\n const ts = header(headers, \"x-serpkite-timestamp\");\n if (!secret || !signature?.startsWith(\"v1=\") || !ts || !/^\\d+$/.test(ts)) return false;\n const now = options.now ?? Math.floor(Date.now() / 1000);\n if (Math.abs(now - Number(ts)) > (options.toleranceSeconds ?? 300)) return false;\n\n const enc = new TextEncoder();\n const body = typeof payload === \"string\" ? enc.encode(payload) : payload;\n const prefix = enc.encode(`${ts}.`);\n const msg = new Uint8Array(prefix.length + body.length);\n msg.set(prefix);\n msg.set(body, prefix.length);\n const key = await crypto.subtle.importKey(\n \"raw\",\n enc.encode(secret),\n { name: \"HMAC\", hash: \"SHA-256\" },\n false,\n [\"sign\"],\n );\n const mac = new Uint8Array(await crypto.subtle.sign(\"HMAC\", key, msg));\n const want = Array.from(mac, (b) => b.toString(16).padStart(2, \"0\")).join(\"\");\n const got = signature.slice(3).toLowerCase();\n if (got.length !== want.length) return false;\n let diff = 0;\n for (let i = 0; i < want.length; i++) diff |= want.charCodeAt(i) ^ got.charCodeAt(i);\n return diff === 0;\n}\n"]}
package/dist/index.d.cts CHANGED
@@ -156,7 +156,7 @@ interface paths {
156
156
  };
157
157
  get?: never;
158
158
  put?: never;
159
- /** Google Maps search (places with coordinates). Accepts `ll` ("@lat,lng,zoomz") */
159
+ /** Google Maps search (places with coordinates). Accepts `ll` ("@lat,lng,zoomz") to search around a point */
160
160
  post: operations["maps"];
161
161
  delete?: never;
162
162
  options?: never;
@@ -266,23 +266,6 @@ interface paths {
266
266
  patch?: never;
267
267
  trace?: never;
268
268
  };
269
- "/v1/lens": {
270
- parameters: {
271
- query?: never;
272
- header?: never;
273
- path?: never;
274
- cookie?: never;
275
- };
276
- get?: never;
277
- put?: never;
278
- /** Google Lens visual matches for an image URL (2 credits) */
279
- post: operations["lens"];
280
- delete?: never;
281
- options?: never;
282
- head?: never;
283
- patch?: never;
284
- trace?: never;
285
- };
286
269
  "/v1/webpage": {
287
270
  parameters: {
288
271
  query?: never;
@@ -487,20 +470,20 @@ interface components {
487
470
  SearchRequest: {
488
471
  q: string;
489
472
  /**
490
- * @description Country code (ISO 3166-1 alpha-2)
473
+ * @description Country code (ISO 3166-1 alpha-2, case-insensitive; uk is accepted as gb). When omitted and location ends in a country name, that country is used
491
474
  * @default us
492
475
  */
493
476
  country?: string;
494
477
  /**
495
- * @description Interface language (e.g. en
478
+ * @description Interface language: a language code with an optional region (e.g. en, de, pt-br, zh-tw, es-419)
496
479
  * @default en
497
480
  */
498
481
  language?: string;
499
482
  /** @description Free-text location, e.g. "Austin, Texas, United States" */
500
483
  location?: string;
501
- /** @description Pre-encoded Google location (overrides location) */
484
+ /** @description Pre-encoded Google location (overrides ll and location; percent-encoded values are decoded) */
502
485
  uule?: string;
503
- /** @description Maps viewport "@lat,lng,14z" (maps only) */
486
+ /** @description Map point "@lat,lng,14z" (maps and places only; zoom optional): the search runs as a searcher at that point. Overrides location */
504
487
  ll?: string;
505
488
  /**
506
489
  * @description 10, or up to 100 for the depth bundle on search and news (7 credits for 100; values between round up to whole pages). Other verticals return one page of 10
@@ -510,11 +493,11 @@ interface components {
510
493
  /** @default 1 */
511
494
  page?: number;
512
495
  /**
513
- * @description Only results from the last hour/day/…
496
+ * @description Only results from the last hour/day/… (search, news, images, videos, shopping). A fallback engine without that window is skipped, never answered unfiltered
514
497
  * @enum {string}
515
498
  */
516
499
  time?: "hour" | "day" | "week" | "month" | "year";
517
- /** @description Advanced: raw Google tbs filter (e.g. qdr:d); overrides time */
500
+ /** @description Advanced: raw Google tbs filter (e.g. qdr:d, qdr:w2, cdr:1,cd_min:1/1/2026,cd_max:1/31/2026); overrides time */
518
501
  tbs?: string;
519
502
  /**
520
503
  * @default desktop
@@ -573,19 +556,6 @@ interface components {
573
556
  fields?: string;
574
557
  max_age?: number;
575
558
  };
576
- LensRequest: {
577
- /**
578
- * Format: uri
579
- * @description Image URL
580
- */
581
- url: string;
582
- country?: string;
583
- language?: string;
584
- /** @enum {string} */
585
- format?: "json" | "markdown" | "compact";
586
- fields?: string;
587
- max_age?: number;
588
- };
589
559
  WebpageRequest: {
590
560
  /** Format: uri */
591
561
  url: string;
@@ -643,7 +613,7 @@ interface components {
643
613
  /**
644
614
  * @example search
645
615
  * @example news
646
- * @example lens
616
+ * @example webpage
647
617
  */
648
618
  endpoint: string;
649
619
  /** @description The engine policy as asked (google, auto, one provider or a list) */
@@ -904,20 +874,6 @@ interface components {
904
874
  results: components["schemas"]["Suggestion"][];
905
875
  meta: components["schemas"]["Meta"];
906
876
  };
907
- LensResult: {
908
- position: number;
909
- title: string;
910
- source?: string;
911
- link: string;
912
- domain?: string;
913
- image_url?: string;
914
- thumbnail_url?: string;
915
- };
916
- LensResponse: {
917
- request: components["schemas"]["RequestEcho"];
918
- results: components["schemas"]["LensResult"][];
919
- meta: components["schemas"]["Meta"];
920
- };
921
877
  PageMetadata: {
922
878
  title?: string;
923
879
  description?: string;
@@ -1020,7 +976,7 @@ interface components {
1020
976
  };
1021
977
  BatchCreateRequest: {
1022
978
  /** @enum {string} */
1023
- endpoint: "search" | "images" | "videos" | "news" | "maps" | "places" | "reviews" | "shopping" | "scholar" | "patents" | "autocomplete" | "lens" | "webpage";
979
+ endpoint: "search" | "images" | "videos" | "news" | "maps" | "places" | "reviews" | "shopping" | "scholar" | "patents" | "autocomplete" | "webpage";
1024
980
  /** @description Request bodies for `endpoint` (same fields as the realtime endpoint) */
1025
981
  requests: {
1026
982
  [key: string]: unknown;
@@ -1265,22 +1221,6 @@ interface components {
1265
1221
  };
1266
1222
  };
1267
1223
  /** @description OK (text/markdown when format=markdown) */
1268
- LensOK: {
1269
- headers: {
1270
- "X-Credits-Used": components["headers"]["CreditsUsed"];
1271
- "X-Credits-Remaining": components["headers"]["CreditsRemaining"];
1272
- "X-Cost-USD": components["headers"]["CostUSD"];
1273
- "X-Cache": components["headers"]["Cache"];
1274
- "X-Latency-Ms": components["headers"]["LatencyMs"];
1275
- "X-Tokens-Estimate": components["headers"]["TokensEstimate"];
1276
- [name: string]: unknown;
1277
- };
1278
- content: {
1279
- "application/json": components["schemas"]["LensResponse"];
1280
- "text/markdown": string;
1281
- };
1282
- };
1283
- /** @description OK (text/markdown when format=markdown) */
1284
1224
  WebpageOK: {
1285
1225
  headers: {
1286
1226
  "X-Credits-Used": components["headers"]["CreditsUsed"];
@@ -1560,28 +1500,6 @@ interface operations {
1560
1500
  503: components["responses"]["Unavailable"];
1561
1501
  };
1562
1502
  };
1563
- lens: {
1564
- parameters: {
1565
- query?: never;
1566
- header?: never;
1567
- path?: never;
1568
- cookie?: never;
1569
- };
1570
- requestBody: {
1571
- content: {
1572
- "application/json": components["schemas"]["LensRequest"];
1573
- };
1574
- };
1575
- responses: {
1576
- 200: components["responses"]["LensOK"];
1577
- 400: components["responses"]["Error"];
1578
- 401: components["responses"]["Error"];
1579
- 402: components["responses"]["Error"];
1580
- 403: components["responses"]["Error"];
1581
- 429: components["responses"]["Error"];
1582
- 503: components["responses"]["Unavailable"];
1583
- };
1584
- };
1585
1503
  webpage: {
1586
1504
  parameters: {
1587
1505
  query?: never;
@@ -1887,7 +1805,6 @@ type SearchParams = Omit<Schemas["SearchRequest"], "engine"> & {
1887
1805
  engine?: Engine;
1888
1806
  };
1889
1807
  type ReviewsParams = Schemas["ReviewsRequest"];
1890
- type LensParams = Schemas["LensRequest"];
1891
1808
  type WebpageParams = Schemas["WebpageRequest"];
1892
1809
  type RankParams = Schemas["RankRequest"];
1893
1810
  /** `format` values accepted by the verticals. */
@@ -1910,7 +1827,6 @@ type ShoppingResult = Schemas["ShoppingResult"];
1910
1827
  type ScholarResult = Schemas["ScholarResult"];
1911
1828
  type PatentResult = Schemas["PatentResult"];
1912
1829
  type Suggestion = Schemas["Suggestion"];
1913
- type LensResult = Schemas["LensResult"];
1914
1830
  type PageMetadata = Schemas["PageMetadata"];
1915
1831
  type RankMatch = Schemas["RankResponse"]["matches"][number];
1916
1832
  type SearchResponse = Schemas["SearchResponse"];
@@ -1925,7 +1841,6 @@ type ShoppingResponse = Schemas["ShoppingResponse"];
1925
1841
  type ScholarResponse = Schemas["ScholarResponse"];
1926
1842
  type PatentsResponse = Schemas["PatentsResponse"];
1927
1843
  type AutocompleteResponse = Schemas["AutocompleteResponse"];
1928
- type LensResponse = Schemas["LensResponse"];
1929
1844
  type WebpageResponse = Schemas["WebpageResponse"];
1930
1845
  type RankResponse = Schemas["RankResponse"];
1931
1846
  type Account = Schemas["Account"];
@@ -1964,7 +1879,6 @@ type BatchRequestMap = {
1964
1879
  scholar: SearchParams;
1965
1880
  patents: SearchParams;
1966
1881
  autocomplete: SearchParams;
1967
- lens: LensParams;
1968
1882
  webpage: WebpageParams;
1969
1883
  };
1970
1884
  /** Body of `POST /v1/batches`. `requests` takes the same fields as the realtime endpoint. */
@@ -1978,7 +1892,7 @@ type BatchCreateParams = {
1978
1892
  };
1979
1893
  }[BatchEndpoint];
1980
1894
 
1981
- declare const VERSION = "0.2.0";
1895
+ declare const VERSION = "0.3.0";
1982
1896
  declare const DEFAULT_BASE_URL = "https://api.serpkite.com";
1983
1897
  interface SerpKiteOptions {
1984
1898
  /** API key (`skt_live_…`). Defaults to the `SERPKITE_API_KEY` environment variable. */
@@ -2167,8 +2081,6 @@ declare class SerpKite {
2167
2081
  metadata: components["schemas"]["PageMetadata"];
2168
2082
  meta: components["schemas"]["Meta"];
2169
2083
  }>;
2170
- /** Google Lens visual matches for an image URL. */
2171
- lens(params: LensParams, options?: RequestOptions): Promise<LensResponse>;
2172
2084
  /** Position of `domain` for keyword `q` in the top `num` results (default 100). */
2173
2085
  rank(params: RankParams, options?: RequestOptions): Promise<RankResponse>;
2174
2086
  /** Balance, limits and this month's usage for the key's account. */
@@ -2256,4 +2168,4 @@ type HeaderSource = Headers | Record<string, string | string[] | undefined>;
2256
2168
  */
2257
2169
  declare function verifyWebhook(secret: string, payload: string | Uint8Array, headers: HeaderSource, options?: VerifyWebhookOptions): Promise<boolean>;
2258
2170
 
2259
- export { type Account, type AnswerBox, type AutocompleteResponse, type Batch, type BatchCreateEntry, type BatchCreateError, type BatchCreateOptions, type BatchCreateParams, type BatchCreateResponse, type BatchEndpoint, type BatchStatus, type CompactResponse, DEFAULT_BASE_URL, type Engine, type ErrorBody, type Format, type ImageResult, type ImagesResponse, type KnowledgeGraph, type LensParams, type LensResponse, type LensResult, type MapsResponse, type Meta, type NewsResponse, type NewsResult, type OrganicResult, type PageMetadata, type PatentResult, type PatentsResponse, type PeopleAlsoAsk, type PlaceResult, type PlacesResponse, type Provider, type RankMatch, type RankParams, type RankResponse, type RelatedSearch, type RequestEcho, type RequestOptions, type ResponseInfo, type ReviewResult, type ReviewsParams, type ReviewsResponse, type RouteOutcome, type RouteStep, type ScholarResponse, type ScholarResult, type SearchParams, type SearchResponse, SerpKite, SerpKiteError, type SerpKiteOptions, type ShoppingResponse, type ShoppingResult, type Sitelink, type Status, type Suggestion, VERSION, type VerifyWebhookOptions, type VerticalMethod, type VideoResult, type VideosResponse, type WaitOptions, type WebpageParams, type WebpageResponse, type components, isBatchError, type operations, parseRetryAfter, type paths, verifyWebhook };
2171
+ export { type Account, type AnswerBox, type AutocompleteResponse, type Batch, type BatchCreateEntry, type BatchCreateError, type BatchCreateOptions, type BatchCreateParams, type BatchCreateResponse, type BatchEndpoint, type BatchStatus, type CompactResponse, DEFAULT_BASE_URL, type Engine, type ErrorBody, type Format, type ImageResult, type ImagesResponse, type KnowledgeGraph, type MapsResponse, type Meta, type NewsResponse, type NewsResult, type OrganicResult, type PageMetadata, type PatentResult, type PatentsResponse, type PeopleAlsoAsk, type PlaceResult, type PlacesResponse, type Provider, type RankMatch, type RankParams, type RankResponse, type RelatedSearch, type RequestEcho, type RequestOptions, type ResponseInfo, type ReviewResult, type ReviewsParams, type ReviewsResponse, type RouteOutcome, type RouteStep, type ScholarResponse, type ScholarResult, type SearchParams, type SearchResponse, SerpKite, SerpKiteError, type SerpKiteOptions, type ShoppingResponse, type ShoppingResult, type Sitelink, type Status, type Suggestion, VERSION, type VerifyWebhookOptions, type VerticalMethod, type VideoResult, type VideosResponse, type WaitOptions, type WebpageParams, type WebpageResponse, type components, isBatchError, type operations, parseRetryAfter, type paths, verifyWebhook };
package/dist/index.d.ts CHANGED
@@ -156,7 +156,7 @@ interface paths {
156
156
  };
157
157
  get?: never;
158
158
  put?: never;
159
- /** Google Maps search (places with coordinates). Accepts `ll` ("@lat,lng,zoomz") */
159
+ /** Google Maps search (places with coordinates). Accepts `ll` ("@lat,lng,zoomz") to search around a point */
160
160
  post: operations["maps"];
161
161
  delete?: never;
162
162
  options?: never;
@@ -266,23 +266,6 @@ interface paths {
266
266
  patch?: never;
267
267
  trace?: never;
268
268
  };
269
- "/v1/lens": {
270
- parameters: {
271
- query?: never;
272
- header?: never;
273
- path?: never;
274
- cookie?: never;
275
- };
276
- get?: never;
277
- put?: never;
278
- /** Google Lens visual matches for an image URL (2 credits) */
279
- post: operations["lens"];
280
- delete?: never;
281
- options?: never;
282
- head?: never;
283
- patch?: never;
284
- trace?: never;
285
- };
286
269
  "/v1/webpage": {
287
270
  parameters: {
288
271
  query?: never;
@@ -487,20 +470,20 @@ interface components {
487
470
  SearchRequest: {
488
471
  q: string;
489
472
  /**
490
- * @description Country code (ISO 3166-1 alpha-2)
473
+ * @description Country code (ISO 3166-1 alpha-2, case-insensitive; uk is accepted as gb). When omitted and location ends in a country name, that country is used
491
474
  * @default us
492
475
  */
493
476
  country?: string;
494
477
  /**
495
- * @description Interface language (e.g. en
478
+ * @description Interface language: a language code with an optional region (e.g. en, de, pt-br, zh-tw, es-419)
496
479
  * @default en
497
480
  */
498
481
  language?: string;
499
482
  /** @description Free-text location, e.g. "Austin, Texas, United States" */
500
483
  location?: string;
501
- /** @description Pre-encoded Google location (overrides location) */
484
+ /** @description Pre-encoded Google location (overrides ll and location; percent-encoded values are decoded) */
502
485
  uule?: string;
503
- /** @description Maps viewport "@lat,lng,14z" (maps only) */
486
+ /** @description Map point "@lat,lng,14z" (maps and places only; zoom optional): the search runs as a searcher at that point. Overrides location */
504
487
  ll?: string;
505
488
  /**
506
489
  * @description 10, or up to 100 for the depth bundle on search and news (7 credits for 100; values between round up to whole pages). Other verticals return one page of 10
@@ -510,11 +493,11 @@ interface components {
510
493
  /** @default 1 */
511
494
  page?: number;
512
495
  /**
513
- * @description Only results from the last hour/day/…
496
+ * @description Only results from the last hour/day/… (search, news, images, videos, shopping). A fallback engine without that window is skipped, never answered unfiltered
514
497
  * @enum {string}
515
498
  */
516
499
  time?: "hour" | "day" | "week" | "month" | "year";
517
- /** @description Advanced: raw Google tbs filter (e.g. qdr:d); overrides time */
500
+ /** @description Advanced: raw Google tbs filter (e.g. qdr:d, qdr:w2, cdr:1,cd_min:1/1/2026,cd_max:1/31/2026); overrides time */
518
501
  tbs?: string;
519
502
  /**
520
503
  * @default desktop
@@ -573,19 +556,6 @@ interface components {
573
556
  fields?: string;
574
557
  max_age?: number;
575
558
  };
576
- LensRequest: {
577
- /**
578
- * Format: uri
579
- * @description Image URL
580
- */
581
- url: string;
582
- country?: string;
583
- language?: string;
584
- /** @enum {string} */
585
- format?: "json" | "markdown" | "compact";
586
- fields?: string;
587
- max_age?: number;
588
- };
589
559
  WebpageRequest: {
590
560
  /** Format: uri */
591
561
  url: string;
@@ -643,7 +613,7 @@ interface components {
643
613
  /**
644
614
  * @example search
645
615
  * @example news
646
- * @example lens
616
+ * @example webpage
647
617
  */
648
618
  endpoint: string;
649
619
  /** @description The engine policy as asked (google, auto, one provider or a list) */
@@ -904,20 +874,6 @@ interface components {
904
874
  results: components["schemas"]["Suggestion"][];
905
875
  meta: components["schemas"]["Meta"];
906
876
  };
907
- LensResult: {
908
- position: number;
909
- title: string;
910
- source?: string;
911
- link: string;
912
- domain?: string;
913
- image_url?: string;
914
- thumbnail_url?: string;
915
- };
916
- LensResponse: {
917
- request: components["schemas"]["RequestEcho"];
918
- results: components["schemas"]["LensResult"][];
919
- meta: components["schemas"]["Meta"];
920
- };
921
877
  PageMetadata: {
922
878
  title?: string;
923
879
  description?: string;
@@ -1020,7 +976,7 @@ interface components {
1020
976
  };
1021
977
  BatchCreateRequest: {
1022
978
  /** @enum {string} */
1023
- endpoint: "search" | "images" | "videos" | "news" | "maps" | "places" | "reviews" | "shopping" | "scholar" | "patents" | "autocomplete" | "lens" | "webpage";
979
+ endpoint: "search" | "images" | "videos" | "news" | "maps" | "places" | "reviews" | "shopping" | "scholar" | "patents" | "autocomplete" | "webpage";
1024
980
  /** @description Request bodies for `endpoint` (same fields as the realtime endpoint) */
1025
981
  requests: {
1026
982
  [key: string]: unknown;
@@ -1265,22 +1221,6 @@ interface components {
1265
1221
  };
1266
1222
  };
1267
1223
  /** @description OK (text/markdown when format=markdown) */
1268
- LensOK: {
1269
- headers: {
1270
- "X-Credits-Used": components["headers"]["CreditsUsed"];
1271
- "X-Credits-Remaining": components["headers"]["CreditsRemaining"];
1272
- "X-Cost-USD": components["headers"]["CostUSD"];
1273
- "X-Cache": components["headers"]["Cache"];
1274
- "X-Latency-Ms": components["headers"]["LatencyMs"];
1275
- "X-Tokens-Estimate": components["headers"]["TokensEstimate"];
1276
- [name: string]: unknown;
1277
- };
1278
- content: {
1279
- "application/json": components["schemas"]["LensResponse"];
1280
- "text/markdown": string;
1281
- };
1282
- };
1283
- /** @description OK (text/markdown when format=markdown) */
1284
1224
  WebpageOK: {
1285
1225
  headers: {
1286
1226
  "X-Credits-Used": components["headers"]["CreditsUsed"];
@@ -1560,28 +1500,6 @@ interface operations {
1560
1500
  503: components["responses"]["Unavailable"];
1561
1501
  };
1562
1502
  };
1563
- lens: {
1564
- parameters: {
1565
- query?: never;
1566
- header?: never;
1567
- path?: never;
1568
- cookie?: never;
1569
- };
1570
- requestBody: {
1571
- content: {
1572
- "application/json": components["schemas"]["LensRequest"];
1573
- };
1574
- };
1575
- responses: {
1576
- 200: components["responses"]["LensOK"];
1577
- 400: components["responses"]["Error"];
1578
- 401: components["responses"]["Error"];
1579
- 402: components["responses"]["Error"];
1580
- 403: components["responses"]["Error"];
1581
- 429: components["responses"]["Error"];
1582
- 503: components["responses"]["Unavailable"];
1583
- };
1584
- };
1585
1503
  webpage: {
1586
1504
  parameters: {
1587
1505
  query?: never;
@@ -1887,7 +1805,6 @@ type SearchParams = Omit<Schemas["SearchRequest"], "engine"> & {
1887
1805
  engine?: Engine;
1888
1806
  };
1889
1807
  type ReviewsParams = Schemas["ReviewsRequest"];
1890
- type LensParams = Schemas["LensRequest"];
1891
1808
  type WebpageParams = Schemas["WebpageRequest"];
1892
1809
  type RankParams = Schemas["RankRequest"];
1893
1810
  /** `format` values accepted by the verticals. */
@@ -1910,7 +1827,6 @@ type ShoppingResult = Schemas["ShoppingResult"];
1910
1827
  type ScholarResult = Schemas["ScholarResult"];
1911
1828
  type PatentResult = Schemas["PatentResult"];
1912
1829
  type Suggestion = Schemas["Suggestion"];
1913
- type LensResult = Schemas["LensResult"];
1914
1830
  type PageMetadata = Schemas["PageMetadata"];
1915
1831
  type RankMatch = Schemas["RankResponse"]["matches"][number];
1916
1832
  type SearchResponse = Schemas["SearchResponse"];
@@ -1925,7 +1841,6 @@ type ShoppingResponse = Schemas["ShoppingResponse"];
1925
1841
  type ScholarResponse = Schemas["ScholarResponse"];
1926
1842
  type PatentsResponse = Schemas["PatentsResponse"];
1927
1843
  type AutocompleteResponse = Schemas["AutocompleteResponse"];
1928
- type LensResponse = Schemas["LensResponse"];
1929
1844
  type WebpageResponse = Schemas["WebpageResponse"];
1930
1845
  type RankResponse = Schemas["RankResponse"];
1931
1846
  type Account = Schemas["Account"];
@@ -1964,7 +1879,6 @@ type BatchRequestMap = {
1964
1879
  scholar: SearchParams;
1965
1880
  patents: SearchParams;
1966
1881
  autocomplete: SearchParams;
1967
- lens: LensParams;
1968
1882
  webpage: WebpageParams;
1969
1883
  };
1970
1884
  /** Body of `POST /v1/batches`. `requests` takes the same fields as the realtime endpoint. */
@@ -1978,7 +1892,7 @@ type BatchCreateParams = {
1978
1892
  };
1979
1893
  }[BatchEndpoint];
1980
1894
 
1981
- declare const VERSION = "0.2.0";
1895
+ declare const VERSION = "0.3.0";
1982
1896
  declare const DEFAULT_BASE_URL = "https://api.serpkite.com";
1983
1897
  interface SerpKiteOptions {
1984
1898
  /** API key (`skt_live_…`). Defaults to the `SERPKITE_API_KEY` environment variable. */
@@ -2167,8 +2081,6 @@ declare class SerpKite {
2167
2081
  metadata: components["schemas"]["PageMetadata"];
2168
2082
  meta: components["schemas"]["Meta"];
2169
2083
  }>;
2170
- /** Google Lens visual matches for an image URL. */
2171
- lens(params: LensParams, options?: RequestOptions): Promise<LensResponse>;
2172
2084
  /** Position of `domain` for keyword `q` in the top `num` results (default 100). */
2173
2085
  rank(params: RankParams, options?: RequestOptions): Promise<RankResponse>;
2174
2086
  /** Balance, limits and this month's usage for the key's account. */
@@ -2256,4 +2168,4 @@ type HeaderSource = Headers | Record<string, string | string[] | undefined>;
2256
2168
  */
2257
2169
  declare function verifyWebhook(secret: string, payload: string | Uint8Array, headers: HeaderSource, options?: VerifyWebhookOptions): Promise<boolean>;
2258
2170
 
2259
- export { type Account, type AnswerBox, type AutocompleteResponse, type Batch, type BatchCreateEntry, type BatchCreateError, type BatchCreateOptions, type BatchCreateParams, type BatchCreateResponse, type BatchEndpoint, type BatchStatus, type CompactResponse, DEFAULT_BASE_URL, type Engine, type ErrorBody, type Format, type ImageResult, type ImagesResponse, type KnowledgeGraph, type LensParams, type LensResponse, type LensResult, type MapsResponse, type Meta, type NewsResponse, type NewsResult, type OrganicResult, type PageMetadata, type PatentResult, type PatentsResponse, type PeopleAlsoAsk, type PlaceResult, type PlacesResponse, type Provider, type RankMatch, type RankParams, type RankResponse, type RelatedSearch, type RequestEcho, type RequestOptions, type ResponseInfo, type ReviewResult, type ReviewsParams, type ReviewsResponse, type RouteOutcome, type RouteStep, type ScholarResponse, type ScholarResult, type SearchParams, type SearchResponse, SerpKite, SerpKiteError, type SerpKiteOptions, type ShoppingResponse, type ShoppingResult, type Sitelink, type Status, type Suggestion, VERSION, type VerifyWebhookOptions, type VerticalMethod, type VideoResult, type VideosResponse, type WaitOptions, type WebpageParams, type WebpageResponse, type components, isBatchError, type operations, parseRetryAfter, type paths, verifyWebhook };
2171
+ export { type Account, type AnswerBox, type AutocompleteResponse, type Batch, type BatchCreateEntry, type BatchCreateError, type BatchCreateOptions, type BatchCreateParams, type BatchCreateResponse, type BatchEndpoint, type BatchStatus, type CompactResponse, DEFAULT_BASE_URL, type Engine, type ErrorBody, type Format, type ImageResult, type ImagesResponse, type KnowledgeGraph, type MapsResponse, type Meta, type NewsResponse, type NewsResult, type OrganicResult, type PageMetadata, type PatentResult, type PatentsResponse, type PeopleAlsoAsk, type PlaceResult, type PlacesResponse, type Provider, type RankMatch, type RankParams, type RankResponse, type RelatedSearch, type RequestEcho, type RequestOptions, type ResponseInfo, type ReviewResult, type ReviewsParams, type ReviewsResponse, type RouteOutcome, type RouteStep, type ScholarResponse, type ScholarResult, type SearchParams, type SearchResponse, SerpKite, SerpKiteError, type SerpKiteOptions, type ShoppingResponse, type ShoppingResult, type Sitelink, type Status, type Suggestion, VERSION, type VerifyWebhookOptions, type VerticalMethod, type VideoResult, type VideosResponse, type WaitOptions, type WebpageParams, type WebpageResponse, type components, isBatchError, type operations, parseRetryAfter, type paths, verifyWebhook };
package/dist/index.js CHANGED
@@ -48,7 +48,7 @@ function errorFromResponse(status, headers, body) {
48
48
  }
49
49
 
50
50
  // src/client.ts
51
- var VERSION = "0.2.0";
51
+ var VERSION = "0.3.0";
52
52
  var DEFAULT_BASE_URL = "https://api.serpkite.com";
53
53
  var SerpKite = class {
54
54
  baseUrl;
@@ -111,10 +111,6 @@ var SerpKite = class {
111
111
  autocomplete = this.#vertical("/v1/autocomplete");
112
112
  /** Fetch any public URL as clean Markdown plus metadata. */
113
113
  webpage = this.#vertical("/v1/webpage");
114
- /** Google Lens visual matches for an image URL. */
115
- lens(params, options) {
116
- return this.request({ method: "POST", path: "/v1/lens", body: params, options });
117
- }
118
114
  /** Position of `domain` for keyword `q` in the top `num` results (default 100). */
119
115
  rank(params, options) {
120
116
  return this.request({ method: "POST", path: "/v1/rank", body: params, options });
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/errors.ts","../src/client.ts","../src/util.ts","../src/webhooks.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Every failure thrown by the SDK. API errors carry the fields of the\n * `{\"error\":{\"code\",\"message\",\"request_id\"}}` envelope; network failures and\n * timeouts use `status: 0` with code `connection_error` or `timeout`.\n */\nexport class SerpKiteError extends Error {\n /** HTTP status, or 0 when no response was received. */\n readonly status: number;\n /** Machine-readable code, e.g. `unauthorized`, `insufficient_credits`, `rate_limited`. */\n readonly code: string;\n /** `X-Request-Id` of the failed request, when the API returned one. */\n readonly requestId: string | undefined;\n /** Response headers, when the API responded. */\n readonly headers: Headers | undefined;\n\n constructor(\n status: number,\n code: string,\n message: string,\n requestId?: string,\n headers?: Headers,\n options?: { cause?: unknown },\n ) {\n super(message, options);\n this.name = \"SerpKiteError\";\n this.status = status;\n this.code = code;\n this.requestId = requestId || undefined;\n this.headers = headers;\n }\n}\n\nconst fallbackCodes: Record<number, string> = {\n 400: \"invalid_request\",\n 401: \"unauthorized\",\n 402: \"insufficient_credits\",\n 403: \"forbidden\",\n 404: \"not_found\",\n 429: \"rate_limited\",\n // The API sends upstream failures as 503 with a JSON body; a bare 502/504\n // comes from a proxy (Cloudflare replaces origin 502/504 bodies).\n 502: \"upstream_error\",\n 503: \"unavailable\",\n 504: \"upstream_timeout\",\n};\n\n/** Builds a SerpKiteError from a non-2xx response body (JSON envelope or anything else). */\nexport function errorFromResponse(status: number, headers: Headers, body: string): SerpKiteError {\n let code = fallbackCodes[status] ?? (status >= 500 ? \"server_error\" : \"http_error\");\n let message = body.trim().slice(0, 500) || `HTTP ${status}`;\n let requestId = headers.get(\"x-request-id\") ?? undefined;\n try {\n const parsed = JSON.parse(body) as {\n error?: { code?: unknown; message?: unknown; request_id?: unknown };\n };\n const e = parsed?.error;\n if (e && typeof e === \"object\") {\n if (typeof e.code === \"string\" && e.code) code = e.code;\n if (typeof e.message === \"string\" && e.message) message = e.message;\n if (typeof e.request_id === \"string\" && e.request_id) requestId = e.request_id;\n }\n } catch {\n // Not JSON: keep the text body as the message.\n }\n return new SerpKiteError(status, code, message, requestId, headers);\n}\n","import { errorFromResponse, SerpKiteError } from \"./errors\";\nimport type {\n Account,\n AutocompleteResponse,\n Batch,\n BatchCreateEntry,\n BatchCreateParams,\n BatchCreateResponse,\n CompactResponse,\n ImagesResponse,\n LensParams,\n LensResponse,\n NewsResponse,\n PatentsResponse,\n PlacesResponse,\n RankParams,\n RankResponse,\n ReviewsParams,\n ReviewsResponse,\n ScholarResponse,\n SearchParams,\n SearchResponse,\n ShoppingResponse,\n VideosResponse,\n WebpageParams,\n WebpageResponse,\n} from \"./types\";\n\nexport const VERSION = \"0.2.0\";\nexport const DEFAULT_BASE_URL = \"https://api.serpkite.com\";\n\nexport interface SerpKiteOptions {\n /** API key (`skt_live_…`). Defaults to the `SERPKITE_API_KEY` environment variable. */\n apiKey?: string;\n /** Defaults to `SERPKITE_BASE_URL` or https://api.serpkite.com. */\n baseUrl?: string;\n /** Per-attempt timeout in milliseconds. Default 60000. */\n timeoutMs?: number;\n /** Retries after the first attempt on 429, 5xx and network errors. Default 2. */\n maxRetries?: number;\n /** Base delay of the exponential backoff in milliseconds. Default 500. */\n retryDelayMs?: number;\n /** Custom fetch implementation. Defaults to the global `fetch`. */\n fetch?: typeof fetch;\n /** Extra headers sent with every request. */\n headers?: Record<string, string>;\n}\n\n/** Billing and tracing details from the response headers. */\nexport interface ResponseInfo {\n status: number;\n headers: Headers;\n requestId: string | undefined;\n creditsUsed: number | undefined;\n creditsRemaining: number | undefined;\n costUsd: number | undefined;\n /** `HIT` when served from cache (`max_age`), else `MISS`. */\n cache: \"HIT\" | \"MISS\" | undefined;\n latencyMs: number | undefined;\n tokensEstimate: number | undefined;\n}\n\nexport interface RequestOptions {\n signal?: AbortSignal;\n /** Overrides the client's per-attempt timeout. */\n timeoutMs?: number;\n /** Overrides the client's retry count. */\n maxRetries?: number;\n headers?: Record<string, string>;\n /** Called with the final response's headers (credits used/remaining, cache, request id). */\n onResponse?: (info: ResponseInfo) => void;\n}\n\nexport interface BatchCreateOptions extends RequestOptions {\n /**\n * Sent as `Idempotency-Key` (1-255 printable ASCII characters, e.g. a UUID).\n * For 24 hours a retry with the same key and body returns the first response\n * instead of queueing and billing the jobs again.\n */\n idempotencyKey?: string;\n}\n\nexport interface WaitOptions {\n /** Give up after this many milliseconds. Default 600000 (10 minutes). */\n timeoutMs?: number;\n /** First delay between polls. Default 1000. Grows 1.5× per poll. */\n pollIntervalMs?: number;\n /** Upper bound of the delay between polls. Default 10000. */\n maxPollIntervalMs?: number;\n signal?: AbortSignal;\n}\n\n/** A vertical whose return type follows `format`: `\"markdown\"` → string, `\"compact\"` → CompactResponse. */\nexport interface VerticalMethod<P, R> {\n (params: P & { format: \"markdown\" }, options?: RequestOptions): Promise<string>;\n (params: P & { format: \"compact\" }, options?: RequestOptions): Promise<CompactResponse>;\n (params: P & { format?: \"json\" }, options?: RequestOptions): Promise<R>;\n (params: P, options?: RequestOptions): Promise<R | CompactResponse | string>;\n}\n\ntype Method = \"GET\" | \"POST\";\n\ninterface Call {\n method: Method;\n path: string;\n body?: unknown;\n options?: RequestOptions;\n /** Which failures are safe to retry. `all` = 429, 5xx and network errors. */\n retry?: \"all\" | \"rate_limit\";\n}\n\nexport class SerpKite {\n readonly baseUrl: string;\n readonly timeoutMs: number;\n readonly maxRetries: number;\n readonly retryDelayMs: number;\n readonly #apiKey: string;\n readonly #fetch: typeof fetch;\n readonly #headers: Record<string, string>;\n\n constructor(options: SerpKiteOptions = {}) {\n const apiKey = options.apiKey ?? env(\"SERPKITE_API_KEY\");\n if (!apiKey) {\n throw new SerpKiteError(\n 0,\n \"missing_api_key\",\n \"No API key: pass { apiKey } or set the SERPKITE_API_KEY environment variable\",\n );\n }\n this.#apiKey = apiKey;\n this.baseUrl = (options.baseUrl ?? env(\"SERPKITE_BASE_URL\") ?? DEFAULT_BASE_URL).replace(\n /\\/+$/,\n \"\",\n );\n this.timeoutMs = options.timeoutMs ?? 60_000;\n this.maxRetries = Math.max(0, options.maxRetries ?? 2);\n this.retryDelayMs = options.retryDelayMs ?? 500;\n const f = options.fetch ?? globalThis.fetch;\n if (typeof f !== \"function\") {\n throw new SerpKiteError(\n 0,\n \"missing_fetch\",\n \"No global fetch: pass { fetch } (Node 18+ has one)\",\n );\n }\n this.#fetch = f;\n this.#headers = { ...options.headers };\n }\n\n // ── Verticals ─────────────────────────────────────────────────────────\n\n /** Google web search: organic results, answer box, knowledge graph, people also ask… */\n readonly search = this.#vertical<SearchParams, SearchResponse>(\"/v1/search\");\n /** Google Images. */\n readonly images = this.#vertical<SearchParams, ImagesResponse>(\"/v1/images\");\n /** Google Videos. */\n readonly videos = this.#vertical<SearchParams, VideosResponse>(\"/v1/videos\");\n /** Google News. */\n readonly news = this.#vertical<SearchParams, NewsResponse>(\"/v1/news\");\n /** Google Maps search (places with coordinates). Accepts `ll` (\"@lat,lng,14z\"). */\n readonly maps = this.#vertical<SearchParams, PlacesResponse>(\"/v1/maps\");\n /** Google local results. */\n readonly places = this.#vertical<SearchParams, PlacesResponse>(\"/v1/places\");\n /** Reviews of a place by `place_id`, `cid` or `fid`. Page with `page_token` = `next_page_token`. */\n readonly reviews = this.#vertical<ReviewsParams, ReviewsResponse>(\"/v1/reviews\");\n /** Google Shopping. */\n readonly shopping = this.#vertical<SearchParams, ShoppingResponse>(\"/v1/shopping\");\n /** Google Scholar. */\n readonly scholar = this.#vertical<SearchParams, ScholarResponse>(\"/v1/scholar\");\n /** Google Patents. */\n readonly patents = this.#vertical<SearchParams, PatentsResponse>(\"/v1/patents\");\n /** Google autocomplete suggestions. */\n readonly autocomplete = this.#vertical<SearchParams, AutocompleteResponse>(\"/v1/autocomplete\");\n /** Fetch any public URL as clean Markdown plus metadata. */\n readonly webpage = this.#vertical<WebpageParams, WebpageResponse>(\"/v1/webpage\");\n\n /** Google Lens visual matches for an image URL. */\n lens(params: LensParams, options?: RequestOptions): Promise<LensResponse> {\n return this.request({ method: \"POST\", path: \"/v1/lens\", body: params, options });\n }\n\n /** Position of `domain` for keyword `q` in the top `num` results (default 100). */\n rank(params: RankParams, options?: RequestOptions): Promise<RankResponse> {\n return this.request({ method: \"POST\", path: \"/v1/rank\", body: params, options });\n }\n\n /** Balance, limits and this month's usage for the key's account. */\n account(options?: RequestOptions): Promise<Account> {\n return this.request({ method: \"GET\", path: \"/v1/account\", options });\n }\n\n // ── Batches ───────────────────────────────────────────────────────────\n\n readonly batches = {\n /**\n * Queue 1-100 requests for one endpoint at half price. Returns one entry per\n * request, in order: a queued `Batch` or an error object. Without an\n * `idempotencyKey` it is only retried on 429, so a lost response never queues\n * (and bills) the same requests twice. With one, 5xx and network errors are\n * retried too: the server replays the first response for the same key and body.\n */\n create: (\n params: BatchCreateParams,\n options: BatchCreateOptions = {},\n ): Promise<BatchCreateResponse> => {\n const { idempotencyKey, ...rest } = options;\n return this.request({\n method: \"POST\",\n path: \"/v1/batches\",\n body: params,\n options: idempotencyKey\n ? { ...rest, headers: { ...rest.headers, \"Idempotency-Key\": idempotencyKey } }\n : rest,\n retry: idempotencyKey ? \"all\" : \"rate_limit\",\n });\n },\n\n /** Poll one batch job. */\n get: (id: string, options?: RequestOptions): Promise<Batch> =>\n this.request({ method: \"GET\", path: `/v1/batches/${encodeURIComponent(id)}`, options }),\n\n /**\n * Poll until the job is `done` or `failed` and return it (a failed job is\n * returned, not thrown; check `status` and `error`). Accepts an id or an\n * entry from `create`; an entry that failed to queue throws its error.\n */\n wait: (idOrEntry: string | BatchCreateEntry | undefined, options: WaitOptions = {}) =>\n this.#wait(idOrEntry, options),\n };\n\n // ── Plumbing ──────────────────────────────────────────────────────────\n\n #vertical<P, R>(path: string): VerticalMethod<P, R> {\n return ((params: P, options?: RequestOptions) =>\n this.request({ method: \"POST\", path, body: params, options })) as VerticalMethod<P, R>;\n }\n\n async #wait(idOrEntry: string | BatchCreateEntry | undefined, o: WaitOptions): Promise<Batch> {\n let id: string | undefined;\n if (typeof idOrEntry === \"string\") {\n id = idOrEntry;\n } else if (idOrEntry && \"id\" in idOrEntry && typeof idOrEntry.id === \"string\") {\n id = idOrEntry.id;\n } else if (idOrEntry && \"error\" in idOrEntry && idOrEntry.error && !(\"id\" in idOrEntry)) {\n const e = idOrEntry.error as { code?: string; message?: string; request_id?: string };\n throw new SerpKiteError(\n 400,\n e.code ?? \"invalid_request\",\n e.message ?? \"batch entry was not queued\",\n e.request_id,\n );\n }\n if (!id) {\n throw new SerpKiteError(0, \"invalid_request\", \"batches.wait needs a batch id\");\n }\n const timeoutMs = o.timeoutMs ?? 600_000;\n const maxInterval = o.maxPollIntervalMs ?? 10_000;\n let interval = o.pollIntervalMs ?? 1_000;\n const deadline = Date.now() + timeoutMs;\n for (;;) {\n const batch = await this.batches.get(id, { signal: o.signal });\n if (batch.status === \"done\" || batch.status === \"failed\") return batch;\n const left = deadline - Date.now();\n if (left <= 0) {\n throw new SerpKiteError(\n 0,\n \"timeout\",\n `batch ${id} still ${batch.status} after ${timeoutMs} ms`,\n );\n }\n await sleep(Math.min(interval, left), o.signal);\n interval = Math.min(interval * 1.5, maxInterval);\n }\n }\n\n /** Low-level request: JSON body in, parsed JSON (or text for non-JSON responses) out. */\n async request<T>(call: Call): Promise<T> {\n const { method, path, body, options = {} } = call;\n const maxRetries = Math.max(0, options.maxRetries ?? this.maxRetries);\n const timeoutMs = options.timeoutMs ?? this.timeoutMs;\n const headers: Record<string, string> = {\n Accept: \"application/json, text/markdown;q=0.9\",\n Authorization: `Bearer ${this.#apiKey}`,\n ...this.#headers,\n ...options.headers,\n };\n if (body !== undefined) headers[\"Content-Type\"] = \"application/json\";\n // Browsers would turn a custom User-Agent into a CORS preflight header.\n if (!isBrowser()) headers[\"User-Agent\"] = `serpkite-typescript/${VERSION}`;\n const init: RequestInit = {\n method,\n headers,\n body: body === undefined ? undefined : JSON.stringify(body),\n };\n\n for (let attempt = 0; ; attempt++) {\n const canRetry = attempt < maxRetries;\n let res: Response;\n const { signal, cleanup, timedOut } = withTimeout(options.signal, timeoutMs);\n try {\n res = await this.#fetch(this.baseUrl + path, { ...init, signal });\n } catch (err) {\n cleanup();\n if (options.signal?.aborted) throw err;\n const code = timedOut() ? \"timeout\" : \"connection_error\";\n if (canRetry && call.retry !== \"rate_limit\") {\n await sleep(this.#backoff(attempt), options.signal);\n continue;\n }\n const msg = timedOut()\n ? `request timed out after ${timeoutMs} ms`\n : `request failed: ${err instanceof Error ? err.message : String(err)}`;\n throw new SerpKiteError(0, code, msg, undefined, undefined, { cause: err });\n }\n\n let text: string;\n try {\n text = await res.text();\n } catch (err) {\n cleanup();\n if (options.signal?.aborted) throw err;\n if (canRetry && call.retry !== \"rate_limit\") {\n await sleep(this.#backoff(attempt), options.signal);\n continue;\n }\n const code = timedOut() ? \"timeout\" : \"connection_error\";\n throw new SerpKiteError(\n 0,\n code,\n \"failed to read the response body\",\n undefined,\n res.headers,\n {\n cause: err,\n },\n );\n }\n cleanup();\n\n if (!res.ok) {\n const retryable = res.status === 429 || (res.status >= 500 && call.retry !== \"rate_limit\");\n if (canRetry && retryable) {\n await sleep(this.#retryDelay(attempt, res.headers), options.signal);\n continue;\n }\n throw errorFromResponse(res.status, res.headers, text);\n }\n\n options.onResponse?.(responseInfo(res));\n const type = res.headers.get(\"content-type\") ?? \"\";\n if (type.includes(\"json\")) {\n try {\n return JSON.parse(text) as T;\n } catch (err) {\n throw new SerpKiteError(\n res.status,\n \"invalid_response\",\n \"response is not valid JSON\",\n res.headers.get(\"x-request-id\") ?? undefined,\n res.headers,\n { cause: err },\n );\n }\n }\n return text as T;\n }\n }\n\n #backoff(attempt: number): number {\n const base = Math.min(this.retryDelayMs * 2 ** attempt, 8_000);\n return base / 2 + Math.random() * (base / 2);\n }\n\n #retryDelay(attempt: number, headers: Headers): number {\n const after = parseRetryAfter(headers.get(\"retry-after\"));\n return after === undefined ? this.#backoff(attempt) : Math.min(after, 60_000);\n }\n}\n\n// ── helpers ─────────────────────────────────────────────────────────────\n\n/** Parses Retry-After (seconds or an HTTP date) into milliseconds. */\nexport function parseRetryAfter(v: string | null): number | undefined {\n if (!v) return undefined;\n const secs = Number(v);\n if (Number.isFinite(secs)) return Math.max(0, secs * 1000);\n const at = Date.parse(v);\n return Number.isNaN(at) ? undefined : Math.max(0, at - Date.now());\n}\n\nfunction responseInfo(res: Response): ResponseInfo {\n const h = res.headers;\n const num = (name: string) => {\n const v = h.get(name);\n if (v === null || v === \"\") return undefined;\n const n = Number(v);\n return Number.isFinite(n) ? n : undefined;\n };\n const cache = h.get(\"x-cache\")?.toUpperCase();\n return {\n status: res.status,\n headers: h,\n requestId: h.get(\"x-request-id\") ?? undefined,\n creditsUsed: num(\"x-credits-used\"),\n creditsRemaining: num(\"x-credits-remaining\"),\n costUsd: num(\"x-cost-usd\"),\n cache: cache === \"HIT\" || cache === \"MISS\" ? cache : undefined,\n latencyMs: num(\"x-latency-ms\"),\n tokensEstimate: num(\"x-tokens-estimate\"),\n };\n}\n\nfunction withTimeout(outer: AbortSignal | undefined, ms: number) {\n const ctrl = new AbortController();\n let timedOut = false;\n const onAbort = () => ctrl.abort(outer?.reason);\n if (outer?.aborted) ctrl.abort(outer.reason);\n else outer?.addEventListener(\"abort\", onAbort, { once: true });\n const timer =\n ms > 0 && Number.isFinite(ms)\n ? setTimeout(() => {\n timedOut = true;\n ctrl.abort(new SerpKiteError(0, \"timeout\", `request timed out after ${ms} ms`));\n }, ms)\n : undefined;\n return {\n signal: ctrl.signal,\n timedOut: () => timedOut,\n cleanup: () => {\n if (timer !== undefined) clearTimeout(timer);\n outer?.removeEventListener(\"abort\", onAbort);\n },\n };\n}\n\nfunction sleep(ms: number, signal?: AbortSignal): Promise<void> {\n return new Promise((resolve, reject) => {\n if (signal?.aborted) return reject(signal.reason);\n const t = setTimeout(() => {\n signal?.removeEventListener(\"abort\", onAbort);\n resolve();\n }, ms);\n const onAbort = () => {\n clearTimeout(t);\n reject(signal?.reason);\n };\n signal?.addEventListener(\"abort\", onAbort, { once: true });\n });\n}\n\ntype EnvHost = {\n process?: { env?: Record<string, string | undefined> };\n Deno?: { env?: { get?: (name: string) => string | undefined } };\n document?: unknown;\n};\n\nfunction env(name: string): string | undefined {\n const g = globalThis as EnvHost;\n try {\n const v = g.process?.env?.[name];\n if (v) return v;\n } catch {\n // process.env may be a throwing proxy on some edge runtimes.\n }\n try {\n return g.Deno?.env?.get?.(name) || undefined;\n } catch {\n // Deno without --allow-env.\n return undefined;\n }\n}\n\nfunction isBrowser(): boolean {\n return typeof (globalThis as EnvHost).document !== \"undefined\";\n}\n","import type { BatchCreateEntry, BatchCreateError } from \"./types\";\n\n/** True when a `batches.create` entry was rejected instead of queued. */\nexport function isBatchError(entry: BatchCreateEntry): entry is BatchCreateError {\n return !(\"id\" in entry && typeof entry.id === \"string\") && \"error\" in entry && !!entry.error;\n}\n","/** Options for {@link verifyWebhook}. */\nexport interface VerifyWebhookOptions {\n /** Reject deliveries whose timestamp is further than this from now. Default 300. */\n toleranceSeconds?: number;\n /** Current time in Unix seconds (tests). */\n now?: number;\n}\n\ntype HeaderSource = Headers | Record<string, string | string[] | undefined>;\n\nfunction header(headers: HeaderSource, name: string): string | undefined {\n if (typeof (headers as Headers).get === \"function\") {\n return (headers as Headers).get(name) ?? undefined;\n }\n const rec = headers as Record<string, string | string[] | undefined>;\n const key = Object.keys(rec).find((k) => k.toLowerCase() === name.toLowerCase());\n const v = key === undefined ? undefined : rec[key];\n return Array.isArray(v) ? v[0] : v;\n}\n\n/**\n * Checks a batch webhook delivery: `X-SerpKite-Signature` must be\n * `v1=<hex HMAC-SHA256(secret, \"<X-SerpKite-Timestamp>.<raw body>\")>` and the\n * timestamp recent. Pass the raw request body exactly as received (not\n * re-serialised JSON). Uses Web Crypto (Node 18+, Deno, Bun, browsers).\n *\n * ```ts\n * const ok = await verifyWebhook(process.env.SERPKITE_WEBHOOK_SECRET!, rawBody, req.headers);\n * ```\n */\nexport async function verifyWebhook(\n secret: string,\n payload: string | Uint8Array,\n headers: HeaderSource,\n options: VerifyWebhookOptions = {},\n): Promise<boolean> {\n const signature = header(headers, \"x-serpkite-signature\");\n const ts = header(headers, \"x-serpkite-timestamp\");\n if (!secret || !signature?.startsWith(\"v1=\") || !ts || !/^\\d+$/.test(ts)) return false;\n const now = options.now ?? Math.floor(Date.now() / 1000);\n if (Math.abs(now - Number(ts)) > (options.toleranceSeconds ?? 300)) return false;\n\n const enc = new TextEncoder();\n const body = typeof payload === \"string\" ? enc.encode(payload) : payload;\n const prefix = enc.encode(`${ts}.`);\n const msg = new Uint8Array(prefix.length + body.length);\n msg.set(prefix);\n msg.set(body, prefix.length);\n const key = await crypto.subtle.importKey(\n \"raw\",\n enc.encode(secret),\n { name: \"HMAC\", hash: \"SHA-256\" },\n false,\n [\"sign\"],\n );\n const mac = new Uint8Array(await crypto.subtle.sign(\"HMAC\", key, msg));\n const want = Array.from(mac, (b) => b.toString(16).padStart(2, \"0\")).join(\"\");\n const got = signature.slice(3).toLowerCase();\n if (got.length !== want.length) return false;\n let diff = 0;\n for (let i = 0; i < want.length; i++) diff |= want.charCodeAt(i) ^ got.charCodeAt(i);\n return diff === 0;\n}\n"]}
1
+ {"version":3,"sources":["../src/errors.ts","../src/client.ts","../src/util.ts","../src/webhooks.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Every failure thrown by the SDK. API errors carry the fields of the\n * `{\"error\":{\"code\",\"message\",\"request_id\"}}` envelope; network failures and\n * timeouts use `status: 0` with code `connection_error` or `timeout`.\n */\nexport class SerpKiteError extends Error {\n /** HTTP status, or 0 when no response was received. */\n readonly status: number;\n /** Machine-readable code, e.g. `unauthorized`, `insufficient_credits`, `rate_limited`. */\n readonly code: string;\n /** `X-Request-Id` of the failed request, when the API returned one. */\n readonly requestId: string | undefined;\n /** Response headers, when the API responded. */\n readonly headers: Headers | undefined;\n\n constructor(\n status: number,\n code: string,\n message: string,\n requestId?: string,\n headers?: Headers,\n options?: { cause?: unknown },\n ) {\n super(message, options);\n this.name = \"SerpKiteError\";\n this.status = status;\n this.code = code;\n this.requestId = requestId || undefined;\n this.headers = headers;\n }\n}\n\nconst fallbackCodes: Record<number, string> = {\n 400: \"invalid_request\",\n 401: \"unauthorized\",\n 402: \"insufficient_credits\",\n 403: \"forbidden\",\n 404: \"not_found\",\n 429: \"rate_limited\",\n // The API sends upstream failures as 503 with a JSON body; a bare 502/504\n // comes from a proxy (Cloudflare replaces origin 502/504 bodies).\n 502: \"upstream_error\",\n 503: \"unavailable\",\n 504: \"upstream_timeout\",\n};\n\n/** Builds a SerpKiteError from a non-2xx response body (JSON envelope or anything else). */\nexport function errorFromResponse(status: number, headers: Headers, body: string): SerpKiteError {\n let code = fallbackCodes[status] ?? (status >= 500 ? \"server_error\" : \"http_error\");\n let message = body.trim().slice(0, 500) || `HTTP ${status}`;\n let requestId = headers.get(\"x-request-id\") ?? undefined;\n try {\n const parsed = JSON.parse(body) as {\n error?: { code?: unknown; message?: unknown; request_id?: unknown };\n };\n const e = parsed?.error;\n if (e && typeof e === \"object\") {\n if (typeof e.code === \"string\" && e.code) code = e.code;\n if (typeof e.message === \"string\" && e.message) message = e.message;\n if (typeof e.request_id === \"string\" && e.request_id) requestId = e.request_id;\n }\n } catch {\n // Not JSON: keep the text body as the message.\n }\n return new SerpKiteError(status, code, message, requestId, headers);\n}\n","import { errorFromResponse, SerpKiteError } from \"./errors\";\nimport type {\n Account,\n AutocompleteResponse,\n Batch,\n BatchCreateEntry,\n BatchCreateParams,\n BatchCreateResponse,\n CompactResponse,\n ImagesResponse,\n NewsResponse,\n PatentsResponse,\n PlacesResponse,\n RankParams,\n RankResponse,\n ReviewsParams,\n ReviewsResponse,\n ScholarResponse,\n SearchParams,\n SearchResponse,\n ShoppingResponse,\n VideosResponse,\n WebpageParams,\n WebpageResponse,\n} from \"./types\";\n\nexport const VERSION = \"0.3.0\";\nexport const DEFAULT_BASE_URL = \"https://api.serpkite.com\";\n\nexport interface SerpKiteOptions {\n /** API key (`skt_live_…`). Defaults to the `SERPKITE_API_KEY` environment variable. */\n apiKey?: string;\n /** Defaults to `SERPKITE_BASE_URL` or https://api.serpkite.com. */\n baseUrl?: string;\n /** Per-attempt timeout in milliseconds. Default 60000. */\n timeoutMs?: number;\n /** Retries after the first attempt on 429, 5xx and network errors. Default 2. */\n maxRetries?: number;\n /** Base delay of the exponential backoff in milliseconds. Default 500. */\n retryDelayMs?: number;\n /** Custom fetch implementation. Defaults to the global `fetch`. */\n fetch?: typeof fetch;\n /** Extra headers sent with every request. */\n headers?: Record<string, string>;\n}\n\n/** Billing and tracing details from the response headers. */\nexport interface ResponseInfo {\n status: number;\n headers: Headers;\n requestId: string | undefined;\n creditsUsed: number | undefined;\n creditsRemaining: number | undefined;\n costUsd: number | undefined;\n /** `HIT` when served from cache (`max_age`), else `MISS`. */\n cache: \"HIT\" | \"MISS\" | undefined;\n latencyMs: number | undefined;\n tokensEstimate: number | undefined;\n}\n\nexport interface RequestOptions {\n signal?: AbortSignal;\n /** Overrides the client's per-attempt timeout. */\n timeoutMs?: number;\n /** Overrides the client's retry count. */\n maxRetries?: number;\n headers?: Record<string, string>;\n /** Called with the final response's headers (credits used/remaining, cache, request id). */\n onResponse?: (info: ResponseInfo) => void;\n}\n\nexport interface BatchCreateOptions extends RequestOptions {\n /**\n * Sent as `Idempotency-Key` (1-255 printable ASCII characters, e.g. a UUID).\n * For 24 hours a retry with the same key and body returns the first response\n * instead of queueing and billing the jobs again.\n */\n idempotencyKey?: string;\n}\n\nexport interface WaitOptions {\n /** Give up after this many milliseconds. Default 600000 (10 minutes). */\n timeoutMs?: number;\n /** First delay between polls. Default 1000. Grows 1.5× per poll. */\n pollIntervalMs?: number;\n /** Upper bound of the delay between polls. Default 10000. */\n maxPollIntervalMs?: number;\n signal?: AbortSignal;\n}\n\n/** A vertical whose return type follows `format`: `\"markdown\"` → string, `\"compact\"` → CompactResponse. */\nexport interface VerticalMethod<P, R> {\n (params: P & { format: \"markdown\" }, options?: RequestOptions): Promise<string>;\n (params: P & { format: \"compact\" }, options?: RequestOptions): Promise<CompactResponse>;\n (params: P & { format?: \"json\" }, options?: RequestOptions): Promise<R>;\n (params: P, options?: RequestOptions): Promise<R | CompactResponse | string>;\n}\n\ntype Method = \"GET\" | \"POST\";\n\ninterface Call {\n method: Method;\n path: string;\n body?: unknown;\n options?: RequestOptions;\n /** Which failures are safe to retry. `all` = 429, 5xx and network errors. */\n retry?: \"all\" | \"rate_limit\";\n}\n\nexport class SerpKite {\n readonly baseUrl: string;\n readonly timeoutMs: number;\n readonly maxRetries: number;\n readonly retryDelayMs: number;\n readonly #apiKey: string;\n readonly #fetch: typeof fetch;\n readonly #headers: Record<string, string>;\n\n constructor(options: SerpKiteOptions = {}) {\n const apiKey = options.apiKey ?? env(\"SERPKITE_API_KEY\");\n if (!apiKey) {\n throw new SerpKiteError(\n 0,\n \"missing_api_key\",\n \"No API key: pass { apiKey } or set the SERPKITE_API_KEY environment variable\",\n );\n }\n this.#apiKey = apiKey;\n this.baseUrl = (options.baseUrl ?? env(\"SERPKITE_BASE_URL\") ?? DEFAULT_BASE_URL).replace(\n /\\/+$/,\n \"\",\n );\n this.timeoutMs = options.timeoutMs ?? 60_000;\n this.maxRetries = Math.max(0, options.maxRetries ?? 2);\n this.retryDelayMs = options.retryDelayMs ?? 500;\n const f = options.fetch ?? globalThis.fetch;\n if (typeof f !== \"function\") {\n throw new SerpKiteError(\n 0,\n \"missing_fetch\",\n \"No global fetch: pass { fetch } (Node 18+ has one)\",\n );\n }\n this.#fetch = f;\n this.#headers = { ...options.headers };\n }\n\n // ── Verticals ─────────────────────────────────────────────────────────\n\n /** Google web search: organic results, answer box, knowledge graph, people also ask… */\n readonly search = this.#vertical<SearchParams, SearchResponse>(\"/v1/search\");\n /** Google Images. */\n readonly images = this.#vertical<SearchParams, ImagesResponse>(\"/v1/images\");\n /** Google Videos. */\n readonly videos = this.#vertical<SearchParams, VideosResponse>(\"/v1/videos\");\n /** Google News. */\n readonly news = this.#vertical<SearchParams, NewsResponse>(\"/v1/news\");\n /** Google Maps search (places with coordinates). Accepts `ll` (\"@lat,lng,14z\"). */\n readonly maps = this.#vertical<SearchParams, PlacesResponse>(\"/v1/maps\");\n /** Google local results. */\n readonly places = this.#vertical<SearchParams, PlacesResponse>(\"/v1/places\");\n /** Reviews of a place by `place_id`, `cid` or `fid`. Page with `page_token` = `next_page_token`. */\n readonly reviews = this.#vertical<ReviewsParams, ReviewsResponse>(\"/v1/reviews\");\n /** Google Shopping. */\n readonly shopping = this.#vertical<SearchParams, ShoppingResponse>(\"/v1/shopping\");\n /** Google Scholar. */\n readonly scholar = this.#vertical<SearchParams, ScholarResponse>(\"/v1/scholar\");\n /** Google Patents. */\n readonly patents = this.#vertical<SearchParams, PatentsResponse>(\"/v1/patents\");\n /** Google autocomplete suggestions. */\n readonly autocomplete = this.#vertical<SearchParams, AutocompleteResponse>(\"/v1/autocomplete\");\n /** Fetch any public URL as clean Markdown plus metadata. */\n readonly webpage = this.#vertical<WebpageParams, WebpageResponse>(\"/v1/webpage\");\n\n /** Position of `domain` for keyword `q` in the top `num` results (default 100). */\n rank(params: RankParams, options?: RequestOptions): Promise<RankResponse> {\n return this.request({ method: \"POST\", path: \"/v1/rank\", body: params, options });\n }\n\n /** Balance, limits and this month's usage for the key's account. */\n account(options?: RequestOptions): Promise<Account> {\n return this.request({ method: \"GET\", path: \"/v1/account\", options });\n }\n\n // ── Batches ───────────────────────────────────────────────────────────\n\n readonly batches = {\n /**\n * Queue 1-100 requests for one endpoint at half price. Returns one entry per\n * request, in order: a queued `Batch` or an error object. Without an\n * `idempotencyKey` it is only retried on 429, so a lost response never queues\n * (and bills) the same requests twice. With one, 5xx and network errors are\n * retried too: the server replays the first response for the same key and body.\n */\n create: (\n params: BatchCreateParams,\n options: BatchCreateOptions = {},\n ): Promise<BatchCreateResponse> => {\n const { idempotencyKey, ...rest } = options;\n return this.request({\n method: \"POST\",\n path: \"/v1/batches\",\n body: params,\n options: idempotencyKey\n ? { ...rest, headers: { ...rest.headers, \"Idempotency-Key\": idempotencyKey } }\n : rest,\n retry: idempotencyKey ? \"all\" : \"rate_limit\",\n });\n },\n\n /** Poll one batch job. */\n get: (id: string, options?: RequestOptions): Promise<Batch> =>\n this.request({ method: \"GET\", path: `/v1/batches/${encodeURIComponent(id)}`, options }),\n\n /**\n * Poll until the job is `done` or `failed` and return it (a failed job is\n * returned, not thrown; check `status` and `error`). Accepts an id or an\n * entry from `create`; an entry that failed to queue throws its error.\n */\n wait: (idOrEntry: string | BatchCreateEntry | undefined, options: WaitOptions = {}) =>\n this.#wait(idOrEntry, options),\n };\n\n // ── Plumbing ──────────────────────────────────────────────────────────\n\n #vertical<P, R>(path: string): VerticalMethod<P, R> {\n return ((params: P, options?: RequestOptions) =>\n this.request({ method: \"POST\", path, body: params, options })) as VerticalMethod<P, R>;\n }\n\n async #wait(idOrEntry: string | BatchCreateEntry | undefined, o: WaitOptions): Promise<Batch> {\n let id: string | undefined;\n if (typeof idOrEntry === \"string\") {\n id = idOrEntry;\n } else if (idOrEntry && \"id\" in idOrEntry && typeof idOrEntry.id === \"string\") {\n id = idOrEntry.id;\n } else if (idOrEntry && \"error\" in idOrEntry && idOrEntry.error && !(\"id\" in idOrEntry)) {\n const e = idOrEntry.error as { code?: string; message?: string; request_id?: string };\n throw new SerpKiteError(\n 400,\n e.code ?? \"invalid_request\",\n e.message ?? \"batch entry was not queued\",\n e.request_id,\n );\n }\n if (!id) {\n throw new SerpKiteError(0, \"invalid_request\", \"batches.wait needs a batch id\");\n }\n const timeoutMs = o.timeoutMs ?? 600_000;\n const maxInterval = o.maxPollIntervalMs ?? 10_000;\n let interval = o.pollIntervalMs ?? 1_000;\n const deadline = Date.now() + timeoutMs;\n for (;;) {\n const batch = await this.batches.get(id, { signal: o.signal });\n if (batch.status === \"done\" || batch.status === \"failed\") return batch;\n const left = deadline - Date.now();\n if (left <= 0) {\n throw new SerpKiteError(\n 0,\n \"timeout\",\n `batch ${id} still ${batch.status} after ${timeoutMs} ms`,\n );\n }\n await sleep(Math.min(interval, left), o.signal);\n interval = Math.min(interval * 1.5, maxInterval);\n }\n }\n\n /** Low-level request: JSON body in, parsed JSON (or text for non-JSON responses) out. */\n async request<T>(call: Call): Promise<T> {\n const { method, path, body, options = {} } = call;\n const maxRetries = Math.max(0, options.maxRetries ?? this.maxRetries);\n const timeoutMs = options.timeoutMs ?? this.timeoutMs;\n const headers: Record<string, string> = {\n Accept: \"application/json, text/markdown;q=0.9\",\n Authorization: `Bearer ${this.#apiKey}`,\n ...this.#headers,\n ...options.headers,\n };\n if (body !== undefined) headers[\"Content-Type\"] = \"application/json\";\n // Browsers would turn a custom User-Agent into a CORS preflight header.\n if (!isBrowser()) headers[\"User-Agent\"] = `serpkite-typescript/${VERSION}`;\n const init: RequestInit = {\n method,\n headers,\n body: body === undefined ? undefined : JSON.stringify(body),\n };\n\n for (let attempt = 0; ; attempt++) {\n const canRetry = attempt < maxRetries;\n let res: Response;\n const { signal, cleanup, timedOut } = withTimeout(options.signal, timeoutMs);\n try {\n res = await this.#fetch(this.baseUrl + path, { ...init, signal });\n } catch (err) {\n cleanup();\n if (options.signal?.aborted) throw err;\n const code = timedOut() ? \"timeout\" : \"connection_error\";\n if (canRetry && call.retry !== \"rate_limit\") {\n await sleep(this.#backoff(attempt), options.signal);\n continue;\n }\n const msg = timedOut()\n ? `request timed out after ${timeoutMs} ms`\n : `request failed: ${err instanceof Error ? err.message : String(err)}`;\n throw new SerpKiteError(0, code, msg, undefined, undefined, { cause: err });\n }\n\n let text: string;\n try {\n text = await res.text();\n } catch (err) {\n cleanup();\n if (options.signal?.aborted) throw err;\n if (canRetry && call.retry !== \"rate_limit\") {\n await sleep(this.#backoff(attempt), options.signal);\n continue;\n }\n const code = timedOut() ? \"timeout\" : \"connection_error\";\n throw new SerpKiteError(\n 0,\n code,\n \"failed to read the response body\",\n undefined,\n res.headers,\n {\n cause: err,\n },\n );\n }\n cleanup();\n\n if (!res.ok) {\n const retryable = res.status === 429 || (res.status >= 500 && call.retry !== \"rate_limit\");\n if (canRetry && retryable) {\n await sleep(this.#retryDelay(attempt, res.headers), options.signal);\n continue;\n }\n throw errorFromResponse(res.status, res.headers, text);\n }\n\n options.onResponse?.(responseInfo(res));\n const type = res.headers.get(\"content-type\") ?? \"\";\n if (type.includes(\"json\")) {\n try {\n return JSON.parse(text) as T;\n } catch (err) {\n throw new SerpKiteError(\n res.status,\n \"invalid_response\",\n \"response is not valid JSON\",\n res.headers.get(\"x-request-id\") ?? undefined,\n res.headers,\n { cause: err },\n );\n }\n }\n return text as T;\n }\n }\n\n #backoff(attempt: number): number {\n const base = Math.min(this.retryDelayMs * 2 ** attempt, 8_000);\n return base / 2 + Math.random() * (base / 2);\n }\n\n #retryDelay(attempt: number, headers: Headers): number {\n const after = parseRetryAfter(headers.get(\"retry-after\"));\n return after === undefined ? this.#backoff(attempt) : Math.min(after, 60_000);\n }\n}\n\n// ── helpers ─────────────────────────────────────────────────────────────\n\n/** Parses Retry-After (seconds or an HTTP date) into milliseconds. */\nexport function parseRetryAfter(v: string | null): number | undefined {\n if (!v) return undefined;\n const secs = Number(v);\n if (Number.isFinite(secs)) return Math.max(0, secs * 1000);\n const at = Date.parse(v);\n return Number.isNaN(at) ? undefined : Math.max(0, at - Date.now());\n}\n\nfunction responseInfo(res: Response): ResponseInfo {\n const h = res.headers;\n const num = (name: string) => {\n const v = h.get(name);\n if (v === null || v === \"\") return undefined;\n const n = Number(v);\n return Number.isFinite(n) ? n : undefined;\n };\n const cache = h.get(\"x-cache\")?.toUpperCase();\n return {\n status: res.status,\n headers: h,\n requestId: h.get(\"x-request-id\") ?? undefined,\n creditsUsed: num(\"x-credits-used\"),\n creditsRemaining: num(\"x-credits-remaining\"),\n costUsd: num(\"x-cost-usd\"),\n cache: cache === \"HIT\" || cache === \"MISS\" ? cache : undefined,\n latencyMs: num(\"x-latency-ms\"),\n tokensEstimate: num(\"x-tokens-estimate\"),\n };\n}\n\nfunction withTimeout(outer: AbortSignal | undefined, ms: number) {\n const ctrl = new AbortController();\n let timedOut = false;\n const onAbort = () => ctrl.abort(outer?.reason);\n if (outer?.aborted) ctrl.abort(outer.reason);\n else outer?.addEventListener(\"abort\", onAbort, { once: true });\n const timer =\n ms > 0 && Number.isFinite(ms)\n ? setTimeout(() => {\n timedOut = true;\n ctrl.abort(new SerpKiteError(0, \"timeout\", `request timed out after ${ms} ms`));\n }, ms)\n : undefined;\n return {\n signal: ctrl.signal,\n timedOut: () => timedOut,\n cleanup: () => {\n if (timer !== undefined) clearTimeout(timer);\n outer?.removeEventListener(\"abort\", onAbort);\n },\n };\n}\n\nfunction sleep(ms: number, signal?: AbortSignal): Promise<void> {\n return new Promise((resolve, reject) => {\n if (signal?.aborted) return reject(signal.reason);\n const t = setTimeout(() => {\n signal?.removeEventListener(\"abort\", onAbort);\n resolve();\n }, ms);\n const onAbort = () => {\n clearTimeout(t);\n reject(signal?.reason);\n };\n signal?.addEventListener(\"abort\", onAbort, { once: true });\n });\n}\n\ntype EnvHost = {\n process?: { env?: Record<string, string | undefined> };\n Deno?: { env?: { get?: (name: string) => string | undefined } };\n document?: unknown;\n};\n\nfunction env(name: string): string | undefined {\n const g = globalThis as EnvHost;\n try {\n const v = g.process?.env?.[name];\n if (v) return v;\n } catch {\n // process.env may be a throwing proxy on some edge runtimes.\n }\n try {\n return g.Deno?.env?.get?.(name) || undefined;\n } catch {\n // Deno without --allow-env.\n return undefined;\n }\n}\n\nfunction isBrowser(): boolean {\n return typeof (globalThis as EnvHost).document !== \"undefined\";\n}\n","import type { BatchCreateEntry, BatchCreateError } from \"./types\";\n\n/** True when a `batches.create` entry was rejected instead of queued. */\nexport function isBatchError(entry: BatchCreateEntry): entry is BatchCreateError {\n return !(\"id\" in entry && typeof entry.id === \"string\") && \"error\" in entry && !!entry.error;\n}\n","/** Options for {@link verifyWebhook}. */\nexport interface VerifyWebhookOptions {\n /** Reject deliveries whose timestamp is further than this from now. Default 300. */\n toleranceSeconds?: number;\n /** Current time in Unix seconds (tests). */\n now?: number;\n}\n\ntype HeaderSource = Headers | Record<string, string | string[] | undefined>;\n\nfunction header(headers: HeaderSource, name: string): string | undefined {\n if (typeof (headers as Headers).get === \"function\") {\n return (headers as Headers).get(name) ?? undefined;\n }\n const rec = headers as Record<string, string | string[] | undefined>;\n const key = Object.keys(rec).find((k) => k.toLowerCase() === name.toLowerCase());\n const v = key === undefined ? undefined : rec[key];\n return Array.isArray(v) ? v[0] : v;\n}\n\n/**\n * Checks a batch webhook delivery: `X-SerpKite-Signature` must be\n * `v1=<hex HMAC-SHA256(secret, \"<X-SerpKite-Timestamp>.<raw body>\")>` and the\n * timestamp recent. Pass the raw request body exactly as received (not\n * re-serialised JSON). Uses Web Crypto (Node 18+, Deno, Bun, browsers).\n *\n * ```ts\n * const ok = await verifyWebhook(process.env.SERPKITE_WEBHOOK_SECRET!, rawBody, req.headers);\n * ```\n */\nexport async function verifyWebhook(\n secret: string,\n payload: string | Uint8Array,\n headers: HeaderSource,\n options: VerifyWebhookOptions = {},\n): Promise<boolean> {\n const signature = header(headers, \"x-serpkite-signature\");\n const ts = header(headers, \"x-serpkite-timestamp\");\n if (!secret || !signature?.startsWith(\"v1=\") || !ts || !/^\\d+$/.test(ts)) return false;\n const now = options.now ?? Math.floor(Date.now() / 1000);\n if (Math.abs(now - Number(ts)) > (options.toleranceSeconds ?? 300)) return false;\n\n const enc = new TextEncoder();\n const body = typeof payload === \"string\" ? enc.encode(payload) : payload;\n const prefix = enc.encode(`${ts}.`);\n const msg = new Uint8Array(prefix.length + body.length);\n msg.set(prefix);\n msg.set(body, prefix.length);\n const key = await crypto.subtle.importKey(\n \"raw\",\n enc.encode(secret),\n { name: \"HMAC\", hash: \"SHA-256\" },\n false,\n [\"sign\"],\n );\n const mac = new Uint8Array(await crypto.subtle.sign(\"HMAC\", key, msg));\n const want = Array.from(mac, (b) => b.toString(16).padStart(2, \"0\")).join(\"\");\n const got = signature.slice(3).toLowerCase();\n if (got.length !== want.length) return false;\n let diff = 0;\n for (let i = 0; i < want.length; i++) diff |= want.charCodeAt(i) ^ got.charCodeAt(i);\n return diff === 0;\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "serpkite",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "Official TypeScript/JavaScript SDK for SerpKite, the Google search API built for AI agents: clean JSON or Markdown results.",
5
5
  "license": "MIT",
6
6
  "author": "SerpKite",