jsonseo 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 JSON SEO
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,510 @@
1
+ # JSON SEO Node SDK
2
+
3
+ Официальный клиент [JSON SEO API](https://jsonseo.ru) для JavaScript и TypeScript: выдача Яндекса, Google и Bing, картинки и видео, поисковые подсказки, Яндекс Вордстат, прогноз показов Директа и геолокация по IP.
4
+
5
+ - Написан на TypeScript, типы едут в пакете — отдельный `@types` не нужен.
6
+ - Работает в **Node 18+, Bun и Deno**, в ESM и в CommonJS.
7
+ - Без зависимостей: только штатный `fetch`.
8
+ - Двадцать один метод сервиса.
9
+ - Три попытки на запрос по умолчанию: если сервис затупил, SDK сходит ещё раз сам.
10
+
11
+ ## Установка
12
+
13
+ ```bash
14
+ npm install jsonseo
15
+ # или
16
+ bun add jsonseo
17
+ ```
18
+
19
+ Ключ берётся в [личном кабинете](https://jsonseo.ru).
20
+
21
+ ## Быстрый старт
22
+
23
+ ```ts
24
+ import { JsonSeoClient } from 'jsonseo';
25
+
26
+ const client = new JsonSeoClient('ВАШ_КЛЮЧ');
27
+
28
+ const serp = await client.yandex({
29
+ text: 'купить ноутбук',
30
+ region: 213,
31
+ });
32
+
33
+ serp.results.forEach((result, index) => {
34
+ console.log(`${index + 1}. ${result.domain} — ${result.title}`);
35
+ });
36
+ ```
37
+
38
+ CommonJS тоже поддерживается:
39
+
40
+ ```js
41
+ const { JsonSeoClient } = require('jsonseo');
42
+ ```
43
+
44
+ Если у метода один обязательный параметр, его можно передать просто строкой:
45
+
46
+ ```ts
47
+ await client.yandex('купить ноутбук');
48
+ await client.geoip('77.88.55.242');
49
+ await client.wordstatFrequency('ремонт айфона');
50
+ ```
51
+
52
+ ---
53
+
54
+ # Примеры запросов
55
+
56
+ ## Позиции сайта в Яндексе
57
+
58
+ `break_domain` останавливает сбор на нужном домене — платить за страницы ниже найденной позиции незачем.
59
+
60
+ ```ts
61
+ const serp = await client.yandex({
62
+ text: 'ремонт айфона',
63
+ region: 213, // Москва
64
+ pages: 10, // до 100 позиций
65
+ break_domain: 'example.com',
66
+ });
67
+
68
+ const position = serp.results.findIndex((r) => r.domain.endsWith('example.com'));
69
+
70
+ console.log(position === -1 ? 'не найден' : `Позиция: ${position + 1}`);
71
+ console.log(`Собрано страниц: ${serp.pages}`);
72
+ console.log(`Нашлось всего: ${serp.found_human}`);
73
+ ```
74
+
75
+ В ответе:
76
+
77
+ ```jsonc
78
+ {
79
+ "pages": 3,
80
+ "exhausted": false,
81
+ "breakDomainHit": true, // остановились на нужном домене
82
+ "query": "ремонт айфона",
83
+ "rawQuery": "ремонт айфона",
84
+ "found": 28000000,
85
+ "found_human": "нашлось 28 млн результатов",
86
+ "lr": 213,
87
+ "url": "https://yandex.ru/search/?text=...",
88
+ "results": [
89
+ {
90
+ "url": "https://example.com/remont-iphone/",
91
+ "domain": "example.com",
92
+ "title": "Ремонт айфонов в Москве",
93
+ "passage": "Починим за 30 минут...",
94
+ "breadcrumbs": "example.com › услуги"
95
+ }
96
+ ]
97
+ }
98
+ ```
99
+
100
+ ## Выдача Google по нужному городу
101
+
102
+ Регион задаётся числовым ID из справочника — сервис сам соберёт `uule` и подставит `gl`.
103
+
104
+ ```ts
105
+ const { regions } = await client.googleRegions('Казань');
106
+
107
+ const serp = await client.google({
108
+ q: 'заказать пиццу',
109
+ region: regions[0].id,
110
+ hl: 'ru',
111
+ device: 'desktop',
112
+ pages: 2,
113
+ });
114
+ ```
115
+
116
+ Если Google схлопнул часть результатов как «очень похожие», причина придёт в `filter_description`, а вернуть их можно параметром `filter`:
117
+
118
+ ```ts
119
+ const serp = await client.google({ q: 'заказать пиццу', filter: 0 });
120
+ ```
121
+
122
+ ## Выдача Bing
123
+
124
+ ```ts
125
+ const serp = await client.bing({
126
+ q: 'buy a laptop',
127
+ mkt: 'en-US',
128
+ pages: 2,
129
+ });
130
+
131
+ console.log(serp.mkt, serp.lang); // фактический рынок и язык
132
+ ```
133
+
134
+ ## Реклама на странице выдачи
135
+
136
+ Приходит отдельным массивом, органика не меняется. Стоит +0.01 ₽ за страницу, на которой реклама нашлась.
137
+
138
+ ```ts
139
+ const serp = await client.yandex({
140
+ text: 'пластиковые окна',
141
+ region: 213,
142
+ ads: true,
143
+ });
144
+
145
+ for (const ad of serp.ads ?? []) {
146
+ console.log(`${ad.block} #${ad.position} — ${ad.domain}`);
147
+ console.log(` ${ad.title}`);
148
+ }
149
+ ```
150
+
151
+ `block` — где стоял блок: `top` до органики, `bottom` после неё, `inline` между результатами. Пустой массив `ads` значит «рекламу просили, но её не было», а отсутствие поля — «не просили».
152
+
153
+ ## Ответ нейросети над выдачей
154
+
155
+ ```ts
156
+ const serp = await client.yandex({
157
+ text: 'чем отличается osb от фанеры',
158
+ ai: true,
159
+ });
160
+
161
+ if (serp.aiAnswer) {
162
+ console.log(serp.aiAnswer.markdown);
163
+
164
+ for (const source of serp.aiAnswer.sources ?? []) {
165
+ console.log(`[${source.id}] ${source.domain}`);
166
+ }
167
+ }
168
+ ```
169
+
170
+ Стоит +0.01 ₽ и только когда ответ есть: если поисковик его не показал, запрос обойдётся в обычную цену. Доступен только с первой страницы.
171
+
172
+ ## Картинки
173
+
174
+ ```ts
175
+ const images = await client.yandexImages({
176
+ q: 'скандинавский интерьер',
177
+ orientation: 'horizontal',
178
+ size: 'large',
179
+ format: 'jpg',
180
+ pages: 2,
181
+ });
182
+
183
+ for (const image of images.results) {
184
+ console.log(`${image.width}×${image.height} ${image.url}`);
185
+ console.log(` источник: ${image.sourceUrl}`);
186
+ }
187
+ ```
188
+
189
+ Те же параметры работают у `googleImages()` и `bingImages()` — SDK переводит общий фильтр в родной параметр движка. Если у поисковика такого значения нет, придёт `ValidationError` с указанием, чем заменить.
190
+
191
+ ## Видео
192
+
193
+ ```ts
194
+ const videos = await client.googleVideo({
195
+ q: 'как заменить ремень грм',
196
+ duration: 'long',
197
+ hl: 'ru',
198
+ });
199
+
200
+ for (const video of videos.results) {
201
+ console.log(`${video.title} — ${video.durationText}`);
202
+ console.log(` ${video.url} (${video.provider})`);
203
+ }
204
+ ```
205
+
206
+ Поле `duration` приходит в секундах, но не всегда: у прямых эфиров вместо длины стоит `LIVE`. Отбор вида `duration < 600` молча выбросит такие ролики — ориентируйтесь на `durationText`, он на месте всегда.
207
+
208
+ ## Поисковые подсказки
209
+
210
+ ```ts
211
+ const suggest = await client.yandexSuggest({ text: 'купить кв', region: 213 });
212
+
213
+ console.log(suggest.results);
214
+ // ['купить квартиру в москве', 'купить квартиру в новостройке', ...]
215
+ ```
216
+
217
+ Есть у всех трёх поисковиков: `yandexSuggest()`, `googleSuggest()`, `bingSuggest()`.
218
+
219
+ ## Справочник регионов
220
+
221
+ ```ts
222
+ const { regions } = await client.yandexRegions('Казань');
223
+
224
+ for (const region of regions) {
225
+ console.log(`${region.id} — ${region.name} (${region.subname})`);
226
+ }
227
+ // 43 — Казань (Республика Татарстан)
228
+ ```
229
+
230
+ Бесплатно, но ключ нужен: по нему считается лимит запросов в минуту. У `googleRegions()` в ответе дополнительно приходит готовая строка `uule`.
231
+
232
+ ## Вордстат: частота запроса
233
+
234
+ ```ts
235
+ const frequency = await client.wordstatFrequency({
236
+ text: 'ремонт айфона',
237
+ kind: 'exact', // точная частотность: "!ремонт !айфона"
238
+ region: 213,
239
+ });
240
+
241
+ console.log(frequency.results.totalValue); // 27356
242
+ ```
243
+
244
+ Вид частотности задаётся параметром `kind`, кавычки и операторы расставит сервис — фразу передавайте как есть:
245
+
246
+ | `kind` | Что считает |
247
+ | --- | --- |
248
+ | `base` | Базовая: фраза как есть |
249
+ | `phrase` | Фразовая: `"фраза"` |
250
+ | `exact` | Точная: `"!слово !слово"` — для прогноза трафика берут её |
251
+ | `superexact` | Сверхточная: `"[!слово !слово]"` |
252
+
253
+ ## Вордстат: расширение семантики
254
+
255
+ ```ts
256
+ const wordstat = await client.wordstat({ text: 'ремонт айфона', region: [213, 2] });
257
+
258
+ for (const phrase of wordstat.results.popular) {
259
+ console.log(phrase.value, phrase.text);
260
+ }
261
+
262
+ for (const phrase of wordstat.results.associations) {
263
+ console.log(phrase.value, phrase.text);
264
+ }
265
+ ```
266
+
267
+ `popular` — что ищут вместе с фразой, `associations` — соседняя семантика.
268
+
269
+ ## Вордстат: сезонность
270
+
271
+ ```ts
272
+ const graph = await client.wordstatGraph({
273
+ text: 'купить ёлку',
274
+ graph_type: 'month',
275
+ });
276
+
277
+ for (const point of graph.results.graph) {
278
+ console.log(point.text, point.absolute);
279
+ }
280
+ // июнь 2026 9042
281
+ // июль 2026 11780
282
+ ```
283
+
284
+ `month` и `week` отдают историю с 2018 года, `day` — последние 60 дней.
285
+
286
+ ## Вордстат: география спроса
287
+
288
+ ```ts
289
+ const map = await client.wordstatMap({ text: 'купить ноутбук', map_type: 'regions' });
290
+
291
+ for (const row of map.results.rows) {
292
+ console.log(row.text, row.absolute, `индекс ${row.popularity}`);
293
+ }
294
+ ```
295
+
296
+ `popularity` — affinity-индекс: 100 означает средний по стране интерес, выше — повышенный. В каждой строке приходит `region_id`, его можно сразу подставить в `region` других методов.
297
+
298
+ ## Прогноз показов Яндекс Директа
299
+
300
+ Рекламный кабинет не нужен. Список фраз передаётся массивом — SDK склеит его сам.
301
+
302
+ ```ts
303
+ const forecast = await client.direct({
304
+ phrases: ['ремонт айфона', 'замена экрана iphone', '"ремонт айфона"'],
305
+ region: 213,
306
+ period: 'month',
307
+ });
308
+
309
+ for (const row of forecast.results) {
310
+ console.log(`${row.phrase}: ${row.shows} показов`);
311
+
312
+ for (const [place, bid] of Object.entries(row.positions)) {
313
+ console.log(` ${place}: ставка ${bid.bid} ₽, бюджет ${bid.budget} ₽, кликов ${bid.clicks}`);
314
+ }
315
+ }
316
+ ```
317
+
318
+ Вид частотности задаётся операторами прямо во фразе: `ремонт айфона` — базовая, `"ремонт айфона"` — фразовая, `"!ремонт !айфона"` — точная.
319
+
320
+ Стоимость — 0.01 ₽ за пачку до 4000 символов, это около 150 обычных фраз. За один запрос принимается до 1000 фраз, на аккаунт — не больше 100 запросов в час.
321
+
322
+ ## Геолокация по IP
323
+
324
+ ```ts
325
+ const geo = await client.geoip('77.88.55.242');
326
+
327
+ console.log(`${geo.country.name}, ${geo.region.name}`);
328
+ console.log(geo.latitude, geo.longitude);
329
+ ```
330
+
331
+ ID региона тот же, что у Яндекса, — его можно сразу подставить в `region` методов выдачи и Вордстата:
332
+
333
+ ```ts
334
+ const serp = await client.yandex({
335
+ text: 'доставка пиццы',
336
+ region: geo.region.id,
337
+ });
338
+ ```
339
+
340
+ ## Баланс
341
+
342
+ ```ts
343
+ const { balance, currency } = await client.balance();
344
+
345
+ console.log(balance, currency); // 123.45 RUB
346
+ ```
347
+
348
+ ---
349
+
350
+ # Справочник методов
351
+
352
+ | Метод | Путь API | Что делает |
353
+ | --- | --- | --- |
354
+ | `yandex(params)` | `/yandex` | Органическая выдача Яндекса |
355
+ | `yandexSuggest(params)` | `/yandex/suggest` | Поисковые подсказки |
356
+ | `yandexRegions(params)` | `/yandex/regions` | Справочник регионов, бесплатно |
357
+ | `yandexImages(params)` | `/yandex/images` | Поиск по картинкам |
358
+ | `yandexVideo(params)` | `/yandex/video` | Поиск по видео |
359
+ | `google(params)` | `/google` | Органическая выдача Google |
360
+ | `googleSuggest(params)` | `/google/suggest` | Подсказки |
361
+ | `googleRegions(params)` | `/google/regions` | Регионы и готовый `uule`, бесплатно |
362
+ | `googleImages(params)` | `/google/images` | Поиск по картинкам |
363
+ | `googleVideo(params)` | `/google/video` | Поиск по видео |
364
+ | `bing(params)` | `/bing` | Органическая выдача Bing |
365
+ | `bingSuggest(params)` | `/bing/suggest` | Подсказки |
366
+ | `bingImages(params)` | `/bing/images` | Поиск по картинкам |
367
+ | `bingVideo(params)` | `/bing/video` | Поиск по видео |
368
+ | `wordstat(params)` | `/wordstat` | Популярные и похожие запросы |
369
+ | `wordstatFrequency(params)` | `/wordstat/frequency` | Частота запроса одним числом |
370
+ | `wordstatGraph(params)` | `/wordstat/graph` | Динамика по месяцам, неделям, дням |
371
+ | `wordstatMap(params)` | `/wordstat/map` | География показов |
372
+ | `direct(params)` | `/direct` | Прогноз показов Яндекс Директа |
373
+ | `geoip(params)` | `/geoip` | Геолокация по IPv4, бесплатно |
374
+ | `balance()` | `/balance` | Остаток на счёте, бесплатно |
375
+
376
+ Параметры каждого метода описаны типами: редактор подскажет имена и допустимые значения прямо на месте вызова. Полное описание — в [документации](https://jsonseo.ru/docs).
377
+
378
+ Появился метод, которого ещё нет в SDK? Его можно вызвать напрямую:
379
+
380
+ ```ts
381
+ await client.call<МойТип>('новый/метод', { параметр: 'значение' }); // разберёт JSON
382
+ await client.callRaw('новый/метод', { параметр: 'значение' }); // вернёт тело как есть
383
+ ```
384
+
385
+ # Как SDK помогает с параметрами
386
+
387
+ **Списки передаются массивами.** Фразы для Директа склеиваются переводом строки, остальные списки — запятой:
388
+
389
+ ```ts
390
+ await client.direct(['ремонт айфона', 'ремонт телефона', 'замена экрана']);
391
+ await client.wordstat({ text: 'ремонт', region: [213, 2], device: ['desktop', 'phone'] });
392
+ ```
393
+
394
+ **Флаги принимаются флагами.** `true` и `false` уезжают как `1` и `0`:
395
+
396
+ ```ts
397
+ await client.yandex({ text: 'купить ноутбук', ai: true, ads: true });
398
+ ```
399
+
400
+ **`null`, `undefined` и пустой массив не отправляются.** Необязательный параметр, который вы ещё не посчитали, можно не вычищать из объекта руками.
401
+
402
+ **Родные параметры поисковиков проходят насквозь.** Вертикали принимают не только общие фильтры, но и `tbs` у Google, `isize` у Яндекса, `qft` у Bing — типы это допускают.
403
+
404
+ # Ошибки
405
+
406
+ Всё, что бросает SDK, наследуется от `JsonSeoError`.
407
+
408
+ | Ошибка | Статус | Когда |
409
+ | --- | --- | --- |
410
+ | `ValidationError` | 422 | Параметры не приняты. `errors` — сообщения по полям, `fields` — их имена |
411
+ | `UnauthorizedError` | 403, 401 | Ключ не передан или недействителен |
412
+ | `PaymentRequiredError` | 402 | На счёте не хватает средств |
413
+ | `RateLimitError` | 429 | Превышен лимит частоты |
414
+ | `ServiceUnavailableError` | 503 | Выдачу получить не вышло. Деньги не списаны |
415
+ | `JsonSeoApiError` | прочие | Любой другой отказ сервиса |
416
+
417
+ У всех ошибок сервиса есть `status`, `body`, разобранный `payload` и `retryAfter` — срок, который назвал сервис, если он его назвал.
418
+
419
+ | Ошибка | Когда |
420
+ | --- | --- |
421
+ | `NetworkError` | До сервиса не достучались: сеть, DNS, TLS |
422
+ | `TimeoutError` | Ответа не дождались |
423
+ | `IncompleteResponseError` | Соединение оборвалось посреди тела |
424
+ | `ParseError` | Ответ пришёл, но не разобрался как JSON. `body` — тело как есть |
425
+ | `AbortError` | Запрос отменён через `AbortSignal` |
426
+ | `InvalidArgumentError` | SDK забраковал аргументы, запрос не отправлялся |
427
+
428
+ ```ts
429
+ import { PaymentRequiredError, RateLimitError, ValidationError } from 'jsonseo';
430
+
431
+ try {
432
+ const serp = await client.yandex({ text: 'купить ноутбук', pages: 50 });
433
+ } catch (error) {
434
+ if (error instanceof ValidationError) {
435
+ for (const [field, messages] of Object.entries(error.errors)) {
436
+ console.error(`${field}: ${messages.join(', ')}`);
437
+ }
438
+ } else if (error instanceof PaymentRequiredError) {
439
+ const { balance } = await client.balance();
440
+ console.error(`Баланс кончился: ${balance}`);
441
+ } else if (error instanceof RateLimitError) {
442
+ console.error(`Вернуться через ${error.retryAfter} с`);
443
+ } else {
444
+ throw error;
445
+ }
446
+ }
447
+ ```
448
+
449
+ # Повторы
450
+
451
+ **У каждого запроса три попытки по умолчанию: одна основная и две повторных.** Если сервис затупил и выдачу собрать не вышло (`503`), SDK сам сходит ещё дважды, и обычно этого хватает. `attempts: 1` отключает повторы совсем.
452
+
453
+ `429`, `5xx` и обрывы связи повторяются автоматически — это ровно те отказы, за которые сервис денег не берёт. Отказы по ключу, балансу и параметрам не повторяются: сами они не изменятся.
454
+
455
+ Таймаут и оборвавшееся посреди тела соединение не повторяются, и это намеренно: работу на стороне сервиса обрыв у клиента не отменяет — выдача будет собрана и оплачена, а повтор стоил бы ещё раз. Если ответ не успевает прийти, поднимайте `timeoutMs`, а не `attempts`.
456
+
457
+ Пауза между попытками удваивается и разбавляется случайной добавкой. Если сервис прислал `Retry-After`, SDK не вернётся раньше названного срока. Когда сервис просит ждать дольше `maxRetryDelayMs`, SDK не ждёт вовсе, а отдаёт ошибку с полем `retryAfter` — решение остаётся за вами.
458
+
459
+ Пауза прерывается переданным `AbortSignal`: отмена срабатывает сразу, а не в конце ожидания.
460
+
461
+ # Настройки клиента
462
+
463
+ ```ts
464
+ const client = new JsonSeoClient({
465
+ apiKey: 'ВАШ_КЛЮЧ',
466
+ baseUrl: 'https://jsonseo.ru/api', // адрес API
467
+ timeoutMs: 300_000, // сколько ждать ответа на одну попытку
468
+ attempts: 3, // всего попыток, вместе с первой
469
+ retryDelayMs: 1_000, // стартовая пауза между попытками
470
+ maxRetryDelayMs: 30_000, // потолок паузы
471
+ auth: 'header', // или 'query' — ключ в параметре key
472
+ userAgent: 'мой-проект/1.0',
473
+ fetch: myFetch, // своя реализация fetch
474
+ });
475
+ ```
476
+
477
+ Незнакомая настройка отвергается сразу — опечатка не превратится в молча взятое значение по умолчанию.
478
+
479
+ Таймаут по умолчанию намеренно большой: многостраничный запрос выдачи собирается минутами. Считается он на **каждую попытку** отдельно, а не на весь вызов: при `attempts: 3` худший случай — три таймаута подряд.
480
+
481
+ Ключ по умолчанию едет в заголовке `Authorization: Bearer`, а не в адресе: так он не оседает в логах прокси и серверов. `auth: 'query'` нужен там, где заголовки до API не доходят.
482
+
483
+ # Отмена и таймаут отдельного запроса
484
+
485
+ Вторым аргументом любой метод принимает `signal` и `timeoutMs`:
486
+
487
+ ```ts
488
+ const controller = new AbortController();
489
+ setTimeout(() => controller.abort(), 5_000);
490
+
491
+ await client.yandex('купить ноутбук', { signal: controller.signal, timeoutMs: 60_000 });
492
+ ```
493
+
494
+ # Разработка
495
+
496
+ ```bash
497
+ npm install
498
+ npm test # сборка и тесты на node:test
499
+ npm run typecheck
500
+ npm run smoke # проверка собранного пакета в текущей среде
501
+ npm run check:consumer # собранный пакет ставится в чистый проект и типизуется
502
+ ```
503
+
504
+ Тесты идут без сети: `fetch` подменяется заглушкой. Тот же набор гоняется
505
+ и в Bun (`bun test test/`), и в Deno (`deno test --allow-all --no-check`),
506
+ на Linux, macOS и Windows.
507
+
508
+ # Лицензия
509
+
510
+ MIT.
@@ -0,0 +1,71 @@
1
+ import type { ParamValue } from './common.js';
2
+ import { type ClientOptions, type RequestOptions } from './http.js';
3
+ import type { BingImagesParams, BingSearchParams, BingSuggestParams, BingVideoParams, DirectParams, GeoipParams, GoogleImagesParams, GoogleSearchParams, GoogleSuggestParams, GoogleVideoParams, RegionsParams, WordstatGraphParams, WordstatMapParams, WordstatParams, YandexImagesParams, YandexSearchParams, YandexSuggestParams, YandexVideoParams } from './params.js';
4
+ import type { BalanceResponse, DirectResponse, GeoipResponse, GoogleRegionsResponse, ImagesResponse, SearchResponse, SuggestResponse, VideoResponse, WordstatFrequencyResponse, WordstatGraphResponse, WordstatMapResponse, WordstatResponse, YandexRegionsResponse } from './responses.js';
5
+ /**
6
+ * Клиент JSON SEO API.
7
+ *
8
+ * ```ts
9
+ * const client = new JsonSeoClient('ВАШ_КЛЮЧ');
10
+ * const serp = await client.yandex({ text: 'купить ноутбук', region: 213 });
11
+ * ```
12
+ */
13
+ export declare class JsonSeoClient {
14
+ private readonly http;
15
+ constructor(apiKey: string, options?: Omit<ClientOptions, 'apiKey'>);
16
+ constructor(options: ClientOptions);
17
+ /** Органическая выдача Яндекса: мобильная, регион 213. 0.01 ₽ за страницу. */
18
+ yandex(params: string | YandexSearchParams, options?: RequestOptions): Promise<SearchResponse>;
19
+ /** Подсказки Яндекса: до 50 фраз с учётом региона. 0.01 ₽ за запрос. */
20
+ yandexSuggest(params: string | YandexSuggestParams, options?: RequestOptions): Promise<SuggestResponse>;
21
+ /** Код региона (lr) по названию города или области. Бесплатно, нужен ключ. */
22
+ yandexRegions(params: string | RegionsParams, options?: RequestOptions): Promise<YandexRegionsResponse>;
23
+ /** Картинки Яндекса: 20 карточек на страницу, 0.01 ₽ за страницу. */
24
+ yandexImages(params: string | YandexImagesParams, options?: RequestOptions): Promise<ImagesResponse>;
25
+ /** Видео Яндекса: 20 карточек на страницу, 0.01 ₽ за страницу. */
26
+ yandexVideo(params: string | YandexVideoParams, options?: RequestOptions): Promise<VideoResponse>;
27
+ /** Органическая выдача google.com: мобильная, 0.01 ₽ за страницу. */
28
+ google(params: string | GoogleSearchParams, options?: RequestOptions): Promise<SearchResponse>;
29
+ /** Подсказки Google: до ~15 фраз. 0.01 ₽ за запрос. */
30
+ googleSuggest(params: string | GoogleSuggestParams, options?: RequestOptions): Promise<SuggestResponse>;
31
+ /** ID региона Google по названию и готовый `uule`. Бесплатно, нужен ключ. */
32
+ googleRegions(params: string | RegionsParams, options?: RequestOptions): Promise<GoogleRegionsResponse>;
33
+ /** Картинки Google: 100 карточек на страницу, 0.01 ₽ за страницу. */
34
+ googleImages(params: string | GoogleImagesParams, options?: RequestOptions): Promise<ImagesResponse>;
35
+ /** Видео Google: 10 карточек на страницу, 0.01 ₽ за страницу. */
36
+ googleVideo(params: string | GoogleVideoParams, options?: RequestOptions): Promise<VideoResponse>;
37
+ /** Органическая выдача bing.com: без локации — Россия, 0.01 ₽ за страницу. */
38
+ bing(params: string | BingSearchParams, options?: RequestOptions): Promise<SearchResponse>;
39
+ /** Подсказки Bing. 0.01 ₽ за запрос. */
40
+ bingSuggest(params: string | BingSuggestParams, options?: RequestOptions): Promise<SuggestResponse>;
41
+ /** Картинки Bing: `count` карточек (по умолчанию 35), дальше 700-й не листает. */
42
+ bingImages(params: string | BingImagesParams, options?: RequestOptions): Promise<ImagesResponse>;
43
+ /** Видео Bing: `count` карточек на страницу, по умолчанию 105. */
44
+ bingVideo(params: string | BingVideoParams, options?: RequestOptions): Promise<VideoResponse>;
45
+ /** Популярные и похожие запросы. 0.01 ₽ за запрос. */
46
+ wordstat(params: string | WordstatParams, options?: RequestOptions): Promise<WordstatResponse>;
47
+ /** Частота запроса одним числом — `results.totalValue`. 0.01 ₽ за запрос. */
48
+ wordstatFrequency(params: string | WordstatParams, options?: RequestOptions): Promise<WordstatFrequencyResponse>;
49
+ /** Динамика показов по месяцам, неделям или дням. 0.01 ₽ за запрос. */
50
+ wordstatGraph(params: string | WordstatGraphParams, options?: RequestOptions): Promise<WordstatGraphResponse>;
51
+ /**
52
+ * Показы по регионам и городам. `popularity` — affinity-индекс: 100 —
53
+ * средний интерес. 0.01 ₽ за запрос.
54
+ */
55
+ wordstatMap(params: string | WordstatMapParams, options?: RequestOptions): Promise<WordstatMapResponse>;
56
+ /**
57
+ * Прогноз показов Директа со ставками и бюджетом. Кабинет не нужен.
58
+ *
59
+ * 0.01 ₽ за пачку до 4000 символов (около 150 фраз). До 1000 фраз за
60
+ * запрос, 100 запросов в час.
61
+ */
62
+ direct(params: string | ReadonlyArray<string> | DirectParams, options?: RequestOptions): Promise<DirectResponse>;
63
+ /** Страна, регион и координаты по IPv4. Бесплатно, нужен ключ. */
64
+ geoip(params: string | GeoipParams, options?: RequestOptions): Promise<GeoipResponse>;
65
+ /** Текущий баланс. Бесплатно, нужен ключ. */
66
+ balance(options?: RequestOptions): Promise<BalanceResponse>;
67
+ /** Произвольный метод API — если в сервисе появился новый. */
68
+ call<T = unknown>(path: string, params?: Record<string, ParamValue>, options?: RequestOptions): Promise<T>;
69
+ /** То же, но ответ возвращается строкой без разбора. */
70
+ callRaw(path: string, params?: Record<string, ParamValue>, options?: RequestOptions): Promise<string>;
71
+ }