seo 0.17.2 → 0.17.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/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { createRequire as __seoCreateRequire } from 'node:module'; const require = __seoCreateRequire(import.meta.url);
2
- import { n as version, t as load } from "./esm-BR8_7rhM.js";
2
+ import { n as version, t as load } from "./esm-HKeFfXOD.js";
3
3
  import { SEO_PROVIDER_API_VERSION } from "./provider-sdk.js";
4
4
  import crypto$1, { createHash, randomUUID, sign } from "node:crypto";
5
5
  import { z } from "zod";
@@ -38202,6 +38202,46 @@ async function saveResearch(store, key, saved) {
38202
38202
  if (!store) return;
38203
38203
  await store.put(key, JSON.stringify(saved), RESEARCH_TTL_SECONDS).catch(() => void 0);
38204
38204
  }
38205
+ // packages/core/src/commands/research-installed.ts
38206
+ async function installedSerpResearch(provider, input, serp) {
38207
+ if (!serp) throw new CommandError("INVALID_INPUT", `${provider} is not a built-in provider. Here the providers are dataforseo and ahrefs; installed provider packages run only in the seo CLI and the local MCP server (seo mcp serve).`);
38208
+ if (input.keywords.length === 0) throw new CommandError("INVALID_INPUT", "serp needs keywords.");
38209
+ const keywords = input.keywords.slice(0, serpKeywords(input));
38210
+ const language = dataForSeoMarket(input.country, null).language_code;
38211
+ const missed = [];
38212
+ const warnings = [];
38213
+ let costMicros = 0;
38214
+ let partial = false;
38215
+ let depth = serpDepth(input);
38216
+ const rows = await eachKeyword(keywords, missed, async (keyword) => {
38217
+ const got = await serp({
38218
+ provider,
38219
+ keyword,
38220
+ country: input.country,
38221
+ language,
38222
+ device: input.device ?? "desktop",
38223
+ depth: serpDepth(input)
38224
+ });
38225
+ depth = Math.min(depth, got.depth);
38226
+ costMicros = costMicros === null || got.costMicros === null ? null : costMicros + got.costMicros;
38227
+ partial ||= got.partial;
38228
+ warnings.push(...got.warnings.map((warning) => `${keyword}: ${warning}`));
38229
+ return got.rows.map((row) => ({
38230
+ keyword,
38231
+ ...row
38232
+ }));
38233
+ });
38234
+ const answered = new Set(rows.map((row) => row.keyword));
38235
+ if (depth < serpDepth(input)) warnings.unshift(`The package reads at most ${depth} results a keyword, so this read ${depth} of the ${serpDepth(input)} asked for.`);
38236
+ return {
38237
+ rows,
38238
+ costUsd: costMicros === null ? null : Number((costMicros / 1e6).toFixed(6)),
38239
+ partial,
38240
+ missed,
38241
+ noData: keywords.filter((keyword) => !missed.includes(keyword) && !answered.has(keyword)),
38242
+ warnings
38243
+ };
38244
+ }
38205
38245
  // packages/core/src/commands/research.ts
