@openserp/sdk 0.1.1 → 0.1.3
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 +46 -16
- package/dist/index.cjs +110 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +39 -2
- package/dist/index.d.ts +39 -2
- package/dist/index.js +110 -5
- package/dist/index.js.map +1 -1
- package/package.json +28 -4
package/README.md
CHANGED
|
@@ -4,9 +4,37 @@
|
|
|
4
4
|
[](https://www.npmjs.com/package/@openserp/sdk)
|
|
5
5
|
[](https://github.com/karust/openserp/blob/master/LICENSE)
|
|
6
6
|
|
|
7
|
+
```bash
|
|
8
|
+
npm install @openserp/sdk
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Cloud:
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
import { OpenSERP } from "@openserp/sdk";
|
|
15
|
+
|
|
16
|
+
const client = new OpenSERP({ apiKey: process.env.OPENSERP_KEY });
|
|
17
|
+
const { results } = await client.search({ engine: "google", text: "openserp" });
|
|
18
|
+
|
|
19
|
+
console.log(results[0]?.title, results[0]?.url);
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Self-hosted:
|
|
23
|
+
|
|
24
|
+
```ts
|
|
25
|
+
import { OpenSERP } from "@openserp/sdk";
|
|
26
|
+
|
|
27
|
+
const client = new OpenSERP({ baseUrl: "http://localhost:7000" });
|
|
28
|
+
const { results } = await client.search({ engine: "bing", text: "openserp" });
|
|
29
|
+
|
|
30
|
+
console.log(results[0]?.title, results[0]?.url);
|
|
31
|
+
```
|
|
32
|
+
|
|
7
33
|
Universal TypeScript / JavaScript SDK for the **OpenSERP** multi-engine SERP API — Google, Bing, Yandex, Baidu, DuckDuckGo, and Ecosia results in a single call. Works against the self-hosted [open source server](https://github.com/karust/openserp) and against [OpenSERP Cloud](https://openserp.org/cloud) with the same code.
|
|
8
34
|
|
|
9
|
-
Use it for AI grounding, RAG pipelines, LLM tool use, SEO
|
|
35
|
+
Use it for AI grounding, RAG pipelines, LLM tool use, agent tool use, LangChain / LlamaIndex integrations, SEO rank tracking, competitor analysis, and search-powered automations. Open-source alternative to SerpAPI, DataForSEO, ScrapingBee, Bright Data SERP, Oxylabs SERP, and Zenserp.
|
|
36
|
+
|
|
37
|
+
> Also available for Python: [`openserp`](https://pypi.org/project/openserp/) ([source](https://github.com/karust/openserp/tree/master/integrations/sdk-python)).
|
|
10
38
|
|
|
11
39
|
> **Alpha — the API may change before `1.0.0`.** Pin a version in production.
|
|
12
40
|
|
|
@@ -22,7 +50,6 @@ Use it for AI grounding, RAG pipelines, LLM tool use, SEO monitoring, competitor
|
|
|
22
50
|
- [Telemetry](#telemetry)
|
|
23
51
|
- [Error handling](#error-handling)
|
|
24
52
|
- [Retry hook](#retry-hook)
|
|
25
|
-
- [Edge runtimes](#edge-runtimes)
|
|
26
53
|
- [Use cases](#use-cases)
|
|
27
54
|
- [Development](#development)
|
|
28
55
|
|
|
@@ -162,11 +189,7 @@ await client.enginesStatus();
|
|
|
162
189
|
await client.enginesCapabilities();
|
|
163
190
|
```
|
|
164
191
|
|
|
165
|
-
The backend is inferred from `baseUrl` and `apiKey`.
|
|
166
|
-
|
|
167
|
-
```ts
|
|
168
|
-
client.config.backend = "oss";
|
|
169
|
-
```
|
|
192
|
+
The backend is inferred from `baseUrl` and `apiKey`. Pass `backend: "oss"` or `backend: "cloud"` to the constructor to override.
|
|
170
193
|
|
|
171
194
|
## Telemetry
|
|
172
195
|
|
|
@@ -204,10 +227,19 @@ try {
|
|
|
204
227
|
The SDK does not apply a retry policy. Provide a hook when you want one:
|
|
205
228
|
|
|
206
229
|
```ts
|
|
230
|
+
import { OpenSERP, SERPError } from "@openserp/sdk";
|
|
231
|
+
|
|
232
|
+
const RETRYABLE = new Set([408, 429, 500, 502, 503]);
|
|
233
|
+
|
|
207
234
|
const client = new OpenSERP({
|
|
208
|
-
|
|
209
|
-
retry: (err, attempt) => {
|
|
210
|
-
|
|
235
|
+
apiKey: process.env.OPENSERP_KEY,
|
|
236
|
+
retry: async (err, attempt) => {
|
|
237
|
+
if (attempt >= 2 || !(err instanceof SERPError) || !RETRYABLE.has(err.status)) {
|
|
238
|
+
return false;
|
|
239
|
+
}
|
|
240
|
+
const wait = Math.min(2 ** attempt * 250, 8_000) + Math.random() * 250;
|
|
241
|
+
await new Promise((r) => setTimeout(r, wait));
|
|
242
|
+
return true;
|
|
211
243
|
},
|
|
212
244
|
});
|
|
213
245
|
```
|
|
@@ -218,20 +250,18 @@ const client = new OpenSERP({
|
|
|
218
250
|
- **LLM tool use** — expose `client.search` as a tool to your agent.
|
|
219
251
|
- **SEO monitoring** — daily rank tracking across multiple engines and regions, export to Sheets or Notion.
|
|
220
252
|
- **Competitor analysis** — weekly diff of top-10 results for a keyword set.
|
|
221
|
-
- **Automations**
|
|
222
253
|
- **Data pipelines** — stream SERPs to ClickHouse, BigQuery, or a DataFrame for NLP on snippets.
|
|
223
254
|
|
|
224
255
|
## Development
|
|
225
256
|
|
|
226
257
|
```bash
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
corepack pnpm build
|
|
258
|
+
pnpm install
|
|
259
|
+
pnpm test
|
|
260
|
+
pnpm build
|
|
231
261
|
```
|
|
232
262
|
|
|
233
263
|
Regenerate OSS API types after changing `openserp/docs/openapi.yaml`:
|
|
234
264
|
|
|
235
265
|
```bash
|
|
236
|
-
|
|
266
|
+
pnpm generate:types
|
|
237
267
|
```
|
package/dist/index.cjs
CHANGED
|
@@ -147,6 +147,80 @@ function isErrorResponse(body) {
|
|
|
147
147
|
return typeof body === "object" && body !== null && "error" in body;
|
|
148
148
|
}
|
|
149
149
|
|
|
150
|
+
// src/debug.ts
|
|
151
|
+
var NO_OP = {
|
|
152
|
+
level: "off",
|
|
153
|
+
emit() {
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
function resolveDebug(config) {
|
|
157
|
+
const setting = config.debug ?? envDebug();
|
|
158
|
+
if (!setting) {
|
|
159
|
+
return NO_OP;
|
|
160
|
+
}
|
|
161
|
+
if (typeof setting === "function") {
|
|
162
|
+
return { level: "verbose", emit: guard(setting) };
|
|
163
|
+
}
|
|
164
|
+
const level = setting === "verbose" ? "verbose" : "info";
|
|
165
|
+
return { level, emit: consoleSink };
|
|
166
|
+
}
|
|
167
|
+
function envDebug() {
|
|
168
|
+
const value = typeof process !== "undefined" ? process.env?.OPENSERP_DEBUG : void 0;
|
|
169
|
+
if (!value) {
|
|
170
|
+
return void 0;
|
|
171
|
+
}
|
|
172
|
+
const normalized = value.trim().toLowerCase();
|
|
173
|
+
if (normalized === "verbose") {
|
|
174
|
+
return "verbose";
|
|
175
|
+
}
|
|
176
|
+
if (normalized === "1" || normalized === "true") {
|
|
177
|
+
return true;
|
|
178
|
+
}
|
|
179
|
+
return void 0;
|
|
180
|
+
}
|
|
181
|
+
function guard(sink) {
|
|
182
|
+
return (event) => {
|
|
183
|
+
try {
|
|
184
|
+
sink(event);
|
|
185
|
+
} catch {
|
|
186
|
+
}
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
var consoleSink = (event) => {
|
|
190
|
+
switch (event.type) {
|
|
191
|
+
case "request":
|
|
192
|
+
console.error(`[openserp] \u2192 ${event.method} ${event.url}`);
|
|
193
|
+
if (event.headers) {
|
|
194
|
+
console.error("[openserp] headers:", event.headers);
|
|
195
|
+
}
|
|
196
|
+
break;
|
|
197
|
+
case "response": {
|
|
198
|
+
const engine = event.engineUsed ? ` engine=${event.engineUsed}` : "";
|
|
199
|
+
const reqId = event.requestId ? ` request-id=${event.requestId}` : "";
|
|
200
|
+
console.error(
|
|
201
|
+
`[openserp] \u2190 ${event.status} ${event.method} ${event.url} (${event.durationMs}ms)${engine}${reqId}`
|
|
202
|
+
);
|
|
203
|
+
if (event.headers) {
|
|
204
|
+
console.error("[openserp] headers:", event.headers);
|
|
205
|
+
}
|
|
206
|
+
break;
|
|
207
|
+
}
|
|
208
|
+
case "error":
|
|
209
|
+
console.error(
|
|
210
|
+
`[openserp] \u2715 ${event.method} ${event.url} (${event.durationMs}ms):`,
|
|
211
|
+
event.error
|
|
212
|
+
);
|
|
213
|
+
break;
|
|
214
|
+
}
|
|
215
|
+
};
|
|
216
|
+
function dumpHeaders(headers) {
|
|
217
|
+
const out = {};
|
|
218
|
+
for (const [key, value] of headers) {
|
|
219
|
+
out[key] = key.toLowerCase() === "authorization" ? "Bearer ***" : value;
|
|
220
|
+
}
|
|
221
|
+
return out;
|
|
222
|
+
}
|
|
223
|
+
|
|
150
224
|
// src/request.ts
|
|
151
225
|
async function request(context, options) {
|
|
152
226
|
let attempt = 0;
|
|
@@ -176,13 +250,24 @@ async function requestOnce({ baseUrl, config, setLastResponse }, options) {
|
|
|
176
250
|
for (const [key, value] of new Headers(options.headers)) {
|
|
177
251
|
headers.set(key, value);
|
|
178
252
|
}
|
|
253
|
+
const debug = resolveDebug(config);
|
|
254
|
+
const method = options.method ?? "GET";
|
|
255
|
+
if (debug.level !== "off") {
|
|
256
|
+
debug.emit({
|
|
257
|
+
type: "request",
|
|
258
|
+
method,
|
|
259
|
+
url: url.toString(),
|
|
260
|
+
...debug.level === "verbose" ? { headers: dumpHeaders(headers) } : {}
|
|
261
|
+
});
|
|
262
|
+
}
|
|
179
263
|
const timeoutMs = config.timeoutMs ?? 3e4;
|
|
180
264
|
const controller = new AbortController();
|
|
181
265
|
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
266
|
+
const startedAt = Date.now();
|
|
182
267
|
let response;
|
|
183
268
|
try {
|
|
184
269
|
const init = {
|
|
185
|
-
method
|
|
270
|
+
method,
|
|
186
271
|
headers,
|
|
187
272
|
signal: controller.signal
|
|
188
273
|
};
|
|
@@ -191,14 +276,34 @@ async function requestOnce({ baseUrl, config, setLastResponse }, options) {
|
|
|
191
276
|
}
|
|
192
277
|
response = await fetchImpl(url, init);
|
|
193
278
|
} catch (err) {
|
|
194
|
-
|
|
195
|
-
|
|
279
|
+
const error = isAbortError(err) ? new TimeoutError(timeoutMs, err) : err;
|
|
280
|
+
if (debug.level !== "off") {
|
|
281
|
+
debug.emit({
|
|
282
|
+
type: "error",
|
|
283
|
+
method,
|
|
284
|
+
url: url.toString(),
|
|
285
|
+
durationMs: Date.now() - startedAt,
|
|
286
|
+
error
|
|
287
|
+
});
|
|
196
288
|
}
|
|
197
|
-
throw
|
|
289
|
+
throw error;
|
|
198
290
|
} finally {
|
|
199
291
|
clearTimeout(timer);
|
|
200
292
|
}
|
|
201
|
-
|
|
293
|
+
const last = readLastResponse(response);
|
|
294
|
+
setLastResponse(last);
|
|
295
|
+
if (debug.level !== "off") {
|
|
296
|
+
debug.emit({
|
|
297
|
+
type: "response",
|
|
298
|
+
method,
|
|
299
|
+
url: url.toString(),
|
|
300
|
+
status: response.status,
|
|
301
|
+
engineUsed: last.engineUsed,
|
|
302
|
+
requestId: last.requestId,
|
|
303
|
+
durationMs: Date.now() - startedAt,
|
|
304
|
+
...debug.level === "verbose" ? { headers: dumpHeaders(response.headers) } : {}
|
|
305
|
+
});
|
|
306
|
+
}
|
|
202
307
|
const body = await readBody(response, options.format);
|
|
203
308
|
if (!response.ok) {
|
|
204
309
|
throw errorFromResponse(response.status, body, response.headers.get("x-request-id") ?? void 0);
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/backend.ts","../src/errors.ts","../src/request.ts","../src/client.ts"],"sourcesContent":["export { OpenSERP } from \"./client\";\nexport {\n CLOUD_BASE_URL,\n OSS_BASE_URL,\n inferBackend,\n normalizeBaseUrl,\n resolveBaseUrl,\n} from \"./backend\";\nexport {\n CaptchaError,\n CloudOnlyError,\n OssOnlyError,\n RateLimitError,\n SERPError,\n TimeoutError,\n} from \"./errors\";\nexport type {\n Backend,\n CacheStats,\n CircuitBreakerStatsResponse,\n Engine,\n ErrorResponse,\n HealthStatus,\n ImageEnvelope,\n ImageParams,\n LastResponse,\n MegaEnginesResponse,\n MegaImageParams,\n MegaMode,\n MegaSearchEnvelope,\n MegaSearchParams,\n OpenSERPConfig,\n ParseParams,\n ProxyStats,\n ReadinessStatus,\n ResponseFormat,\n SearchEnvelope,\n SearchParams,\n StatsResponse,\n} from \"./types/public\";\nexport type {\n CloudAccount,\n CreditInfo,\n EngineCapability,\n EngineStatus,\n EnginesCapabilities,\n EnginesStatus,\n ModeCapability,\n OverallStatus,\n Price,\n Pricing,\n} from \"./types/cloud\";\n","import type { Backend, OpenSERPConfig } from \"./types/public\";\n\nexport const OSS_BASE_URL = \"http://localhost:7000\";\nexport const CLOUD_BASE_URL = \"https://api.openserp.org/v1\";\n\nexport function normalizeBaseUrl(baseUrl: string): string {\n return baseUrl.replace(/\\/+$/, \"\");\n}\n\nexport function resolveBaseUrl(config: OpenSERPConfig): string {\n if (config.baseUrl) {\n return normalizeBaseUrl(config.baseUrl);\n }\n\n if (config.apiKey) {\n return CLOUD_BASE_URL;\n }\n\n return OSS_BASE_URL;\n}\n\nexport function inferBackend(config: Pick<OpenSERPConfig, \"apiKey\" | \"baseUrl\" | \"backend\">): Backend {\n if (config.backend) {\n return config.backend;\n }\n\n if (config.baseUrl) {\n try {\n if (new URL(config.baseUrl).hostname === \"api.openserp.org\") {\n return \"cloud\";\n }\n } catch {\n if (config.baseUrl.includes(\"api.openserp.org\")) {\n return \"cloud\";\n }\n }\n }\n\n if (config.apiKey) {\n return \"cloud\";\n }\n\n return \"oss\";\n}\n","import type { ErrorResponse } from \"./types/public\";\n\nexport class SERPError extends Error {\n readonly status: number;\n readonly code?: string | undefined;\n readonly reason?: string | undefined;\n readonly requestId?: string | undefined;\n readonly meta?: Record<string, unknown> | undefined;\n readonly response?: ErrorResponse | unknown | undefined;\n\n constructor(message: string, options: {\n status?: number | undefined;\n code?: string | undefined;\n reason?: string | undefined;\n requestId?: string | undefined;\n meta?: Record<string, unknown> | undefined;\n response?: ErrorResponse | unknown | undefined;\n cause?: unknown | undefined;\n } = {}) {\n super(message, { cause: options.cause });\n this.name = \"SERPError\";\n this.status = options.status ?? 0;\n this.code = options.code;\n this.reason = options.reason;\n this.requestId = options.requestId;\n this.meta = options.meta;\n this.response = options.response;\n }\n}\n\nexport class RateLimitError extends SERPError {\n constructor(message: string, options: ConstructorParameters<typeof SERPError>[1] = {}) {\n super(message, options);\n this.name = \"RateLimitError\";\n }\n}\n\nexport class CaptchaError extends SERPError {\n constructor(message: string, options: ConstructorParameters<typeof SERPError>[1] = {}) {\n super(message, options);\n this.name = \"CaptchaError\";\n }\n}\n\nexport class CloudOnlyError extends SERPError {\n constructor(method: string) {\n super(`${method} is only available against OpenSERP Cloud. Configure apiKey/baseUrl for https://api.openserp.org/v1 or set client.config.backend = \"cloud\".`);\n this.name = \"CloudOnlyError\";\n }\n}\n\nexport class OssOnlyError extends SERPError {\n constructor(method: string) {\n super(`${method} is only available against a self-hosted OpenSERP server. Configure baseUrl for your OSS server or set client.config.backend = \"oss\".`);\n this.name = \"OssOnlyError\";\n }\n}\n\nexport class TimeoutError extends SERPError {\n constructor(timeoutMs: number, cause?: unknown) {\n super(`OpenSERP request timed out after ${timeoutMs}ms`, {\n code: \"request_timeout\",\n cause,\n });\n this.name = \"TimeoutError\";\n }\n}\n\nexport function errorFromResponse(status: number, body: unknown, requestId?: string): SERPError {\n const data = isErrorResponse(body) ? body : undefined;\n const code = data?.error;\n const message = data?.message ?? `OpenSERP request failed with status ${status}`;\n const options = {\n status,\n code,\n reason: data?.reason,\n requestId: data?.request_id ?? requestId,\n meta: data?.meta as Record<string, unknown> | undefined,\n response: body,\n };\n\n if (status === 429 || code === \"rate_limited\") {\n return new RateLimitError(message, options);\n }\n\n if (code === \"captcha_detected\") {\n return new CaptchaError(message, options);\n }\n\n return new SERPError(message, options);\n}\n\nfunction isErrorResponse(body: unknown): body is ErrorResponse {\n return typeof body === \"object\" && body !== null && \"error\" in body;\n}\n","import { TimeoutError, errorFromResponse } from \"./errors\";\nimport type { LastResponse, OpenSERPConfig, ResponseFormat } from \"./types/public\";\n\nexport type QueryValue =\n | string\n | number\n | boolean\n | readonly string[]\n | undefined\n | null;\n\nexport interface RequestOptions {\n method?: \"GET\" | \"POST\" | undefined;\n path: string;\n query?: Record<string, QueryValue> | undefined;\n headers?: HeadersInit | undefined;\n body?: BodyInit | null | undefined;\n format?: ResponseFormat | undefined;\n}\n\nexport interface RequestContext {\n baseUrl: string;\n config: OpenSERPConfig;\n setLastResponse(response: LastResponse): void;\n}\n\nexport async function request<T>(\n context: RequestContext,\n options: RequestOptions,\n): Promise<T> {\n let attempt = 0;\n\n for (;;) {\n try {\n return await requestOnce<T>(context, options);\n } catch (err) {\n const shouldRetry = await context.config.retry?.(err, attempt);\n if (!shouldRetry) {\n throw err;\n }\n attempt += 1;\n }\n }\n}\n\nasync function requestOnce<T>(\n { baseUrl, config, setLastResponse }: RequestContext,\n options: RequestOptions,\n): Promise<T> {\n const fetchImpl = config.fetch ?? globalThis.fetch;\n if (!fetchImpl) {\n throw new TypeError(\"OpenSERP SDK requires a fetch implementation.\");\n }\n\n const url = new URL(`${baseUrl}${options.path}`);\n appendQuery(url, options.query);\n\n const headers = new Headers(config.headers);\n if (config.apiKey) {\n headers.set(\"Authorization\", `Bearer ${config.apiKey}`);\n }\n for (const [key, value] of new Headers(options.headers)) {\n headers.set(key, value);\n }\n\n const timeoutMs = config.timeoutMs ?? 30_000;\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), timeoutMs);\n\n let response: Response;\n try {\n const init: RequestInit = {\n method: options.method ?? \"GET\",\n headers,\n signal: controller.signal,\n };\n if (options.body !== undefined) {\n init.body = options.body;\n }\n\n response = await fetchImpl(url, init);\n } catch (err) {\n if (isAbortError(err)) {\n throw new TimeoutError(timeoutMs, err);\n }\n throw err;\n } finally {\n clearTimeout(timer);\n }\n\n setLastResponse(readLastResponse(response));\n\n const body = await readBody(response, options.format);\n if (!response.ok) {\n throw errorFromResponse(response.status, body, response.headers.get(\"x-request-id\") ?? undefined);\n }\n\n return body as T;\n}\n\nfunction appendQuery(url: URL, query: Record<string, QueryValue> | undefined): void {\n if (!query) {\n return;\n }\n\n for (const [key, value] of Object.entries(query)) {\n if (value === undefined || value === null) {\n continue;\n }\n const encoded = Array.isArray(value) ? value.join(\",\") : String(value);\n url.searchParams.set(key, encoded);\n }\n}\n\nasync function readBody(response: Response, format?: ResponseFormat): Promise<unknown> {\n if (response.status === 204) {\n return undefined;\n }\n\n if (format && format !== \"json\") {\n return response.text();\n }\n\n const contentType = response.headers.get(\"content-type\") ?? \"\";\n if (contentType.includes(\"application/json\")) {\n return response.json();\n }\n\n const text = await response.text();\n if (!text) {\n return undefined;\n }\n\n try {\n return JSON.parse(text);\n } catch {\n return text;\n }\n}\n\nfunction readLastResponse(response: Response): LastResponse {\n const credits = {\n used: numberHeader(response.headers, \"x-credits-used\"),\n remaining: numberHeader(response.headers, \"x-credits-remaining\"),\n };\n const hasCredits = credits.used !== undefined || credits.remaining !== undefined;\n\n return {\n status: response.status,\n requestId: response.headers.get(\"x-request-id\") ?? undefined,\n credits: hasCredits ? credits : undefined,\n engineUsed: response.headers.get(\"x-engine-used\") ?? undefined,\n fallbackEngine: response.headers.get(\"x-fallback-engine\") ?? undefined,\n cache: response.headers.get(\"x-cache\") ?? undefined,\n proxyMode: response.headers.get(\"x-proxy-mode\") ?? undefined,\n proxyTag: response.headers.get(\"x-proxy-tag\") ?? undefined,\n proxyUsed: response.headers.get(\"x-proxy-used\") ?? undefined,\n networkBytes: numberHeader(response.headers, \"x-network-bytes\"),\n browserProfileId: response.headers.get(\"x-browser-profile-id\") ?? undefined,\n headers: response.headers,\n };\n}\n\nfunction numberHeader(headers: Headers, name: string): number | undefined {\n const value = headers.get(name);\n if (value === null || value === \"\") {\n return undefined;\n }\n const parsed = Number(value);\n return Number.isFinite(parsed) ? parsed : undefined;\n}\n\nfunction isAbortError(err: unknown): boolean {\n return err instanceof DOMException && err.name === \"AbortError\";\n}\n","import { inferBackend, resolveBaseUrl } from \"./backend\";\nimport { CloudOnlyError, OssOnlyError } from \"./errors\";\nimport { request, type QueryValue } from \"./request\";\nimport type {\n CacheStats,\n CircuitBreakerStatsResponse,\n HealthStatus,\n ImageEnvelope,\n ImageParams,\n LastResponse,\n MegaEnginesResponse,\n MegaImageParams,\n MegaSearchEnvelope,\n MegaSearchParams,\n OpenSERPConfig,\n ParseParams,\n ReadinessStatus,\n SearchEnvelope,\n SearchParams,\n StatsResponse,\n ProxyStats,\n} from \"./types/public\";\nimport type {\n CloudAccount,\n EnginesCapabilities,\n EnginesStatus,\n Pricing,\n} from \"./types/cloud\";\n\nexport class OpenSERP {\n readonly config: OpenSERPConfig;\n lastResponse?: LastResponse;\n\n constructor(config: OpenSERPConfig = {}) {\n this.config = { ...config };\n }\n\n get backend() {\n return inferBackend(this.config);\n }\n\n get baseUrl() {\n return resolveBaseUrl(this.config);\n }\n\n search(params: SearchParams): Promise<SearchEnvelope | string> {\n const { engine, format, ...query } = params;\n return this.get<SearchEnvelope | string>(`/${engine}/search`, query, format);\n }\n\n image(params: ImageParams): Promise<ImageEnvelope | string> {\n const { engine, format, ...query } = params;\n return this.get<ImageEnvelope | string>(`/${engine}/image`, query, format);\n }\n\n megaSearch(params: MegaSearchParams): Promise<MegaSearchEnvelope | string> {\n const { format, ...query } = params;\n return this.get<MegaSearchEnvelope | string>(\"/mega/search\", query, format);\n }\n\n fastSearch(params: Omit<MegaSearchParams, \"mode\">): Promise<MegaSearchEnvelope | string> {\n return this.megaSearch({ ...params, mode: \"fast\" });\n }\n\n anySearch(params: Omit<MegaSearchParams, \"mode\">): Promise<MegaSearchEnvelope | string> {\n return this.megaSearch({ ...params, mode: \"any\" });\n }\n\n megaImage(params: MegaImageParams): Promise<ImageEnvelope | string> {\n const { format, ...query } = params;\n return this.get<ImageEnvelope | string>(\"/mega/image\", query, format);\n }\n\n fastImage(params: Omit<MegaImageParams, \"mode\">): Promise<ImageEnvelope | string> {\n return this.megaImage({ ...params, mode: \"fast\" });\n }\n\n anyImage(params: Omit<MegaImageParams, \"mode\">): Promise<ImageEnvelope | string> {\n return this.megaImage({ ...params, mode: \"any\" });\n }\n\n parseGoogle(params: ParseParams): Promise<SearchEnvelope | string> {\n this.assertOss(\"parseGoogle\");\n return this.parse(\"/google/parse\", params);\n }\n\n parseBing(params: ParseParams): Promise<SearchEnvelope | string> {\n this.assertOss(\"parseBing\");\n return this.parse(\"/bing/parse\", params);\n }\n\n health(): Promise<HealthStatus> {\n this.assertOss(\"health\");\n return this.get<HealthStatus>(\"/health\");\n }\n\n ready(): Promise<ReadinessStatus> {\n this.assertOss(\"ready\");\n return this.get<ReadinessStatus>(\"/ready\");\n }\n\n stats(): Promise<StatsResponse> {\n this.assertOss(\"stats\");\n return this.get<StatsResponse>(\"/stats\");\n }\n\n cacheStats(): Promise<CacheStats> {\n this.assertOss(\"cacheStats\");\n return this.get<CacheStats>(\"/stats/cache\");\n }\n\n proxyStats(): Promise<ProxyStats> {\n this.assertOss(\"proxyStats\");\n return this.get<ProxyStats>(\"/stats/proxy\");\n }\n\n circuitBreakerStats(): Promise<CircuitBreakerStatsResponse> {\n this.assertOss(\"circuitBreakerStats\");\n return this.get<CircuitBreakerStatsResponse>(\"/stats/cb\");\n }\n\n engines(): Promise<MegaEnginesResponse> {\n this.assertOss(\"engines\");\n return this.get<MegaEnginesResponse>(\"/mega/engines\");\n }\n\n me(): Promise<CloudAccount> {\n this.assertCloud(\"me\");\n return this.get<CloudAccount>(\"/me\");\n }\n\n pricing(): Promise<Pricing> {\n this.assertCloud(\"pricing\");\n return this.get<Pricing>(\"/pricing\");\n }\n\n enginesStatus(): Promise<EnginesStatus> {\n this.assertCloud(\"enginesStatus\");\n return this.get<EnginesStatus>(\"/engines/status\");\n }\n\n enginesCapabilities(): Promise<EnginesCapabilities> {\n this.assertCloud(\"enginesCapabilities\");\n return this.get<EnginesCapabilities>(\"/engines/capabilities\");\n }\n\n private parse(path: string, params: ParseParams): Promise<SearchEnvelope | string> {\n return request<SearchEnvelope | string>(this.requestContext(), {\n method: \"POST\",\n path,\n query: params.format ? { format: params.format } : undefined,\n headers: {\n \"Content-Type\": \"text/html; charset=utf-8\",\n },\n body: params.html,\n format: params.format,\n });\n }\n\n private get<T>(\n path: string,\n query?: Record<string, QueryValue>,\n format?: SearchParams[\"format\"],\n ): Promise<T> {\n const { query: cleanQuery, headers } = splitQueryAndHeaders({\n ...query,\n format,\n });\n\n return request<T>(this.requestContext(), {\n path,\n query: cleanQuery,\n headers,\n format,\n });\n }\n\n private requestContext() {\n return {\n baseUrl: this.baseUrl,\n config: this.config,\n setLastResponse: (response: LastResponse) => {\n this.lastResponse = response;\n },\n };\n }\n\n private assertCloud(method: string): void {\n if (this.backend !== \"cloud\") {\n throw new CloudOnlyError(method);\n }\n }\n\n private assertOss(method: string): void {\n if (this.backend !== \"oss\") {\n throw new OssOnlyError(method);\n }\n }\n}\n\nfunction splitQueryAndHeaders(query: Record<string, QueryValue>): {\n query: Record<string, QueryValue>;\n headers: HeadersInit;\n} {\n const {\n useProxy,\n proxyUrl,\n proxyCountry,\n proxyClass,\n proxyProvider,\n proxySessionId,\n tenant,\n ...cleanQuery\n } = query;\n const headers: Record<string, string> = {};\n\n addHeader(headers, \"X-Use-Proxy\", useProxy);\n addHeader(headers, \"X-Proxy-URL\", proxyUrl);\n addHeader(headers, \"X-Proxy-Country\", proxyCountry);\n addHeader(headers, \"X-Proxy-Class\", proxyClass);\n addHeader(headers, \"X-Proxy-Provider\", proxyProvider);\n addHeader(headers, \"X-Proxy-Session-ID\", proxySessionId);\n addHeader(headers, \"X-Tenant\", tenant);\n\n return { query: cleanQuery, headers };\n}\n\nfunction addHeader(headers: Record<string, string>, name: string, value: QueryValue): void {\n if (value === undefined || value === null) {\n return;\n }\n headers[name] = Array.isArray(value) ? value.join(\",\") : String(value);\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/backend.ts","../src/errors.ts","../src/debug.ts","../src/request.ts","../src/client.ts"],"sourcesContent":["export { OpenSERP } from \"./client\";\nexport {\n CLOUD_BASE_URL,\n OSS_BASE_URL,\n inferBackend,\n normalizeBaseUrl,\n resolveBaseUrl,\n} from \"./backend\";\nexport {\n CaptchaError,\n CloudOnlyError,\n OssOnlyError,\n RateLimitError,\n SERPError,\n TimeoutError,\n} from \"./errors\";\nexport type {\n Backend,\n CacheStats,\n CircuitBreakerStatsResponse,\n DebugEvent,\n Engine,\n ErrorResponse,\n HealthStatus,\n ImageEnvelope,\n ImageParams,\n LastResponse,\n MegaEnginesResponse,\n MegaImageParams,\n MegaMode,\n MegaSearchEnvelope,\n MegaSearchParams,\n OpenSERPConfig,\n ParseParams,\n ProxyStats,\n ReadinessStatus,\n ResponseFormat,\n SearchEnvelope,\n SearchParams,\n StatsResponse,\n} from \"./types/public\";\nexport type {\n CloudAccount,\n CreditInfo,\n EngineCapability,\n EngineStatus,\n EnginesCapabilities,\n EnginesStatus,\n ModeCapability,\n OverallStatus,\n Price,\n Pricing,\n} from \"./types/cloud\";\n","import type { Backend, OpenSERPConfig } from \"./types/public\";\n\nexport const OSS_BASE_URL = \"http://localhost:7000\";\nexport const CLOUD_BASE_URL = \"https://api.openserp.org/v1\";\n\nexport function normalizeBaseUrl(baseUrl: string): string {\n return baseUrl.replace(/\\/+$/, \"\");\n}\n\nexport function resolveBaseUrl(config: OpenSERPConfig): string {\n if (config.baseUrl) {\n return normalizeBaseUrl(config.baseUrl);\n }\n\n if (config.apiKey) {\n return CLOUD_BASE_URL;\n }\n\n return OSS_BASE_URL;\n}\n\nexport function inferBackend(config: Pick<OpenSERPConfig, \"apiKey\" | \"baseUrl\" | \"backend\">): Backend {\n if (config.backend) {\n return config.backend;\n }\n\n if (config.baseUrl) {\n try {\n if (new URL(config.baseUrl).hostname === \"api.openserp.org\") {\n return \"cloud\";\n }\n } catch {\n if (config.baseUrl.includes(\"api.openserp.org\")) {\n return \"cloud\";\n }\n }\n }\n\n if (config.apiKey) {\n return \"cloud\";\n }\n\n return \"oss\";\n}\n","import type { ErrorResponse } from \"./types/public\";\n\nexport class SERPError extends Error {\n readonly status: number;\n readonly code?: string | undefined;\n readonly reason?: string | undefined;\n readonly requestId?: string | undefined;\n readonly meta?: Record<string, unknown> | undefined;\n readonly response?: ErrorResponse | unknown | undefined;\n\n constructor(message: string, options: {\n status?: number | undefined;\n code?: string | undefined;\n reason?: string | undefined;\n requestId?: string | undefined;\n meta?: Record<string, unknown> | undefined;\n response?: ErrorResponse | unknown | undefined;\n cause?: unknown | undefined;\n } = {}) {\n super(message, { cause: options.cause });\n this.name = \"SERPError\";\n this.status = options.status ?? 0;\n this.code = options.code;\n this.reason = options.reason;\n this.requestId = options.requestId;\n this.meta = options.meta;\n this.response = options.response;\n }\n}\n\nexport class RateLimitError extends SERPError {\n constructor(message: string, options: ConstructorParameters<typeof SERPError>[1] = {}) {\n super(message, options);\n this.name = \"RateLimitError\";\n }\n}\n\nexport class CaptchaError extends SERPError {\n constructor(message: string, options: ConstructorParameters<typeof SERPError>[1] = {}) {\n super(message, options);\n this.name = \"CaptchaError\";\n }\n}\n\nexport class CloudOnlyError extends SERPError {\n constructor(method: string) {\n super(`${method} is only available against OpenSERP Cloud. Configure apiKey/baseUrl for https://api.openserp.org/v1 or set client.config.backend = \"cloud\".`);\n this.name = \"CloudOnlyError\";\n }\n}\n\nexport class OssOnlyError extends SERPError {\n constructor(method: string) {\n super(`${method} is only available against a self-hosted OpenSERP server. Configure baseUrl for your OSS server or set client.config.backend = \"oss\".`);\n this.name = \"OssOnlyError\";\n }\n}\n\nexport class TimeoutError extends SERPError {\n constructor(timeoutMs: number, cause?: unknown) {\n super(`OpenSERP request timed out after ${timeoutMs}ms`, {\n code: \"request_timeout\",\n cause,\n });\n this.name = \"TimeoutError\";\n }\n}\n\nexport function errorFromResponse(status: number, body: unknown, requestId?: string): SERPError {\n const data = isErrorResponse(body) ? body : undefined;\n const code = data?.error;\n const message = data?.message ?? `OpenSERP request failed with status ${status}`;\n const options = {\n status,\n code,\n reason: data?.reason,\n requestId: data?.request_id ?? requestId,\n meta: data?.meta as Record<string, unknown> | undefined,\n response: body,\n };\n\n if (status === 429 || code === \"rate_limited\") {\n return new RateLimitError(message, options);\n }\n\n if (code === \"captcha_detected\") {\n return new CaptchaError(message, options);\n }\n\n return new SERPError(message, options);\n}\n\nfunction isErrorResponse(body: unknown): body is ErrorResponse {\n return typeof body === \"object\" && body !== null && \"error\" in body;\n}\n","import type { DebugEvent, OpenSERPConfig } from \"./types/public\";\n\nexport type DebugLevel = \"off\" | \"info\" | \"verbose\";\n\ntype DebugSink = (event: DebugEvent) => void;\n\n/** Resolved debug configuration: the active level and where events go. */\nexport interface DebugReporter {\n level: DebugLevel;\n emit(event: DebugEvent): void;\n}\n\nconst NO_OP: DebugReporter = {\n level: \"off\",\n emit() {},\n};\n\n/**\n * Resolves the effective debug behaviour from config (falling back to the\n * OPENSERP_DEBUG env var). Returns a no-op reporter when debugging is off so\n * callers can emit unconditionally without a hot-path branch of their own.\n */\nexport function resolveDebug(config: OpenSERPConfig): DebugReporter {\n const setting = config.debug ?? envDebug();\n\n if (!setting) {\n return NO_OP;\n }\n\n if (typeof setting === \"function\") {\n // A custom sink always sees verbose detail; it decides what to keep.\n return { level: \"verbose\", emit: guard(setting) };\n }\n\n const level: DebugLevel = setting === \"verbose\" ? \"verbose\" : \"info\";\n return { level, emit: consoleSink };\n}\n\nfunction envDebug(): boolean | \"verbose\" | undefined {\n // Guarded so the SDK still works in browsers / runtimes without `process`.\n const value =\n typeof process !== \"undefined\" ? process.env?.OPENSERP_DEBUG : undefined;\n if (!value) {\n return undefined;\n }\n const normalized = value.trim().toLowerCase();\n if (normalized === \"verbose\") {\n return \"verbose\";\n }\n if (normalized === \"1\" || normalized === \"true\") {\n return true;\n }\n return undefined;\n}\n\n/** Wraps a user-provided sink so a thrown logger never breaks a request. */\nfunction guard(sink: DebugSink): DebugSink {\n return (event) => {\n try {\n sink(event);\n } catch {\n // A broken debug logger must not take down the actual request.\n }\n };\n}\n\nconst consoleSink: DebugSink = (event) => {\n switch (event.type) {\n case \"request\":\n console.error(`[openserp] → ${event.method} ${event.url}`);\n if (event.headers) {\n console.error(\"[openserp] headers:\", event.headers);\n }\n break;\n case \"response\": {\n const engine = event.engineUsed ? ` engine=${event.engineUsed}` : \"\";\n const reqId = event.requestId ? ` request-id=${event.requestId}` : \"\";\n console.error(\n `[openserp] ← ${event.status} ${event.method} ${event.url} (${event.durationMs}ms)${engine}${reqId}`,\n );\n if (event.headers) {\n console.error(\"[openserp] headers:\", event.headers);\n }\n break;\n }\n case \"error\":\n console.error(\n `[openserp] ✕ ${event.method} ${event.url} (${event.durationMs}ms):`,\n event.error,\n );\n break;\n }\n};\n\n/** Snapshots headers into a plain object, redacting Authorization. */\nexport function dumpHeaders(headers: Headers): Record<string, string> {\n const out: Record<string, string> = {};\n for (const [key, value] of headers) {\n out[key] = key.toLowerCase() === \"authorization\" ? \"Bearer ***\" : value;\n }\n return out;\n}\n","import { dumpHeaders, resolveDebug } from \"./debug\";\nimport { TimeoutError, errorFromResponse } from \"./errors\";\nimport type { LastResponse, OpenSERPConfig, ResponseFormat } from \"./types/public\";\n\nexport type QueryValue =\n | string\n | number\n | boolean\n | readonly string[]\n | undefined\n | null;\n\nexport interface RequestOptions {\n method?: \"GET\" | \"POST\" | undefined;\n path: string;\n query?: Record<string, QueryValue> | undefined;\n headers?: HeadersInit | undefined;\n body?: BodyInit | null | undefined;\n format?: ResponseFormat | undefined;\n}\n\nexport interface RequestContext {\n baseUrl: string;\n config: OpenSERPConfig;\n setLastResponse(response: LastResponse): void;\n}\n\nexport async function request<T>(\n context: RequestContext,\n options: RequestOptions,\n): Promise<T> {\n let attempt = 0;\n\n for (;;) {\n try {\n return await requestOnce<T>(context, options);\n } catch (err) {\n const shouldRetry = await context.config.retry?.(err, attempt);\n if (!shouldRetry) {\n throw err;\n }\n attempt += 1;\n }\n }\n}\n\nasync function requestOnce<T>(\n { baseUrl, config, setLastResponse }: RequestContext,\n options: RequestOptions,\n): Promise<T> {\n const fetchImpl = config.fetch ?? globalThis.fetch;\n if (!fetchImpl) {\n throw new TypeError(\"OpenSERP SDK requires a fetch implementation.\");\n }\n\n const url = new URL(`${baseUrl}${options.path}`);\n appendQuery(url, options.query);\n\n const headers = new Headers(config.headers);\n if (config.apiKey) {\n headers.set(\"Authorization\", `Bearer ${config.apiKey}`);\n }\n for (const [key, value] of new Headers(options.headers)) {\n headers.set(key, value);\n }\n\n const debug = resolveDebug(config);\n const method = options.method ?? \"GET\";\n if (debug.level !== \"off\") {\n debug.emit({\n type: \"request\",\n method,\n url: url.toString(),\n ...(debug.level === \"verbose\" ? { headers: dumpHeaders(headers) } : {}),\n });\n }\n\n const timeoutMs = config.timeoutMs ?? 30_000;\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), timeoutMs);\n const startedAt = Date.now();\n\n let response: Response;\n try {\n const init: RequestInit = {\n method,\n headers,\n signal: controller.signal,\n };\n if (options.body !== undefined) {\n init.body = options.body;\n }\n\n response = await fetchImpl(url, init);\n } catch (err) {\n const error = isAbortError(err) ? new TimeoutError(timeoutMs, err) : err;\n if (debug.level !== \"off\") {\n debug.emit({\n type: \"error\",\n method,\n url: url.toString(),\n durationMs: Date.now() - startedAt,\n error,\n });\n }\n throw error;\n } finally {\n clearTimeout(timer);\n }\n\n const last = readLastResponse(response);\n setLastResponse(last);\n if (debug.level !== \"off\") {\n debug.emit({\n type: \"response\",\n method,\n url: url.toString(),\n status: response.status,\n engineUsed: last.engineUsed,\n requestId: last.requestId,\n durationMs: Date.now() - startedAt,\n ...(debug.level === \"verbose\" ? { headers: dumpHeaders(response.headers) } : {}),\n });\n }\n\n const body = await readBody(response, options.format);\n if (!response.ok) {\n throw errorFromResponse(response.status, body, response.headers.get(\"x-request-id\") ?? undefined);\n }\n\n return body as T;\n}\n\nfunction appendQuery(url: URL, query: Record<string, QueryValue> | undefined): void {\n if (!query) {\n return;\n }\n\n for (const [key, value] of Object.entries(query)) {\n if (value === undefined || value === null) {\n continue;\n }\n const encoded = Array.isArray(value) ? value.join(\",\") : String(value);\n url.searchParams.set(key, encoded);\n }\n}\n\nasync function readBody(response: Response, format?: ResponseFormat): Promise<unknown> {\n if (response.status === 204) {\n return undefined;\n }\n\n if (format && format !== \"json\") {\n return response.text();\n }\n\n const contentType = response.headers.get(\"content-type\") ?? \"\";\n if (contentType.includes(\"application/json\")) {\n return response.json();\n }\n\n const text = await response.text();\n if (!text) {\n return undefined;\n }\n\n try {\n return JSON.parse(text);\n } catch {\n return text;\n }\n}\n\nfunction readLastResponse(response: Response): LastResponse {\n const credits = {\n used: numberHeader(response.headers, \"x-credits-used\"),\n remaining: numberHeader(response.headers, \"x-credits-remaining\"),\n };\n const hasCredits = credits.used !== undefined || credits.remaining !== undefined;\n\n return {\n status: response.status,\n requestId: response.headers.get(\"x-request-id\") ?? undefined,\n credits: hasCredits ? credits : undefined,\n engineUsed: response.headers.get(\"x-engine-used\") ?? undefined,\n fallbackEngine: response.headers.get(\"x-fallback-engine\") ?? undefined,\n cache: response.headers.get(\"x-cache\") ?? undefined,\n proxyMode: response.headers.get(\"x-proxy-mode\") ?? undefined,\n proxyTag: response.headers.get(\"x-proxy-tag\") ?? undefined,\n proxyUsed: response.headers.get(\"x-proxy-used\") ?? undefined,\n networkBytes: numberHeader(response.headers, \"x-network-bytes\"),\n browserProfileId: response.headers.get(\"x-browser-profile-id\") ?? undefined,\n headers: response.headers,\n };\n}\n\nfunction numberHeader(headers: Headers, name: string): number | undefined {\n const value = headers.get(name);\n if (value === null || value === \"\") {\n return undefined;\n }\n const parsed = Number(value);\n return Number.isFinite(parsed) ? parsed : undefined;\n}\n\nfunction isAbortError(err: unknown): boolean {\n return err instanceof DOMException && err.name === \"AbortError\";\n}\n","import { inferBackend, resolveBaseUrl } from \"./backend\";\nimport { CloudOnlyError, OssOnlyError } from \"./errors\";\nimport { request, type QueryValue } from \"./request\";\nimport type {\n CacheStats,\n CircuitBreakerStatsResponse,\n HealthStatus,\n ImageEnvelope,\n ImageParams,\n LastResponse,\n MegaEnginesResponse,\n MegaImageParams,\n MegaSearchEnvelope,\n MegaSearchParams,\n OpenSERPConfig,\n ParseParams,\n ReadinessStatus,\n SearchEnvelope,\n SearchParams,\n StatsResponse,\n ProxyStats,\n} from \"./types/public\";\nimport type {\n CloudAccount,\n EnginesCapabilities,\n EnginesStatus,\n Pricing,\n} from \"./types/cloud\";\n\nexport class OpenSERP {\n readonly config: OpenSERPConfig;\n lastResponse?: LastResponse;\n\n constructor(config: OpenSERPConfig = {}) {\n this.config = { ...config };\n }\n\n get backend() {\n return inferBackend(this.config);\n }\n\n get baseUrl() {\n return resolveBaseUrl(this.config);\n }\n\n search(params: SearchParams): Promise<SearchEnvelope | string> {\n const { engine, format, ...query } = params;\n return this.get<SearchEnvelope | string>(`/${engine}/search`, query, format);\n }\n\n image(params: ImageParams): Promise<ImageEnvelope | string> {\n const { engine, format, ...query } = params;\n return this.get<ImageEnvelope | string>(`/${engine}/image`, query, format);\n }\n\n megaSearch(params: MegaSearchParams): Promise<MegaSearchEnvelope | string> {\n const { format, ...query } = params;\n return this.get<MegaSearchEnvelope | string>(\"/mega/search\", query, format);\n }\n\n fastSearch(params: Omit<MegaSearchParams, \"mode\">): Promise<MegaSearchEnvelope | string> {\n return this.megaSearch({ ...params, mode: \"fast\" });\n }\n\n anySearch(params: Omit<MegaSearchParams, \"mode\">): Promise<MegaSearchEnvelope | string> {\n return this.megaSearch({ ...params, mode: \"any\" });\n }\n\n megaImage(params: MegaImageParams): Promise<ImageEnvelope | string> {\n const { format, ...query } = params;\n return this.get<ImageEnvelope | string>(\"/mega/image\", query, format);\n }\n\n fastImage(params: Omit<MegaImageParams, \"mode\">): Promise<ImageEnvelope | string> {\n return this.megaImage({ ...params, mode: \"fast\" });\n }\n\n anyImage(params: Omit<MegaImageParams, \"mode\">): Promise<ImageEnvelope | string> {\n return this.megaImage({ ...params, mode: \"any\" });\n }\n\n parseGoogle(params: ParseParams): Promise<SearchEnvelope | string> {\n this.assertOss(\"parseGoogle\");\n return this.parse(\"/google/parse\", params);\n }\n\n parseBing(params: ParseParams): Promise<SearchEnvelope | string> {\n this.assertOss(\"parseBing\");\n return this.parse(\"/bing/parse\", params);\n }\n\n health(): Promise<HealthStatus> {\n this.assertOss(\"health\");\n return this.get<HealthStatus>(\"/health\");\n }\n\n ready(): Promise<ReadinessStatus> {\n this.assertOss(\"ready\");\n return this.get<ReadinessStatus>(\"/ready\");\n }\n\n stats(): Promise<StatsResponse> {\n this.assertOss(\"stats\");\n return this.get<StatsResponse>(\"/stats\");\n }\n\n cacheStats(): Promise<CacheStats> {\n this.assertOss(\"cacheStats\");\n return this.get<CacheStats>(\"/stats/cache\");\n }\n\n proxyStats(): Promise<ProxyStats> {\n this.assertOss(\"proxyStats\");\n return this.get<ProxyStats>(\"/stats/proxy\");\n }\n\n circuitBreakerStats(): Promise<CircuitBreakerStatsResponse> {\n this.assertOss(\"circuitBreakerStats\");\n return this.get<CircuitBreakerStatsResponse>(\"/stats/cb\");\n }\n\n engines(): Promise<MegaEnginesResponse> {\n this.assertOss(\"engines\");\n return this.get<MegaEnginesResponse>(\"/mega/engines\");\n }\n\n me(): Promise<CloudAccount> {\n this.assertCloud(\"me\");\n return this.get<CloudAccount>(\"/me\");\n }\n\n pricing(): Promise<Pricing> {\n this.assertCloud(\"pricing\");\n return this.get<Pricing>(\"/pricing\");\n }\n\n enginesStatus(): Promise<EnginesStatus> {\n this.assertCloud(\"enginesStatus\");\n return this.get<EnginesStatus>(\"/engines/status\");\n }\n\n enginesCapabilities(): Promise<EnginesCapabilities> {\n this.assertCloud(\"enginesCapabilities\");\n return this.get<EnginesCapabilities>(\"/engines/capabilities\");\n }\n\n private parse(path: string, params: ParseParams): Promise<SearchEnvelope | string> {\n return request<SearchEnvelope | string>(this.requestContext(), {\n method: \"POST\",\n path,\n query: params.format ? { format: params.format } : undefined,\n headers: {\n \"Content-Type\": \"text/html; charset=utf-8\",\n },\n body: params.html,\n format: params.format,\n });\n }\n\n private get<T>(\n path: string,\n query?: Record<string, QueryValue>,\n format?: SearchParams[\"format\"],\n ): Promise<T> {\n const { query: cleanQuery, headers } = splitQueryAndHeaders({\n ...query,\n format,\n });\n\n return request<T>(this.requestContext(), {\n path,\n query: cleanQuery,\n headers,\n format,\n });\n }\n\n private requestContext() {\n return {\n baseUrl: this.baseUrl,\n config: this.config,\n setLastResponse: (response: LastResponse) => {\n this.lastResponse = response;\n },\n };\n }\n\n private assertCloud(method: string): void {\n if (this.backend !== \"cloud\") {\n throw new CloudOnlyError(method);\n }\n }\n\n private assertOss(method: string): void {\n if (this.backend !== \"oss\") {\n throw new OssOnlyError(method);\n }\n }\n}\n\nfunction splitQueryAndHeaders(query: Record<string, QueryValue>): {\n query: Record<string, QueryValue>;\n headers: HeadersInit;\n} {\n const {\n useProxy,\n proxyUrl,\n proxyCountry,\n proxyClass,\n proxyProvider,\n proxySessionId,\n tenant,\n ...cleanQuery\n } = query;\n const headers: Record<string, string> = {};\n\n addHeader(headers, \"X-Use-Proxy\", useProxy);\n addHeader(headers, \"X-Proxy-URL\", proxyUrl);\n addHeader(headers, \"X-Proxy-Country\", proxyCountry);\n addHeader(headers, \"X-Proxy-Class\", proxyClass);\n addHeader(headers, \"X-Proxy-Provider\", proxyProvider);\n addHeader(headers, \"X-Proxy-Session-ID\", proxySessionId);\n addHeader(headers, \"X-Tenant\", tenant);\n\n return { query: cleanQuery, headers };\n}\n\nfunction addHeader(headers: Record<string, string>, name: string, value: QueryValue): void {\n if (value === undefined || value === null) {\n return;\n }\n headers[name] = Array.isArray(value) ? value.join(\",\") : String(value);\n}\n"],"mappings":"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","names":[]}
|
package/dist/index.d.cts
CHANGED
|
@@ -77,7 +77,44 @@ interface OpenSERPConfig {
|
|
|
77
77
|
fetch?: typeof fetch | undefined;
|
|
78
78
|
headers?: HeadersInit | undefined;
|
|
79
79
|
retry?: ((err: unknown, attempt: number) => boolean | Promise<boolean>) | undefined;
|
|
80
|
-
|
|
80
|
+
/**
|
|
81
|
+
* Logs each request and response to help debug what the SDK actually sends.
|
|
82
|
+
* - `true` / `"info"`: logs method, URL (with query string), and response
|
|
83
|
+
* status / engine-used / request-id via `console.error`.
|
|
84
|
+
* - `"verbose"`: additionally logs request and response headers
|
|
85
|
+
* (the `Authorization` header is redacted).
|
|
86
|
+
* - A function: receives a structured {@link DebugEvent} so you can route it
|
|
87
|
+
* to your own logger instead of the console.
|
|
88
|
+
*
|
|
89
|
+
* Defaults to off. The `OPENSERP_DEBUG` env var (`1`/`true`/`verbose`) enables
|
|
90
|
+
* it when this option is left unset and `process` is available.
|
|
91
|
+
*/
|
|
92
|
+
debug?: boolean | "info" | "verbose" | ((event: DebugEvent) => void) | undefined;
|
|
93
|
+
}
|
|
94
|
+
/** A single request/response lifecycle event emitted when debug is enabled. */
|
|
95
|
+
type DebugEvent = {
|
|
96
|
+
type: "request";
|
|
97
|
+
method: string;
|
|
98
|
+
url: string;
|
|
99
|
+
/** Present only at "verbose" level. Authorization is redacted. */
|
|
100
|
+
headers?: Record<string, string>;
|
|
101
|
+
} | {
|
|
102
|
+
type: "response";
|
|
103
|
+
method: string;
|
|
104
|
+
url: string;
|
|
105
|
+
status: number;
|
|
106
|
+
engineUsed?: string | undefined;
|
|
107
|
+
requestId?: string | undefined;
|
|
108
|
+
durationMs: number;
|
|
109
|
+
/** Present only at "verbose" level. */
|
|
110
|
+
headers?: Record<string, string>;
|
|
111
|
+
} | {
|
|
112
|
+
type: "error";
|
|
113
|
+
method: string;
|
|
114
|
+
url: string;
|
|
115
|
+
durationMs: number;
|
|
116
|
+
error: unknown;
|
|
117
|
+
};
|
|
81
118
|
interface LastResponse {
|
|
82
119
|
status: number;
|
|
83
120
|
requestId?: string | undefined;
|
|
@@ -199,4 +236,4 @@ declare class TimeoutError extends SERPError {
|
|
|
199
236
|
constructor(timeoutMs: number, cause?: unknown);
|
|
200
237
|
}
|
|
201
238
|
|
|
202
|
-
export { type Backend, CLOUD_BASE_URL, type CacheStats, CaptchaError, type CircuitBreakerStatsResponse, type CloudAccount, CloudOnlyError, type CreditInfo, type Engine, type EngineCapability, type EngineStatus, type EnginesCapabilities, type EnginesStatus, type ErrorResponse, type HealthStatus, type ImageEnvelope, type ImageParams, type LastResponse, type MegaEnginesResponse, type MegaImageParams, type MegaMode, type MegaSearchEnvelope, type MegaSearchParams, type ModeCapability, OSS_BASE_URL, OpenSERP, type OpenSERPConfig, OssOnlyError, type OverallStatus, type ParseParams, type Price, type Pricing, type ProxyStats, RateLimitError, type ReadinessStatus, type ResponseFormat, SERPError, type SearchEnvelope, type SearchParams, type StatsResponse, TimeoutError, inferBackend, normalizeBaseUrl, resolveBaseUrl };
|
|
239
|
+
export { type Backend, CLOUD_BASE_URL, type CacheStats, CaptchaError, type CircuitBreakerStatsResponse, type CloudAccount, CloudOnlyError, type CreditInfo, type DebugEvent, type Engine, type EngineCapability, type EngineStatus, type EnginesCapabilities, type EnginesStatus, type ErrorResponse, type HealthStatus, type ImageEnvelope, type ImageParams, type LastResponse, type MegaEnginesResponse, type MegaImageParams, type MegaMode, type MegaSearchEnvelope, type MegaSearchParams, type ModeCapability, OSS_BASE_URL, OpenSERP, type OpenSERPConfig, OssOnlyError, type OverallStatus, type ParseParams, type Price, type Pricing, type ProxyStats, RateLimitError, type ReadinessStatus, type ResponseFormat, SERPError, type SearchEnvelope, type SearchParams, type StatsResponse, TimeoutError, inferBackend, normalizeBaseUrl, resolveBaseUrl };
|
package/dist/index.d.ts
CHANGED
|
@@ -77,7 +77,44 @@ interface OpenSERPConfig {
|
|
|
77
77
|
fetch?: typeof fetch | undefined;
|
|
78
78
|
headers?: HeadersInit | undefined;
|
|
79
79
|
retry?: ((err: unknown, attempt: number) => boolean | Promise<boolean>) | undefined;
|
|
80
|
-
|
|
80
|
+
/**
|
|
81
|
+
* Logs each request and response to help debug what the SDK actually sends.
|
|
82
|
+
* - `true` / `"info"`: logs method, URL (with query string), and response
|
|
83
|
+
* status / engine-used / request-id via `console.error`.
|
|
84
|
+
* - `"verbose"`: additionally logs request and response headers
|
|
85
|
+
* (the `Authorization` header is redacted).
|
|
86
|
+
* - A function: receives a structured {@link DebugEvent} so you can route it
|
|
87
|
+
* to your own logger instead of the console.
|
|
88
|
+
*
|
|
89
|
+
* Defaults to off. The `OPENSERP_DEBUG` env var (`1`/`true`/`verbose`) enables
|
|
90
|
+
* it when this option is left unset and `process` is available.
|
|
91
|
+
*/
|
|
92
|
+
debug?: boolean | "info" | "verbose" | ((event: DebugEvent) => void) | undefined;
|
|
93
|
+
}
|
|
94
|
+
/** A single request/response lifecycle event emitted when debug is enabled. */
|
|
95
|
+
type DebugEvent = {
|
|
96
|
+
type: "request";
|
|
97
|
+
method: string;
|
|
98
|
+
url: string;
|
|
99
|
+
/** Present only at "verbose" level. Authorization is redacted. */
|
|
100
|
+
headers?: Record<string, string>;
|
|
101
|
+
} | {
|
|
102
|
+
type: "response";
|
|
103
|
+
method: string;
|
|
104
|
+
url: string;
|
|
105
|
+
status: number;
|
|
106
|
+
engineUsed?: string | undefined;
|
|
107
|
+
requestId?: string | undefined;
|
|
108
|
+
durationMs: number;
|
|
109
|
+
/** Present only at "verbose" level. */
|
|
110
|
+
headers?: Record<string, string>;
|
|
111
|
+
} | {
|
|
112
|
+
type: "error";
|
|
113
|
+
method: string;
|
|
114
|
+
url: string;
|
|
115
|
+
durationMs: number;
|
|
116
|
+
error: unknown;
|
|
117
|
+
};
|
|
81
118
|
interface LastResponse {
|
|
82
119
|
status: number;
|
|
83
120
|
requestId?: string | undefined;
|
|
@@ -199,4 +236,4 @@ declare class TimeoutError extends SERPError {
|
|
|
199
236
|
constructor(timeoutMs: number, cause?: unknown);
|
|
200
237
|
}
|
|
201
238
|
|
|
202
|
-
export { type Backend, CLOUD_BASE_URL, type CacheStats, CaptchaError, type CircuitBreakerStatsResponse, type CloudAccount, CloudOnlyError, type CreditInfo, type Engine, type EngineCapability, type EngineStatus, type EnginesCapabilities, type EnginesStatus, type ErrorResponse, type HealthStatus, type ImageEnvelope, type ImageParams, type LastResponse, type MegaEnginesResponse, type MegaImageParams, type MegaMode, type MegaSearchEnvelope, type MegaSearchParams, type ModeCapability, OSS_BASE_URL, OpenSERP, type OpenSERPConfig, OssOnlyError, type OverallStatus, type ParseParams, type Price, type Pricing, type ProxyStats, RateLimitError, type ReadinessStatus, type ResponseFormat, SERPError, type SearchEnvelope, type SearchParams, type StatsResponse, TimeoutError, inferBackend, normalizeBaseUrl, resolveBaseUrl };
|
|
239
|
+
export { type Backend, CLOUD_BASE_URL, type CacheStats, CaptchaError, type CircuitBreakerStatsResponse, type CloudAccount, CloudOnlyError, type CreditInfo, type DebugEvent, type Engine, type EngineCapability, type EngineStatus, type EnginesCapabilities, type EnginesStatus, type ErrorResponse, type HealthStatus, type ImageEnvelope, type ImageParams, type LastResponse, type MegaEnginesResponse, type MegaImageParams, type MegaMode, type MegaSearchEnvelope, type MegaSearchParams, type ModeCapability, OSS_BASE_URL, OpenSERP, type OpenSERPConfig, OssOnlyError, type OverallStatus, type ParseParams, type Price, type Pricing, type ProxyStats, RateLimitError, type ReadinessStatus, type ResponseFormat, SERPError, type SearchEnvelope, type SearchParams, type StatsResponse, TimeoutError, inferBackend, normalizeBaseUrl, resolveBaseUrl };
|
package/dist/index.js
CHANGED
|
@@ -110,6 +110,80 @@ function isErrorResponse(body) {
|
|
|
110
110
|
return typeof body === "object" && body !== null && "error" in body;
|
|
111
111
|
}
|
|
112
112
|
|
|
113
|
+
// src/debug.ts
|
|
114
|
+
var NO_OP = {
|
|
115
|
+
level: "off",
|
|
116
|
+
emit() {
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
function resolveDebug(config) {
|
|
120
|
+
const setting = config.debug ?? envDebug();
|
|
121
|
+
if (!setting) {
|
|
122
|
+
return NO_OP;
|
|
123
|
+
}
|
|
124
|
+
if (typeof setting === "function") {
|
|
125
|
+
return { level: "verbose", emit: guard(setting) };
|
|
126
|
+
}
|
|
127
|
+
const level = setting === "verbose" ? "verbose" : "info";
|
|
128
|
+
return { level, emit: consoleSink };
|
|
129
|
+
}
|
|
130
|
+
function envDebug() {
|
|
131
|
+
const value = typeof process !== "undefined" ? process.env?.OPENSERP_DEBUG : void 0;
|
|
132
|
+
if (!value) {
|
|
133
|
+
return void 0;
|
|
134
|
+
}
|
|
135
|
+
const normalized = value.trim().toLowerCase();
|
|
136
|
+
if (normalized === "verbose") {
|
|
137
|
+
return "verbose";
|
|
138
|
+
}
|
|
139
|
+
if (normalized === "1" || normalized === "true") {
|
|
140
|
+
return true;
|
|
141
|
+
}
|
|
142
|
+
return void 0;
|
|
143
|
+
}
|
|
144
|
+
function guard(sink) {
|
|
145
|
+
return (event) => {
|
|
146
|
+
try {
|
|
147
|
+
sink(event);
|
|
148
|
+
} catch {
|
|
149
|
+
}
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
var consoleSink = (event) => {
|
|
153
|
+
switch (event.type) {
|
|
154
|
+
case "request":
|
|
155
|
+
console.error(`[openserp] \u2192 ${event.method} ${event.url}`);
|
|
156
|
+
if (event.headers) {
|
|
157
|
+
console.error("[openserp] headers:", event.headers);
|
|
158
|
+
}
|
|
159
|
+
break;
|
|
160
|
+
case "response": {
|
|
161
|
+
const engine = event.engineUsed ? ` engine=${event.engineUsed}` : "";
|
|
162
|
+
const reqId = event.requestId ? ` request-id=${event.requestId}` : "";
|
|
163
|
+
console.error(
|
|
164
|
+
`[openserp] \u2190 ${event.status} ${event.method} ${event.url} (${event.durationMs}ms)${engine}${reqId}`
|
|
165
|
+
);
|
|
166
|
+
if (event.headers) {
|
|
167
|
+
console.error("[openserp] headers:", event.headers);
|
|
168
|
+
}
|
|
169
|
+
break;
|
|
170
|
+
}
|
|
171
|
+
case "error":
|
|
172
|
+
console.error(
|
|
173
|
+
`[openserp] \u2715 ${event.method} ${event.url} (${event.durationMs}ms):`,
|
|
174
|
+
event.error
|
|
175
|
+
);
|
|
176
|
+
break;
|
|
177
|
+
}
|
|
178
|
+
};
|
|
179
|
+
function dumpHeaders(headers) {
|
|
180
|
+
const out = {};
|
|
181
|
+
for (const [key, value] of headers) {
|
|
182
|
+
out[key] = key.toLowerCase() === "authorization" ? "Bearer ***" : value;
|
|
183
|
+
}
|
|
184
|
+
return out;
|
|
185
|
+
}
|
|
186
|
+
|
|
113
187
|
// src/request.ts
|
|
114
188
|
async function request(context, options) {
|
|
115
189
|
let attempt = 0;
|
|
@@ -139,13 +213,24 @@ async function requestOnce({ baseUrl, config, setLastResponse }, options) {
|
|
|
139
213
|
for (const [key, value] of new Headers(options.headers)) {
|
|
140
214
|
headers.set(key, value);
|
|
141
215
|
}
|
|
216
|
+
const debug = resolveDebug(config);
|
|
217
|
+
const method = options.method ?? "GET";
|
|
218
|
+
if (debug.level !== "off") {
|
|
219
|
+
debug.emit({
|
|
220
|
+
type: "request",
|
|
221
|
+
method,
|
|
222
|
+
url: url.toString(),
|
|
223
|
+
...debug.level === "verbose" ? { headers: dumpHeaders(headers) } : {}
|
|
224
|
+
});
|
|
225
|
+
}
|
|
142
226
|
const timeoutMs = config.timeoutMs ?? 3e4;
|
|
143
227
|
const controller = new AbortController();
|
|
144
228
|
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
229
|
+
const startedAt = Date.now();
|
|
145
230
|
let response;
|
|
146
231
|
try {
|
|
147
232
|
const init = {
|
|
148
|
-
method
|
|
233
|
+
method,
|
|
149
234
|
headers,
|
|
150
235
|
signal: controller.signal
|
|
151
236
|
};
|
|
@@ -154,14 +239,34 @@ async function requestOnce({ baseUrl, config, setLastResponse }, options) {
|
|
|
154
239
|
}
|
|
155
240
|
response = await fetchImpl(url, init);
|
|
156
241
|
} catch (err) {
|
|
157
|
-
|
|
158
|
-
|
|
242
|
+
const error = isAbortError(err) ? new TimeoutError(timeoutMs, err) : err;
|
|
243
|
+
if (debug.level !== "off") {
|
|
244
|
+
debug.emit({
|
|
245
|
+
type: "error",
|
|
246
|
+
method,
|
|
247
|
+
url: url.toString(),
|
|
248
|
+
durationMs: Date.now() - startedAt,
|
|
249
|
+
error
|
|
250
|
+
});
|
|
159
251
|
}
|
|
160
|
-
throw
|
|
252
|
+
throw error;
|
|
161
253
|
} finally {
|
|
162
254
|
clearTimeout(timer);
|
|
163
255
|
}
|
|
164
|
-
|
|
256
|
+
const last = readLastResponse(response);
|
|
257
|
+
setLastResponse(last);
|
|
258
|
+
if (debug.level !== "off") {
|
|
259
|
+
debug.emit({
|
|
260
|
+
type: "response",
|
|
261
|
+
method,
|
|
262
|
+
url: url.toString(),
|
|
263
|
+
status: response.status,
|
|
264
|
+
engineUsed: last.engineUsed,
|
|
265
|
+
requestId: last.requestId,
|
|
266
|
+
durationMs: Date.now() - startedAt,
|
|
267
|
+
...debug.level === "verbose" ? { headers: dumpHeaders(response.headers) } : {}
|
|
268
|
+
});
|
|
269
|
+
}
|
|
165
270
|
const body = await readBody(response, options.format);
|
|
166
271
|
if (!response.ok) {
|
|
167
272
|
throw errorFromResponse(response.status, body, response.headers.get("x-request-id") ?? void 0);
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/backend.ts","../src/errors.ts","../src/request.ts","../src/client.ts"],"sourcesContent":["import type { Backend, OpenSERPConfig } from \"./types/public\";\n\nexport const OSS_BASE_URL = \"http://localhost:7000\";\nexport const CLOUD_BASE_URL = \"https://api.openserp.org/v1\";\n\nexport function normalizeBaseUrl(baseUrl: string): string {\n return baseUrl.replace(/\\/+$/, \"\");\n}\n\nexport function resolveBaseUrl(config: OpenSERPConfig): string {\n if (config.baseUrl) {\n return normalizeBaseUrl(config.baseUrl);\n }\n\n if (config.apiKey) {\n return CLOUD_BASE_URL;\n }\n\n return OSS_BASE_URL;\n}\n\nexport function inferBackend(config: Pick<OpenSERPConfig, \"apiKey\" | \"baseUrl\" | \"backend\">): Backend {\n if (config.backend) {\n return config.backend;\n }\n\n if (config.baseUrl) {\n try {\n if (new URL(config.baseUrl).hostname === \"api.openserp.org\") {\n return \"cloud\";\n }\n } catch {\n if (config.baseUrl.includes(\"api.openserp.org\")) {\n return \"cloud\";\n }\n }\n }\n\n if (config.apiKey) {\n return \"cloud\";\n }\n\n return \"oss\";\n}\n","import type { ErrorResponse } from \"./types/public\";\n\nexport class SERPError extends Error {\n readonly status: number;\n readonly code?: string | undefined;\n readonly reason?: string | undefined;\n readonly requestId?: string | undefined;\n readonly meta?: Record<string, unknown> | undefined;\n readonly response?: ErrorResponse | unknown | undefined;\n\n constructor(message: string, options: {\n status?: number | undefined;\n code?: string | undefined;\n reason?: string | undefined;\n requestId?: string | undefined;\n meta?: Record<string, unknown> | undefined;\n response?: ErrorResponse | unknown | undefined;\n cause?: unknown | undefined;\n } = {}) {\n super(message, { cause: options.cause });\n this.name = \"SERPError\";\n this.status = options.status ?? 0;\n this.code = options.code;\n this.reason = options.reason;\n this.requestId = options.requestId;\n this.meta = options.meta;\n this.response = options.response;\n }\n}\n\nexport class RateLimitError extends SERPError {\n constructor(message: string, options: ConstructorParameters<typeof SERPError>[1] = {}) {\n super(message, options);\n this.name = \"RateLimitError\";\n }\n}\n\nexport class CaptchaError extends SERPError {\n constructor(message: string, options: ConstructorParameters<typeof SERPError>[1] = {}) {\n super(message, options);\n this.name = \"CaptchaError\";\n }\n}\n\nexport class CloudOnlyError extends SERPError {\n constructor(method: string) {\n super(`${method} is only available against OpenSERP Cloud. Configure apiKey/baseUrl for https://api.openserp.org/v1 or set client.config.backend = \"cloud\".`);\n this.name = \"CloudOnlyError\";\n }\n}\n\nexport class OssOnlyError extends SERPError {\n constructor(method: string) {\n super(`${method} is only available against a self-hosted OpenSERP server. Configure baseUrl for your OSS server or set client.config.backend = \"oss\".`);\n this.name = \"OssOnlyError\";\n }\n}\n\nexport class TimeoutError extends SERPError {\n constructor(timeoutMs: number, cause?: unknown) {\n super(`OpenSERP request timed out after ${timeoutMs}ms`, {\n code: \"request_timeout\",\n cause,\n });\n this.name = \"TimeoutError\";\n }\n}\n\nexport function errorFromResponse(status: number, body: unknown, requestId?: string): SERPError {\n const data = isErrorResponse(body) ? body : undefined;\n const code = data?.error;\n const message = data?.message ?? `OpenSERP request failed with status ${status}`;\n const options = {\n status,\n code,\n reason: data?.reason,\n requestId: data?.request_id ?? requestId,\n meta: data?.meta as Record<string, unknown> | undefined,\n response: body,\n };\n\n if (status === 429 || code === \"rate_limited\") {\n return new RateLimitError(message, options);\n }\n\n if (code === \"captcha_detected\") {\n return new CaptchaError(message, options);\n }\n\n return new SERPError(message, options);\n}\n\nfunction isErrorResponse(body: unknown): body is ErrorResponse {\n return typeof body === \"object\" && body !== null && \"error\" in body;\n}\n","import { TimeoutError, errorFromResponse } from \"./errors\";\nimport type { LastResponse, OpenSERPConfig, ResponseFormat } from \"./types/public\";\n\nexport type QueryValue =\n | string\n | number\n | boolean\n | readonly string[]\n | undefined\n | null;\n\nexport interface RequestOptions {\n method?: \"GET\" | \"POST\" | undefined;\n path: string;\n query?: Record<string, QueryValue> | undefined;\n headers?: HeadersInit | undefined;\n body?: BodyInit | null | undefined;\n format?: ResponseFormat | undefined;\n}\n\nexport interface RequestContext {\n baseUrl: string;\n config: OpenSERPConfig;\n setLastResponse(response: LastResponse): void;\n}\n\nexport async function request<T>(\n context: RequestContext,\n options: RequestOptions,\n): Promise<T> {\n let attempt = 0;\n\n for (;;) {\n try {\n return await requestOnce<T>(context, options);\n } catch (err) {\n const shouldRetry = await context.config.retry?.(err, attempt);\n if (!shouldRetry) {\n throw err;\n }\n attempt += 1;\n }\n }\n}\n\nasync function requestOnce<T>(\n { baseUrl, config, setLastResponse }: RequestContext,\n options: RequestOptions,\n): Promise<T> {\n const fetchImpl = config.fetch ?? globalThis.fetch;\n if (!fetchImpl) {\n throw new TypeError(\"OpenSERP SDK requires a fetch implementation.\");\n }\n\n const url = new URL(`${baseUrl}${options.path}`);\n appendQuery(url, options.query);\n\n const headers = new Headers(config.headers);\n if (config.apiKey) {\n headers.set(\"Authorization\", `Bearer ${config.apiKey}`);\n }\n for (const [key, value] of new Headers(options.headers)) {\n headers.set(key, value);\n }\n\n const timeoutMs = config.timeoutMs ?? 30_000;\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), timeoutMs);\n\n let response: Response;\n try {\n const init: RequestInit = {\n method: options.method ?? \"GET\",\n headers,\n signal: controller.signal,\n };\n if (options.body !== undefined) {\n init.body = options.body;\n }\n\n response = await fetchImpl(url, init);\n } catch (err) {\n if (isAbortError(err)) {\n throw new TimeoutError(timeoutMs, err);\n }\n throw err;\n } finally {\n clearTimeout(timer);\n }\n\n setLastResponse(readLastResponse(response));\n\n const body = await readBody(response, options.format);\n if (!response.ok) {\n throw errorFromResponse(response.status, body, response.headers.get(\"x-request-id\") ?? undefined);\n }\n\n return body as T;\n}\n\nfunction appendQuery(url: URL, query: Record<string, QueryValue> | undefined): void {\n if (!query) {\n return;\n }\n\n for (const [key, value] of Object.entries(query)) {\n if (value === undefined || value === null) {\n continue;\n }\n const encoded = Array.isArray(value) ? value.join(\",\") : String(value);\n url.searchParams.set(key, encoded);\n }\n}\n\nasync function readBody(response: Response, format?: ResponseFormat): Promise<unknown> {\n if (response.status === 204) {\n return undefined;\n }\n\n if (format && format !== \"json\") {\n return response.text();\n }\n\n const contentType = response.headers.get(\"content-type\") ?? \"\";\n if (contentType.includes(\"application/json\")) {\n return response.json();\n }\n\n const text = await response.text();\n if (!text) {\n return undefined;\n }\n\n try {\n return JSON.parse(text);\n } catch {\n return text;\n }\n}\n\nfunction readLastResponse(response: Response): LastResponse {\n const credits = {\n used: numberHeader(response.headers, \"x-credits-used\"),\n remaining: numberHeader(response.headers, \"x-credits-remaining\"),\n };\n const hasCredits = credits.used !== undefined || credits.remaining !== undefined;\n\n return {\n status: response.status,\n requestId: response.headers.get(\"x-request-id\") ?? undefined,\n credits: hasCredits ? credits : undefined,\n engineUsed: response.headers.get(\"x-engine-used\") ?? undefined,\n fallbackEngine: response.headers.get(\"x-fallback-engine\") ?? undefined,\n cache: response.headers.get(\"x-cache\") ?? undefined,\n proxyMode: response.headers.get(\"x-proxy-mode\") ?? undefined,\n proxyTag: response.headers.get(\"x-proxy-tag\") ?? undefined,\n proxyUsed: response.headers.get(\"x-proxy-used\") ?? undefined,\n networkBytes: numberHeader(response.headers, \"x-network-bytes\"),\n browserProfileId: response.headers.get(\"x-browser-profile-id\") ?? undefined,\n headers: response.headers,\n };\n}\n\nfunction numberHeader(headers: Headers, name: string): number | undefined {\n const value = headers.get(name);\n if (value === null || value === \"\") {\n return undefined;\n }\n const parsed = Number(value);\n return Number.isFinite(parsed) ? parsed : undefined;\n}\n\nfunction isAbortError(err: unknown): boolean {\n return err instanceof DOMException && err.name === \"AbortError\";\n}\n","import { inferBackend, resolveBaseUrl } from \"./backend\";\nimport { CloudOnlyError, OssOnlyError } from \"./errors\";\nimport { request, type QueryValue } from \"./request\";\nimport type {\n CacheStats,\n CircuitBreakerStatsResponse,\n HealthStatus,\n ImageEnvelope,\n ImageParams,\n LastResponse,\n MegaEnginesResponse,\n MegaImageParams,\n MegaSearchEnvelope,\n MegaSearchParams,\n OpenSERPConfig,\n ParseParams,\n ReadinessStatus,\n SearchEnvelope,\n SearchParams,\n StatsResponse,\n ProxyStats,\n} from \"./types/public\";\nimport type {\n CloudAccount,\n EnginesCapabilities,\n EnginesStatus,\n Pricing,\n} from \"./types/cloud\";\n\nexport class OpenSERP {\n readonly config: OpenSERPConfig;\n lastResponse?: LastResponse;\n\n constructor(config: OpenSERPConfig = {}) {\n this.config = { ...config };\n }\n\n get backend() {\n return inferBackend(this.config);\n }\n\n get baseUrl() {\n return resolveBaseUrl(this.config);\n }\n\n search(params: SearchParams): Promise<SearchEnvelope | string> {\n const { engine, format, ...query } = params;\n return this.get<SearchEnvelope | string>(`/${engine}/search`, query, format);\n }\n\n image(params: ImageParams): Promise<ImageEnvelope | string> {\n const { engine, format, ...query } = params;\n return this.get<ImageEnvelope | string>(`/${engine}/image`, query, format);\n }\n\n megaSearch(params: MegaSearchParams): Promise<MegaSearchEnvelope | string> {\n const { format, ...query } = params;\n return this.get<MegaSearchEnvelope | string>(\"/mega/search\", query, format);\n }\n\n fastSearch(params: Omit<MegaSearchParams, \"mode\">): Promise<MegaSearchEnvelope | string> {\n return this.megaSearch({ ...params, mode: \"fast\" });\n }\n\n anySearch(params: Omit<MegaSearchParams, \"mode\">): Promise<MegaSearchEnvelope | string> {\n return this.megaSearch({ ...params, mode: \"any\" });\n }\n\n megaImage(params: MegaImageParams): Promise<ImageEnvelope | string> {\n const { format, ...query } = params;\n return this.get<ImageEnvelope | string>(\"/mega/image\", query, format);\n }\n\n fastImage(params: Omit<MegaImageParams, \"mode\">): Promise<ImageEnvelope | string> {\n return this.megaImage({ ...params, mode: \"fast\" });\n }\n\n anyImage(params: Omit<MegaImageParams, \"mode\">): Promise<ImageEnvelope | string> {\n return this.megaImage({ ...params, mode: \"any\" });\n }\n\n parseGoogle(params: ParseParams): Promise<SearchEnvelope | string> {\n this.assertOss(\"parseGoogle\");\n return this.parse(\"/google/parse\", params);\n }\n\n parseBing(params: ParseParams): Promise<SearchEnvelope | string> {\n this.assertOss(\"parseBing\");\n return this.parse(\"/bing/parse\", params);\n }\n\n health(): Promise<HealthStatus> {\n this.assertOss(\"health\");\n return this.get<HealthStatus>(\"/health\");\n }\n\n ready(): Promise<ReadinessStatus> {\n this.assertOss(\"ready\");\n return this.get<ReadinessStatus>(\"/ready\");\n }\n\n stats(): Promise<StatsResponse> {\n this.assertOss(\"stats\");\n return this.get<StatsResponse>(\"/stats\");\n }\n\n cacheStats(): Promise<CacheStats> {\n this.assertOss(\"cacheStats\");\n return this.get<CacheStats>(\"/stats/cache\");\n }\n\n proxyStats(): Promise<ProxyStats> {\n this.assertOss(\"proxyStats\");\n return this.get<ProxyStats>(\"/stats/proxy\");\n }\n\n circuitBreakerStats(): Promise<CircuitBreakerStatsResponse> {\n this.assertOss(\"circuitBreakerStats\");\n return this.get<CircuitBreakerStatsResponse>(\"/stats/cb\");\n }\n\n engines(): Promise<MegaEnginesResponse> {\n this.assertOss(\"engines\");\n return this.get<MegaEnginesResponse>(\"/mega/engines\");\n }\n\n me(): Promise<CloudAccount> {\n this.assertCloud(\"me\");\n return this.get<CloudAccount>(\"/me\");\n }\n\n pricing(): Promise<Pricing> {\n this.assertCloud(\"pricing\");\n return this.get<Pricing>(\"/pricing\");\n }\n\n enginesStatus(): Promise<EnginesStatus> {\n this.assertCloud(\"enginesStatus\");\n return this.get<EnginesStatus>(\"/engines/status\");\n }\n\n enginesCapabilities(): Promise<EnginesCapabilities> {\n this.assertCloud(\"enginesCapabilities\");\n return this.get<EnginesCapabilities>(\"/engines/capabilities\");\n }\n\n private parse(path: string, params: ParseParams): Promise<SearchEnvelope | string> {\n return request<SearchEnvelope | string>(this.requestContext(), {\n method: \"POST\",\n path,\n query: params.format ? { format: params.format } : undefined,\n headers: {\n \"Content-Type\": \"text/html; charset=utf-8\",\n },\n body: params.html,\n format: params.format,\n });\n }\n\n private get<T>(\n path: string,\n query?: Record<string, QueryValue>,\n format?: SearchParams[\"format\"],\n ): Promise<T> {\n const { query: cleanQuery, headers } = splitQueryAndHeaders({\n ...query,\n format,\n });\n\n return request<T>(this.requestContext(), {\n path,\n query: cleanQuery,\n headers,\n format,\n });\n }\n\n private requestContext() {\n return {\n baseUrl: this.baseUrl,\n config: this.config,\n setLastResponse: (response: LastResponse) => {\n this.lastResponse = response;\n },\n };\n }\n\n private assertCloud(method: string): void {\n if (this.backend !== \"cloud\") {\n throw new CloudOnlyError(method);\n }\n }\n\n private assertOss(method: string): void {\n if (this.backend !== \"oss\") {\n throw new OssOnlyError(method);\n }\n }\n}\n\nfunction splitQueryAndHeaders(query: Record<string, QueryValue>): {\n query: Record<string, QueryValue>;\n headers: HeadersInit;\n} {\n const {\n useProxy,\n proxyUrl,\n proxyCountry,\n proxyClass,\n proxyProvider,\n proxySessionId,\n tenant,\n ...cleanQuery\n } = query;\n const headers: Record<string, string> = {};\n\n addHeader(headers, \"X-Use-Proxy\", useProxy);\n addHeader(headers, \"X-Proxy-URL\", proxyUrl);\n addHeader(headers, \"X-Proxy-Country\", proxyCountry);\n addHeader(headers, \"X-Proxy-Class\", proxyClass);\n addHeader(headers, \"X-Proxy-Provider\", proxyProvider);\n addHeader(headers, \"X-Proxy-Session-ID\", proxySessionId);\n addHeader(headers, \"X-Tenant\", tenant);\n\n return { query: cleanQuery, headers };\n}\n\nfunction addHeader(headers: Record<string, string>, name: string, value: QueryValue): void {\n if (value === undefined || value === null) {\n return;\n }\n headers[name] = Array.isArray(value) ? value.join(\",\") : String(value);\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/backend.ts","../src/errors.ts","../src/debug.ts","../src/request.ts","../src/client.ts"],"sourcesContent":["import type { Backend, OpenSERPConfig } from \"./types/public\";\n\nexport const OSS_BASE_URL = \"http://localhost:7000\";\nexport const CLOUD_BASE_URL = \"https://api.openserp.org/v1\";\n\nexport function normalizeBaseUrl(baseUrl: string): string {\n return baseUrl.replace(/\\/+$/, \"\");\n}\n\nexport function resolveBaseUrl(config: OpenSERPConfig): string {\n if (config.baseUrl) {\n return normalizeBaseUrl(config.baseUrl);\n }\n\n if (config.apiKey) {\n return CLOUD_BASE_URL;\n }\n\n return OSS_BASE_URL;\n}\n\nexport function inferBackend(config: Pick<OpenSERPConfig, \"apiKey\" | \"baseUrl\" | \"backend\">): Backend {\n if (config.backend) {\n return config.backend;\n }\n\n if (config.baseUrl) {\n try {\n if (new URL(config.baseUrl).hostname === \"api.openserp.org\") {\n return \"cloud\";\n }\n } catch {\n if (config.baseUrl.includes(\"api.openserp.org\")) {\n return \"cloud\";\n }\n }\n }\n\n if (config.apiKey) {\n return \"cloud\";\n }\n\n return \"oss\";\n}\n","import type { ErrorResponse } from \"./types/public\";\n\nexport class SERPError extends Error {\n readonly status: number;\n readonly code?: string | undefined;\n readonly reason?: string | undefined;\n readonly requestId?: string | undefined;\n readonly meta?: Record<string, unknown> | undefined;\n readonly response?: ErrorResponse | unknown | undefined;\n\n constructor(message: string, options: {\n status?: number | undefined;\n code?: string | undefined;\n reason?: string | undefined;\n requestId?: string | undefined;\n meta?: Record<string, unknown> | undefined;\n response?: ErrorResponse | unknown | undefined;\n cause?: unknown | undefined;\n } = {}) {\n super(message, { cause: options.cause });\n this.name = \"SERPError\";\n this.status = options.status ?? 0;\n this.code = options.code;\n this.reason = options.reason;\n this.requestId = options.requestId;\n this.meta = options.meta;\n this.response = options.response;\n }\n}\n\nexport class RateLimitError extends SERPError {\n constructor(message: string, options: ConstructorParameters<typeof SERPError>[1] = {}) {\n super(message, options);\n this.name = \"RateLimitError\";\n }\n}\n\nexport class CaptchaError extends SERPError {\n constructor(message: string, options: ConstructorParameters<typeof SERPError>[1] = {}) {\n super(message, options);\n this.name = \"CaptchaError\";\n }\n}\n\nexport class CloudOnlyError extends SERPError {\n constructor(method: string) {\n super(`${method} is only available against OpenSERP Cloud. Configure apiKey/baseUrl for https://api.openserp.org/v1 or set client.config.backend = \"cloud\".`);\n this.name = \"CloudOnlyError\";\n }\n}\n\nexport class OssOnlyError extends SERPError {\n constructor(method: string) {\n super(`${method} is only available against a self-hosted OpenSERP server. Configure baseUrl for your OSS server or set client.config.backend = \"oss\".`);\n this.name = \"OssOnlyError\";\n }\n}\n\nexport class TimeoutError extends SERPError {\n constructor(timeoutMs: number, cause?: unknown) {\n super(`OpenSERP request timed out after ${timeoutMs}ms`, {\n code: \"request_timeout\",\n cause,\n });\n this.name = \"TimeoutError\";\n }\n}\n\nexport function errorFromResponse(status: number, body: unknown, requestId?: string): SERPError {\n const data = isErrorResponse(body) ? body : undefined;\n const code = data?.error;\n const message = data?.message ?? `OpenSERP request failed with status ${status}`;\n const options = {\n status,\n code,\n reason: data?.reason,\n requestId: data?.request_id ?? requestId,\n meta: data?.meta as Record<string, unknown> | undefined,\n response: body,\n };\n\n if (status === 429 || code === \"rate_limited\") {\n return new RateLimitError(message, options);\n }\n\n if (code === \"captcha_detected\") {\n return new CaptchaError(message, options);\n }\n\n return new SERPError(message, options);\n}\n\nfunction isErrorResponse(body: unknown): body is ErrorResponse {\n return typeof body === \"object\" && body !== null && \"error\" in body;\n}\n","import type { DebugEvent, OpenSERPConfig } from \"./types/public\";\n\nexport type DebugLevel = \"off\" | \"info\" | \"verbose\";\n\ntype DebugSink = (event: DebugEvent) => void;\n\n/** Resolved debug configuration: the active level and where events go. */\nexport interface DebugReporter {\n level: DebugLevel;\n emit(event: DebugEvent): void;\n}\n\nconst NO_OP: DebugReporter = {\n level: \"off\",\n emit() {},\n};\n\n/**\n * Resolves the effective debug behaviour from config (falling back to the\n * OPENSERP_DEBUG env var). Returns a no-op reporter when debugging is off so\n * callers can emit unconditionally without a hot-path branch of their own.\n */\nexport function resolveDebug(config: OpenSERPConfig): DebugReporter {\n const setting = config.debug ?? envDebug();\n\n if (!setting) {\n return NO_OP;\n }\n\n if (typeof setting === \"function\") {\n // A custom sink always sees verbose detail; it decides what to keep.\n return { level: \"verbose\", emit: guard(setting) };\n }\n\n const level: DebugLevel = setting === \"verbose\" ? \"verbose\" : \"info\";\n return { level, emit: consoleSink };\n}\n\nfunction envDebug(): boolean | \"verbose\" | undefined {\n // Guarded so the SDK still works in browsers / runtimes without `process`.\n const value =\n typeof process !== \"undefined\" ? process.env?.OPENSERP_DEBUG : undefined;\n if (!value) {\n return undefined;\n }\n const normalized = value.trim().toLowerCase();\n if (normalized === \"verbose\") {\n return \"verbose\";\n }\n if (normalized === \"1\" || normalized === \"true\") {\n return true;\n }\n return undefined;\n}\n\n/** Wraps a user-provided sink so a thrown logger never breaks a request. */\nfunction guard(sink: DebugSink): DebugSink {\n return (event) => {\n try {\n sink(event);\n } catch {\n // A broken debug logger must not take down the actual request.\n }\n };\n}\n\nconst consoleSink: DebugSink = (event) => {\n switch (event.type) {\n case \"request\":\n console.error(`[openserp] → ${event.method} ${event.url}`);\n if (event.headers) {\n console.error(\"[openserp] headers:\", event.headers);\n }\n break;\n case \"response\": {\n const engine = event.engineUsed ? ` engine=${event.engineUsed}` : \"\";\n const reqId = event.requestId ? ` request-id=${event.requestId}` : \"\";\n console.error(\n `[openserp] ← ${event.status} ${event.method} ${event.url} (${event.durationMs}ms)${engine}${reqId}`,\n );\n if (event.headers) {\n console.error(\"[openserp] headers:\", event.headers);\n }\n break;\n }\n case \"error\":\n console.error(\n `[openserp] ✕ ${event.method} ${event.url} (${event.durationMs}ms):`,\n event.error,\n );\n break;\n }\n};\n\n/** Snapshots headers into a plain object, redacting Authorization. */\nexport function dumpHeaders(headers: Headers): Record<string, string> {\n const out: Record<string, string> = {};\n for (const [key, value] of headers) {\n out[key] = key.toLowerCase() === \"authorization\" ? \"Bearer ***\" : value;\n }\n return out;\n}\n","import { dumpHeaders, resolveDebug } from \"./debug\";\nimport { TimeoutError, errorFromResponse } from \"./errors\";\nimport type { LastResponse, OpenSERPConfig, ResponseFormat } from \"./types/public\";\n\nexport type QueryValue =\n | string\n | number\n | boolean\n | readonly string[]\n | undefined\n | null;\n\nexport interface RequestOptions {\n method?: \"GET\" | \"POST\" | undefined;\n path: string;\n query?: Record<string, QueryValue> | undefined;\n headers?: HeadersInit | undefined;\n body?: BodyInit | null | undefined;\n format?: ResponseFormat | undefined;\n}\n\nexport interface RequestContext {\n baseUrl: string;\n config: OpenSERPConfig;\n setLastResponse(response: LastResponse): void;\n}\n\nexport async function request<T>(\n context: RequestContext,\n options: RequestOptions,\n): Promise<T> {\n let attempt = 0;\n\n for (;;) {\n try {\n return await requestOnce<T>(context, options);\n } catch (err) {\n const shouldRetry = await context.config.retry?.(err, attempt);\n if (!shouldRetry) {\n throw err;\n }\n attempt += 1;\n }\n }\n}\n\nasync function requestOnce<T>(\n { baseUrl, config, setLastResponse }: RequestContext,\n options: RequestOptions,\n): Promise<T> {\n const fetchImpl = config.fetch ?? globalThis.fetch;\n if (!fetchImpl) {\n throw new TypeError(\"OpenSERP SDK requires a fetch implementation.\");\n }\n\n const url = new URL(`${baseUrl}${options.path}`);\n appendQuery(url, options.query);\n\n const headers = new Headers(config.headers);\n if (config.apiKey) {\n headers.set(\"Authorization\", `Bearer ${config.apiKey}`);\n }\n for (const [key, value] of new Headers(options.headers)) {\n headers.set(key, value);\n }\n\n const debug = resolveDebug(config);\n const method = options.method ?? \"GET\";\n if (debug.level !== \"off\") {\n debug.emit({\n type: \"request\",\n method,\n url: url.toString(),\n ...(debug.level === \"verbose\" ? { headers: dumpHeaders(headers) } : {}),\n });\n }\n\n const timeoutMs = config.timeoutMs ?? 30_000;\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), timeoutMs);\n const startedAt = Date.now();\n\n let response: Response;\n try {\n const init: RequestInit = {\n method,\n headers,\n signal: controller.signal,\n };\n if (options.body !== undefined) {\n init.body = options.body;\n }\n\n response = await fetchImpl(url, init);\n } catch (err) {\n const error = isAbortError(err) ? new TimeoutError(timeoutMs, err) : err;\n if (debug.level !== \"off\") {\n debug.emit({\n type: \"error\",\n method,\n url: url.toString(),\n durationMs: Date.now() - startedAt,\n error,\n });\n }\n throw error;\n } finally {\n clearTimeout(timer);\n }\n\n const last = readLastResponse(response);\n setLastResponse(last);\n if (debug.level !== \"off\") {\n debug.emit({\n type: \"response\",\n method,\n url: url.toString(),\n status: response.status,\n engineUsed: last.engineUsed,\n requestId: last.requestId,\n durationMs: Date.now() - startedAt,\n ...(debug.level === \"verbose\" ? { headers: dumpHeaders(response.headers) } : {}),\n });\n }\n\n const body = await readBody(response, options.format);\n if (!response.ok) {\n throw errorFromResponse(response.status, body, response.headers.get(\"x-request-id\") ?? undefined);\n }\n\n return body as T;\n}\n\nfunction appendQuery(url: URL, query: Record<string, QueryValue> | undefined): void {\n if (!query) {\n return;\n }\n\n for (const [key, value] of Object.entries(query)) {\n if (value === undefined || value === null) {\n continue;\n }\n const encoded = Array.isArray(value) ? value.join(\",\") : String(value);\n url.searchParams.set(key, encoded);\n }\n}\n\nasync function readBody(response: Response, format?: ResponseFormat): Promise<unknown> {\n if (response.status === 204) {\n return undefined;\n }\n\n if (format && format !== \"json\") {\n return response.text();\n }\n\n const contentType = response.headers.get(\"content-type\") ?? \"\";\n if (contentType.includes(\"application/json\")) {\n return response.json();\n }\n\n const text = await response.text();\n if (!text) {\n return undefined;\n }\n\n try {\n return JSON.parse(text);\n } catch {\n return text;\n }\n}\n\nfunction readLastResponse(response: Response): LastResponse {\n const credits = {\n used: numberHeader(response.headers, \"x-credits-used\"),\n remaining: numberHeader(response.headers, \"x-credits-remaining\"),\n };\n const hasCredits = credits.used !== undefined || credits.remaining !== undefined;\n\n return {\n status: response.status,\n requestId: response.headers.get(\"x-request-id\") ?? undefined,\n credits: hasCredits ? credits : undefined,\n engineUsed: response.headers.get(\"x-engine-used\") ?? undefined,\n fallbackEngine: response.headers.get(\"x-fallback-engine\") ?? undefined,\n cache: response.headers.get(\"x-cache\") ?? undefined,\n proxyMode: response.headers.get(\"x-proxy-mode\") ?? undefined,\n proxyTag: response.headers.get(\"x-proxy-tag\") ?? undefined,\n proxyUsed: response.headers.get(\"x-proxy-used\") ?? undefined,\n networkBytes: numberHeader(response.headers, \"x-network-bytes\"),\n browserProfileId: response.headers.get(\"x-browser-profile-id\") ?? undefined,\n headers: response.headers,\n };\n}\n\nfunction numberHeader(headers: Headers, name: string): number | undefined {\n const value = headers.get(name);\n if (value === null || value === \"\") {\n return undefined;\n }\n const parsed = Number(value);\n return Number.isFinite(parsed) ? parsed : undefined;\n}\n\nfunction isAbortError(err: unknown): boolean {\n return err instanceof DOMException && err.name === \"AbortError\";\n}\n","import { inferBackend, resolveBaseUrl } from \"./backend\";\nimport { CloudOnlyError, OssOnlyError } from \"./errors\";\nimport { request, type QueryValue } from \"./request\";\nimport type {\n CacheStats,\n CircuitBreakerStatsResponse,\n HealthStatus,\n ImageEnvelope,\n ImageParams,\n LastResponse,\n MegaEnginesResponse,\n MegaImageParams,\n MegaSearchEnvelope,\n MegaSearchParams,\n OpenSERPConfig,\n ParseParams,\n ReadinessStatus,\n SearchEnvelope,\n SearchParams,\n StatsResponse,\n ProxyStats,\n} from \"./types/public\";\nimport type {\n CloudAccount,\n EnginesCapabilities,\n EnginesStatus,\n Pricing,\n} from \"./types/cloud\";\n\nexport class OpenSERP {\n readonly config: OpenSERPConfig;\n lastResponse?: LastResponse;\n\n constructor(config: OpenSERPConfig = {}) {\n this.config = { ...config };\n }\n\n get backend() {\n return inferBackend(this.config);\n }\n\n get baseUrl() {\n return resolveBaseUrl(this.config);\n }\n\n search(params: SearchParams): Promise<SearchEnvelope | string> {\n const { engine, format, ...query } = params;\n return this.get<SearchEnvelope | string>(`/${engine}/search`, query, format);\n }\n\n image(params: ImageParams): Promise<ImageEnvelope | string> {\n const { engine, format, ...query } = params;\n return this.get<ImageEnvelope | string>(`/${engine}/image`, query, format);\n }\n\n megaSearch(params: MegaSearchParams): Promise<MegaSearchEnvelope | string> {\n const { format, ...query } = params;\n return this.get<MegaSearchEnvelope | string>(\"/mega/search\", query, format);\n }\n\n fastSearch(params: Omit<MegaSearchParams, \"mode\">): Promise<MegaSearchEnvelope | string> {\n return this.megaSearch({ ...params, mode: \"fast\" });\n }\n\n anySearch(params: Omit<MegaSearchParams, \"mode\">): Promise<MegaSearchEnvelope | string> {\n return this.megaSearch({ ...params, mode: \"any\" });\n }\n\n megaImage(params: MegaImageParams): Promise<ImageEnvelope | string> {\n const { format, ...query } = params;\n return this.get<ImageEnvelope | string>(\"/mega/image\", query, format);\n }\n\n fastImage(params: Omit<MegaImageParams, \"mode\">): Promise<ImageEnvelope | string> {\n return this.megaImage({ ...params, mode: \"fast\" });\n }\n\n anyImage(params: Omit<MegaImageParams, \"mode\">): Promise<ImageEnvelope | string> {\n return this.megaImage({ ...params, mode: \"any\" });\n }\n\n parseGoogle(params: ParseParams): Promise<SearchEnvelope | string> {\n this.assertOss(\"parseGoogle\");\n return this.parse(\"/google/parse\", params);\n }\n\n parseBing(params: ParseParams): Promise<SearchEnvelope | string> {\n this.assertOss(\"parseBing\");\n return this.parse(\"/bing/parse\", params);\n }\n\n health(): Promise<HealthStatus> {\n this.assertOss(\"health\");\n return this.get<HealthStatus>(\"/health\");\n }\n\n ready(): Promise<ReadinessStatus> {\n this.assertOss(\"ready\");\n return this.get<ReadinessStatus>(\"/ready\");\n }\n\n stats(): Promise<StatsResponse> {\n this.assertOss(\"stats\");\n return this.get<StatsResponse>(\"/stats\");\n }\n\n cacheStats(): Promise<CacheStats> {\n this.assertOss(\"cacheStats\");\n return this.get<CacheStats>(\"/stats/cache\");\n }\n\n proxyStats(): Promise<ProxyStats> {\n this.assertOss(\"proxyStats\");\n return this.get<ProxyStats>(\"/stats/proxy\");\n }\n\n circuitBreakerStats(): Promise<CircuitBreakerStatsResponse> {\n this.assertOss(\"circuitBreakerStats\");\n return this.get<CircuitBreakerStatsResponse>(\"/stats/cb\");\n }\n\n engines(): Promise<MegaEnginesResponse> {\n this.assertOss(\"engines\");\n return this.get<MegaEnginesResponse>(\"/mega/engines\");\n }\n\n me(): Promise<CloudAccount> {\n this.assertCloud(\"me\");\n return this.get<CloudAccount>(\"/me\");\n }\n\n pricing(): Promise<Pricing> {\n this.assertCloud(\"pricing\");\n return this.get<Pricing>(\"/pricing\");\n }\n\n enginesStatus(): Promise<EnginesStatus> {\n this.assertCloud(\"enginesStatus\");\n return this.get<EnginesStatus>(\"/engines/status\");\n }\n\n enginesCapabilities(): Promise<EnginesCapabilities> {\n this.assertCloud(\"enginesCapabilities\");\n return this.get<EnginesCapabilities>(\"/engines/capabilities\");\n }\n\n private parse(path: string, params: ParseParams): Promise<SearchEnvelope | string> {\n return request<SearchEnvelope | string>(this.requestContext(), {\n method: \"POST\",\n path,\n query: params.format ? { format: params.format } : undefined,\n headers: {\n \"Content-Type\": \"text/html; charset=utf-8\",\n },\n body: params.html,\n format: params.format,\n });\n }\n\n private get<T>(\n path: string,\n query?: Record<string, QueryValue>,\n format?: SearchParams[\"format\"],\n ): Promise<T> {\n const { query: cleanQuery, headers } = splitQueryAndHeaders({\n ...query,\n format,\n });\n\n return request<T>(this.requestContext(), {\n path,\n query: cleanQuery,\n headers,\n format,\n });\n }\n\n private requestContext() {\n return {\n baseUrl: this.baseUrl,\n config: this.config,\n setLastResponse: (response: LastResponse) => {\n this.lastResponse = response;\n },\n };\n }\n\n private assertCloud(method: string): void {\n if (this.backend !== \"cloud\") {\n throw new CloudOnlyError(method);\n }\n }\n\n private assertOss(method: string): void {\n if (this.backend !== \"oss\") {\n throw new OssOnlyError(method);\n }\n }\n}\n\nfunction splitQueryAndHeaders(query: Record<string, QueryValue>): {\n query: Record<string, QueryValue>;\n headers: HeadersInit;\n} {\n const {\n useProxy,\n proxyUrl,\n proxyCountry,\n proxyClass,\n proxyProvider,\n proxySessionId,\n tenant,\n ...cleanQuery\n } = query;\n const headers: Record<string, string> = {};\n\n addHeader(headers, \"X-Use-Proxy\", useProxy);\n addHeader(headers, \"X-Proxy-URL\", proxyUrl);\n addHeader(headers, \"X-Proxy-Country\", proxyCountry);\n addHeader(headers, \"X-Proxy-Class\", proxyClass);\n addHeader(headers, \"X-Proxy-Provider\", proxyProvider);\n addHeader(headers, \"X-Proxy-Session-ID\", proxySessionId);\n addHeader(headers, \"X-Tenant\", tenant);\n\n return { query: cleanQuery, headers };\n}\n\nfunction addHeader(headers: Record<string, string>, name: string, value: QueryValue): void {\n if (value === undefined || value === null) {\n return;\n }\n headers[name] = Array.isArray(value) ? value.join(\",\") : String(value);\n}\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openserp/sdk",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"description": "TypeScript/JavaScript SDK for the OpenSERP self-hosted server and OpenSERP Cloud.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -8,8 +8,7 @@
|
|
|
8
8
|
"homepage": "https://openserp.org",
|
|
9
9
|
"repository": {
|
|
10
10
|
"type": "git",
|
|
11
|
-
"url": "https://github.com/karust/openserp.git"
|
|
12
|
-
"directory": "integrations/sdk-js"
|
|
11
|
+
"url": "git+https://github.com/karust/openserp.git"
|
|
13
12
|
},
|
|
14
13
|
"bugs": {
|
|
15
14
|
"url": "https://github.com/karust/openserp/issues"
|
|
@@ -17,15 +16,40 @@
|
|
|
17
16
|
"keywords": [
|
|
18
17
|
"openserp",
|
|
19
18
|
"serp",
|
|
19
|
+
"serp-api",
|
|
20
20
|
"search",
|
|
21
|
+
"search-api",
|
|
22
|
+
"google-search",
|
|
23
|
+
"google-search-api",
|
|
21
24
|
"google",
|
|
22
25
|
"bing",
|
|
23
26
|
"yandex",
|
|
24
27
|
"baidu",
|
|
25
28
|
"duckduckgo",
|
|
26
29
|
"ecosia",
|
|
30
|
+
"scraper",
|
|
31
|
+
"scraping",
|
|
32
|
+
"web-scraping",
|
|
33
|
+
"serpapi",
|
|
34
|
+
"serpapi-alternative",
|
|
27
35
|
"seo",
|
|
28
|
-
"
|
|
36
|
+
"rank-tracking",
|
|
37
|
+
"rank-tracker",
|
|
38
|
+
"keyword-research",
|
|
39
|
+
"ai",
|
|
40
|
+
"ai-grounding",
|
|
41
|
+
"rag",
|
|
42
|
+
"llm",
|
|
43
|
+
"llm-tools",
|
|
44
|
+
"agent",
|
|
45
|
+
"agent-tools",
|
|
46
|
+
"tool-use",
|
|
47
|
+
"openai",
|
|
48
|
+
"anthropic",
|
|
49
|
+
"mcp",
|
|
50
|
+
"typescript",
|
|
51
|
+
"nodejs",
|
|
52
|
+
"edge-runtime"
|
|
29
53
|
],
|
|
30
54
|
"sideEffects": false,
|
|
31
55
|
"exports": {
|