38206
38246
  const RESEARCH_ACTIONS = [
38207
38247
  "keyword_metrics",
@@ -38218,7 +38258,7 @@ const RESEARCH_ACTIONS = [
38218
38258
  "index_check"
38219
38259
  ];
38220
38260
  const RESEARCH_PROVIDERS = ["dataforseo", "ahrefs"];
38221
- const RESEARCH_HELP = `provider is optional: without it the call uses the saved key, DataForSEO when both are saved. The target is a domain (the whole site), a path ending in / such as example.com/blog/ (every URL under it), or one page; scope overrides that. keyword_metrics (keywords: volume, difficulty, CPC), keyword_ideas (up to 5 seed keywords: searches that contain each seed, by volume), ranked_keywords (target: keywords a site, subfolder or page ranks for, with the provider's traffic total for the whole target), top_pages (target: the pages with the most estimated organic traffic), serp (keywords, up to 5: the ranking pages with their organic position beside DataForSEO's rank_absolute, which also counts AI Overviews and other blocks, plus the AI Overview's sources; device desktop or mobile, DataForSEO only; each with its domain's authority: DataForSEO domain_rank 0 to 100, Ahrefs domain_rating; depth sets results per keyword, default 20; rows run position by position across the keywords), index_check (DataForSEO only; target: one page URL; keywords: up to 2 exact phrases from the page, default its H1 or title. Searches Google for site:<url> and each "<phrase>" on desktop and mobile, retries failed searches, treats Google's fallback to unrelated sites as no match, and says indexed, not found or unknown with each search's evidence; about $0.01 a page), serp_overlap (2 to 10 keywords: for each pair, how many of their top 10 pages and sites are the same, to decide one page or several; results without a real page are counted, not compared), competitors (target: domains that share keywords), backlinks (target: referring domains), pages_by_backlinks (target: the pages with the most referring domains), link_gap (target and 2 to 5 competitors: referring domains that link to two or more competitors and not the target, highest authority first, from each site's top 1,000 referring domains; costs one backlinks call per site), ai_answers (DataForSEO only; target: the site. Without keywords it takes the site’s top 10 chat-style and long questions from Search Console’s AI-shaped queries itself. With up to 10 questions in keywords it asks those instead, and the target can be any domain, such as a competitor's. Each answer row also lists the other sites it cites, and the notes rank them. Answers come from DataForSEO's queue: answers not ready after about 40 seconds are returned as tasks, already paid for; call again with the same target and those tasks to read them at no cost. It asks ChatGPT search, Google AI Mode and Google AI Overviews each one and says whether the answer cites or mentions the site. DataForSEO’s queue prices are about $0.0072 a question across the three engines, so about $0.07 a run: tell the person before running it). Rows with a domain, and the target, get a free Ahrefs domain_rating column. Numbers are provider estimates, not Search Console data.`;
38261
+ const RESEARCH_HELP = `provider is optional: without it the call uses the saved key, DataForSEO when both are saved. In the CLI and the local MCP server, serp can also use a provider package installed on this machine that supplies live search results: pass its id as provider. The target is a domain (the whole site), a path ending in / such as example.com/blog/ (every URL under it), or one page; scope overrides that. keyword_metrics (keywords: volume, difficulty, CPC), keyword_ideas (up to 5 seed keywords: searches that contain each seed, by volume), ranked_keywords (target: keywords a site, subfolder or page ranks for, with the provider's traffic total for the whole target), top_pages (target: the pages with the most estimated organic traffic), serp (keywords, up to 5: the ranking pages with their organic position beside DataForSEO's rank_absolute, which also counts AI Overviews and other blocks, plus the AI Overview's sources; device desktop or mobile, DataForSEO only; each with its domain's authority: DataForSEO domain_rank 0 to 100, Ahrefs domain_rating; depth sets results per keyword, default 20; rows run position by position across the keywords), index_check (DataForSEO only; target: one page URL; keywords: up to 2 exact phrases from the page, default its H1 or title. Searches Google for site:<url> and each "<phrase>" on desktop and mobile, retries failed searches, treats Google's fallback to unrelated sites as no match, and says indexed, not found or unknown with each search's evidence; about $0.01 a page), serp_overlap (2 to 10 keywords: for each pair, how many of their top 10 pages and sites are the same, to decide one page or several; results without a real page are counted, not compared), competitors (target: domains that share keywords), backlinks (target: referring domains), pages_by_backlinks (target: the pages with the most referring domains), link_gap (target and 2 to 5 competitors: referring domains that link to two or more competitors and not the target, highest authority first, from each site's top 1,000 referring domains; costs one backlinks call per site), ai_answers (DataForSEO only; target: the site. Without keywords it takes the site’s top 10 chat-style and long questions from Search Console’s AI-shaped queries itself. With up to 10 questions in keywords it asks those instead, and the target can be any domain, such as a competitor's. Each answer row also lists the other sites it cites, and the notes rank them. Answers come from DataForSEO's queue: answers not ready after about 40 seconds are returned as tasks, already paid for; call again with the same target and those tasks to read them at no cost. It asks ChatGPT search, Google AI Mode and Google AI Overviews each one and says whether the answer cites or mentions the site. DataForSEO’s queue prices are about $0.0072 a question across the three engines, so about $0.07 a run: tell the person before running it). Rows with a domain, and the target, get a free Ahrefs domain_rating column. Numbers are provider estimates, not Search Console data.`;
38222
38262
  const GENERIC_PLATFORMS = [
38223
38263
  "youtube.com",
38224
38264
  "facebook.com",
@@ -38280,6 +38320,8 @@ async function runResearch(input, keys, options) {
38280
38320
  const offset = input.offset ?? 0;
38281
38321
  if (input.action === "ai_answers") throw new CommandError("INVALID_INPUT", "ai_answers runs on its own.");
38282
38322
  const provider = chooseProvider(input.provider, keys);
38323
+ const builtIn = RESEARCH_PROVIDERS.includes(provider) ? provider : null;
38324
+ if (!builtIn && input.action !== "serp") throw new CommandError("INVALID_INPUT", `An installed provider answers serp only; ${input.action} needs a built-in provider.`);
38283
38325
  if (input.action === "index_check") {
38284
38326
  if (provider === "ahrefs") throw new CommandError("INVALID_INPUT", "index_check uses DataForSEO: it runs live Google searches, which Ahrefs does not offer.");
38285
38327
  return runIndexCheck({
@@ -38312,20 +38354,23 @@ async function runResearch(input, keys, options) {
38312
38354
  const store = options.store ?? workersResearchStore();
38313
38355
  const key = await researchKey([
38314
38356
  provider,
38315
- provider === "dataforseo" ? keys.get("x-dataforseo-login") : keys.get("x-ahrefs-key"),
38357
+ builtIn ? keys.get(KEY_HEADER[builtIn]) : null,
38316
38358
  request
38317
38359
  ]);
38318
38360
  const saved = await readResearch(store, key, limit);
38319
- const result = saved?.result ?? await research(provider, keys, {
38361
+ const result = saved?.result ?? (builtIn ? await research(builtIn, keys, {
38320
38362
  ...request,
38321
38363
  limit
38322
- });
38364
+ }) : await installedSerpResearch(provider, {
38365
+ ...request,
38366
+ limit
38367
+ }, options.installedSerp));
38323
38368
  if (!saved) await saveResearch(store, key, {
38324
38369
  limit,
38325
38370
  savedAt: (/* @__PURE__ */ new Date()).toISOString(),
38326
38371
  result
38327
38372
  });
38328
- const { rows: fetched, costUsd: paid, partial, missed, noData, floor, leftOut, available, siteTotal, rankFailed, compared, aiOverviews } = result;
38373
+ const { rows: fetched, costUsd: paid, partial, missed, noData, floor, leftOut, available, siteTotal, rankFailed, compared, aiOverviews, warnings } = result;
38329
38374
  const costUsd = saved ? 0 : paid;
38330
38375
  const order = new Map(request.keywords.map((word, index) => [word, index]));
38331
38376
  const found = input.action === "serp" && request.keywords.length > 1 ? [...fetched].sort((a, b) => Number(a.position ?? 0) - Number(b.position ?? 0) || (order.get(String(a.keyword)) ?? 0) - (order.get(String(b.keyword)) ?? 0)) : fetched;
@@ -38354,18 +38399,19 @@ async function runResearch(input, keys, options) {
38354
38399
  notes: [
38355
38400
  `${provider} estimates, in the provider’s own units.`,
38356
38401
  ...compared ? [`Compared: ${compared.withPage} of ${compared.results} top results had a real page, so shared_pages counts only those; ${compared.results - compared.withPage} came back as Google redirect links and could not be compared by page. ${compared.withSite} had a known site for shared_sites. Unique pages and sites are counted per keyword.${compared.withPage < compared.results / 2 && provider === "dataforseo" ? " With this few pages, shared_pages cannot settle one page or several; provider ahrefs returns real pages." : ""}`] : [],
38357
- ...VOLUME_ACTIONS.includes(input.action) ? [`Volume model: ${VOLUME_MODEL[provider]} ${VOLUMES_DIFFER}`] : [],
38402
+ ...VOLUME_ACTIONS.includes(input.action) && builtIn ? [`Volume model: ${VOLUME_MODEL[builtIn]} ${VOLUMES_DIFFER}`] : [],
38358
38403
  ...input.action === "serp" || input.action === "ranked_keywords" ? [positionNote(provider)] : [],
38359
38404
  ...aiOverviews?.length ? [aiOverviewNote(aiOverviews, request.keywords.length)] : input.action === "serp" && provider === "dataforseo" && rows.length ? ["No AI Overview on these results pages."] : [],
38360
38405
  ...perKeyword ? [`Results per keyword: ${Object.entries(perKeyword).map(([word, count]) => `${word} ${count}`).join(", ")}. Rows run position by position across the keywords.`] : [],
38361
- ...siteTotal ? [siteTotalNote(provider, siteTotal, rows.length)] : [],
38406
+ ...siteTotal && builtIn ? [siteTotalNote(builtIn, siteTotal, rows.length)] : [],
38362
38407
  ...available !== void 0 && available > found.length ? [`Capped: ${provider} has ${available.toLocaleString("en-US")} rows for this; this read the first ${found.length.toLocaleString("en-US")} in its order.`] : [],
38363
38408
  ...!found.length && scope ? [emptyNote(provider, input.action)] : [],
38364
38409
  ...input.action === "serp" && provider === "dataforseo" ? [rankFailed ? "domain_rank is missing: the DataForSEO rank call failed, so it is unknown, not zero." : "domain_rank is DataForSEO's own authority score for the domain, 0 to 100. It is not Ahrefs' Domain Rating."] : [],
38365
38410
  ...input.action === "serp" && !drKey && provider === "dataforseo" ? ["No domain_rating column: Domain Rating by Ahrefs needs an Ahrefs key (or the hosted MCP at https://seoskill.dev/mcp, which adds it)."] : [],
38366
38411
  ...store && rated.rows.length > 50 ? ["The result is kept for a day, so the next pages, and the same rows in full, cost nothing more."] : [],
38367
- ...saved ? [`Read from the result saved at ${saved.savedAt}, at no new cost${paid ? ` (it cost $${paid} then)` : ""}. Results are kept for a day.`] : costUsd !== null ? [`DataForSEO cost: $${costUsd}.`] : [],
38368
- ...partial ? ["Partial: DataForSEO could not fetch some pages of results, so rows may be missing."] : [],
38412
+ ...saved ? [`Read from the result saved at ${saved.savedAt}, at no new cost${paid ? ` (it cost $${paid} then)` : ""}. Results are kept for a day.`] : costUsd !== null ? [builtIn ? `DataForSEO cost: $${costUsd}.` : `Cost the ${provider} package reports: $${costUsd}.`] : [],
38413
+ ...partial ? [`Partial: ${builtIn ? "DataForSEO" : provider} could not fetch some pages of results, so rows may be missing.`] : [],
38414
+ ...warnings?.length ? [`${provider} warnings: ${warnings.join(" ")}`] : [],
38369
38415
  ...missed.length ? [`Partial: ${provider} failed for ${missed.join(", ")}, so those keywords have no rows. Ask for them again.`] : [],
38370
38416
  ...noData.length ? [noDataNote(provider, input.action, noData)] : [],
38371
38417
  ...byDr ? [rows.length > GAP_RATED ? `Sorted by Domain Rating for the top ${GAP_RATED} rows by DataForSEO rank; the ${rows.length - GAP_RATED} rows after them follow by rank, with no Domain Rating.` : "Sorted by Domain Rating, then DataForSEO rank."] : [],
@@ -38383,9 +38429,9 @@ async function runResearch(input, keys, options) {
38383
38429
  action: input.action,
38384
38430
  target: target || null,
38385
38431
  scope,
38386
- siteTotal: siteTotal ? {
38432
+ siteTotal: siteTotal && builtIn ? {
38387
38433
  ...siteTotal,
38388
- model: TRAFFIC_MODEL[provider]
38434
+ model: TRAFFIC_MODEL[builtIn]
38389
38435
  } : null,
38390
38436
  available: available ?? null,
38391
38437
  country,
@@ -38400,6 +38446,7 @@ async function runResearch(input, keys, options) {
38400
38446
  partial,
38401
38447
  missedKeywords: missed,
38402
38448
  noDataKeywords: noData,
38449
+ ...warnings?.length ? { warnings } : {},
38403
38450
  ...input.action === "link_gap" ? {
38404
38451
  competitors: input.competitors ?? [],
38405
38452
  cutAt: floor ?? null,
@@ -38416,6 +38463,7 @@ async function runResearch(input, keys, options) {
38416
38463
  };
38417
38464
  }
38418
38465
  function positionNote(provider) {
38466
+ if (provider !== "dataforseo" && provider !== "ahrefs") return `position is the organic position the ${provider} package reports (its rankGroup); rank_absolute is its rank among every block on the page, and type is featured_snippet for a featured snippet, which has no organic position.`;
38419
38467
  return provider === "dataforseo" ? "position is the organic position: the nth organic link (DataForSEO rank_group). rank_absolute counts every block on the page from the top, AI Overviews, People Also Ask, videos and images included, so it is higher. A featured snippet has type featured_snippet and no organic position." : "position is the organic position: the nth row Ahrefs marks organic. ahrefs_position is Ahrefs' own position field, and type lists what each row is.";
38420
38468
  }
38421
38469
  function aiOverviewNote(overviews, keywords) {
@@ -39403,7 +39451,7 @@ const SHARED_TOOLS = [
39403
39451
  title: "Keyword, competitor, backlink and AI answer data",
39404
39452
  description: `Data from the person’s own DataForSEO or Ahrefs account, which costs them credits. It uses the key the person saved on their seoskill.dev account (or on this machine for the CLI). Actions: ${RESEARCH_HELP}`,
39405
39453
  input: z.object({
39406
- provider: z.enum(RESEARCH_PROVIDERS).optional().describe("Optional. Without it, the saved key; DataForSEO when both are saved."),
39454
+ provider: z.string().max(64).regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/).optional().describe(`${RESEARCH_PROVIDERS.join(" or ")}. Optional: without it, the saved key; DataForSEO when both are saved. For serp in the CLI and the local MCP server it can also be the id of an installed provider package with live search results.`),
39407
39455
  action: z.enum(RESEARCH_ACTIONS),
39408
39456
  keywords: z.array(z.string().min(1)).max(100).default([]),
39409
39457
  target: z.string().default("").describe("Domain (the whole site), a path ending in / for every URL under it, such as example.com/blog/, or one page."),
@@ -39420,7 +39468,7 @@ const SHARED_TOOLS = [
39420
39468
  run: async (surface, input) => {
39421
39469
  const more = (offset) => `seo_research with the same input, detail "rows", offset ${offset}`;
39422
39470
  if (input.action === "ai_answers") {
39423
- if (input.provider === "ahrefs") throw new CommandError("INVALID_INPUT", "ai_answers uses dataforseo.");
39471
+ if (input.provider && input.provider !== "dataforseo") throw new CommandError("INVALID_INPUT", "ai_answers uses dataforseo.");
39424
39472
  return runAiAnswers({
39425
39473
  site: input.keywords.length || input.tasks.length ? input.target : await surface.resolveSite(input.target),
39426
39474
  country: input.country,
@@ -39435,6 +39483,7 @@ const SHARED_TOOLS = [
39435
39483
  return runResearch(input, await surface.keys(), {
39436
39484
  drKey: surface.drKey,
39437
39485
  store: surface.researchStore,
39486
+ installedSerp: surface.installedSerp,
39438
39487
  call: more
39439
39488
  });
39440
39489
  }
@@ -41314,6 +41363,133 @@ async function uninstallProviderExtension(id, options = {}) {
41314
41363
  ], { cwd: packagesDir });
41315
41364
  return removeInstalledProviderPackage(id);
41316
41365
  }
41366
+ // packages/core/src/provider-extensions/serp.ts
41367
+ const nullableText = z.string().max(5e4).nullable();
41368
+ const serpSnapshotResultSchema = z.object({
41369
+ observedAt: z.string().max(100),
41370
+ effectiveKeyword: z.string().trim().min(1).max(1e3),
41371
+ searchEngineDomain: z.string().max(253).nullable(),
41372
+ checkUrl: z.url().max(8192).nullable(),
41373
+ resultCount: z.number().int().nonnegative().safe().nullable(),
41374
+ pagesCount: z.number().int().nonnegative().max(100).safe().nullable(),
41375
+ features: z.array(z.string().trim().min(1).max(100)).max(100),
41376
+ organicResults: z.array(z.object({
41377
+ rankGroup: z.number().int().positive().safe(),
41378
+ rankAbsolute: z.number().int().positive().safe(),
41379
+ page: z.number().int().positive().max(100).safe(),
41380
+ domain: z.string().trim().min(1).max(253),
41381
+ url: z.url().max(8192),
41382
+ title: z.string().max(1e4).nullable(),
41383
+ description: nullableText,
41384
+ isFeaturedSnippet: z.boolean().nullable()
41385
+ }).strict()).max(100),
41386
+ localPack: z.object({
41387
+ present: z.boolean(),
41388
+ returnedRows: z.number().int().nonnegative().max(100).safe(),
41389
+ retainedRows: z.number().int().nonnegative().max(100).safe(),
41390
+ invalidRows: z.number().int().nonnegative().max(100).safe(),
41391
+ results: z.array(z.unknown()).max(100)
41392
+ }).strict(),
41393
+ coverage: z.object({
41394
+ returnedRows: z.number().int().nonnegative().max(1e4).safe(),
41395
+ retainedRows: z.number().int().nonnegative().max(100).safe(),
41396
+ invalidRows: z.number().int().nonnegative().max(1e4).safe(),
41397
+ providerTotalRows: z.number().int().nonnegative().safe().nullable(),
41398
+ completeness: z.enum([
41399
+ "complete",
41400
+ "partial",
41401
+ "capped"
41402
+ ]),
41403
+ nextCursor: z.string().max(500).nullable()
41404
+ }).strict(),
41405
+ request: z.object({
41406
+ endpoint: z.string().trim().min(1).max(500),
41407
+ filters: z.record(z.string().min(1).max(100), z.union([
41408
+ z.string().max(1e3),
41409
+ z.number().finite(),
41410
+ z.boolean()
41411
+ ])),
41412
+ sort: z.array(z.string().min(1).max(200)).max(20)
41413
+ }).strict(),
41414
+ cost: z.object({
41415
+ estimatedMicros: z.number().int().nonnegative().safe().nullable(),
41416
+ actualMicros: z.number().int().nonnegative().safe().nullable(),
41417
+ taskIds: z.array(z.string().min(1).max(500)).max(20),
41418
+ native: z.object({
41419
+ unit: z.string().trim().min(1).max(100),
41420
+ estimatedUnits: z.number().finite().nonnegative().nullable(),
41421
+ actualUnits: z.number().finite().nonnegative().nullable(),
41422
+ remainingBefore: z.number().finite().nonnegative().nullable()
41423
+ }).strict().optional()
41424
+ }).strict(),
41425
+ qualityWarnings: z.array(z.object({
41426
+ code: z.string().trim().min(1).max(100),
41427
+ message: z.string().trim().min(1).max(500),
41428
+ field: z.string().max(200).optional(),
41429
+ row: z.number().int().positive().safe().optional()
41430
+ }).strict()).max(50)
41431
+ }).strict();
41432
+ const same = (list, value) => !list || list.some((item) => item.toLowerCase() === value.toLowerCase());
41433
+ function supports(capability, market) {
41434
+ return capability.markets.some((entry) => same(entry.searchEngines, market.searchEngine) && same(entry.countryCodes, market.countryCode) && same(entry.languageCodes, market.languageCode) && same(entry.devices, market.device ?? "desktop"));
41435
+ }
41436
+ const installedProviderSerp = async (input) => {
41437
+ const loaded = await loadProviderExtensions();
41438
+ const provider = loaded.registry.get(input.provider);
41439
+ if (!provider) throw new CommandError("INVALID_INPUT", `No provider ${input.provider} is installed. The built-in providers are dataforseo and ahrefs; \`seo providers list\` shows installed packages.`);
41440
+ const capability = loaded.registry.capability(provider.id, "serp-snapshot");
41441
+ if (!capability) throw new CommandError("INVALID_INPUT", `${provider.displayName} has no live search results (serp-snapshot), so it cannot answer serp. \`seo providers describe ${provider.id}\` lists its own actions.`);
41442
+ const market = {
41443
+ searchEngine: "google",
41444
+ countryCode: input.country.toUpperCase(),
41445
+ languageCode: input.language,
41446
+ device: input.device
41447
+ };
41448
+ if (!supports(capability, market)) throw new CommandError("INVALID_INPUT", `${provider.displayName} has no ${input.device} Google results for country ${input.country} in language ${input.language}.`);
41449
+ let account;
41450
+ let credentials;
41451
+ try {
41452
+ account = normalizeProviderExtensionAccount(provider, readProviderExtensionAccount(provider.id));
41453
+ credentials = await readProviderExtensionCredentials({
41454
+ providerId: provider.id,
41455
+ account,
41456
+ fields: provider.connection.fields
41457
+ });
41458
+ } catch (error) {
41459
+ throw new CommandError("NO_KEY", `${error instanceof Error ? error.message : String(error)} Connect it with \`seo providers connect ${provider.id}\`.`);
41460
+ }
41461
+ const depth = Math.min(input.depth, capability.maxDepth);
41462
+ let raw;
41463
+ try {
41464
+ raw = await capability.run({
41465
+ account,
41466
+ credentials,
41467
+ keyword: input.keyword,
41468
+ market,
41469
+ depth
41470
+ }, runtimeForProvider(provider.id, { maxRequests: capability.maxRequests }));
41471
+ } catch (error) {
41472
+ throw new CommandError("PROVIDER_ERROR", safeProviderAdapterError(provider.id, error, credentials).message);
41473
+ }
41474
+ const parsed = serpSnapshotResultSchema.safeParse(raw);
41475
+ if (!parsed.success) throw new CommandError("PROVIDER_ERROR", `${provider.displayName} returned a results page that does not match the serp-snapshot shape.`);
41476
+ const result = parsed.data;
41477
+ const warnings = result.qualityWarnings.map((warning) => warning.message);
41478
+ return {
41479
+ rows: [...result.organicResults].sort((a, b) => a.rankAbsolute - b.rankAbsolute || (a.url < b.url ? -1 : 1)).map((item) => ({
41480
+ position: item.isFeaturedSnippet ? null : item.rankGroup,
41481
+ rank_absolute: item.rankAbsolute,
41482
+ type: item.isFeaturedSnippet ? "featured_snippet" : "organic",
41483
+ url: item.url,
41484
+ domain: item.domain,
41485
+ title: item.title
41486
+ })),
41487
+ costMicros: result.cost.actualMicros,
41488
+ partial: result.coverage.completeness === "partial",
41489
+ warnings,
41490
+ depth
41491
+ };
41492
+ };
41317
41493
  // packages/core/src/providers/ahrefs/schema.ts
41318
41494
  const ahrefsLimitsAndUsageResponseSchema = z.object({ limits_and_usage: z.object({
41319
41495
  api_key_expiration_date: z.string().trim().min(1).max(100),
@@ -42363,6 +42539,6 @@ function isoDate(daysAgo = 0) {
42363
42539
  date.setUTCDate(date.getUTCDate() - daysAgo);
42364
42540
  return date.toISOString().slice(0, 10);
42365
42541
  }
42366
- export { AHREFS_API_KEY_ENV, AHREFS_API_KEY_SECRET, AI_REFERRAL_SOURCES, AI_REFERRAL_SOURCES_VERSION, ANALYTICS_PROVIDER_IDS, AUDIT_PAGE_RULE_IDS, AhrefsClient, BING_API_KEY_ENV, BING_API_KEY_SECRET, BROWSER_USER_AGENT, CANNIBAL_MAXIMUM_DOMINANT_SHARE, CANNIBAL_MINIMUM_PAGE_IMPRESSIONS, CANNIBAL_MINIMUM_PAGE_SHARE, CLICKY_SITEKEY_ENV, CLICKY_SITE_KEYS_SECRET, CLOUD_SIGN_IN, CLOUD_URL, CRAWL_SKIP_REASONS, CTR_DEFAULT_LIMIT, CTR_MAX_LIMIT, CTR_MAX_MIN_IMPRESSIONS, DATAFORSEO_CREDENTIAL_SECRET, DATAFORSEO_LOGIN_ENV, DATAFORSEO_PASSWORD_ENV, DEFAULT_MAX_PAGES, DEFAULT_SEARCH_CONSOLE_EXPORT_ROW_LIMIT, DEFAULT_UNREACHED_PAGE_LIMIT, DataForSeoClient, DecisionModelError, DecisionRunner, GOOGLE_TIMEOUT_MS, GSC_FINAL_DATA_LAG_DAYS, GSC_TIME_ZONE, GoogleApiError, INCIDENTS_URL, JsonFileStorageAdapter, LINK_ROLES, LINT_MAX_FILES, LOCAL_BING_CONNECT, LOCAL_SIGN_IN, LOG_MAX_AGE_MS, LOG_MAX_FILE_BYTES, LOG_MAX_TOTAL_BYTES, LocalCredentialsProvider, MANAGED_PROVIDER_SECRET_NAMES, MAX_CRAWL_CONCURRENCY, MAX_CRAWL_DEPTH, MAX_CRAWL_PAGES, MAX_CRAWL_TIMEOUT_MS, MAX_MAX_PAGES, MAX_SEARCH_CONSOLE_EXPORT_FILES, MAX_SEARCH_CONSOLE_EXPORT_ROW_LIMIT, PAGE_TYPES, PROVIDER_ERROR_CODES, PROVIDER_SECRET_NAMES, ProviderError, ProviderExtensionRegistry, RESEARCH_IMPORT_COLUMN_KEYS, ResponseSizeLimitError, SEARCH_INTENTS, SEO_CRAWLER_IDENTITY, SEO_CRAWLER_TOKEN, SEO_CRAWLER_USER_AGENT, SEO_PROVIDER_API_VERSION, SEO_VERSION, SERP_TITLE_REFERENCE_WIDTH_PX, SERP_TITLE_WIDTH_PROFILE, SITEMAP_FILE_URL_LIMIT, SITE_CHECK_MAX_ISSUES, SITE_CHECK_MAX_PAGES, SITE_FACTS_DEFAULT_CONCURRENCY, SITE_FACTS_MAX_CONCURRENCY, SITE_FACTS_MAX_SITES, SITE_FACTS_TIMEOUT_MS, STEP_CHANGE_RULES, SeoError, ServiceAccountAccessTokenClient, SessionLedger, TELEMETRY_AGENTS, TELEMETRY_ENDPOINT, TELEMETRY_ERROR_CATEGORIES, TELEMETRY_EVENTS, TELEMETRY_FAILURE_CONTEXTS, TELEMETRY_FAILURE_REASONS, TELEMETRY_NOTICE, TELEMETRY_OPERATIONS, TELEMETRY_REPORTS, TELEMETRY_SCHEMA_VERSION, TELEMETRY_TIMEOUT_MS, TYPESAFE_API_KEY_ENV, URL_INSPECTION_TIMEOUT_MS, agentActionsView, aiReferralSourceForValue, aiReferralsReport, analyticsConnectionLabel, analyticsConnectionProviderId, analyticsConnectionSchema, analyticsProviderDetails, analyticsProviderSchema, analyzeAiReferralRows, analyzeCannibalImportRows, analyzeCannibalRows, analyzeCtrUnderperformersFromRows, analyzeDecay, analyzeIndexCoverageSignals, analyzePageOpportunitiesFromRows, analyzeQueryClustersFromRows, analyzeQuickWinsFromRows, analyzeSecondPageRows, analyzeSegmentRows, analyzeStrikingDistanceRows, analyzeTrafficAnomalyRows, assertCrawlConfigLimits, assertUrlMatchesGscProperty, auditCrawlPages, auditCrawlRequests, auditPage, authStatus, bearerFetch, boundedSitemapInventory, buildAgentFindings, buildQueryClusterReportFromRows, buildTelemetryPayload, builtPagePath, cacheDb, cannibalDataStatus, cannibalImportReport, cannibalReport, cannibalReportWith, changeWindow, checkBuiltSite, checkDatabaseReadiness, checkSites, classifyTelemetryFailure, clearCache, cloudAccountFor, cloudBing, cloudCredentials, cloudGoogleEmails, cloudGoogleToken, cloudKeys, cloudLinked, cloudLogout, cloudWeek, clusterQueryRows, combineRobotsValues, compareSegmentRows, configSchema, contentCoverageRecommendation, contentCoverageType, contentOptimizationFromPageOpportunities, contentOptimizationReport, countLabel, crawlConfigHash, crawlConfigSchema, crawlCoverageCaveat, crawlDefinitionId, crawlFixToQueueItem, crawlImplementationQueueWorkflow, crawlIssueGroupSchema, crawlIssueSchema, crawlOne, crawlPageSnapshotSchema, crawlReportSchema, crawlReportSummarySchema, crawlRequestObservationSchema, crawlRunId, crawlSite, crawlSkipImpact, crawlSkipReasonCountsFromRecord, crawlStatusOnly, crawlTopFixSchema, crawlerJsonSchemas, crawlerRuleCategorySchema, crawlerRuleIdSchema, crawlerRuleInfoSchema, crawlerRuleRecommendationSchema, crawlerRuleSeveritySchema, crawlerSchemas, createAuthorizedClient, createCrawlReport, createCtrBenchmarkContext, createGoogleAccessTokenClient, createLogger, createPageRenderer, ctrUnderperformersReport, ctrUnderperformersReportWith, decayClusterDrafts, decayComparisonRange, decayingReport, decayingReportWith, deleteAhrefsApiKey, deleteBingApiKey, deleteClickySiteKey, deleteDataForSeoCredentials, deleteManagedProviderSecrets, deleteProviderExtensionAccount, deleteProviderExtensionCredentials, deleteProviderSecret, deleteTokens, deriveBrandTerms, describeInstalledProviderExtension, detectAgentName, detectBrandTerms, detectTelemetryAgent, diagnoseCsvFiles, diagnoseProperty, diagnosePropertyWorkflow, effectiveRobotsDirectives, effectiveSnippetControl, ensurePrivateDatabaseFiles, ensureSeoCliDirs, estimateSerpTitleWidth, expectedCtrForPosition, explainRule, fetchCruxFieldData, fetchFailureKind, fetchPage, fetchPageStatus, fetchSearchStatusIncidents, fetchSitemapUrls, fileSize, finalGscDateRange, findOverlappingSearchUpdates, finishCloudLogin, formatRelativeExpiry, ga4MatchReason, ga4PropertyIdFromName, ga4ReportQualityWarnings, ga4RequestCanUseCache, ga4RowsToObjects, getAuthModeStatus, getCacheStats, getClientConfig, getDb, getPrivacySnapshot, getSeoCliPaths, getServiceAccountConfig, getServiceAccountStatus, getTelemetryStatus, getTokenStorageStatus, googleJson, groupCrawlIssues, hasMetaRobotsDirective, hasRule, hasXRobotsDirective, hashKey, indexCoverageSignals, inferTemplateMovement, initializeTelemetry, inspectProviderPackage, inspectSearchConsoleUrl, inspectUrl, installProviderPackage, installedProviderPackageSchema, installedProviderPackagesSchema, internalLinksReport, internalLinksReportWith, interpretUpdateCorrelation, isBrandQuery, isNewerVersion, isSkippableReportError, isTelemetryCi, isTelemetryOperation, isTelemetryReport, isoDate, isoWeek, latestFinalGscDate, linkRecover, linkRecoverRecommendation, lintPaths, listAnalyticsAccounts, listAnalyticsDataStreams, listGa4AccountSummaries, listGa4DataStreams, listGoogleAccounts, listInstalledProviderExtensions, listRules, listSearchConsoleSites, listSearchUpdates, listSites, loadInstalledProviderExtensions, loadProviderExtensions, loadProviderPackage, loadSearchConsoleExport, localAccounts, localBing, localCredentialsProvider, localError, localGoogleFetch, localInternalLinksDependencies, localRefreshClicky, localResearchKeys, localResearchStore, loginWithLoopback, makeRunId, matchGa4WebStreams, measureCoverage, metaRobotsDirectives, migrateLegacyMacConfig, missingOAuthClientMessage, missingSharedClientLoginMessage, nodeCommandDeps, normalizeBrandText, normalizeClickySiteId, normalizeClickySiteKey, normalizeCrawlConfig, normalizeCrawlSkipReasonCounts, normalizeForCoverage, normalizeHttpUrl, normalizeJavaScriptRenderingMode, normalizeLoadedCrawlReport, normalizeProviderExtensionAccount, normalizedResearchColumnName, notSignedIn, noteCacheWrite, openCloudLink, pageEvidenceRecommendation, pageOpportunitiesReport, parseOlderThan, pendingCloudLogin, performanceAudit, performanceReportIsCacheable, plural, providerCapabilitySchema, providerConnectionFieldSchema, providerExactVersionSchema, providerExtensionIdSchema, providerIdSchema, providerIntegritySchema, providerKindSchema, providerPackageManifestSchema, providerPackageNameSchema, providerPreferenceSchema, providerRegistrationSchema, providerRequestJson, providerRequestText, pruneLogs, publicHttpFetch, queryClusterReport, queryClusterTokens, queryContentCoverageFromPage, queryContentFieldsFromPage, queryFieldCoverage, queryOpportunityRecommendation, queryPageMetrics, queryPageTopQuery, queryPagesMetrics, queryPagesMetricsBatch, queryPagesTopQueries, queryPagesTopQueriesBatch, querySearchAnalytics, quickWinsCsvRows, quickWinsReport, quickWinsReportWith, readAhrefsApiKey, readAllTokens, readBingApiKey, readBoundedResponseText, readClickySiteKey, readClickySiteKeys, readConfig, readDataForSeoCredentials, readInstalledProviderPackages, readJson, readJsonOrUndefined, readLintFiles, readOauthClient, readProviderExtensionAccount, readProviderExtensionCredentials, readProviderSecret, readTokens, recommendationForRule, reconcileExportPagesWithCrawl, redirectTrace, refreshAuthToken, refreshPrioritiesCsvFiles, refreshPrioritiesWorkflow, registrableDomain, removeInstalledProviderPackage, renderCrawlCsv, renderCrawlHtml, renderCrawlJunit, renderCrawlMarkdownTickets, renderCrawlPagesCsv, renderCrawlPretty, renderCsv, renderPresentationTablesMarkdown, renderWorkflowMarkdown, reportNarrative, requestHeaders, requirePageVerification, researchImportColumns, resetSeoData, resolveLocalSite, resolveSegmentRanges, resolveSeoCliPaths, reviewObservations, roundedPosition, runAnalyticsProviderLandingPages, runAnalyticsReport, runDoctor, runGa4Report, runProviderExtensionAction, runtimeForProvider, safeProviderAdapterError, saveInstalledProviderPackage, searchAnalyticsRows, searchUpdatesFromIncidents, secondPage, secondPageWith, segmentComparisonRange, segmentImpact, segmentRangeDays, seoErrorEnvelope, sessionSourceInListFilter, setActiveGoogleAccount, setTelemetryEnabled, setTokenStorageMode, shiftIsoDate, shouldExcludeBrandQuery, siteStartUrl, snapshotFetchedPage, startCloudLogin, strikingDistance, strikingDistanceWith, summarizeCrawlReport, pageTechnicalSignals as technicalPageSignals, telemetryErrorCategory, toSeoError, tokenSchema, tokenStoreSchema, topFixes, trackTelemetryCommandFailed, trackTelemetryReportComplete, trackTelemetryReportFailed, trackTelemetryReportStart, trackTelemetrySetupComplete, trafficAnomaly, trafficAnomalyWith, typesafeDecisionModel, unavailableSegmentImpactReport, unicodeTokens, uninstallProviderExtension, updateCorrelation, updateNotice, updatePostmortemCsvFiles, updatePostmortemWorkflow, urlInspectionQuota, validateResearchImportColumnSources, verifyAnalyticsProvider, verifyProviderExtension, verifyQueryContent, verifyQueryContentWith, withAgentReportContract, withRankingHistory, withinGoogleTimeout, workflowPresentation, writeAhrefsApiKey, writeBingApiKey, writeClickySiteKey, writeConfig, writeDataForSeoCredentials, writeInstalledProviderPackages, writeOauthClient, writeProviderExtensionAccount, writeProviderExtensionCredentials, writeProviderSecret, writeToCache, writeTokens, xRobotsDirectives };
42542
+ export { AHREFS_API_KEY_ENV, AHREFS_API_KEY_SECRET, AI_REFERRAL_SOURCES, AI_REFERRAL_SOURCES_VERSION, ANALYTICS_PROVIDER_IDS, AUDIT_PAGE_RULE_IDS, AhrefsClient, BING_API_KEY_ENV, BING_API_KEY_SECRET, BROWSER_USER_AGENT, CANNIBAL_MAXIMUM_DOMINANT_SHARE, CANNIBAL_MINIMUM_PAGE_IMPRESSIONS, CANNIBAL_MINIMUM_PAGE_SHARE, CLICKY_SITEKEY_ENV, CLICKY_SITE_KEYS_SECRET, CLOUD_SIGN_IN, CLOUD_URL, CRAWL_SKIP_REASONS, CTR_DEFAULT_LIMIT, CTR_MAX_LIMIT, CTR_MAX_MIN_IMPRESSIONS, DATAFORSEO_CREDENTIAL_SECRET, DATAFORSEO_LOGIN_ENV, DATAFORSEO_PASSWORD_ENV, DEFAULT_MAX_PAGES, DEFAULT_SEARCH_CONSOLE_EXPORT_ROW_LIMIT, DEFAULT_UNREACHED_PAGE_LIMIT, DataForSeoClient, DecisionModelError, DecisionRunner, GOOGLE_TIMEOUT_MS, GSC_FINAL_DATA_LAG_DAYS, GSC_TIME_ZONE, GoogleApiError, INCIDENTS_URL, JsonFileStorageAdapter, LINK_ROLES, LINT_MAX_FILES, LOCAL_BING_CONNECT, LOCAL_SIGN_IN, LOG_MAX_AGE_MS, LOG_MAX_FILE_BYTES, LOG_MAX_TOTAL_BYTES, LocalCredentialsProvider, MANAGED_PROVIDER_SECRET_NAMES, MAX_CRAWL_CONCURRENCY, MAX_CRAWL_DEPTH, MAX_CRAWL_PAGES, MAX_CRAWL_TIMEOUT_MS, MAX_MAX_PAGES, MAX_SEARCH_CONSOLE_EXPORT_FILES, MAX_SEARCH_CONSOLE_EXPORT_ROW_LIMIT, PAGE_TYPES, PROVIDER_ERROR_CODES, PROVIDER_SECRET_NAMES, ProviderError, ProviderExtensionRegistry, RESEARCH_IMPORT_COLUMN_KEYS, ResponseSizeLimitError, SEARCH_INTENTS, SEO_CRAWLER_IDENTITY, SEO_CRAWLER_TOKEN, SEO_CRAWLER_USER_AGENT, SEO_PROVIDER_API_VERSION, SEO_VERSION, SERP_TITLE_REFERENCE_WIDTH_PX, SERP_TITLE_WIDTH_PROFILE, SITEMAP_FILE_URL_LIMIT, SITE_CHECK_MAX_ISSUES, SITE_CHECK_MAX_PAGES, SITE_FACTS_DEFAULT_CONCURRENCY, SITE_FACTS_MAX_CONCURRENCY, SITE_FACTS_MAX_SITES, SITE_FACTS_TIMEOUT_MS, STEP_CHANGE_RULES, SeoError, ServiceAccountAccessTokenClient, SessionLedger, TELEMETRY_AGENTS, TELEMETRY_ENDPOINT, TELEMETRY_ERROR_CATEGORIES, TELEMETRY_EVENTS, TELEMETRY_FAILURE_CONTEXTS, TELEMETRY_FAILURE_REASONS, TELEMETRY_NOTICE, TELEMETRY_OPERATIONS, TELEMETRY_REPORTS, TELEMETRY_SCHEMA_VERSION, TELEMETRY_TIMEOUT_MS, TYPESAFE_API_KEY_ENV, URL_INSPECTION_TIMEOUT_MS, agentActionsView, aiReferralSourceForValue, aiReferralsReport, analyticsConnectionLabel, analyticsConnectionProviderId, analyticsConnectionSchema, analyticsProviderDetails, analyticsProviderSchema, analyzeAiReferralRows, analyzeCannibalImportRows, analyzeCannibalRows, analyzeCtrUnderperformersFromRows, analyzeDecay, analyzeIndexCoverageSignals, analyzePageOpportunitiesFromRows, analyzeQueryClustersFromRows, analyzeQuickWinsFromRows, analyzeSecondPageRows, analyzeSegmentRows, analyzeStrikingDistanceRows, analyzeTrafficAnomalyRows, assertCrawlConfigLimits, assertUrlMatchesGscProperty, auditCrawlPages, auditCrawlRequests, auditPage, authStatus, bearerFetch, boundedSitemapInventory, buildAgentFindings, buildQueryClusterReportFromRows, buildTelemetryPayload, builtPagePath, cacheDb, cannibalDataStatus, cannibalImportReport, cannibalReport, cannibalReportWith, changeWindow, checkBuiltSite, checkDatabaseReadiness, checkSites, classifyTelemetryFailure, clearCache, cloudAccountFor, cloudBing, cloudCredentials, cloudGoogleEmails, cloudGoogleToken, cloudKeys, cloudLinked, cloudLogout, cloudWeek, clusterQueryRows, combineRobotsValues, compareSegmentRows, configSchema, contentCoverageRecommendation, contentCoverageType, contentOptimizationFromPageOpportunities, contentOptimizationReport, countLabel, crawlConfigHash, crawlConfigSchema, crawlCoverageCaveat, crawlDefinitionId, crawlFixToQueueItem, crawlImplementationQueueWorkflow, crawlIssueGroupSchema, crawlIssueSchema, crawlOne, crawlPageSnapshotSchema, crawlReportSchema, crawlReportSummarySchema, crawlRequestObservationSchema, crawlRunId, crawlSite, crawlSkipImpact, crawlSkipReasonCountsFromRecord, crawlStatusOnly, crawlTopFixSchema, crawlerJsonSchemas, crawlerRuleCategorySchema, crawlerRuleIdSchema, crawlerRuleInfoSchema, crawlerRuleRecommendationSchema, crawlerRuleSeveritySchema, crawlerSchemas, createAuthorizedClient, createCrawlReport, createCtrBenchmarkContext, createGoogleAccessTokenClient, createLogger, createPageRenderer, ctrUnderperformersReport, ctrUnderperformersReportWith, decayClusterDrafts, decayComparisonRange, decayingReport, decayingReportWith, deleteAhrefsApiKey, deleteBingApiKey, deleteClickySiteKey, deleteDataForSeoCredentials, deleteManagedProviderSecrets, deleteProviderExtensionAccount, deleteProviderExtensionCredentials, deleteProviderSecret, deleteTokens, deriveBrandTerms, describeInstalledProviderExtension, detectAgentName, detectBrandTerms, detectTelemetryAgent, diagnoseCsvFiles, diagnoseProperty, diagnosePropertyWorkflow, effectiveRobotsDirectives, effectiveSnippetControl, ensurePrivateDatabaseFiles, ensureSeoCliDirs, estimateSerpTitleWidth, expectedCtrForPosition, explainRule, fetchCruxFieldData, fetchFailureKind, fetchPage, fetchPageStatus, fetchSearchStatusIncidents, fetchSitemapUrls, fileSize, finalGscDateRange, findOverlappingSearchUpdates, finishCloudLogin, formatRelativeExpiry, ga4MatchReason, ga4PropertyIdFromName, ga4ReportQualityWarnings, ga4RequestCanUseCache, ga4RowsToObjects, getAuthModeStatus, getCacheStats, getClientConfig, getDb, getPrivacySnapshot, getSeoCliPaths, getServiceAccountConfig, getServiceAccountStatus, getTelemetryStatus, getTokenStorageStatus, googleJson, groupCrawlIssues, hasMetaRobotsDirective, hasRule, hasXRobotsDirective, hashKey, indexCoverageSignals, inferTemplateMovement, initializeTelemetry, inspectProviderPackage, inspectSearchConsoleUrl, inspectUrl, installProviderPackage, installedProviderPackageSchema, installedProviderPackagesSchema, installedProviderSerp, internalLinksReport, internalLinksReportWith, interpretUpdateCorrelation, isBrandQuery, isNewerVersion, isSkippableReportError, isTelemetryCi, isTelemetryOperation, isTelemetryReport, isoDate, isoWeek, latestFinalGscDate, linkRecover, linkRecoverRecommendation, lintPaths, listAnalyticsAccounts, listAnalyticsDataStreams, listGa4AccountSummaries, listGa4DataStreams, listGoogleAccounts, listInstalledProviderExtensions, listRules, listSearchConsoleSites, listSearchUpdates, listSites, loadInstalledProviderExtensions, loadProviderExtensions, loadProviderPackage, loadSearchConsoleExport, localAccounts, localBing, localCredentialsProvider, localError, localGoogleFetch, localInternalLinksDependencies, localRefreshClicky, localResearchKeys, localResearchStore, loginWithLoopback, makeRunId, matchGa4WebStreams, measureCoverage, metaRobotsDirectives, migrateLegacyMacConfig, missingOAuthClientMessage, missingSharedClientLoginMessage, nodeCommandDeps, normalizeBrandText, normalizeClickySiteId, normalizeClickySiteKey, normalizeCrawlConfig, normalizeCrawlSkipReasonCounts, normalizeForCoverage, normalizeHttpUrl, normalizeJavaScriptRenderingMode, normalizeLoadedCrawlReport, normalizeProviderExtensionAccount, normalizedResearchColumnName, notSignedIn, noteCacheWrite, openCloudLink, pageEvidenceRecommendation, pageOpportunitiesReport, parseOlderThan, pendingCloudLogin, performanceAudit, performanceReportIsCacheable, plural, providerCapabilitySchema, providerConnectionFieldSchema, providerExactVersionSchema, providerExtensionIdSchema, providerIdSchema, providerIntegritySchema, providerKindSchema, providerPackageManifestSchema, providerPackageNameSchema, providerPreferenceSchema, providerRegistrationSchema, providerRequestJson, providerRequestText, pruneLogs, publicHttpFetch, queryClusterReport, queryClusterTokens, queryContentCoverageFromPage, queryContentFieldsFromPage, queryFieldCoverage, queryOpportunityRecommendation, queryPageMetrics, queryPageTopQuery, queryPagesMetrics, queryPagesMetricsBatch, queryPagesTopQueries, queryPagesTopQueriesBatch, querySearchAnalytics, quickWinsCsvRows, quickWinsReport, quickWinsReportWith, readAhrefsApiKey, readAllTokens, readBingApiKey, readBoundedResponseText, readClickySiteKey, readClickySiteKeys, readConfig, readDataForSeoCredentials, readInstalledProviderPackages, readJson, readJsonOrUndefined, readLintFiles, readOauthClient, readProviderExtensionAccount, readProviderExtensionCredentials, readProviderSecret, readTokens, recommendationForRule, reconcileExportPagesWithCrawl, redirectTrace, refreshAuthToken, refreshPrioritiesCsvFiles, refreshPrioritiesWorkflow, registrableDomain, removeInstalledProviderPackage, renderCrawlCsv, renderCrawlHtml, renderCrawlJunit, renderCrawlMarkdownTickets, renderCrawlPagesCsv, renderCrawlPretty, renderCsv, renderPresentationTablesMarkdown, renderWorkflowMarkdown, reportNarrative, requestHeaders, requirePageVerification, researchImportColumns, resetSeoData, resolveLocalSite, resolveSegmentRanges, resolveSeoCliPaths, reviewObservations, roundedPosition, runAnalyticsProviderLandingPages, runAnalyticsReport, runDoctor, runGa4Report, runProviderExtensionAction, runtimeForProvider, safeProviderAdapterError, saveInstalledProviderPackage, searchAnalyticsRows, searchUpdatesFromIncidents, secondPage, secondPageWith, segmentComparisonRange, segmentImpact, segmentRangeDays, seoErrorEnvelope, sessionSourceInListFilter, setActiveGoogleAccount, setTelemetryEnabled, setTokenStorageMode, shiftIsoDate, shouldExcludeBrandQuery, siteStartUrl, snapshotFetchedPage, startCloudLogin, strikingDistance, strikingDistanceWith, summarizeCrawlReport, pageTechnicalSignals as technicalPageSignals, telemetryErrorCategory, toSeoError, tokenSchema, tokenStoreSchema, topFixes, trackTelemetryCommandFailed, trackTelemetryReportComplete, trackTelemetryReportFailed, trackTelemetryReportStart, trackTelemetrySetupComplete, trafficAnomaly, trafficAnomalyWith, typesafeDecisionModel, unavailableSegmentImpactReport, unicodeTokens, uninstallProviderExtension, updateCorrelation, updateNotice, updatePostmortemCsvFiles, updatePostmortemWorkflow, urlInspectionQuota, validateResearchImportColumnSources, verifyAnalyticsProvider, verifyProviderExtension, verifyQueryContent, verifyQueryContentWith, withAgentReportContract, withRankingHistory, withinGoogleTimeout, workflowPresentation, writeAhrefsApiKey, writeBingApiKey, writeClickySiteKey, writeConfig, writeDataForSeoCredentials, writeInstalledProviderPackages, writeOauthClient, writeProviderExtensionAccount, writeProviderExtensionCredentials, writeProviderSecret, writeToCache, writeTokens, xRobotsDirectives };
42367
42543
 
42368
42544
  //# sourceMappingURL=index.js.map