seo 0.2.19 → 0.2.21
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 +24 -4
- package/dist/cli.js +127 -127
- package/dist/cli.js.map +1 -1
- package/dist/{dist-B0a6PpwF.js → dist-B-zhNcyH.js} +130 -130
- package/dist/dist-B-zhNcyH.js.map +1 -0
- package/dist/{dist-orqZyOnQ.js → dist-BITHJak_.js} +1 -1
- package/dist/{package-Dl66IhTH.js → esm-CSE-hgHf.js} +5 -5
- package/dist/esm-CSE-hgHf.js.map +1 -0
- package/dist/index.d.ts +571 -110
- package/dist/index.js +1515 -317
- package/dist/index.js.map +1 -1
- package/dist/mcp.js +1531 -331
- package/dist/mcp.js.map +1 -1
- package/evals/link-evidence.json +13 -0
- package/package.json +1 -1
- package/skills/seo/SKILL.md +4 -3
- package/dist/dist-B0a6PpwF.js.map +0 -1
- package/dist/package-Dl66IhTH.js.map +0 -1
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
|
|
2
|
+
import { n as version, t as load } from "./esm-CSE-hgHf.js";
|
|
3
3
|
import { Headers, fetch as fetch$1 } from "undici";
|
|
4
4
|
import { chmodSync, createReadStream, createWriteStream, existsSync, mkdirSync, readFileSync, readdirSync, renameSync, rmSync, statSync, writeFileSync } from "node:fs";
|
|
5
5
|
import { arch, homedir, platform, totalmem } from "node:os";
|
|
@@ -112,6 +112,88 @@ function seoErrorEnvelope(error) {
|
|
|
112
112
|
};
|
|
113
113
|
}
|
|
114
114
|
//#endregion
|
|
115
|
+
//#region packages/core/src/version.ts
|
|
116
|
+
const SEO_VERSION = version;
|
|
117
|
+
//#endregion
|
|
118
|
+
//#region packages/core/src/fetch/crawler-identity.ts
|
|
119
|
+
const SEO_CRAWLER_TOKEN = "SEO-Skill";
|
|
120
|
+
const SEO_CRAWLER_USER_AGENT = `${SEO_CRAWLER_TOKEN}/${SEO_VERSION} (+https://seoskill.dev)`;
|
|
121
|
+
const SEO_CRAWLER_IDENTITY = {
|
|
122
|
+
name: "SEO Skill",
|
|
123
|
+
robotsToken: SEO_CRAWLER_TOKEN,
|
|
124
|
+
version: SEO_VERSION,
|
|
125
|
+
userAgent: SEO_CRAWLER_USER_AGENT,
|
|
126
|
+
documentationUrl: "https://seoskill.dev/docs/crawler/"
|
|
127
|
+
};
|
|
128
|
+
//#endregion
|
|
129
|
+
//#region packages/core/src/fetch/http-client.ts
|
|
130
|
+
var ResponseSizeLimitError = class extends Error {
|
|
131
|
+
maxBytes;
|
|
132
|
+
constructor(maxBytes, label = "Response") {
|
|
133
|
+
super(`${label} exceeds the ${maxBytes}-byte response limit.`);
|
|
134
|
+
this.maxBytes = maxBytes;
|
|
135
|
+
this.name = "ResponseSizeLimitError";
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
/** @deprecated Use SEO_CRAWLER_USER_AGENT. */
|
|
139
|
+
const BROWSER_USER_AGENT = SEO_CRAWLER_USER_AGENT;
|
|
140
|
+
function requestHeaders(profile) {
|
|
141
|
+
if (profile === "bot") return new Headers({
|
|
142
|
+
accept: "text/plain,*/*;q=0.8",
|
|
143
|
+
"accept-language": "en-US,en;q=0.9",
|
|
144
|
+
connection: "close",
|
|
145
|
+
"user-agent": SEO_CRAWLER_USER_AGENT
|
|
146
|
+
});
|
|
147
|
+
return new Headers({
|
|
148
|
+
accept: "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
|
|
149
|
+
"accept-language": "en-US,en;q=0.9",
|
|
150
|
+
connection: "close",
|
|
151
|
+
"sec-ch-ua-mobile": "?0",
|
|
152
|
+
"sec-ch-ua-platform": "\"macOS\"",
|
|
153
|
+
"upgrade-insecure-requests": "1",
|
|
154
|
+
"user-agent": SEO_CRAWLER_USER_AGENT
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
function publicHttpFetch(url, input = {}) {
|
|
158
|
+
const { profile = "browser", headers, ...init } = input;
|
|
159
|
+
const base = requestHeaders(profile);
|
|
160
|
+
if (headers instanceof Headers) for (const [key, value] of headers.entries()) base.set(key, value);
|
|
161
|
+
else if (Array.isArray(headers)) for (const [key, value] of headers) base.set(key, value);
|
|
162
|
+
else if (headers) {
|
|
163
|
+
for (const [key, value] of Object.entries(headers)) if (value !== void 0) base.set(key, value);
|
|
164
|
+
}
|
|
165
|
+
return fetch$1(url, {
|
|
166
|
+
...init,
|
|
167
|
+
headers: base
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
async function readBoundedResponseText(response, maxBytes, label = "Response") {
|
|
171
|
+
const declaredLength = Number(response.headers.get("content-length"));
|
|
172
|
+
if (Number.isFinite(declaredLength) && declaredLength > maxBytes) {
|
|
173
|
+
await response.body?.cancel().catch(() => void 0);
|
|
174
|
+
throw new ResponseSizeLimitError(maxBytes, label);
|
|
175
|
+
}
|
|
176
|
+
const reader = response.body?.getReader();
|
|
177
|
+
if (!reader) return "";
|
|
178
|
+
const chunks = [];
|
|
179
|
+
let total = 0;
|
|
180
|
+
try {
|
|
181
|
+
while (true) {
|
|
182
|
+
const { done, value } = await reader.read();
|
|
183
|
+
if (done) break;
|
|
184
|
+
total += value.byteLength;
|
|
185
|
+
if (total > maxBytes) {
|
|
186
|
+
await reader.cancel().catch(() => void 0);
|
|
187
|
+
throw new ResponseSizeLimitError(maxBytes, label);
|
|
188
|
+
}
|
|
189
|
+
chunks.push(value);
|
|
190
|
+
}
|
|
191
|
+
} finally {
|
|
192
|
+
reader.releaseLock();
|
|
193
|
+
}
|
|
194
|
+
return Buffer.concat(chunks, total).toString("utf8");
|
|
195
|
+
}
|
|
196
|
+
//#endregion
|
|
115
197
|
//#region packages/core/src/paths.ts
|
|
116
198
|
let memoizedPaths;
|
|
117
199
|
function defaultConfigDir(input) {
|
|
@@ -1925,8 +2007,48 @@ function clearCache(provider, olderThanMs) {
|
|
|
1925
2007
|
compactCacheDatabase(database, { allowFullVacuum: true });
|
|
1926
2008
|
return removed;
|
|
1927
2009
|
}
|
|
2010
|
+
const propertySummarySchema = z.object({
|
|
2011
|
+
property: z.string().trim().min(1),
|
|
2012
|
+
displayName: z.string().optional(),
|
|
2013
|
+
propertyType: z.string().optional(),
|
|
2014
|
+
parent: z.string().optional()
|
|
2015
|
+
}).strip();
|
|
2016
|
+
const accountSummaryPageSchema = z.object({
|
|
2017
|
+
accountSummaries: z.array(z.object({
|
|
2018
|
+
account: z.string().trim().min(1),
|
|
2019
|
+
displayName: z.string().optional(),
|
|
2020
|
+
propertySummaries: z.array(propertySummarySchema).optional()
|
|
2021
|
+
}).strip()).max(200).optional(),
|
|
2022
|
+
nextPageToken: z.string().optional()
|
|
2023
|
+
}).strip();
|
|
2024
|
+
function parseGa4AccountSummaryPage(value) {
|
|
2025
|
+
const parsed = accountSummaryPageSchema.safeParse(value);
|
|
2026
|
+
if (!parsed.success) throw new Error("Google Analytics account summary response was invalid.");
|
|
2027
|
+
return {
|
|
2028
|
+
accountSummaries: (parsed.data.accountSummaries ?? []).map((account) => ({
|
|
2029
|
+
...account,
|
|
2030
|
+
propertySummaries: account.propertySummaries ?? []
|
|
2031
|
+
})),
|
|
2032
|
+
nextPageToken: parsed.data.nextPageToken || void 0
|
|
2033
|
+
};
|
|
2034
|
+
}
|
|
2035
|
+
async function collectGa4AccountSummaries(fetchPage) {
|
|
2036
|
+
const summaries = [];
|
|
2037
|
+
const seenPageTokens = /* @__PURE__ */ new Set();
|
|
2038
|
+
let pageToken;
|
|
2039
|
+
for (let page = 0; page < 20; page += 1) {
|
|
2040
|
+
const result = parseGa4AccountSummaryPage(await fetchPage(pageToken));
|
|
2041
|
+
summaries.push(...result.accountSummaries);
|
|
2042
|
+
if (!result.nextPageToken) return summaries;
|
|
2043
|
+
if (seenPageTokens.has(result.nextPageToken)) throw new Error("Google Analytics account summary pagination repeated a page token.");
|
|
2044
|
+
seenPageTokens.add(result.nextPageToken);
|
|
2045
|
+
pageToken = result.nextPageToken;
|
|
2046
|
+
}
|
|
2047
|
+
throw new Error(`Google Analytics account summary discovery exceeded 20 pages.`);
|
|
2048
|
+
}
|
|
1928
2049
|
//#endregion
|
|
1929
2050
|
//#region packages/core/src/ga4/client.ts
|
|
2051
|
+
const GA4_ACCOUNT_SUMMARY_RESPONSE_LIMIT_BYTES = 10 * 1024 * 1024;
|
|
1930
2052
|
function ga4RequestCanUseCache(body) {
|
|
1931
2053
|
return body.dateRanges.every((range) => /^\d{4}-\d{2}-\d{2}$/.test(range.startDate) && /^\d{4}-\d{2}-\d{2}$/.test(range.endDate));
|
|
1932
2054
|
}
|
|
@@ -1971,12 +2093,22 @@ async function runGa4Report(propertyId, body, opts = {}) {
|
|
|
1971
2093
|
}
|
|
1972
2094
|
async function listGa4AccountSummaries() {
|
|
1973
2095
|
const { client } = await createGoogleAccessTokenClient();
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
2096
|
+
return collectGa4AccountSummaries(async (pageToken) => {
|
|
2097
|
+
const url = new URL("https://analyticsadmin.googleapis.com/v1beta/accountSummaries");
|
|
2098
|
+
url.searchParams.set("pageSize", "200");
|
|
2099
|
+
if (pageToken) url.searchParams.set("pageToken", pageToken);
|
|
2100
|
+
const response = await authedFetch$1(client, url.toString());
|
|
2101
|
+
if (!response.ok) {
|
|
2102
|
+
if (response.status === 403) throw new Error("Google Analytics account summary fetch failed with 403. Enable the Google Analytics Admin API and check Analytics access.");
|
|
2103
|
+
throw new Error(`Google Analytics account summary fetch failed with ${response.status}.`);
|
|
2104
|
+
}
|
|
2105
|
+
const text = await readBoundedResponseText(response, GA4_ACCOUNT_SUMMARY_RESPONSE_LIMIT_BYTES, "Google Analytics account summary response");
|
|
2106
|
+
try {
|
|
2107
|
+
return JSON.parse(text);
|
|
2108
|
+
} catch {
|
|
2109
|
+
throw new Error("Google Analytics account summary response was invalid.");
|
|
2110
|
+
}
|
|
2111
|
+
});
|
|
1980
2112
|
}
|
|
1981
2113
|
async function listGa4DataStreams(propertyId) {
|
|
1982
2114
|
const { client } = await createGoogleAccessTokenClient();
|
|
@@ -2120,7 +2252,7 @@ function aiReferralSourceForValue(value) {
|
|
|
2120
2252
|
function compareText$18(left, right) {
|
|
2121
2253
|
return left < right ? -1 : left > right ? 1 : 0;
|
|
2122
2254
|
}
|
|
2123
|
-
function metric(row, name) {
|
|
2255
|
+
function metric$1(row, name) {
|
|
2124
2256
|
const value = row[name];
|
|
2125
2257
|
const parsed = Number(value);
|
|
2126
2258
|
if (value === void 0 || value.trim() === "" || !Number.isInteger(parsed) || parsed < 0) throw new SeoError("PROVIDER_UNAVAILABLE", `Google Analytics returned an invalid ${name} value.`);
|
|
@@ -2155,8 +2287,8 @@ function analyzeAiReferralRows(input) {
|
|
|
2155
2287
|
...emptyMetrics()
|
|
2156
2288
|
};
|
|
2157
2289
|
addMetrics(total, {
|
|
2158
|
-
sessions: metric(row, "sessions"),
|
|
2159
|
-
eventCount: metric(row, "eventCount")
|
|
2290
|
+
sessions: metric$1(row, "sessions"),
|
|
2291
|
+
eventCount: metric$1(row, "eventCount")
|
|
2160
2292
|
});
|
|
2161
2293
|
total.observedSessionSources.add(row.sessionSource ?? "");
|
|
2162
2294
|
sourceTotals.set(definition.id, total);
|
|
@@ -2168,8 +2300,8 @@ function analyzeAiReferralRows(input) {
|
|
|
2168
2300
|
const definition = aiReferralSourceForValue(row.sessionSource ?? "");
|
|
2169
2301
|
if (!definition || !sourceTotals.has(definition.id)) throw new SeoError("PROVIDER_UNAVAILABLE", "Google Analytics detail rows contained an unexpected session source.");
|
|
2170
2302
|
const metrics = {
|
|
2171
|
-
sessions: metric(row, "sessions"),
|
|
2172
|
-
eventCount: metric(row, "eventCount")
|
|
2303
|
+
sessions: metric$1(row, "sessions"),
|
|
2304
|
+
eventCount: metric$1(row, "eventCount")
|
|
2173
2305
|
};
|
|
2174
2306
|
addMetrics(detailTotal, metrics);
|
|
2175
2307
|
const landingPage = row.landingPagePlusQueryString || "(not set)";
|
|
@@ -3812,20 +3944,6 @@ async function extractPage(fetchResult, extractor = "defuddle", dependencies = {
|
|
|
3812
3944
|
};
|
|
3813
3945
|
}
|
|
3814
3946
|
//#endregion
|
|
3815
|
-
//#region packages/core/src/version.ts
|
|
3816
|
-
const SEO_VERSION = version;
|
|
3817
|
-
//#endregion
|
|
3818
|
-
//#region packages/core/src/fetch/crawler-identity.ts
|
|
3819
|
-
const SEO_CRAWLER_TOKEN = "SEO-Skill";
|
|
3820
|
-
const SEO_CRAWLER_USER_AGENT = `${SEO_CRAWLER_TOKEN}/${SEO_VERSION} (+https://seoskill.dev)`;
|
|
3821
|
-
const SEO_CRAWLER_IDENTITY = {
|
|
3822
|
-
name: "SEO Skill",
|
|
3823
|
-
robotsToken: SEO_CRAWLER_TOKEN,
|
|
3824
|
-
version: SEO_VERSION,
|
|
3825
|
-
userAgent: SEO_CRAWLER_USER_AGENT,
|
|
3826
|
-
documentationUrl: "https://seoskill.dev/docs/crawler/"
|
|
3827
|
-
};
|
|
3828
|
-
//#endregion
|
|
3829
3947
|
//#region packages/core/src/fetch/access-block.ts
|
|
3830
3948
|
const CLOUDFLARE_SKIP_DOCS = "https://developers.cloudflare.com/waf/custom-rules/skip/";
|
|
3831
3949
|
function isHeadersLike(headers) {
|
|
@@ -3897,74 +4015,6 @@ function detectAccessBlock(input) {
|
|
|
3897
4015
|
};
|
|
3898
4016
|
}
|
|
3899
4017
|
//#endregion
|
|
3900
|
-
//#region packages/core/src/fetch/http-client.ts
|
|
3901
|
-
var ResponseSizeLimitError = class extends Error {
|
|
3902
|
-
maxBytes;
|
|
3903
|
-
constructor(maxBytes, label = "Response") {
|
|
3904
|
-
super(`${label} exceeds the ${maxBytes}-byte response limit.`);
|
|
3905
|
-
this.maxBytes = maxBytes;
|
|
3906
|
-
this.name = "ResponseSizeLimitError";
|
|
3907
|
-
}
|
|
3908
|
-
};
|
|
3909
|
-
/** @deprecated Use SEO_CRAWLER_USER_AGENT. */
|
|
3910
|
-
const BROWSER_USER_AGENT = SEO_CRAWLER_USER_AGENT;
|
|
3911
|
-
function requestHeaders(profile) {
|
|
3912
|
-
if (profile === "bot") return new Headers({
|
|
3913
|
-
accept: "text/plain,*/*;q=0.8",
|
|
3914
|
-
"accept-language": "en-US,en;q=0.9",
|
|
3915
|
-
connection: "close",
|
|
3916
|
-
"user-agent": SEO_CRAWLER_USER_AGENT
|
|
3917
|
-
});
|
|
3918
|
-
return new Headers({
|
|
3919
|
-
accept: "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
|
|
3920
|
-
"accept-language": "en-US,en;q=0.9",
|
|
3921
|
-
connection: "close",
|
|
3922
|
-
"sec-ch-ua-mobile": "?0",
|
|
3923
|
-
"sec-ch-ua-platform": "\"macOS\"",
|
|
3924
|
-
"upgrade-insecure-requests": "1",
|
|
3925
|
-
"user-agent": SEO_CRAWLER_USER_AGENT
|
|
3926
|
-
});
|
|
3927
|
-
}
|
|
3928
|
-
function publicHttpFetch(url, input = {}) {
|
|
3929
|
-
const { profile = "browser", headers, ...init } = input;
|
|
3930
|
-
const base = requestHeaders(profile);
|
|
3931
|
-
if (headers instanceof Headers) for (const [key, value] of headers.entries()) base.set(key, value);
|
|
3932
|
-
else if (Array.isArray(headers)) for (const [key, value] of headers) base.set(key, value);
|
|
3933
|
-
else if (headers) {
|
|
3934
|
-
for (const [key, value] of Object.entries(headers)) if (value !== void 0) base.set(key, value);
|
|
3935
|
-
}
|
|
3936
|
-
return fetch$1(url, {
|
|
3937
|
-
...init,
|
|
3938
|
-
headers: base
|
|
3939
|
-
});
|
|
3940
|
-
}
|
|
3941
|
-
async function readBoundedResponseText(response, maxBytes, label = "Response") {
|
|
3942
|
-
const declaredLength = Number(response.headers.get("content-length"));
|
|
3943
|
-
if (Number.isFinite(declaredLength) && declaredLength > maxBytes) {
|
|
3944
|
-
await response.body?.cancel().catch(() => void 0);
|
|
3945
|
-
throw new ResponseSizeLimitError(maxBytes, label);
|
|
3946
|
-
}
|
|
3947
|
-
const reader = response.body?.getReader();
|
|
3948
|
-
if (!reader) return "";
|
|
3949
|
-
const chunks = [];
|
|
3950
|
-
let total = 0;
|
|
3951
|
-
try {
|
|
3952
|
-
while (true) {
|
|
3953
|
-
const { done, value } = await reader.read();
|
|
3954
|
-
if (done) break;
|
|
3955
|
-
total += value.byteLength;
|
|
3956
|
-
if (total > maxBytes) {
|
|
3957
|
-
await reader.cancel().catch(() => void 0);
|
|
3958
|
-
throw new ResponseSizeLimitError(maxBytes, label);
|
|
3959
|
-
}
|
|
3960
|
-
chunks.push(value);
|
|
3961
|
-
}
|
|
3962
|
-
} finally {
|
|
3963
|
-
reader.releaseLock();
|
|
3964
|
-
}
|
|
3965
|
-
return Buffer.concat(chunks, total).toString("utf8");
|
|
3966
|
-
}
|
|
3967
|
-
//#endregion
|
|
3968
4018
|
//#region packages/core/src/fetch/page-fetcher/rate-controls.ts
|
|
3969
4019
|
const HOST_QUEUES = /* @__PURE__ */ new Map();
|
|
3970
4020
|
const HOST_HEALTH = /* @__PURE__ */ new Map();
|
|
@@ -5725,7 +5775,7 @@ const AUDIT_PAGE_RULE_IDS = [
|
|
|
5725
5775
|
"canonical_outside_head",
|
|
5726
5776
|
"canonical_mismatch"
|
|
5727
5777
|
];
|
|
5728
|
-
const defaultDependencies$
|
|
5778
|
+
const defaultDependencies$17 = {
|
|
5729
5779
|
fetchPage,
|
|
5730
5780
|
queryPageMetrics,
|
|
5731
5781
|
now: () => /* @__PURE__ */ new Date()
|
|
@@ -5756,7 +5806,7 @@ function buildRecommendations(report) {
|
|
|
5756
5806
|
});
|
|
5757
5807
|
return recommendations;
|
|
5758
5808
|
}
|
|
5759
|
-
async function auditPage(input, dependencies = defaultDependencies$
|
|
5809
|
+
async function auditPage(input, dependencies = defaultDependencies$17) {
|
|
5760
5810
|
const fetched = await dependencies.fetchPage(input.url, {
|
|
5761
5811
|
js: input.js,
|
|
5762
5812
|
refresh: input.refresh
|
|
@@ -7439,7 +7489,7 @@ function pageOpportunityRecommendations(analysis) {
|
|
|
7439
7489
|
//#endregion
|
|
7440
7490
|
//#region packages/core/src/analyze/page-opportunities.ts
|
|
7441
7491
|
const MAX_BENCHMARK_ROWS = 1e5;
|
|
7442
|
-
const defaultDependencies$
|
|
7492
|
+
const defaultDependencies$16 = {
|
|
7443
7493
|
searchAnalytics: querySearchAnalytics,
|
|
7444
7494
|
fetch: fetchPage,
|
|
7445
7495
|
extract: extractPage,
|
|
@@ -7511,7 +7561,7 @@ function reportCaveats$1(input) {
|
|
|
7511
7561
|
input.benchmarkTruncated ? `The site-wide benchmark reached its ${MAX_BENCHMARK_ROWS.toLocaleString("en-US")}-row cap, so provenance is complete but the peer sample is truncated.` : ""
|
|
7512
7562
|
].filter(Boolean);
|
|
7513
7563
|
}
|
|
7514
|
-
async function pageOpportunitiesReport(input, dependencies = defaultDependencies$
|
|
7564
|
+
async function pageOpportunitiesReport(input, dependencies = defaultDependencies$16) {
|
|
7515
7565
|
const url = assertUrlMatchesGscProperty(input.site, input.url);
|
|
7516
7566
|
const days = reportDays$1(input.days);
|
|
7517
7567
|
const range = defaultDateRange$1(days);
|
|
@@ -11308,7 +11358,7 @@ function absoluteHttpUrl(value) {
|
|
|
11308
11358
|
return false;
|
|
11309
11359
|
}
|
|
11310
11360
|
}
|
|
11311
|
-
function urlKey(value) {
|
|
11361
|
+
function urlKey$1(value) {
|
|
11312
11362
|
if (!value) return void 0;
|
|
11313
11363
|
try {
|
|
11314
11364
|
const url = new URL(value);
|
|
@@ -11507,7 +11557,7 @@ function auditCrawlPages(pages, opts = {}) {
|
|
|
11507
11557
|
for (const page of pages) {
|
|
11508
11558
|
if (!isAuditableHtmlPage(page)) continue;
|
|
11509
11559
|
for (const value of [page.url, page.finalUrl]) {
|
|
11510
|
-
const key = urlKey(value);
|
|
11560
|
+
const key = urlKey$1(value);
|
|
11511
11561
|
if (key) pageByUrl.set(key, page);
|
|
11512
11562
|
}
|
|
11513
11563
|
}
|
|
@@ -11649,7 +11699,7 @@ function auditCrawlPages(pages, opts = {}) {
|
|
|
11649
11699
|
canonicalRaw: page.canonicalRaw,
|
|
11650
11700
|
canonical: page.canonical
|
|
11651
11701
|
}));
|
|
11652
|
-
const canonicalTarget = pageByUrl.get(urlKey(page.canonical) ?? "");
|
|
11702
|
+
const canonicalTarget = pageByUrl.get(urlKey$1(page.canonical) ?? "");
|
|
11653
11703
|
if (canonicalTarget?.canonical && !sameUrl(canonicalTarget.canonical, page.canonical)) issues.push(issue("canonical_chain", page, page.canonical, {
|
|
11654
11704
|
canonical: page.canonical,
|
|
11655
11705
|
nextCanonical: canonicalTarget.canonical,
|
|
@@ -11824,7 +11874,7 @@ const SENSITIVE_FIELD_NAMES = /* @__PURE__ */ new Set([
|
|
|
11824
11874
|
"refresh-token"
|
|
11825
11875
|
]);
|
|
11826
11876
|
const SENSITIVE_PARAM_PATTERN = /^(access_?token|auth|api_?key|client_?secret|code|jwt|key|password|refresh_?token|secret|session|sig|signature|token)$/i;
|
|
11827
|
-
function uniqueSorted(values = []) {
|
|
11877
|
+
function uniqueSorted$1(values = []) {
|
|
11828
11878
|
return [...new Set(values.filter(Boolean))].sort();
|
|
11829
11879
|
}
|
|
11830
11880
|
function normalizeFetchRate(input, strategy) {
|
|
@@ -11844,13 +11894,13 @@ function normalizeCrawlConfig(input) {
|
|
|
11844
11894
|
mode: input.mode ?? (strategy === "health" ? "sitemap" : "site"),
|
|
11845
11895
|
strategy,
|
|
11846
11896
|
...input.sitemapUrl ? { sitemapUrl: new URL(input.sitemapUrl).toString() } : {},
|
|
11847
|
-
urls: uniqueSorted(input.urls ?? []),
|
|
11897
|
+
urls: uniqueSorted$1(input.urls ?? []),
|
|
11848
11898
|
maxPages: input.maxPages ?? 500,
|
|
11849
11899
|
maxDepth: input.maxDepth ?? 16,
|
|
11850
11900
|
concurrency,
|
|
11851
11901
|
timeoutMs: input.timeoutMs ?? 2e4,
|
|
11852
|
-
include: uniqueSorted(input.include ?? []),
|
|
11853
|
-
exclude: uniqueSorted(input.exclude ?? []),
|
|
11902
|
+
include: uniqueSorted$1(input.include ?? []),
|
|
11903
|
+
exclude: uniqueSorted$1(input.exclude ?? []),
|
|
11854
11904
|
respectRobots: input.respectRobots ?? true,
|
|
11855
11905
|
useSitemap: input.useSitemap ?? true,
|
|
11856
11906
|
checkExternal: strategy === "health" ? false : input.checkExternal ?? true,
|
|
@@ -14104,7 +14154,7 @@ async function fetchSitemapUrls(input) {
|
|
|
14104
14154
|
}
|
|
14105
14155
|
//#endregion
|
|
14106
14156
|
//#region packages/core/src/analyze/workflows/analytics-value.ts
|
|
14107
|
-
const defaultDependencies$
|
|
14157
|
+
const defaultDependencies$15 = { runGa4Report };
|
|
14108
14158
|
function normalizePath(value) {
|
|
14109
14159
|
if (!value || value === "(not set)") return "";
|
|
14110
14160
|
const [path = ""] = value.split("?");
|
|
@@ -14164,7 +14214,7 @@ function landingPageRankingPolicy(input) {
|
|
|
14164
14214
|
warnings
|
|
14165
14215
|
};
|
|
14166
14216
|
}
|
|
14167
|
-
async function fetchLandingPageValues(input, dependencies = defaultDependencies$
|
|
14217
|
+
async function fetchLandingPageValues(input, dependencies = defaultDependencies$15) {
|
|
14168
14218
|
const retainedRowLimit = input.limit ?? 5e3;
|
|
14169
14219
|
if (!input.propertyId) return {
|
|
14170
14220
|
values: /* @__PURE__ */ new Map(),
|
|
@@ -14934,7 +14984,7 @@ async function crawlSite(input, dependencies) {
|
|
|
14934
14984
|
const REPORT_BASELINE_MAX_PAGES = 100;
|
|
14935
14985
|
const REPORT_BASELINE_MAX_DEPTH = 4;
|
|
14936
14986
|
const REPORT_BASELINE_MAX_AGE_MS = 10080 * 60 * 1e3;
|
|
14937
|
-
const defaultDependencies$
|
|
14987
|
+
const defaultDependencies$14 = {
|
|
14938
14988
|
latestCrawlReport,
|
|
14939
14989
|
crawlSite,
|
|
14940
14990
|
saveCrawlReport: (report) => saveCrawlReport(report, crawlReportStore, { retention: "baseline" }),
|
|
@@ -14983,7 +15033,7 @@ function crawlInput$1(input) {
|
|
|
14983
15033
|
refresh: input.refresh ?? false
|
|
14984
15034
|
};
|
|
14985
15035
|
}
|
|
14986
|
-
async function resolveTechnicalBaseline(input, dependencies = defaultDependencies$
|
|
15036
|
+
async function resolveTechnicalBaseline(input, dependencies = defaultDependencies$14) {
|
|
14987
15037
|
if (input.crawl === false) return {
|
|
14988
15038
|
status: "skipped",
|
|
14989
15039
|
reason: "Technical crawl evidence was skipped with --no-crawl."
|
|
@@ -18564,15 +18614,15 @@ function analyzeCtrUnderperformersFromRows(input) {
|
|
|
18564
18614
|
}
|
|
18565
18615
|
//#endregion
|
|
18566
18616
|
//#region packages/core/src/analyze/ctr-underperformers.ts
|
|
18567
|
-
const MAX_GSC_ROWS$
|
|
18617
|
+
const MAX_GSC_ROWS$5 = 1e5;
|
|
18568
18618
|
function plural$4(count, singular, pluralLabel = `${singular}s`) {
|
|
18569
18619
|
return count === 1 ? singular : pluralLabel;
|
|
18570
18620
|
}
|
|
18571
|
-
const defaultDependencies$
|
|
18621
|
+
const defaultDependencies$13 = {
|
|
18572
18622
|
searchAnalytics: querySearchAnalytics,
|
|
18573
18623
|
now: () => /* @__PURE__ */ new Date()
|
|
18574
18624
|
};
|
|
18575
|
-
async function ctrUnderperformersReport(input, dependencies = defaultDependencies$
|
|
18625
|
+
async function ctrUnderperformersReport(input, dependencies = defaultDependencies$13) {
|
|
18576
18626
|
const minImpressions = integerOption$2({
|
|
18577
18627
|
value: input.minImpressions,
|
|
18578
18628
|
fallback: 200,
|
|
@@ -18594,7 +18644,7 @@ async function ctrUnderperformersReport(input, dependencies = defaultDependencie
|
|
|
18594
18644
|
dimensions: ["query", "page"],
|
|
18595
18645
|
type: "web",
|
|
18596
18646
|
dataState: "final",
|
|
18597
|
-
maxRows: MAX_GSC_ROWS$
|
|
18647
|
+
maxRows: MAX_GSC_ROWS$5
|
|
18598
18648
|
}, { refresh: input.refresh });
|
|
18599
18649
|
const { items, totalClickShortfall, returnedClickShortfall, selection } = analyzeCtrUnderperformersFromRows({
|
|
18600
18650
|
rows: source.rows,
|
|
@@ -18605,7 +18655,7 @@ async function ctrUnderperformersReport(input, dependencies = defaultDependencie
|
|
|
18605
18655
|
includeBrand: input.includeBrand
|
|
18606
18656
|
});
|
|
18607
18657
|
const top = items[0];
|
|
18608
|
-
const possiblyTruncated = source.rowsFetched >= MAX_GSC_ROWS$
|
|
18658
|
+
const possiblyTruncated = source.rowsFetched >= MAX_GSC_ROWS$5;
|
|
18609
18659
|
const partialValidation = selection.invalidRows > 0;
|
|
18610
18660
|
const dataStatus = selection.sourceRows === 0 ? "empty" : possiblyTruncated || partialValidation ? "partial" : selection.eligibleUnderperformers === 0 ? "filtered" : "complete";
|
|
18611
18661
|
const completeness = possiblyTruncated && partialValidation ? "partial-and-possibly-truncated" : possiblyTruncated ? "possibly-truncated" : partialValidation ? "partial" : "complete";
|
|
@@ -18622,7 +18672,7 @@ async function ctrUnderperformersReport(input, dependencies = defaultDependencie
|
|
|
18622
18672
|
dataState: "final",
|
|
18623
18673
|
rowsFetched: source.rowsFetched,
|
|
18624
18674
|
calls: source.calls,
|
|
18625
|
-
maxRows: MAX_GSC_ROWS$
|
|
18675
|
+
maxRows: MAX_GSC_ROWS$5,
|
|
18626
18676
|
possiblyTruncated,
|
|
18627
18677
|
completeness,
|
|
18628
18678
|
validation: {
|
|
@@ -18652,7 +18702,7 @@ async function ctrUnderperformersReport(input, dependencies = defaultDependencie
|
|
|
18652
18702
|
"CTR benchmarks and calculated click shortfalls are directional heuristics, not forecasts or proof that clicks are available. Validate the search intent and live SERP before editing.",
|
|
18653
18703
|
...selection.invalidRows ? [`${selection.invalidRows} invalid provider ${plural$4(selection.invalidRows, "row")} ${selection.invalidRows === 1 ? "was" : "were"} excluded, so this report is partial.`] : [],
|
|
18654
18704
|
...selection.duplicateRows ? [`${selection.duplicateRows} repeated query/page ${plural$4(selection.duplicateRows, "row")} ${selection.duplicateRows === 1 ? "was" : "were"} aggregated before CTR and average position were calculated.`] : [],
|
|
18655
|
-
...possiblyTruncated ? [`The retained-row limit of ${MAX_GSC_ROWS$
|
|
18705
|
+
...possiblyTruncated ? [`The retained-row limit of ${MAX_GSC_ROWS$5} was reached, so lower-ranked source rows may be absent.`] : [],
|
|
18656
18706
|
...selection.limitedUnderperformers ? [`${selection.limitedUnderperformers} eligible ${plural$4(selection.limitedUnderperformers, "underperformer")} ${selection.limitedUnderperformers === 1 ? "was" : "were"} omitted by the output limit.`] : []
|
|
18657
18707
|
],
|
|
18658
18708
|
recommendations: top ? [
|
|
@@ -19176,7 +19226,7 @@ function unavailableSegmentImpactReport(input) {
|
|
|
19176
19226
|
//#endregion
|
|
19177
19227
|
//#region packages/core/src/analyze/segment-impact.ts
|
|
19178
19228
|
const DEFAULT_MAX_ROWS = 1e5;
|
|
19179
|
-
const defaultDependencies$
|
|
19229
|
+
const defaultDependencies$12 = {
|
|
19180
19230
|
searchAnalytics: querySearchAnalytics,
|
|
19181
19231
|
now: () => /* @__PURE__ */ new Date()
|
|
19182
19232
|
};
|
|
@@ -19216,7 +19266,7 @@ function compareSegmentRows(input) {
|
|
|
19216
19266
|
generatedAt: input.generatedAt ?? (/* @__PURE__ */ new Date()).toISOString()
|
|
19217
19267
|
});
|
|
19218
19268
|
}
|
|
19219
|
-
async function segmentImpact(input, dependencies = defaultDependencies$
|
|
19269
|
+
async function segmentImpact(input, dependencies = defaultDependencies$12) {
|
|
19220
19270
|
validateSegmentSite(input.site);
|
|
19221
19271
|
const now = dependencies.now();
|
|
19222
19272
|
const ranges = resolveSegmentRanges({
|
|
@@ -19771,8 +19821,8 @@ const CANNIBAL_MINIMUM_PAGE_SHARE = MINIMUM_PAGE_SHARE;
|
|
|
19771
19821
|
const CANNIBAL_MAXIMUM_DOMINANT_SHARE = MAXIMUM_DOMINANT_SHARE;
|
|
19772
19822
|
//#endregion
|
|
19773
19823
|
//#region packages/core/src/analyze/site-diagnostics/cannibal.ts
|
|
19774
|
-
const MAX_GSC_ROWS$
|
|
19775
|
-
const defaultDependencies$
|
|
19824
|
+
const MAX_GSC_ROWS$4 = 1e5;
|
|
19825
|
+
const defaultDependencies$11 = {
|
|
19776
19826
|
searchAnalytics: querySearchAnalytics,
|
|
19777
19827
|
now: () => /* @__PURE__ */ new Date()
|
|
19778
19828
|
};
|
|
@@ -19785,7 +19835,7 @@ function verdict$4(input) {
|
|
|
19785
19835
|
const result = `${input.returned} of ${input.eligible} multi-URL query candidate${input.eligible === 1 ? "" : "s"} returned for intent and technical review.`;
|
|
19786
19836
|
return input.status === "partial" ? `${result} Provider evidence is partial.` : result;
|
|
19787
19837
|
}
|
|
19788
|
-
async function cannibalReport(input, dependencies = defaultDependencies$
|
|
19838
|
+
async function cannibalReport(input, dependencies = defaultDependencies$11) {
|
|
19789
19839
|
const days = integerOption$2({
|
|
19790
19840
|
value: input.days,
|
|
19791
19841
|
fallback: 28,
|
|
@@ -19815,7 +19865,7 @@ async function cannibalReport(input, dependencies = defaultDependencies$10) {
|
|
|
19815
19865
|
...range,
|
|
19816
19866
|
type: "web",
|
|
19817
19867
|
dataState: "final",
|
|
19818
|
-
maxRows: MAX_GSC_ROWS$
|
|
19868
|
+
maxRows: MAX_GSC_ROWS$4
|
|
19819
19869
|
};
|
|
19820
19870
|
const [pageExposure, propertyDemand] = await Promise.all([dependencies.searchAnalytics(input.site, {
|
|
19821
19871
|
...requestBase,
|
|
@@ -19838,8 +19888,8 @@ async function cannibalReport(input, dependencies = defaultDependencies$10) {
|
|
|
19838
19888
|
brandTerms: input.brandTerms,
|
|
19839
19889
|
includeBrand: input.includeBrand
|
|
19840
19890
|
});
|
|
19841
|
-
const pageTruncated = pageExposure.rowsFetched >= MAX_GSC_ROWS$
|
|
19842
|
-
const propertyTruncated = propertyDemand.rowsFetched >= MAX_GSC_ROWS$
|
|
19891
|
+
const pageTruncated = pageExposure.rowsFetched >= MAX_GSC_ROWS$4;
|
|
19892
|
+
const propertyTruncated = propertyDemand.rowsFetched >= MAX_GSC_ROWS$4;
|
|
19843
19893
|
const possiblyTruncated = pageTruncated || propertyTruncated;
|
|
19844
19894
|
const partialValidation = analysis.selection.invalidRows + analysis.selection.propertyInvalidRows > 0;
|
|
19845
19895
|
const completeness = possiblyTruncated && partialValidation ? "partial-and-possibly-truncated" : possiblyTruncated ? "possibly-truncated" : partialValidation ? "partial" : "complete";
|
|
@@ -19864,7 +19914,7 @@ async function cannibalReport(input, dependencies = defaultDependencies$10) {
|
|
|
19864
19914
|
invalidRows: analysis.selection.invalidRows
|
|
19865
19915
|
},
|
|
19866
19916
|
calls: pageExposure.calls,
|
|
19867
|
-
maxRows: MAX_GSC_ROWS$
|
|
19917
|
+
maxRows: MAX_GSC_ROWS$4,
|
|
19868
19918
|
possiblyTruncated: pageTruncated
|
|
19869
19919
|
},
|
|
19870
19920
|
propertyDemand: {
|
|
@@ -19876,7 +19926,7 @@ async function cannibalReport(input, dependencies = defaultDependencies$10) {
|
|
|
19876
19926
|
invalidRows: analysis.selection.propertyInvalidRows
|
|
19877
19927
|
},
|
|
19878
19928
|
calls: propertyDemand.calls,
|
|
19879
|
-
maxRows: MAX_GSC_ROWS$
|
|
19929
|
+
maxRows: MAX_GSC_ROWS$4,
|
|
19880
19930
|
possiblyTruncated: propertyTruncated
|
|
19881
19931
|
},
|
|
19882
19932
|
completeness
|
|
@@ -20184,8 +20234,8 @@ function analyzeDecay(input) {
|
|
|
20184
20234
|
}
|
|
20185
20235
|
//#endregion
|
|
20186
20236
|
//#region packages/core/src/analyze/site-diagnostics/decaying.ts
|
|
20187
|
-
const MAX_GSC_ROWS$
|
|
20188
|
-
const defaultDependencies$
|
|
20237
|
+
const MAX_GSC_ROWS$3 = 1e5;
|
|
20238
|
+
const defaultDependencies$10 = {
|
|
20189
20239
|
searchAnalytics: querySearchAnalytics,
|
|
20190
20240
|
now: () => /* @__PURE__ */ new Date()
|
|
20191
20241
|
};
|
|
@@ -20196,7 +20246,7 @@ function verdict$3(report) {
|
|
|
20196
20246
|
if (!report.selection.eligibleRows) return "No observed retained query/page declines matched the report filters.";
|
|
20197
20247
|
return `${report.selection.returnedRows} of ${report.selection.eligibleRows} observed retained query/page declines returned for review.`;
|
|
20198
20248
|
}
|
|
20199
|
-
async function decayingReport(input, dependencies = defaultDependencies$
|
|
20249
|
+
async function decayingReport(input, dependencies = defaultDependencies$10) {
|
|
20200
20250
|
if (input.comparison !== void 0 && input.comparison !== "previous-period" && input.comparison !== "year-over-year") throw new SeoError("INVALID_INPUT", "comparison must be previous-period or year-over-year.");
|
|
20201
20251
|
if (input.brandTerms && (input.brandTerms.length > 20 || input.brandTerms.some((term) => !term.trim() || term.trim().length > 200))) throw new SeoError("INVALID_INPUT", "brandTerms must contain at most 20 non-empty terms of 200 characters or fewer.");
|
|
20202
20252
|
const days = integerOption$2({
|
|
@@ -20249,7 +20299,7 @@ async function decayingReport(input, dependencies = defaultDependencies$9) {
|
|
|
20249
20299
|
aggregationType: "auto",
|
|
20250
20300
|
type: "web",
|
|
20251
20301
|
dataState: "final",
|
|
20252
|
-
maxRows: MAX_GSC_ROWS$
|
|
20302
|
+
maxRows: MAX_GSC_ROWS$3
|
|
20253
20303
|
};
|
|
20254
20304
|
const [current, previous] = await Promise.all([dependencies.searchAnalytics(input.site, {
|
|
20255
20305
|
...request,
|
|
@@ -20272,8 +20322,8 @@ async function decayingReport(input, dependencies = defaultDependencies$9) {
|
|
|
20272
20322
|
brandTerms: input.brandTerms,
|
|
20273
20323
|
includeBrand: input.includeBrand
|
|
20274
20324
|
});
|
|
20275
|
-
const currentTruncated = current.rowsFetched >= MAX_GSC_ROWS$
|
|
20276
|
-
const previousTruncated = previous.rowsFetched >= MAX_GSC_ROWS$
|
|
20325
|
+
const currentTruncated = current.rowsFetched >= MAX_GSC_ROWS$3;
|
|
20326
|
+
const previousTruncated = previous.rowsFetched >= MAX_GSC_ROWS$3;
|
|
20277
20327
|
const possiblyTruncated = currentTruncated || previousTruncated;
|
|
20278
20328
|
const dataStatus = current.rowsFetched === 0 && previous.rowsFetched === 0 ? "empty" : current.rowsFetched === 0 || previous.rowsFetched === 0 || possiblyTruncated || analysis.selection.currentInvalidRows > 0 || analysis.selection.previousInvalidRows > 0 || analysis.selection.currentRowNotRetained > 0 ? "partial" : analysis.selection.eligibleRows === 0 ? "filtered" : "complete";
|
|
20279
20329
|
const reportBase = {
|
|
@@ -20300,13 +20350,13 @@ async function decayingReport(input, dependencies = defaultDependencies$9) {
|
|
|
20300
20350
|
current: {
|
|
20301
20351
|
rowsFetched: current.rowsFetched,
|
|
20302
20352
|
calls: current.calls,
|
|
20303
|
-
maxRows: MAX_GSC_ROWS$
|
|
20353
|
+
maxRows: MAX_GSC_ROWS$3,
|
|
20304
20354
|
possiblyTruncated: currentTruncated
|
|
20305
20355
|
},
|
|
20306
20356
|
previous: {
|
|
20307
20357
|
rowsFetched: previous.rowsFetched,
|
|
20308
20358
|
calls: previous.calls,
|
|
20309
|
-
maxRows: MAX_GSC_ROWS$
|
|
20359
|
+
maxRows: MAX_GSC_ROWS$3,
|
|
20310
20360
|
possiblyTruncated: previousTruncated
|
|
20311
20361
|
},
|
|
20312
20362
|
completeness: possiblyTruncated ? "possibly-truncated" : "retained-query-rows-only"
|
|
@@ -20682,12 +20732,12 @@ function quickWinTemplateSummaries(items) {
|
|
|
20682
20732
|
}
|
|
20683
20733
|
//#endregion
|
|
20684
20734
|
//#region packages/core/src/analyze/site-diagnostics/quick-wins.ts
|
|
20685
|
-
const DEFAULT_DAYS$
|
|
20686
|
-
const MAX_DAYS$
|
|
20735
|
+
const DEFAULT_DAYS$3 = 28;
|
|
20736
|
+
const MAX_DAYS$3 = 548;
|
|
20687
20737
|
const DEFAULT_VERIFY_LIMIT$1 = 5;
|
|
20688
20738
|
const MAX_VERIFY_LIMIT = 100;
|
|
20689
20739
|
const MAX_SOURCE_ROWS$3 = 1e5;
|
|
20690
|
-
const defaultDependencies$
|
|
20740
|
+
const defaultDependencies$9 = {
|
|
20691
20741
|
searchAnalytics: querySearchAnalytics,
|
|
20692
20742
|
fetch: fetchPage,
|
|
20693
20743
|
extract: extractPage,
|
|
@@ -20706,13 +20756,13 @@ function applyVerification$1(item, coverage) {
|
|
|
20706
20756
|
evidenceRef: `${item.recommendation.evidenceRef} ${coverage.summary}`
|
|
20707
20757
|
};
|
|
20708
20758
|
}
|
|
20709
|
-
async function quickWinsReport(input, dependencies = defaultDependencies$
|
|
20710
|
-
const explicitRange = explicitDateRange(input, MAX_DAYS$
|
|
20759
|
+
async function quickWinsReport(input, dependencies = defaultDependencies$9) {
|
|
20760
|
+
const explicitRange = explicitDateRange(input, MAX_DAYS$3);
|
|
20711
20761
|
const days = explicitRange?.days ?? integerOption$2({
|
|
20712
20762
|
value: input.days,
|
|
20713
|
-
fallback: DEFAULT_DAYS$
|
|
20763
|
+
fallback: DEFAULT_DAYS$3,
|
|
20714
20764
|
minimum: 1,
|
|
20715
|
-
maximum: MAX_DAYS$
|
|
20765
|
+
maximum: MAX_DAYS$3,
|
|
20716
20766
|
label: "Days"
|
|
20717
20767
|
});
|
|
20718
20768
|
const verifyLimit = integerOption$2({
|
|
@@ -21079,11 +21129,11 @@ function analyzeStrikingDistanceRows(input) {
|
|
|
21079
21129
|
}
|
|
21080
21130
|
//#endregion
|
|
21081
21131
|
//#region packages/core/src/analyze/striking-distance.ts
|
|
21082
|
-
const DEFAULT_DAYS$
|
|
21083
|
-
const MAX_DAYS$
|
|
21132
|
+
const DEFAULT_DAYS$2 = 28;
|
|
21133
|
+
const MAX_DAYS$2 = 548;
|
|
21084
21134
|
const DEFAULT_VERIFY_LIMIT = 5;
|
|
21085
21135
|
const MAX_SOURCE_ROWS$2 = 1e5;
|
|
21086
|
-
const defaultDependencies$
|
|
21136
|
+
const defaultDependencies$8 = {
|
|
21087
21137
|
searchAnalytics: querySearchAnalytics,
|
|
21088
21138
|
verifyContent: verifyQueryContent,
|
|
21089
21139
|
now: () => /* @__PURE__ */ new Date()
|
|
@@ -21093,8 +21143,8 @@ function boundedInteger$3(value, fallback, minimum, maximum) {
|
|
|
21093
21143
|
return Math.min(maximum, Math.max(minimum, Math.floor(value)));
|
|
21094
21144
|
}
|
|
21095
21145
|
function reportDays(value) {
|
|
21096
|
-
if (value === void 0) return DEFAULT_DAYS$
|
|
21097
|
-
if (!Number.isInteger(value) || value < 1 || value > MAX_DAYS$
|
|
21146
|
+
if (value === void 0) return DEFAULT_DAYS$2;
|
|
21147
|
+
if (!Number.isInteger(value) || value < 1 || value > MAX_DAYS$2) throw new SeoError("INVALID_INPUT", `Days must be a whole number between 1 and ${MAX_DAYS$2}.`);
|
|
21098
21148
|
return value;
|
|
21099
21149
|
}
|
|
21100
21150
|
function dateRange(days, now) {
|
|
@@ -21133,7 +21183,7 @@ function verdict$2(analysis) {
|
|
|
21133
21183
|
if (analysis.dataStatus === "filtered") return "No retained query/page rows met the report filters.";
|
|
21134
21184
|
return `${countLabel(analysis.summary.eligibleRows, "eligible query/page row")} found; ${countLabel(analysis.summary.returnedRows, "row")} returned for review.`;
|
|
21135
21185
|
}
|
|
21136
|
-
async function strikingDistance(input, dependencies = defaultDependencies$
|
|
21186
|
+
async function strikingDistance(input, dependencies = defaultDependencies$8) {
|
|
21137
21187
|
const days = reportDays(input.days);
|
|
21138
21188
|
const generatedAt = dependencies.now().toISOString();
|
|
21139
21189
|
const range = dateRange(days, new Date(generatedAt));
|
|
@@ -21980,7 +22030,7 @@ function emptyQuickWins(input) {
|
|
|
21980
22030
|
warnings: []
|
|
21981
22031
|
};
|
|
21982
22032
|
}
|
|
21983
|
-
const defaultDependencies$
|
|
22033
|
+
const defaultDependencies$7 = {
|
|
21984
22034
|
trafficAnomaly,
|
|
21985
22035
|
updateCorrelation,
|
|
21986
22036
|
segmentImpact,
|
|
@@ -21991,7 +22041,7 @@ const defaultDependencies$6 = {
|
|
|
21991
22041
|
};
|
|
21992
22042
|
async function diagnoseProperty(input, dependencies = {}) {
|
|
21993
22043
|
const providers = {
|
|
21994
|
-
...defaultDependencies$
|
|
22044
|
+
...defaultDependencies$7,
|
|
21995
22045
|
...dependencies
|
|
21996
22046
|
};
|
|
21997
22047
|
const limit = input.limit ?? 10;
|
|
@@ -22939,6 +22989,42 @@ async function providerRequestJson(input) {
|
|
|
22939
22989
|
return parsed.data;
|
|
22940
22990
|
}
|
|
22941
22991
|
//#endregion
|
|
22992
|
+
//#region packages/core/src/providers/dataforseo/account-pricing.ts
|
|
22993
|
+
function unitPrice(components) {
|
|
22994
|
+
const prices = components ?? [];
|
|
22995
|
+
const total = (type) => {
|
|
22996
|
+
const matching = prices.filter((item) => item.cost_type === type);
|
|
22997
|
+
return matching.length ? matching.reduce((sum, item) => sum + Math.round(item.cost * 1e6), 0) : prices.length ? 0 : null;
|
|
22998
|
+
};
|
|
22999
|
+
return {
|
|
23000
|
+
perRequestMicros: total("per_request"),
|
|
23001
|
+
perResultMicros: total("per_result")
|
|
23002
|
+
};
|
|
23003
|
+
}
|
|
23004
|
+
function dataForSeoAccountPrices(account) {
|
|
23005
|
+
return {
|
|
23006
|
+
keywordOverviewPrice: unitPrice(account.price?.dataforseo_labs?.keyword_overview?.live?.priority_normal),
|
|
23007
|
+
keywordDiscoveryPrices: {
|
|
23008
|
+
ideas: unitPrice(account.price?.dataforseo_labs?.keyword_ideas?.live?.priority_normal),
|
|
23009
|
+
related: unitPrice(account.price?.dataforseo_labs?.related_keywords?.live?.priority_normal),
|
|
23010
|
+
suggestions: unitPrice(account.price?.dataforseo_labs?.keyword_suggestions?.live?.priority_normal)
|
|
23011
|
+
},
|
|
23012
|
+
domainResearchPrices: {
|
|
23013
|
+
domainOverview: unitPrice(account.price?.dataforseo_labs?.domain_rank_overview?.live?.priority_normal),
|
|
23014
|
+
rankedKeywords: unitPrice(account.price?.dataforseo_labs?.ranked_keywords?.live?.priority_normal),
|
|
23015
|
+
rankingPages: unitPrice(account.price?.dataforseo_labs?.relevant_pages?.live?.priority_normal),
|
|
23016
|
+
serpCompetitors: unitPrice(account.price?.dataforseo_labs?.serp_competitors?.live?.priority_normal)
|
|
23017
|
+
},
|
|
23018
|
+
linkPrices: {
|
|
23019
|
+
summary: unitPrice(account.price?.backlinks?.summary?.live?.priority_normal),
|
|
23020
|
+
backlinks: unitPrice(account.price?.backlinks?.backlinks?.live?.priority_normal),
|
|
23021
|
+
referringDomains: unitPrice(account.price?.backlinks?.referring_domains?.live?.priority_normal)
|
|
23022
|
+
},
|
|
23023
|
+
serpLiveAdvancedPrice: unitPrice(account.price?.serp?.live?.advanced?.priority_normal),
|
|
23024
|
+
serpTaskPostPrice: unitPrice(account.price?.serp?.task_post?.priority_normal)
|
|
23025
|
+
};
|
|
23026
|
+
}
|
|
23027
|
+
//#endregion
|
|
22942
23028
|
//#region packages/core/src/providers/dataforseo/account-schema.ts
|
|
22943
23029
|
const userDataMoneySchema = z.object({
|
|
22944
23030
|
total: z.number().finite().nonnegative().optional(),
|
|
@@ -22956,6 +23042,11 @@ const priceComponentSchema = z.object({
|
|
|
22956
23042
|
const normalPriorityPriceSchema = z.object({ priority_normal: z.array(priceComponentSchema).max(20).optional() }).passthrough();
|
|
22957
23043
|
const livePriceSchema = z.object({ live: normalPriorityPriceSchema.optional() }).passthrough();
|
|
22958
23044
|
const userDataPriceSchema = z.object({
|
|
23045
|
+
backlinks: z.object({
|
|
23046
|
+
summary: livePriceSchema.optional(),
|
|
23047
|
+
backlinks: livePriceSchema.optional(),
|
|
23048
|
+
referring_domains: livePriceSchema.optional()
|
|
23049
|
+
}).passthrough().optional(),
|
|
22959
23050
|
dataforseo_labs: z.object({
|
|
22960
23051
|
keyword_overview: livePriceSchema.optional(),
|
|
22961
23052
|
keyword_ideas: livePriceSchema.optional(),
|
|
@@ -23013,7 +23104,7 @@ function discoveryNextCursor(response) {
|
|
|
23013
23104
|
//#region packages/core/src/providers/dataforseo/schema.ts
|
|
23014
23105
|
const MAX_PROVIDER_MONTHLY_SEARCH_ROWS = 120;
|
|
23015
23106
|
const nullableNumber$1 = z.number().finite().nullable().optional();
|
|
23016
|
-
const nullableCount$
|
|
23107
|
+
const nullableCount$2 = z.union([z.number().finite(), z.string().trim().min(1)]).nullable().optional();
|
|
23017
23108
|
const monthlySearchSchema$1 = z.object({
|
|
23018
23109
|
year: z.number().int(),
|
|
23019
23110
|
month: z.number().int(),
|
|
@@ -23029,7 +23120,7 @@ const keywordOverviewItemSchema = z.object({
|
|
|
23029
23120
|
last_updated_time: z.string().trim().min(1).nullable().optional()
|
|
23030
23121
|
}).nullish(),
|
|
23031
23122
|
keyword_properties: z.object({ keyword_difficulty: nullableNumber$1 }).nullish(),
|
|
23032
|
-
serp_info: z.object({ se_results_count: nullableCount$
|
|
23123
|
+
serp_info: z.object({ se_results_count: nullableCount$2 }).nullish(),
|
|
23033
23124
|
search_intent_info: z.object({ main_intent: z.enum([
|
|
23034
23125
|
"informational",
|
|
23035
23126
|
"navigational",
|
|
@@ -23102,37 +23193,37 @@ const dataForSeoDiscoveryResponseSchema = z.object({
|
|
|
23102
23193
|
//#region packages/core/src/providers/dataforseo/domain-schema.ts
|
|
23103
23194
|
const nullableNumber = z.number().finite().nullable().optional();
|
|
23104
23195
|
const nullableNonnegativeNumber = z.number().finite().nonnegative().nullable().optional();
|
|
23105
|
-
const nullableCount = z.number().int().nonnegative().nullable().optional();
|
|
23196
|
+
const nullableCount$1 = z.number().int().nonnegative().nullable().optional();
|
|
23106
23197
|
const rankingMetricsSchema = z.object({
|
|
23107
|
-
pos_1: nullableCount,
|
|
23108
|
-
pos_2_3: nullableCount,
|
|
23109
|
-
pos_4_10: nullableCount,
|
|
23110
|
-
pos_11_20: nullableCount,
|
|
23111
|
-
pos_21_30: nullableCount,
|
|
23112
|
-
pos_31_40: nullableCount,
|
|
23113
|
-
pos_41_50: nullableCount,
|
|
23114
|
-
pos_51_60: nullableCount,
|
|
23115
|
-
pos_61_70: nullableCount,
|
|
23116
|
-
pos_71_80: nullableCount,
|
|
23117
|
-
pos_81_90: nullableCount,
|
|
23118
|
-
pos_91_100: nullableCount,
|
|
23198
|
+
pos_1: nullableCount$1,
|
|
23199
|
+
pos_2_3: nullableCount$1,
|
|
23200
|
+
pos_4_10: nullableCount$1,
|
|
23201
|
+
pos_11_20: nullableCount$1,
|
|
23202
|
+
pos_21_30: nullableCount$1,
|
|
23203
|
+
pos_31_40: nullableCount$1,
|
|
23204
|
+
pos_41_50: nullableCount$1,
|
|
23205
|
+
pos_51_60: nullableCount$1,
|
|
23206
|
+
pos_61_70: nullableCount$1,
|
|
23207
|
+
pos_71_80: nullableCount$1,
|
|
23208
|
+
pos_81_90: nullableCount$1,
|
|
23209
|
+
pos_91_100: nullableCount$1,
|
|
23119
23210
|
etv: nullableNonnegativeNumber,
|
|
23120
|
-
count: nullableCount,
|
|
23211
|
+
count: nullableCount$1,
|
|
23121
23212
|
estimated_paid_traffic_cost: nullableNonnegativeNumber,
|
|
23122
|
-
is_new: nullableCount,
|
|
23123
|
-
is_up: nullableCount,
|
|
23124
|
-
is_down: nullableCount,
|
|
23125
|
-
is_lost: nullableCount
|
|
23213
|
+
is_new: nullableCount$1,
|
|
23214
|
+
is_up: nullableCount$1,
|
|
23215
|
+
is_down: nullableCount$1,
|
|
23216
|
+
is_lost: nullableCount$1
|
|
23126
23217
|
}).passthrough();
|
|
23127
23218
|
const metricsSchema = z.object({ organic: rankingMetricsSchema.nullable().optional() }).passthrough();
|
|
23128
|
-
const paidResponseSchema = z.object({
|
|
23219
|
+
const paidResponseSchema$1 = z.object({
|
|
23129
23220
|
status_code: z.number().int(),
|
|
23130
23221
|
status_message: z.string().max(1e3),
|
|
23131
23222
|
cost: z.number().finite().nonnegative().optional(),
|
|
23132
23223
|
tasks_count: z.number().int().nonnegative(),
|
|
23133
23224
|
tasks_error: z.number().int().nonnegative()
|
|
23134
23225
|
}).passthrough();
|
|
23135
|
-
const taskFields = {
|
|
23226
|
+
const taskFields$1 = {
|
|
23136
23227
|
id: z.string().trim().min(1).max(100).optional(),
|
|
23137
23228
|
status_code: z.number().int(),
|
|
23138
23229
|
status_message: z.string().max(1e3),
|
|
@@ -23152,8 +23243,8 @@ const overviewResultSchema = z.object({
|
|
|
23152
23243
|
items_count: z.number().int().nonnegative().optional(),
|
|
23153
23244
|
items: z.array(overviewItemSchema).max(1e3).nullable().optional()
|
|
23154
23245
|
}).passthrough();
|
|
23155
|
-
const dataForSeoDomainOverviewResponseSchema = paidResponseSchema.extend({ tasks: z.array(z.object({
|
|
23156
|
-
...taskFields,
|
|
23246
|
+
const dataForSeoDomainOverviewResponseSchema = paidResponseSchema$1.extend({ tasks: z.array(z.object({
|
|
23247
|
+
...taskFields$1,
|
|
23157
23248
|
result: z.array(overviewResultSchema).max(10).nullable().optional()
|
|
23158
23249
|
}).passthrough()).max(10) });
|
|
23159
23250
|
const rankedSerpItemSchema = z.object({
|
|
@@ -23173,8 +23264,8 @@ const rankedKeywordsResultSchema = z.object({
|
|
|
23173
23264
|
items_count: z.number().int().nonnegative().optional(),
|
|
23174
23265
|
items: z.array(rankedKeywordItemSchema).max(1e3).nullable().optional()
|
|
23175
23266
|
}).passthrough();
|
|
23176
|
-
const dataForSeoRankedKeywordsResponseSchema = paidResponseSchema.extend({ tasks: z.array(z.object({
|
|
23177
|
-
...taskFields,
|
|
23267
|
+
const dataForSeoRankedKeywordsResponseSchema = paidResponseSchema$1.extend({ tasks: z.array(z.object({
|
|
23268
|
+
...taskFields$1,
|
|
23178
23269
|
result: z.array(rankedKeywordsResultSchema).max(10).nullable().optional()
|
|
23179
23270
|
}).passthrough()).max(10) });
|
|
23180
23271
|
const rankingPageItemSchema = z.object({
|
|
@@ -23187,8 +23278,8 @@ const rankingPagesResultSchema = z.object({
|
|
|
23187
23278
|
items_count: z.number().int().nonnegative().optional(),
|
|
23188
23279
|
items: z.array(rankingPageItemSchema).max(1e3).nullable().optional()
|
|
23189
23280
|
}).passthrough();
|
|
23190
|
-
const dataForSeoRankingPagesResponseSchema = paidResponseSchema.extend({ tasks: z.array(z.object({
|
|
23191
|
-
...taskFields,
|
|
23281
|
+
const dataForSeoRankingPagesResponseSchema = paidResponseSchema$1.extend({ tasks: z.array(z.object({
|
|
23282
|
+
...taskFields$1,
|
|
23192
23283
|
result: z.array(rankingPagesResultSchema).max(10).nullable().optional()
|
|
23193
23284
|
}).passthrough()).max(10) });
|
|
23194
23285
|
const competitorItemSchema = z.object({
|
|
@@ -23196,9 +23287,9 @@ const competitorItemSchema = z.object({
|
|
|
23196
23287
|
avg_position: nullableNumber,
|
|
23197
23288
|
median_position: nullableNumber,
|
|
23198
23289
|
etv: nullableNonnegativeNumber,
|
|
23199
|
-
keywords_count: nullableCount,
|
|
23290
|
+
keywords_count: nullableCount$1,
|
|
23200
23291
|
visibility: nullableNonnegativeNumber,
|
|
23201
|
-
relevant_serp_items: nullableCount,
|
|
23292
|
+
relevant_serp_items: nullableCount$1,
|
|
23202
23293
|
keywords_positions: z.record(z.string().trim().min(1).max(80), z.array(z.number().int().positive()).max(100)).nullable().optional()
|
|
23203
23294
|
}).passthrough();
|
|
23204
23295
|
const competitorsResultSchema = z.object({
|
|
@@ -23207,8 +23298,8 @@ const competitorsResultSchema = z.object({
|
|
|
23207
23298
|
items_count: z.number().int().nonnegative().optional(),
|
|
23208
23299
|
items: z.array(competitorItemSchema).max(1e3).nullable().optional()
|
|
23209
23300
|
}).passthrough();
|
|
23210
|
-
const dataForSeoSerpCompetitorsResponseSchema = paidResponseSchema.extend({ tasks: z.array(z.object({
|
|
23211
|
-
...taskFields,
|
|
23301
|
+
const dataForSeoSerpCompetitorsResponseSchema = paidResponseSchema$1.extend({ tasks: z.array(z.object({
|
|
23302
|
+
...taskFields$1,
|
|
23212
23303
|
result: z.array(competitorsResultSchema).max(10).nullable().optional()
|
|
23213
23304
|
}).passthrough()).max(10) });
|
|
23214
23305
|
const DOMAIN_OVERVIEW_PATH = "v3/dataforseo_labs/google/domain_rank_overview/live";
|
|
@@ -23398,6 +23489,209 @@ function serpCompetitorsPaidRequest(input, ttlMs) {
|
|
|
23398
23489
|
};
|
|
23399
23490
|
}
|
|
23400
23491
|
//#endregion
|
|
23492
|
+
//#region packages/core/src/providers/dataforseo/link-schema.ts
|
|
23493
|
+
const nullableCount = z.number().int().nonnegative().nullable().optional();
|
|
23494
|
+
const nullableScore = z.number().finite().nonnegative().nullable().optional();
|
|
23495
|
+
const nullableText = z.string().max(2e4).nullable().optional();
|
|
23496
|
+
const paidResponseSchema = z.object({
|
|
23497
|
+
status_code: z.number().int(),
|
|
23498
|
+
status_message: z.string().max(1e3),
|
|
23499
|
+
cost: z.number().finite().nonnegative().optional(),
|
|
23500
|
+
tasks_count: z.number().int().nonnegative(),
|
|
23501
|
+
tasks_error: z.number().int().nonnegative()
|
|
23502
|
+
}).passthrough();
|
|
23503
|
+
const taskFields = {
|
|
23504
|
+
id: z.string().trim().min(1).max(100).optional(),
|
|
23505
|
+
status_code: z.number().int(),
|
|
23506
|
+
status_message: z.string().max(1e3),
|
|
23507
|
+
cost: z.number().finite().nonnegative().optional(),
|
|
23508
|
+
result_count: z.number().int().nonnegative().optional()
|
|
23509
|
+
};
|
|
23510
|
+
const dataForSeoLinkSummaryItemSchema = z.object({
|
|
23511
|
+
target: z.string().trim().min(1).max(2048).optional(),
|
|
23512
|
+
rank: nullableScore,
|
|
23513
|
+
backlinks: nullableCount,
|
|
23514
|
+
referring_pages: nullableCount,
|
|
23515
|
+
referring_domains: nullableCount,
|
|
23516
|
+
broken_backlinks: nullableCount,
|
|
23517
|
+
broken_pages: nullableCount,
|
|
23518
|
+
backlinks_spam_score: nullableScore,
|
|
23519
|
+
info: z.object({ target_spam_score: nullableScore }).passthrough().nullable().optional()
|
|
23520
|
+
}).passthrough();
|
|
23521
|
+
const dataForSeoLinkSummaryResponseSchema = paidResponseSchema.extend({ tasks: z.array(z.object({
|
|
23522
|
+
...taskFields,
|
|
23523
|
+
result: z.array(dataForSeoLinkSummaryItemSchema).max(10).nullable().optional()
|
|
23524
|
+
}).passthrough()).max(10) });
|
|
23525
|
+
const dataForSeoBacklinkItemSchema = z.object({
|
|
23526
|
+
domain_from: nullableText,
|
|
23527
|
+
url_from: nullableText,
|
|
23528
|
+
url_to: nullableText,
|
|
23529
|
+
anchor: nullableText,
|
|
23530
|
+
item_type: z.string().max(100).nullable().optional(),
|
|
23531
|
+
dofollow: z.boolean().nullable().optional(),
|
|
23532
|
+
rank: nullableScore,
|
|
23533
|
+
domain_from_rank: nullableScore,
|
|
23534
|
+
page_from_rank: nullableScore,
|
|
23535
|
+
backlink_spam_score: nullableScore,
|
|
23536
|
+
backlinks_spam_score: nullableScore,
|
|
23537
|
+
first_seen: z.string().max(100).nullable().optional(),
|
|
23538
|
+
last_visited: z.string().max(100).nullable().optional(),
|
|
23539
|
+
lost_date: z.string().max(100).nullable().optional(),
|
|
23540
|
+
is_lost: z.boolean().nullable().optional(),
|
|
23541
|
+
is_indirect_link: z.boolean().nullable().optional(),
|
|
23542
|
+
links_count: nullableCount,
|
|
23543
|
+
group_count: nullableCount,
|
|
23544
|
+
rel_attributes: z.array(z.string().trim().min(1).max(100)).max(100).nullable().optional(),
|
|
23545
|
+
attributes: z.array(z.string().trim().min(1).max(100)).max(100).nullable().optional()
|
|
23546
|
+
}).passthrough();
|
|
23547
|
+
const backlinkResultSchema = z.object({
|
|
23548
|
+
target: z.string().trim().min(1).max(2048).optional(),
|
|
23549
|
+
total_count: nullableCount,
|
|
23550
|
+
items_count: nullableCount,
|
|
23551
|
+
search_after_token: z.string().max(2e4).nullable().optional(),
|
|
23552
|
+
items: z.array(dataForSeoBacklinkItemSchema).max(1e3).nullable().optional()
|
|
23553
|
+
}).passthrough();
|
|
23554
|
+
const dataForSeoBacklinksResponseSchema = paidResponseSchema.extend({ tasks: z.array(z.object({
|
|
23555
|
+
...taskFields,
|
|
23556
|
+
result: z.array(backlinkResultSchema).max(10).nullable().optional()
|
|
23557
|
+
}).passthrough()).max(10) });
|
|
23558
|
+
const dataForSeoReferringDomainItemSchema = z.object({
|
|
23559
|
+
domain: z.string().trim().min(1).max(2048).nullable().optional(),
|
|
23560
|
+
backlinks: nullableCount,
|
|
23561
|
+
referring_pages: nullableCount,
|
|
23562
|
+
broken_backlinks: nullableCount,
|
|
23563
|
+
broken_pages: nullableCount,
|
|
23564
|
+
rank: nullableScore,
|
|
23565
|
+
backlinks_spam_score: nullableScore,
|
|
23566
|
+
first_seen: z.string().max(100).nullable().optional()
|
|
23567
|
+
}).passthrough();
|
|
23568
|
+
const referringDomainsResultSchema = z.object({
|
|
23569
|
+
target: z.string().trim().min(1).max(2048).optional(),
|
|
23570
|
+
total_count: nullableCount,
|
|
23571
|
+
items_count: nullableCount,
|
|
23572
|
+
items: z.array(dataForSeoReferringDomainItemSchema).max(1e3).nullable().optional()
|
|
23573
|
+
}).passthrough();
|
|
23574
|
+
const dataForSeoReferringDomainsResponseSchema = paidResponseSchema.extend({ tasks: z.array(z.object({
|
|
23575
|
+
...taskFields,
|
|
23576
|
+
result: z.array(referringDomainsResultSchema).max(10).nullable().optional()
|
|
23577
|
+
}).passthrough()).max(10) });
|
|
23578
|
+
const MAX_LINK_ROWS$1 = 1e3;
|
|
23579
|
+
const MAX_LINK_OFFSET = 2e4;
|
|
23580
|
+
const LINK_ENDPOINTS = {
|
|
23581
|
+
summary: "v3/backlinks/summary/live",
|
|
23582
|
+
backlinks: "v3/backlinks/backlinks/live",
|
|
23583
|
+
referringDomains: "v3/backlinks/referring_domains/live"
|
|
23584
|
+
};
|
|
23585
|
+
function resultRows(response) {
|
|
23586
|
+
return response.tasks.reduce((taskTotal, task) => taskTotal + (task.result ?? []).reduce((resultTotal, result) => resultTotal + (result.items?.length ?? 0), 0), 0);
|
|
23587
|
+
}
|
|
23588
|
+
function summaryRows(response) {
|
|
23589
|
+
return response.tasks.reduce((total, task) => total + (task.result?.length ?? 0), 0);
|
|
23590
|
+
}
|
|
23591
|
+
function commonRequest(input) {
|
|
23592
|
+
return {
|
|
23593
|
+
target: input.target,
|
|
23594
|
+
include_subdomains: input.scope === "domain" ? input.includeSubdomains : false,
|
|
23595
|
+
include_indirect_links: true,
|
|
23596
|
+
exclude_internal_backlinks: true,
|
|
23597
|
+
backlinks_status_type: "live",
|
|
23598
|
+
rank_scale: "one_hundred"
|
|
23599
|
+
};
|
|
23600
|
+
}
|
|
23601
|
+
function validatePage(input) {
|
|
23602
|
+
if (!Number.isSafeInteger(input.limit) || input.limit < 1 || input.limit > 1e3) throw new ProviderError({
|
|
23603
|
+
provider: "dataforseo",
|
|
23604
|
+
operation: input.operation,
|
|
23605
|
+
code: "configuration",
|
|
23606
|
+
message: `Link row limit must be from 1 to ${MAX_LINK_ROWS$1}.`
|
|
23607
|
+
});
|
|
23608
|
+
if (!Number.isSafeInteger(input.offset) || input.offset < 0 || input.offset > 2e4) throw new ProviderError({
|
|
23609
|
+
provider: "dataforseo",
|
|
23610
|
+
operation: input.operation,
|
|
23611
|
+
code: "configuration",
|
|
23612
|
+
message: `Link row offset must be from 0 to ${MAX_LINK_OFFSET}.`
|
|
23613
|
+
});
|
|
23614
|
+
}
|
|
23615
|
+
function linkSummaryPaidRequest(input, ttlMs) {
|
|
23616
|
+
return {
|
|
23617
|
+
operation: "link-summary",
|
|
23618
|
+
capability: "link-summary",
|
|
23619
|
+
endpoint: LINK_ENDPOINTS.summary,
|
|
23620
|
+
request: commonRequest(input),
|
|
23621
|
+
schema: dataForSeoLinkSummaryResponseSchema,
|
|
23622
|
+
requestedRows: 1,
|
|
23623
|
+
price: (account) => account.linkPrices.summary,
|
|
23624
|
+
context: input.context,
|
|
23625
|
+
ttlMs,
|
|
23626
|
+
refresh: input.refresh,
|
|
23627
|
+
rowCount: summaryRows
|
|
23628
|
+
};
|
|
23629
|
+
}
|
|
23630
|
+
function backlinksPaidRequest(input, ttlMs) {
|
|
23631
|
+
validatePage({
|
|
23632
|
+
limit: input.limit,
|
|
23633
|
+
offset: input.offset,
|
|
23634
|
+
operation: "backlinks"
|
|
23635
|
+
});
|
|
23636
|
+
if (input.orderBy.length < 1 || input.orderBy.length > 3) throw new ProviderError({
|
|
23637
|
+
provider: "dataforseo",
|
|
23638
|
+
operation: "backlinks",
|
|
23639
|
+
code: "configuration",
|
|
23640
|
+
message: "Backlink rows need from 1 to 3 sort rules."
|
|
23641
|
+
});
|
|
23642
|
+
return {
|
|
23643
|
+
operation: "backlinks",
|
|
23644
|
+
capability: "backlinks",
|
|
23645
|
+
endpoint: LINK_ENDPOINTS.backlinks,
|
|
23646
|
+
request: {
|
|
23647
|
+
...commonRequest(input),
|
|
23648
|
+
mode: input.mode,
|
|
23649
|
+
backlinks_status_type: input.status,
|
|
23650
|
+
limit: input.limit,
|
|
23651
|
+
offset: input.offset,
|
|
23652
|
+
order_by: input.orderBy
|
|
23653
|
+
},
|
|
23654
|
+
schema: dataForSeoBacklinksResponseSchema,
|
|
23655
|
+
requestedRows: input.limit,
|
|
23656
|
+
price: (account) => account.linkPrices.backlinks,
|
|
23657
|
+
context: input.context,
|
|
23658
|
+
ttlMs,
|
|
23659
|
+
refresh: input.refresh,
|
|
23660
|
+
rowCount: resultRows
|
|
23661
|
+
};
|
|
23662
|
+
}
|
|
23663
|
+
function referringDomainsPaidRequest(input, ttlMs) {
|
|
23664
|
+
validatePage({
|
|
23665
|
+
limit: input.limit,
|
|
23666
|
+
offset: input.offset,
|
|
23667
|
+
operation: "referring-domains"
|
|
23668
|
+
});
|
|
23669
|
+
if (input.orderBy.length < 1 || input.orderBy.length > 3) throw new ProviderError({
|
|
23670
|
+
provider: "dataforseo",
|
|
23671
|
+
operation: "referring-domains",
|
|
23672
|
+
code: "configuration",
|
|
23673
|
+
message: "Referring-domain rows need from 1 to 3 sort rules."
|
|
23674
|
+
});
|
|
23675
|
+
return {
|
|
23676
|
+
operation: "referring-domains",
|
|
23677
|
+
capability: "referring-domains",
|
|
23678
|
+
endpoint: LINK_ENDPOINTS.referringDomains,
|
|
23679
|
+
request: {
|
|
23680
|
+
...commonRequest(input),
|
|
23681
|
+
limit: input.limit,
|
|
23682
|
+
offset: input.offset,
|
|
23683
|
+
order_by: input.orderBy
|
|
23684
|
+
},
|
|
23685
|
+
schema: dataForSeoReferringDomainsResponseSchema,
|
|
23686
|
+
requestedRows: input.limit,
|
|
23687
|
+
price: (account) => account.linkPrices.referringDomains,
|
|
23688
|
+
context: input.context,
|
|
23689
|
+
ttlMs,
|
|
23690
|
+
refresh: input.refresh,
|
|
23691
|
+
rowCount: resultRows
|
|
23692
|
+
};
|
|
23693
|
+
}
|
|
23694
|
+
//#endregion
|
|
23401
23695
|
//#region packages/core/src/providers/dataforseo/paid-request.ts
|
|
23402
23696
|
function usdToMicros(value) {
|
|
23403
23697
|
if (value === void 0) return null;
|
|
@@ -23921,41 +24215,6 @@ const MAX_KEYWORD_CHARACTERS = 80;
|
|
|
23921
24215
|
const MAX_KEYWORD_WORDS = 10;
|
|
23922
24216
|
const MAX_DISCOVERY_SEEDS$1 = 5;
|
|
23923
24217
|
const MAX_DISCOVERY_ROWS$1 = 100;
|
|
23924
|
-
function unitPrice(components) {
|
|
23925
|
-
const prices = components ?? [];
|
|
23926
|
-
const total = (type) => {
|
|
23927
|
-
const matching = prices.filter((item) => item.cost_type === type);
|
|
23928
|
-
return matching.length ? matching.reduce((sum, item) => sum + Math.round(item.cost * 1e6), 0) : prices.length ? 0 : null;
|
|
23929
|
-
};
|
|
23930
|
-
return {
|
|
23931
|
-
perRequestMicros: total("per_request"),
|
|
23932
|
-
perResultMicros: total("per_result")
|
|
23933
|
-
};
|
|
23934
|
-
}
|
|
23935
|
-
function keywordOverviewPrice(account) {
|
|
23936
|
-
return unitPrice(account.price?.dataforseo_labs?.keyword_overview?.live?.priority_normal);
|
|
23937
|
-
}
|
|
23938
|
-
function keywordDiscoveryPrices(account) {
|
|
23939
|
-
return {
|
|
23940
|
-
ideas: unitPrice(account.price?.dataforseo_labs?.keyword_ideas?.live?.priority_normal),
|
|
23941
|
-
related: unitPrice(account.price?.dataforseo_labs?.related_keywords?.live?.priority_normal),
|
|
23942
|
-
suggestions: unitPrice(account.price?.dataforseo_labs?.keyword_suggestions?.live?.priority_normal)
|
|
23943
|
-
};
|
|
23944
|
-
}
|
|
23945
|
-
function domainResearchPrices(account) {
|
|
23946
|
-
return {
|
|
23947
|
-
domainOverview: unitPrice(account.price?.dataforseo_labs?.domain_rank_overview?.live?.priority_normal),
|
|
23948
|
-
rankedKeywords: unitPrice(account.price?.dataforseo_labs?.ranked_keywords?.live?.priority_normal),
|
|
23949
|
-
rankingPages: unitPrice(account.price?.dataforseo_labs?.relevant_pages?.live?.priority_normal),
|
|
23950
|
-
serpCompetitors: unitPrice(account.price?.dataforseo_labs?.serp_competitors?.live?.priority_normal)
|
|
23951
|
-
};
|
|
23952
|
-
}
|
|
23953
|
-
function serpLiveAdvancedPrice(account) {
|
|
23954
|
-
return unitPrice(account.price?.serp?.live?.advanced?.priority_normal);
|
|
23955
|
-
}
|
|
23956
|
-
function serpTaskPostPrice(account) {
|
|
23957
|
-
return unitPrice(account.price?.serp?.task_post?.priority_normal);
|
|
23958
|
-
}
|
|
23959
24218
|
function responseTaskIds(response) {
|
|
23960
24219
|
return [...new Set(response.tasks.flatMap((task) => task.id ? [task.id] : []))].sort((left, right) => left < right ? -1 : left > right ? 1 : 0);
|
|
23961
24220
|
}
|
|
@@ -23975,6 +24234,7 @@ var DataForSeoClient = class {
|
|
|
23975
24234
|
serpTtlMs;
|
|
23976
24235
|
accountPricingTtlMs;
|
|
23977
24236
|
domainResearchTtlMs;
|
|
24237
|
+
linkTtlMs;
|
|
23978
24238
|
spendLimits;
|
|
23979
24239
|
accountPricing;
|
|
23980
24240
|
accountPricingRequest;
|
|
@@ -23991,6 +24251,7 @@ var DataForSeoClient = class {
|
|
|
23991
24251
|
this.serpTtlMs = options.serpTtlMs ?? DEFAULT_SERP_TTL_MS;
|
|
23992
24252
|
this.accountPricingTtlMs = options.accountPricingTtlMs ?? DEFAULT_ACCOUNT_PRICING_TTL_MS;
|
|
23993
24253
|
this.domainResearchTtlMs = options.domainResearchTtlMs ?? 6048e5;
|
|
24254
|
+
this.linkTtlMs = options.linkTtlMs ?? 864e5;
|
|
23994
24255
|
this.spendLimits = options.spendLimits;
|
|
23995
24256
|
}
|
|
23996
24257
|
async getCredentials(operation) {
|
|
@@ -24073,11 +24334,7 @@ var DataForSeoClient = class {
|
|
|
24073
24334
|
accountDailySpendMicros: dataForSeoUsdToMicros(account.money?.statistics?.day?.total),
|
|
24074
24335
|
accountDailySpendPeriod: account.money?.statistics?.day?.value ?? null,
|
|
24075
24336
|
accountDailyLimitMicros: dataForSeoUsdToMicros(account.money?.limits?.day?.total),
|
|
24076
|
-
|
|
24077
|
-
keywordDiscoveryPrices: keywordDiscoveryPrices(account),
|
|
24078
|
-
domainResearchPrices: domainResearchPrices(account),
|
|
24079
|
-
serpLiveAdvancedPrice: serpLiveAdvancedPrice(account),
|
|
24080
|
-
serpTaskPostPrice: serpTaskPostPrice(account),
|
|
24337
|
+
...dataForSeoAccountPrices(account),
|
|
24081
24338
|
backlinksSubscriptionExpiresAt: account.backlinks_subscription_expiry_date ?? null,
|
|
24082
24339
|
aiMentionsSubscriptionExpiresAt: account.llm_mentions_subscription_expiry_date ?? null,
|
|
24083
24340
|
apiVersion: response.version ?? null,
|
|
@@ -24140,6 +24397,15 @@ var DataForSeoClient = class {
|
|
|
24140
24397
|
async serpCompetitors(input) {
|
|
24141
24398
|
return this.paidPost(serpCompetitorsPaidRequest(input, this.domainResearchTtlMs));
|
|
24142
24399
|
}
|
|
24400
|
+
async linkSummary(input) {
|
|
24401
|
+
return this.paidPost(linkSummaryPaidRequest(input, this.linkTtlMs));
|
|
24402
|
+
}
|
|
24403
|
+
async backlinks(input) {
|
|
24404
|
+
return this.paidPost(backlinksPaidRequest(input, this.linkTtlMs));
|
|
24405
|
+
}
|
|
24406
|
+
async referringDomains(input) {
|
|
24407
|
+
return this.paidPost(referringDomainsPaidRequest(input, this.linkTtlMs));
|
|
24408
|
+
}
|
|
24143
24409
|
async keywordOverview(input) {
|
|
24144
24410
|
const keywords = input.keywords.map((keyword) => keyword.trim());
|
|
24145
24411
|
if (keywords.length < 1 || keywords.length > MAX_KEYWORDS_PER_OVERVIEW_REQUEST || keywords.some((keyword) => keyword.length < 1 || keyword.length > MAX_KEYWORD_CHARACTERS || keyword.split(/\s+/u).length > MAX_KEYWORD_WORDS)) throw new ProviderError({
|
|
@@ -24483,20 +24749,20 @@ function compareCodepoints$3(left, right) {
|
|
|
24483
24749
|
function normalizedKeyword$2(keyword) {
|
|
24484
24750
|
return keyword.trim().replace(/\s+/gu, " ").toLowerCase();
|
|
24485
24751
|
}
|
|
24486
|
-
function missing$
|
|
24752
|
+
function missing$2(field) {
|
|
24487
24753
|
return unavailableValue("missing", `DataForSEO omitted ${field}.`);
|
|
24488
24754
|
}
|
|
24489
24755
|
function numericValue(values, field, valid) {
|
|
24490
24756
|
const present = values.filter((value) => value !== null && value !== void 0);
|
|
24491
|
-
if (present.length === 0) return missing$
|
|
24757
|
+
if (present.length === 0) return missing$2(field);
|
|
24492
24758
|
const numbers = present.filter((value) => typeof value === "number" && valid(value));
|
|
24493
24759
|
if (numbers.length !== present.length) return unavailableValue("invalid", `DataForSEO returned an invalid ${field}.`);
|
|
24494
24760
|
const unique = [...new Set(numbers)];
|
|
24495
24761
|
return unique.length === 1 ? observedValue(unique[0]) : unavailableValue("invalid", `DataForSEO returned conflicting ${field} values.`);
|
|
24496
24762
|
}
|
|
24497
|
-
function stringValue(values, field, normalize) {
|
|
24763
|
+
function stringValue$1(values, field, normalize) {
|
|
24498
24764
|
const present = values.filter((value) => value !== null && value !== void 0);
|
|
24499
|
-
if (present.length === 0) return missing$
|
|
24765
|
+
if (present.length === 0) return missing$2(field);
|
|
24500
24766
|
const strings = present.flatMap((value) => {
|
|
24501
24767
|
if (typeof value !== "string") return [];
|
|
24502
24768
|
const normalized = normalize(value);
|
|
@@ -24508,7 +24774,7 @@ function stringValue(values, field, normalize) {
|
|
|
24508
24774
|
}
|
|
24509
24775
|
function monthlySearchesValue(rows) {
|
|
24510
24776
|
const histories = rows.map((row) => row.keyword_info?.monthly_searches).filter((value) => value !== null && value !== void 0);
|
|
24511
|
-
if (histories.length === 0) return missing$
|
|
24777
|
+
if (histories.length === 0) return missing$2("monthlySearches");
|
|
24512
24778
|
const byMonth = /* @__PURE__ */ new Map();
|
|
24513
24779
|
let invalid = false;
|
|
24514
24780
|
for (const history of histories) for (const item of history) {
|
|
@@ -24541,27 +24807,27 @@ function resultCountValues(rows) {
|
|
|
24541
24807
|
function metricForKeyword(keyword, rows) {
|
|
24542
24808
|
if (rows.length === 0) return {
|
|
24543
24809
|
keyword,
|
|
24544
|
-
monthlySearchVolume: missing$
|
|
24545
|
-
monthlySearches: missing$
|
|
24546
|
-
searchVolumeUpdatedAt: missing$
|
|
24547
|
-
cpcUsd: missing$
|
|
24548
|
-
paidCompetition: missing$
|
|
24549
|
-
keywordDifficulty: missing$
|
|
24550
|
-
intent: missing$
|
|
24551
|
-
resultCount: missing$
|
|
24810
|
+
monthlySearchVolume: missing$2("monthlySearchVolume"),
|
|
24811
|
+
monthlySearches: missing$2("monthlySearches"),
|
|
24812
|
+
searchVolumeUpdatedAt: missing$2("searchVolumeUpdatedAt"),
|
|
24813
|
+
cpcUsd: missing$2("cpcUsd"),
|
|
24814
|
+
paidCompetition: missing$2("paidCompetition"),
|
|
24815
|
+
keywordDifficulty: missing$2("keywordDifficulty"),
|
|
24816
|
+
intent: missing$2("intent"),
|
|
24817
|
+
resultCount: missing$2("resultCount")
|
|
24552
24818
|
};
|
|
24553
24819
|
return {
|
|
24554
24820
|
keyword,
|
|
24555
24821
|
monthlySearchVolume: numericValue(rows.map((row) => row.keyword_info?.search_volume), "monthlySearchVolume", (value) => Number.isSafeInteger(value) && value >= 0),
|
|
24556
24822
|
monthlySearches: monthlySearchesValue(rows),
|
|
24557
|
-
searchVolumeUpdatedAt: stringValue(rows.map((row) => row.keyword_info?.last_updated_time), "searchVolumeUpdatedAt", (value) => {
|
|
24823
|
+
searchVolumeUpdatedAt: stringValue$1(rows.map((row) => row.keyword_info?.last_updated_time), "searchVolumeUpdatedAt", (value) => {
|
|
24558
24824
|
const timestamp = Date.parse(value);
|
|
24559
24825
|
return Number.isFinite(timestamp) ? new Date(timestamp).toISOString() : null;
|
|
24560
24826
|
}),
|
|
24561
24827
|
cpcUsd: numericValue(rows.map((row) => row.keyword_info?.cpc), "cpcUsd", (value) => Number.isFinite(value) && value >= 0),
|
|
24562
24828
|
paidCompetition: numericValue(rows.map((row) => row.keyword_info?.competition), "paidCompetition", (value) => Number.isFinite(value) && value >= 0 && value <= 1),
|
|
24563
24829
|
keywordDifficulty: numericValue(rows.map((row) => row.keyword_properties?.keyword_difficulty), "keywordDifficulty", (value) => Number.isFinite(value) && value >= 0 && value <= 100),
|
|
24564
|
-
intent: stringValue(rows.map((row) => row.search_intent_info?.main_intent), "intent", (value) => value.trim().toLowerCase() || null),
|
|
24830
|
+
intent: stringValue$1(rows.map((row) => row.search_intent_info?.main_intent), "intent", (value) => value.trim().toLowerCase() || null),
|
|
24565
24831
|
resultCount: numericValue(resultCountValues(rows), "resultCount", (value) => Number.isSafeInteger(value) && value >= 0)
|
|
24566
24832
|
};
|
|
24567
24833
|
}
|
|
@@ -24614,21 +24880,21 @@ const COMPETITOR_RESULT_TYPES = /* @__PURE__ */ new Set([
|
|
|
24614
24880
|
"featured_snippet",
|
|
24615
24881
|
"local_pack"
|
|
24616
24882
|
]);
|
|
24617
|
-
function missing(field) {
|
|
24883
|
+
function missing$1(field) {
|
|
24618
24884
|
return unavailableValue("missing", `DataForSEO omitted ${field}.`);
|
|
24619
24885
|
}
|
|
24620
|
-
function numberValue(value, field) {
|
|
24621
|
-
return value === null || value === void 0 ? missing(field) : observedValue(value);
|
|
24886
|
+
function numberValue$1(value, field) {
|
|
24887
|
+
return value === null || value === void 0 ? missing$1(field) : observedValue(value);
|
|
24622
24888
|
}
|
|
24623
24889
|
function countValue(value, field) {
|
|
24624
|
-
return numberValue(value, field);
|
|
24890
|
+
return numberValue$1(value, field);
|
|
24625
24891
|
}
|
|
24626
24892
|
function sumBuckets(metrics, fields, label) {
|
|
24627
24893
|
const values = fields.map((field) => metrics[field]);
|
|
24628
|
-
return values.some((value) => value === null || value === void 0) ? missing(label) : observedValue(values.reduce((sum, value) => sum + (typeof value === "number" ? value : 0), 0));
|
|
24894
|
+
return values.some((value) => value === null || value === void 0) ? missing$1(label) : observedValue(values.reduce((sum, value) => sum + (typeof value === "number" ? value : 0), 0));
|
|
24629
24895
|
}
|
|
24630
24896
|
function rankingDistribution(metrics) {
|
|
24631
|
-
if (!metrics) return missing("organic ranking distribution");
|
|
24897
|
+
if (!metrics) return missing$1("organic ranking distribution");
|
|
24632
24898
|
const buckets = {
|
|
24633
24899
|
first: sumBuckets(metrics, ["pos_1"], "position 1 rankings"),
|
|
24634
24900
|
top3: sumBuckets(metrics, ["pos_1", "pos_2_3"], "top 3 rankings"),
|
|
@@ -24679,9 +24945,9 @@ function rankingDistribution(metrics) {
|
|
|
24679
24945
|
}
|
|
24680
24946
|
function organicFootprint(metrics) {
|
|
24681
24947
|
return {
|
|
24682
|
-
estimatedMonthlyTraffic: numberValue(metrics?.etv, "estimated organic monthly traffic"),
|
|
24948
|
+
estimatedMonthlyTraffic: numberValue$1(metrics?.etv, "estimated organic monthly traffic"),
|
|
24683
24949
|
rankedKeywords: countValue(metrics?.count, "ranked organic keywords"),
|
|
24684
|
-
estimatedMonthlyTrafficCostUsd: numberValue(metrics?.estimated_paid_traffic_cost, "estimated organic traffic cost"),
|
|
24950
|
+
estimatedMonthlyTrafficCostUsd: numberValue$1(metrics?.estimated_paid_traffic_cost, "estimated organic traffic cost"),
|
|
24685
24951
|
rankings: rankingDistribution(metrics),
|
|
24686
24952
|
newRankings: countValue(metrics?.is_new, "new rankings"),
|
|
24687
24953
|
improvedRankings: countValue(metrics?.is_up, "improved rankings"),
|
|
@@ -24736,7 +25002,7 @@ function researchMarket(input, operation) {
|
|
|
24736
25002
|
});
|
|
24737
25003
|
return parsed;
|
|
24738
25004
|
}
|
|
24739
|
-
function rowLimit(limit, offset = 0) {
|
|
25005
|
+
function rowLimit$1(limit, offset = 0) {
|
|
24740
25006
|
if (!Number.isSafeInteger(limit) || limit < 1 || limit > 1e3) throw new ProviderError({
|
|
24741
25007
|
provider: "dataforseo",
|
|
24742
25008
|
operation: "domain-research",
|
|
@@ -24760,7 +25026,7 @@ function resultTypes(input, allowed) {
|
|
|
24760
25026
|
});
|
|
24761
25027
|
return normalized;
|
|
24762
25028
|
}
|
|
24763
|
-
function safeUrl$
|
|
25029
|
+
function safeUrl$2(value) {
|
|
24764
25030
|
if (!value) return null;
|
|
24765
25031
|
try {
|
|
24766
25032
|
const url = new URL(value);
|
|
@@ -24780,7 +25046,7 @@ function dedupeBy(rows, key) {
|
|
|
24780
25046
|
}
|
|
24781
25047
|
return [...grouped.entries()].sort(([left], [right]) => compareCodepoints$3(left, right)).map(([, matches]) => [...matches].sort((left, right) => compareCodepoints$3(JSON.stringify(left), JSON.stringify(right)))[0]);
|
|
24782
25048
|
}
|
|
24783
|
-
function observedNumber(value) {
|
|
25049
|
+
function observedNumber$1(value) {
|
|
24784
25050
|
return value.state === "observed" ? value.value : -1;
|
|
24785
25051
|
}
|
|
24786
25052
|
function duplicateWarning(available, retained, label) {
|
|
@@ -24791,7 +25057,7 @@ function duplicateWarning(available, retained, label) {
|
|
|
24791
25057
|
message: `${duplicates} duplicate ${label} row${duplicates === 1 ? "" : "s"} were collapsed deterministically.`
|
|
24792
25058
|
}] : [];
|
|
24793
25059
|
}
|
|
24794
|
-
function totalRows(values) {
|
|
25060
|
+
function totalRows$1(values) {
|
|
24795
25061
|
const present = values.filter((value) => value !== null && value !== void 0);
|
|
24796
25062
|
return present.length ? Math.max(...present) : null;
|
|
24797
25063
|
}
|
|
@@ -24807,7 +25073,7 @@ function coverage(input) {
|
|
|
24807
25073
|
nextCursor: hasMore ? String(input.offset + input.returnedRows) : null
|
|
24808
25074
|
};
|
|
24809
25075
|
}
|
|
24810
|
-
function requestContext(reportId, supplied) {
|
|
25076
|
+
function requestContext$1(reportId, supplied) {
|
|
24811
25077
|
return supplied ?? {
|
|
24812
25078
|
reportId,
|
|
24813
25079
|
reportRunId: randomUUID()
|
|
@@ -24856,7 +25122,7 @@ async function dataForSeoDomainOverview(client, input) {
|
|
|
24856
25122
|
languageCode: market.languageCode.split("-")[0],
|
|
24857
25123
|
...location,
|
|
24858
25124
|
refresh: input.refresh,
|
|
24859
|
-
context: requestContext("domain-overview", input.context)
|
|
25125
|
+
context: requestContext$1("domain-overview", input.context)
|
|
24860
25126
|
});
|
|
24861
25127
|
const results = snapshot.response.tasks.flatMap((task) => task.result ?? []);
|
|
24862
25128
|
const matchingResult = results.find((row) => !row.target || domain(row.target) === target);
|
|
@@ -24948,7 +25214,7 @@ async function dataForSeoRankedKeywords(client, input) {
|
|
|
24948
25214
|
const market = researchMarket(input.market, "ranked-keywords");
|
|
24949
25215
|
const target = rankedTarget(input.target);
|
|
24950
25216
|
const offset = input.offset ?? 0;
|
|
24951
|
-
rowLimit(input.limit, offset);
|
|
25217
|
+
rowLimit$1(input.limit, offset);
|
|
24952
25218
|
const types = resultTypes(input.resultTypes, RANKED_RESULT_TYPES);
|
|
24953
25219
|
const excluded = excludedTerms(input);
|
|
24954
25220
|
const requestedFilters = filters$1(input, excluded);
|
|
@@ -24968,7 +25234,7 @@ async function dataForSeoRankedKeywords(client, input) {
|
|
|
24968
25234
|
limit: input.limit,
|
|
24969
25235
|
offset,
|
|
24970
25236
|
refresh: input.refresh,
|
|
24971
|
-
context: requestContext("ranked-keywords", input.context)
|
|
25237
|
+
context: requestContext$1("ranked-keywords", input.context)
|
|
24972
25238
|
});
|
|
24973
25239
|
const responseResults = snapshot.response.tasks.flatMap((task) => task.result ?? []);
|
|
24974
25240
|
const rawRows = responseResults.flatMap((result) => result.items ?? []);
|
|
@@ -24977,7 +25243,7 @@ async function dataForSeoRankedKeywords(client, input) {
|
|
|
24977
25243
|
const keywordData = row.keyword_data;
|
|
24978
25244
|
const serp = row.ranked_serp_element?.serp_item;
|
|
24979
25245
|
const keyword = keywordData?.keyword ? normalizedKeyword$2(keywordData.keyword) : "";
|
|
24980
|
-
const url = safeUrl$
|
|
25246
|
+
const url = safeUrl$2(serp?.url);
|
|
24981
25247
|
if (!keywordData || !keyword || !url || !serp?.rank_group || !serp.rank_absolute || !serp.type) {
|
|
24982
25248
|
invalidRows += 1;
|
|
24983
25249
|
return [];
|
|
@@ -24988,11 +25254,11 @@ async function dataForSeoRankedKeywords(client, input) {
|
|
|
24988
25254
|
rankGroup: serp.rank_group,
|
|
24989
25255
|
rankAbsolute: serp.rank_absolute,
|
|
24990
25256
|
resultType: serp.type,
|
|
24991
|
-
estimatedMonthlyTraffic: numberValue(serp.etv, "estimated keyword traffic")
|
|
25257
|
+
estimatedMonthlyTraffic: numberValue$1(serp.etv, "estimated keyword traffic")
|
|
24992
25258
|
}];
|
|
24993
25259
|
});
|
|
24994
|
-
const rows = dedupeBy(mappedRows, (row) => `${row.keyword}\0${row.url}\0${row.resultType}`).sort((left, right) => observedNumber(right.monthlySearchVolume) - observedNumber(left.monthlySearchVolume) || left.rankGroup - right.rankGroup || compareCodepoints$3(left.keyword, right.keyword) || compareCodepoints$3(left.url, right.url));
|
|
24995
|
-
const providerTotalRows = totalRows(responseResults.map((result) => result.total_count));
|
|
25260
|
+
const rows = dedupeBy(mappedRows, (row) => `${row.keyword}\0${row.url}\0${row.resultType}`).sort((left, right) => observedNumber$1(right.monthlySearchVolume) - observedNumber$1(left.monthlySearchVolume) || left.rankGroup - right.rankGroup || compareCodepoints$3(left.keyword, right.keyword) || compareCodepoints$3(left.url, right.url));
|
|
25261
|
+
const providerTotalRows = totalRows$1(responseResults.map((result) => result.total_count));
|
|
24996
25262
|
return domainEvidence({
|
|
24997
25263
|
capability: "ranked-keywords",
|
|
24998
25264
|
data: {
|
|
@@ -25065,7 +25331,7 @@ async function dataForSeoRankingPages(client, input) {
|
|
|
25065
25331
|
const market = researchMarket(input.market, "ranking-pages");
|
|
25066
25332
|
const target = domain(input.domain);
|
|
25067
25333
|
const offset = input.offset ?? 0;
|
|
25068
|
-
rowLimit(input.limit, offset);
|
|
25334
|
+
rowLimit$1(input.limit, offset);
|
|
25069
25335
|
const requestedFilters = filters(input);
|
|
25070
25336
|
const orderBy = ["metrics.organic.etv,desc", "page_address,asc"];
|
|
25071
25337
|
const snapshot = await client.rankingPages({
|
|
@@ -25077,13 +25343,13 @@ async function dataForSeoRankingPages(client, input) {
|
|
|
25077
25343
|
limit: input.limit,
|
|
25078
25344
|
offset,
|
|
25079
25345
|
refresh: input.refresh,
|
|
25080
|
-
context: requestContext("ranking-pages", input.context)
|
|
25346
|
+
context: requestContext$1("ranking-pages", input.context)
|
|
25081
25347
|
});
|
|
25082
25348
|
const responseResults = snapshot.response.tasks.flatMap((task) => task.result ?? []);
|
|
25083
25349
|
const rawRows = responseResults.flatMap((result) => result.items ?? []);
|
|
25084
25350
|
let invalidRows = 0;
|
|
25085
25351
|
const mappedRows = rawRows.flatMap((row) => {
|
|
25086
|
-
const url = safeUrl$
|
|
25352
|
+
const url = safeUrl$2(row.page_address);
|
|
25087
25353
|
if (!url) {
|
|
25088
25354
|
invalidRows += 1;
|
|
25089
25355
|
return [];
|
|
@@ -25093,8 +25359,8 @@ async function dataForSeoRankingPages(client, input) {
|
|
|
25093
25359
|
organic: organicFootprint(row.metrics?.organic)
|
|
25094
25360
|
}];
|
|
25095
25361
|
});
|
|
25096
|
-
const rows = dedupeBy(mappedRows, (row) => row.url).sort((left, right) => observedNumber(right.organic.estimatedMonthlyTraffic) - observedNumber(left.organic.estimatedMonthlyTraffic) || compareCodepoints$3(left.url, right.url));
|
|
25097
|
-
const providerTotalRows = totalRows(responseResults.map((result) => result.total_count));
|
|
25362
|
+
const rows = dedupeBy(mappedRows, (row) => row.url).sort((left, right) => observedNumber$1(right.organic.estimatedMonthlyTraffic) - observedNumber$1(left.organic.estimatedMonthlyTraffic) || compareCodepoints$3(left.url, right.url));
|
|
25363
|
+
const providerTotalRows = totalRows$1(responseResults.map((result) => result.total_count));
|
|
25098
25364
|
return domainEvidence({
|
|
25099
25365
|
capability: "relevant-pages",
|
|
25100
25366
|
data: {
|
|
@@ -25139,7 +25405,7 @@ function keywords(input) {
|
|
|
25139
25405
|
async function dataForSeoSerpCompetitors(client, input) {
|
|
25140
25406
|
const market = researchMarket(input.market, "serp-competitors");
|
|
25141
25407
|
const offset = input.offset ?? 0;
|
|
25142
|
-
rowLimit(input.limit, offset);
|
|
25408
|
+
rowLimit$1(input.limit, offset);
|
|
25143
25409
|
const requestedKeywords = keywords(input.keywords);
|
|
25144
25410
|
const types = resultTypes(input.resultTypes, COMPETITOR_RESULT_TYPES);
|
|
25145
25411
|
const orderBy = [
|
|
@@ -25157,7 +25423,7 @@ async function dataForSeoSerpCompetitors(client, input) {
|
|
|
25157
25423
|
limit: input.limit,
|
|
25158
25424
|
offset,
|
|
25159
25425
|
refresh: input.refresh,
|
|
25160
|
-
context: requestContext("serp-competitors", input.context)
|
|
25426
|
+
context: requestContext$1("serp-competitors", input.context)
|
|
25161
25427
|
});
|
|
25162
25428
|
const responseResults = snapshot.response.tasks.flatMap((task) => task.result ?? []);
|
|
25163
25429
|
const rawRows = responseResults.flatMap((result) => result.items ?? []);
|
|
@@ -25180,16 +25446,16 @@ async function dataForSeoSerpCompetitors(client, input) {
|
|
|
25180
25446
|
return [{
|
|
25181
25447
|
domain: normalizedDomain,
|
|
25182
25448
|
matchedKeywords: row.keywords_count,
|
|
25183
|
-
averagePosition: numberValue(row.avg_position, "average position"),
|
|
25184
|
-
medianPosition: numberValue(row.median_position, "median position"),
|
|
25185
|
-
visibility: numberValue(row.visibility, "visibility"),
|
|
25186
|
-
estimatedMonthlyTraffic: numberValue(row.etv, "estimated monthly traffic"),
|
|
25449
|
+
averagePosition: numberValue$1(row.avg_position, "average position"),
|
|
25450
|
+
medianPosition: numberValue$1(row.median_position, "median position"),
|
|
25451
|
+
visibility: numberValue$1(row.visibility, "visibility"),
|
|
25452
|
+
estimatedMonthlyTraffic: numberValue$1(row.etv, "estimated monthly traffic"),
|
|
25187
25453
|
relevantResults: countValue(row.relevant_serp_items, "relevant result count"),
|
|
25188
25454
|
keywordPositions
|
|
25189
25455
|
}];
|
|
25190
25456
|
});
|
|
25191
|
-
const rows = dedupeBy(mappedRows, (row) => row.domain).sort((left, right) => observedNumber(right.visibility) - observedNumber(left.visibility) || right.matchedKeywords - left.matchedKeywords || compareCodepoints$3(left.domain, right.domain));
|
|
25192
|
-
const providerTotalRows = totalRows(responseResults.map((result) => result.total_count));
|
|
25457
|
+
const rows = dedupeBy(mappedRows, (row) => row.domain).sort((left, right) => observedNumber$1(right.visibility) - observedNumber$1(left.visibility) || right.matchedKeywords - left.matchedKeywords || compareCodepoints$3(left.domain, right.domain));
|
|
25458
|
+
const providerTotalRows = totalRows$1(responseResults.map((result) => result.total_count));
|
|
25193
25459
|
return domainEvidence({
|
|
25194
25460
|
capability: "serp-competitors",
|
|
25195
25461
|
data: {
|
|
@@ -26104,7 +26370,7 @@ function analyzeCompetitorGap(acquisition) {
|
|
|
26104
26370
|
}
|
|
26105
26371
|
//#endregion
|
|
26106
26372
|
//#region packages/core/src/analyze/domain-research/gap-report.ts
|
|
26107
|
-
const MAX_FINDINGS = 10;
|
|
26373
|
+
const MAX_FINDINGS$2 = 10;
|
|
26108
26374
|
const MAX_SOURCE_BRIEFS = 5;
|
|
26109
26375
|
function count(candidates, classification) {
|
|
26110
26376
|
return candidates.filter((item) => item.classification === classification).length;
|
|
@@ -26119,7 +26385,7 @@ function dataStatus(input) {
|
|
|
26119
26385
|
function findings$2(input) {
|
|
26120
26386
|
const result = [];
|
|
26121
26387
|
for (const [index, candidate] of input.candidates.entries()) {
|
|
26122
|
-
if (result.length >= MAX_FINDINGS) break;
|
|
26388
|
+
if (result.length >= MAX_FINDINGS$2) break;
|
|
26123
26389
|
if (candidate.classification === "relevant-gap-candidate") result.push({
|
|
26124
26390
|
code: "relevant-competitor-gap",
|
|
26125
26391
|
evidenceRefs: [`candidates[${index}]`, ...candidate.evidenceRefs],
|
|
@@ -26134,7 +26400,7 @@ function findings$2(input) {
|
|
|
26134
26400
|
});
|
|
26135
26401
|
}
|
|
26136
26402
|
for (const [index, pattern] of input.patterns.entries()) {
|
|
26137
|
-
if (result.length >= MAX_FINDINGS) break;
|
|
26403
|
+
if (result.length >= MAX_FINDINGS$2) break;
|
|
26138
26404
|
result.push({
|
|
26139
26405
|
code: "competitor-template-pattern",
|
|
26140
26406
|
evidenceRefs: [`repeatedCompetitorPatterns[${index}]`, ...pattern.evidenceRefs],
|
|
@@ -27181,7 +27447,7 @@ function measurementWindow(input) {
|
|
|
27181
27447
|
}
|
|
27182
27448
|
//#endregion
|
|
27183
27449
|
//#region packages/core/src/analyze/experiments/measure-change.ts
|
|
27184
|
-
const defaultDependencies$
|
|
27450
|
+
const defaultDependencies$6 = {
|
|
27185
27451
|
searchAnalytics: querySearchAnalytics,
|
|
27186
27452
|
googleAnalyticsReport: runGa4Report,
|
|
27187
27453
|
contentGroup: getContentGroup,
|
|
@@ -27199,7 +27465,7 @@ function counterfactualDelta(input) {
|
|
|
27199
27465
|
const expectedAfter = input.treatmentBefore * (input.controlAfter / input.controlBefore);
|
|
27200
27466
|
return fixed(input.treatmentAfter - expectedAfter);
|
|
27201
27467
|
}
|
|
27202
|
-
async function measureChange(input, dependencies = defaultDependencies$
|
|
27468
|
+
async function measureChange(input, dependencies = defaultDependencies$6) {
|
|
27203
27469
|
const now = dependencies.now();
|
|
27204
27470
|
const change = (input.id ? getChange(input.id) : void 0) ?? {
|
|
27205
27471
|
id: "adhoc",
|
|
@@ -27924,14 +28190,14 @@ async function verifyInternalLinkCandidate(input) {
|
|
|
27924
28190
|
}
|
|
27925
28191
|
//#endregion
|
|
27926
28192
|
//#region packages/core/src/analyze/internal-links.ts
|
|
27927
|
-
const MAX_GSC_ROWS$
|
|
27928
|
-
const defaultDependencies$
|
|
28193
|
+
const MAX_GSC_ROWS$2 = 1e5;
|
|
28194
|
+
const defaultDependencies$5 = {
|
|
27929
28195
|
searchAnalytics: querySearchAnalytics,
|
|
27930
28196
|
fetch: fetchPage,
|
|
27931
28197
|
extract: extractPage,
|
|
27932
28198
|
now: () => /* @__PURE__ */ new Date()
|
|
27933
28199
|
};
|
|
27934
|
-
async function internalLinksReport(input, dependencies = defaultDependencies$
|
|
28200
|
+
async function internalLinksReport(input, dependencies = defaultDependencies$5) {
|
|
27935
28201
|
const targetPage = new URL(assertUrlMatchesGscProperty(input.site, input.targetUrl));
|
|
27936
28202
|
targetPage.hash = "";
|
|
27937
28203
|
const targetUrl = targetPage.toString();
|
|
@@ -27980,7 +28246,7 @@ async function internalLinksReport(input, dependencies = defaultDependencies$4)
|
|
|
27980
28246
|
dimensions: ["query", "page"],
|
|
27981
28247
|
type: "web",
|
|
27982
28248
|
dataState: "final",
|
|
27983
|
-
maxRows: MAX_GSC_ROWS$
|
|
28249
|
+
maxRows: MAX_GSC_ROWS$2,
|
|
27984
28250
|
dimensionFilterGroups: [{
|
|
27985
28251
|
groupType: "and",
|
|
27986
28252
|
filters: [{
|
|
@@ -28012,7 +28278,7 @@ async function internalLinksReport(input, dependencies = defaultDependencies$4)
|
|
|
28012
28278
|
dimensions: ["query", "page"],
|
|
28013
28279
|
type: "web",
|
|
28014
28280
|
dataState: "final",
|
|
28015
|
-
maxRows: MAX_GSC_ROWS$
|
|
28281
|
+
maxRows: MAX_GSC_ROWS$2
|
|
28016
28282
|
}, { refresh: input.refresh }) : {
|
|
28017
28283
|
rows: [],
|
|
28018
28284
|
calls: 0,
|
|
@@ -28057,8 +28323,8 @@ async function internalLinksReport(input, dependencies = defaultDependencies$4)
|
|
|
28057
28323
|
else checkedSources += 1;
|
|
28058
28324
|
}
|
|
28059
28325
|
const uncheckedCandidates = Math.max(0, analysis.candidates.length - attemptedSources);
|
|
28060
|
-
const targetTruncated = targetRequests.some(({ result }) => result.rowsFetched >= MAX_GSC_ROWS$
|
|
28061
|
-
const sourceTruncated = sourceResult.rowsFetched >= MAX_GSC_ROWS$
|
|
28326
|
+
const targetTruncated = targetRequests.some(({ result }) => result.rowsFetched >= MAX_GSC_ROWS$2);
|
|
28327
|
+
const sourceTruncated = sourceResult.rowsFetched >= MAX_GSC_ROWS$2;
|
|
28062
28328
|
const invalidRows = analysis.selection.targetInvalidRows + analysis.selection.sourceInvalidRows;
|
|
28063
28329
|
const structuredWarnings = uniqueInternalLinksWarnings(warnings);
|
|
28064
28330
|
const dataStatus = target.verification === "technical-issue" ? "target-technical-issue" : target.verification === "failed" ? "partial" : targetRows.length === 0 ? "empty" : targetTruncated || sourceTruncated || invalidRows > 0 ? "partial" : queryCandidates && sourceResult.rows.length === 0 ? "source-empty" : analysis.selection.targetEligibleQueries === 0 || analysis.candidates.length === 0 ? "filtered" : failedChecks > 0 || uncheckedCandidates > 0 ? "partial" : "complete";
|
|
@@ -28099,18 +28365,18 @@ async function internalLinksReport(input, dependencies = defaultDependencies$4)
|
|
|
28099
28365
|
pageFilter: alias,
|
|
28100
28366
|
rowsFetched: result.rowsFetched,
|
|
28101
28367
|
calls: result.calls,
|
|
28102
|
-
possiblyTruncated: result.rowsFetched >= MAX_GSC_ROWS$
|
|
28368
|
+
possiblyTruncated: result.rowsFetched >= MAX_GSC_ROWS$2
|
|
28103
28369
|
})),
|
|
28104
28370
|
rowsFetched: targetRequests.reduce((sum, { result }) => sum + result.rowsFetched, 0),
|
|
28105
28371
|
calls: targetRequests.reduce((sum, { result }) => sum + result.calls, 0),
|
|
28106
|
-
maxRowsPerRequest: MAX_GSC_ROWS$
|
|
28372
|
+
maxRowsPerRequest: MAX_GSC_ROWS$2,
|
|
28107
28373
|
possiblyTruncated: targetTruncated
|
|
28108
28374
|
},
|
|
28109
28375
|
candidates: {
|
|
28110
28376
|
queried: queryCandidates,
|
|
28111
28377
|
rowsFetched: sourceResult.rowsFetched,
|
|
28112
28378
|
calls: sourceResult.calls,
|
|
28113
|
-
maxRows: MAX_GSC_ROWS$
|
|
28379
|
+
maxRows: MAX_GSC_ROWS$2,
|
|
28114
28380
|
possiblyTruncated: sourceTruncated
|
|
28115
28381
|
},
|
|
28116
28382
|
completeness: !queryCandidates ? "not-queried" : targetTruncated || sourceTruncated ? "possibly-truncated" : "retained-rows-only"
|
|
@@ -28129,7 +28395,7 @@ async function internalLinksReport(input, dependencies = defaultDependencies$4)
|
|
|
28129
28395
|
minImpressions,
|
|
28130
28396
|
resultLimit: limit,
|
|
28131
28397
|
checkLimit,
|
|
28132
|
-
maxGscRowsPerRequest: MAX_GSC_ROWS$
|
|
28398
|
+
maxGscRowsPerRequest: MAX_GSC_ROWS$2
|
|
28133
28399
|
},
|
|
28134
28400
|
target: {
|
|
28135
28401
|
requestedUrl: target.requestedUrl,
|
|
@@ -29069,8 +29335,8 @@ function analyzeSecondPageRows(input) {
|
|
|
29069
29335
|
}
|
|
29070
29336
|
//#endregion
|
|
29071
29337
|
//#region packages/core/src/analyze/keyword-opportunities.ts
|
|
29072
|
-
const DEFAULT_DAYS = 28;
|
|
29073
|
-
const MAX_DAYS = 548;
|
|
29338
|
+
const DEFAULT_DAYS$1 = 28;
|
|
29339
|
+
const MAX_DAYS$1 = 548;
|
|
29074
29340
|
const DEFAULT_REPORT_LIMIT = 10;
|
|
29075
29341
|
const MAX_REPORT_LIMIT = 25;
|
|
29076
29342
|
const DEFAULT_KEYWORD_LIMIT = 30;
|
|
@@ -29117,9 +29383,9 @@ function validateInput$2(input) {
|
|
|
29117
29383
|
site,
|
|
29118
29384
|
days: integerOption$1({
|
|
29119
29385
|
value: input.days,
|
|
29120
|
-
fallback: DEFAULT_DAYS,
|
|
29386
|
+
fallback: DEFAULT_DAYS$1,
|
|
29121
29387
|
minimum: 1,
|
|
29122
|
-
maximum: MAX_DAYS,
|
|
29388
|
+
maximum: MAX_DAYS$1,
|
|
29123
29389
|
label: "Days"
|
|
29124
29390
|
}),
|
|
29125
29391
|
limit: integerOption$1({
|
|
@@ -30657,7 +30923,7 @@ function analyzeIndexCoverageSignals(input) {
|
|
|
30657
30923
|
const MAX_SITEMAP_DOCUMENTS = 20;
|
|
30658
30924
|
const MAX_SEARCH_ROWS = 25e4;
|
|
30659
30925
|
const MAX_SITEMAP_URLS = 25e4;
|
|
30660
|
-
const defaultDependencies$
|
|
30926
|
+
const defaultDependencies$4 = {
|
|
30661
30927
|
loadCrawl: loadCrawlReport,
|
|
30662
30928
|
latestCrawl: latestCrawlReport,
|
|
30663
30929
|
searchAnalytics: querySearchAnalytics,
|
|
@@ -30689,7 +30955,7 @@ function sitemapCompleteness(input) {
|
|
|
30689
30955
|
if (input.inventoryTruncated) return "truncated";
|
|
30690
30956
|
return input.results.every((result) => result.dataStatus === "complete") ? "complete" : "partial";
|
|
30691
30957
|
}
|
|
30692
|
-
async function indexCoverageSignals(input, dependencies = defaultDependencies$
|
|
30958
|
+
async function indexCoverageSignals(input, dependencies = defaultDependencies$4) {
|
|
30693
30959
|
const days = integerOption$2({
|
|
30694
30960
|
value: input.days,
|
|
30695
30961
|
fallback: 90,
|
|
@@ -31173,7 +31439,7 @@ function pruneIndexWatchSnapshots(rootSite, url, database = getDb()) {
|
|
|
31173
31439
|
WHERE attempts.attempt_rank > ? AND latest_success.id IS NULL
|
|
31174
31440
|
)`).run(rootSite, url, rootSite, url, 20).changes;
|
|
31175
31441
|
}
|
|
31176
|
-
const defaultDependencies$
|
|
31442
|
+
const defaultDependencies$3 = {
|
|
31177
31443
|
inspectUrl,
|
|
31178
31444
|
now: () => /* @__PURE__ */ new Date(),
|
|
31179
31445
|
store: {
|
|
@@ -31218,7 +31484,7 @@ function isFatalBatchError(error) {
|
|
|
31218
31484
|
"AUTH_REQUIRED"
|
|
31219
31485
|
].includes(error.code);
|
|
31220
31486
|
}
|
|
31221
|
-
async function indexWatch(input, dependencies = defaultDependencies$
|
|
31487
|
+
async function indexWatch(input, dependencies = defaultDependencies$3) {
|
|
31222
31488
|
const languageCode = validateLanguageCode(input.languageCode);
|
|
31223
31489
|
const dailyLimit = integerOption$2({
|
|
31224
31490
|
value: input.dailyLimit,
|
|
@@ -33400,9 +33666,9 @@ function pseoSampleUrls(report) {
|
|
|
33400
33666
|
}
|
|
33401
33667
|
//#endregion
|
|
33402
33668
|
//#region packages/core/src/analyze/pseo/audit.ts
|
|
33403
|
-
const MAX_GSC_ROWS = 5e4;
|
|
33669
|
+
const MAX_GSC_ROWS$1 = 5e4;
|
|
33404
33670
|
const DEFAULT_SITEMAP_URLS = 5e4;
|
|
33405
|
-
const defaultDependencies$
|
|
33671
|
+
const defaultDependencies$2 = {
|
|
33406
33672
|
searchAnalytics: querySearchAnalytics,
|
|
33407
33673
|
fetchPage,
|
|
33408
33674
|
inspectUrl,
|
|
@@ -33604,7 +33870,7 @@ async function inspectSample(input) {
|
|
|
33604
33870
|
};
|
|
33605
33871
|
}
|
|
33606
33872
|
}
|
|
33607
|
-
async function acquirePseoAuditEvidence(input, dependencies = defaultDependencies$
|
|
33873
|
+
async function acquirePseoAuditEvidence(input, dependencies = defaultDependencies$2) {
|
|
33608
33874
|
const options = pseoAuditOptions(input);
|
|
33609
33875
|
const now = dependencies.now();
|
|
33610
33876
|
const generatedAt = now.toISOString();
|
|
@@ -33623,7 +33889,7 @@ async function acquirePseoAuditEvidence(input, dependencies = defaultDependencie
|
|
|
33623
33889
|
type: "web",
|
|
33624
33890
|
dataState: "final",
|
|
33625
33891
|
aggregationType: "auto",
|
|
33626
|
-
maxRows: MAX_GSC_ROWS
|
|
33892
|
+
maxRows: MAX_GSC_ROWS$1
|
|
33627
33893
|
};
|
|
33628
33894
|
input.progress?.(`Fetching ${options.days} days of GSC page and query/page rows`);
|
|
33629
33895
|
const [pageResponse, queryPageResponse] = await Promise.all([dependencies.searchAnalytics(input.site, {
|
|
@@ -33674,7 +33940,7 @@ function buildPseoAuditFromAcquisition(input, acquisition, evidence) {
|
|
|
33674
33940
|
minimumTemplateImpressions: options.minimumTemplateImpressions,
|
|
33675
33941
|
crawlSamplesPerTemplate: options.crawlSamples,
|
|
33676
33942
|
inspectionSamplesPerTemplate: options.inspectSamples,
|
|
33677
|
-
maxRowsPerRequest: MAX_GSC_ROWS,
|
|
33943
|
+
maxRowsPerRequest: MAX_GSC_ROWS$1,
|
|
33678
33944
|
pageRowsFetched: acquisition.pageRowsFetched,
|
|
33679
33945
|
queryPageRowsFetched: acquisition.queryPageRowsFetched,
|
|
33680
33946
|
sitemapsRequested: input.sitemaps?.length ?? 0,
|
|
@@ -33685,7 +33951,7 @@ function buildPseoAuditFromAcquisition(input, acquisition, evidence) {
|
|
|
33685
33951
|
caveats: [`Data freshness: ${input.refresh ? "fresh fetch requested; caches bypassed where supported" : "local cache allowed; use --refresh to bypass cached provider and HTTP data"}.`, input.sitemaps?.length ? `Sitemaps: ${countLabel(input.sitemaps.length, "sitemap URL")} requested.` : "Sitemaps: none provided; template discovery used retained GSC page rows."]
|
|
33686
33952
|
});
|
|
33687
33953
|
}
|
|
33688
|
-
async function pseoAuditReport(input, dependencies = defaultDependencies$
|
|
33954
|
+
async function pseoAuditReport(input, dependencies = defaultDependencies$2) {
|
|
33689
33955
|
const acquisition = await acquirePseoAuditEvidence(input, dependencies);
|
|
33690
33956
|
const sampleUrls = pseoSampleUrls(buildPseoAuditFromAcquisition(input, acquisition));
|
|
33691
33957
|
const topQueries = topQueryByUrl(acquisition.queryPageRows, input);
|
|
@@ -34527,7 +34793,7 @@ function pseoOpportunityVerdict(input) {
|
|
|
34527
34793
|
//#region packages/core/src/providers/dataforseo/serp-snapshot.ts
|
|
34528
34794
|
const MAX_SERP_DEPTH = 100;
|
|
34529
34795
|
const SERP_ENDPOINT = "v3/serp/google/organic/live/advanced";
|
|
34530
|
-
function safeUrl(value) {
|
|
34796
|
+
function safeUrl$1(value) {
|
|
34531
34797
|
if (!value) return null;
|
|
34532
34798
|
try {
|
|
34533
34799
|
const parsed = new URL(value);
|
|
@@ -34540,11 +34806,11 @@ function safeUrl(value) {
|
|
|
34540
34806
|
}
|
|
34541
34807
|
}
|
|
34542
34808
|
function validOrganic(item) {
|
|
34543
|
-
return item.type === "organic" && Number.isSafeInteger(item.rank_group) && (item.rank_group ?? 0) > 0 && Number.isSafeInteger(item.rank_absolute) && (item.rank_absolute ?? 0) > 0 && Number.isSafeInteger(item.page) && (item.page ?? 0) > 0 && Boolean(item.domain?.trim()) && safeUrl(item.url) !== null;
|
|
34809
|
+
return item.type === "organic" && Number.isSafeInteger(item.rank_group) && (item.rank_group ?? 0) > 0 && Number.isSafeInteger(item.rank_absolute) && (item.rank_absolute ?? 0) > 0 && Number.isSafeInteger(item.page) && (item.page ?? 0) > 0 && Boolean(item.domain?.trim()) && safeUrl$1(item.url) !== null;
|
|
34544
34810
|
}
|
|
34545
34811
|
function organicResult(item) {
|
|
34546
34812
|
if (!validOrganic(item)) return null;
|
|
34547
|
-
const url = safeUrl(item.url);
|
|
34813
|
+
const url = safeUrl$1(item.url);
|
|
34548
34814
|
if (!url) return null;
|
|
34549
34815
|
return {
|
|
34550
34816
|
rankGroup: item.rank_group,
|
|
@@ -34593,7 +34859,7 @@ function mapDataForSeoSerpSnapshot(input, snapshot, endpoint = SERP_ENDPOINT) {
|
|
|
34593
34859
|
field: "checkedAt",
|
|
34594
34860
|
message: "DataForSEO returned an invalid SERP observation time; the local response time was retained."
|
|
34595
34861
|
});
|
|
34596
|
-
const checkUrl = safeUrl(result.check_url);
|
|
34862
|
+
const checkUrl = safeUrl$1(result.check_url);
|
|
34597
34863
|
if (result.check_url && !checkUrl) warnings.push({
|
|
34598
34864
|
code: "invalid-serp-check-url",
|
|
34599
34865
|
field: "checkUrl",
|
|
@@ -37141,7 +37407,7 @@ function groupedMappings(evidence) {
|
|
|
37141
37407
|
//#endregion
|
|
37142
37408
|
//#region packages/core/src/analyze/second-page.ts
|
|
37143
37409
|
const MAX_SOURCE_ROWS = 1e5;
|
|
37144
|
-
const defaultDependencies = {
|
|
37410
|
+
const defaultDependencies$1 = {
|
|
37145
37411
|
searchAnalytics: querySearchAnalytics,
|
|
37146
37412
|
fetch: fetchPage,
|
|
37147
37413
|
extract: extractPage,
|
|
@@ -37218,7 +37484,7 @@ function reportRecommendations(items) {
|
|
|
37218
37484
|
"Treat the priority score as a triage heuristic, not an estimated traffic lift."
|
|
37219
37485
|
]);
|
|
37220
37486
|
}
|
|
37221
|
-
async function secondPage(input, dependencies = defaultDependencies) {
|
|
37487
|
+
async function secondPage(input, dependencies = defaultDependencies$1) {
|
|
37222
37488
|
const days = integerOption({
|
|
37223
37489
|
value: input.range,
|
|
37224
37490
|
fallback: 28,
|
|
@@ -40384,10 +40650,10 @@ const DEFAULT_TARGET_LIMIT = 20;
|
|
|
40384
40650
|
const MAX_TARGET_LIMIT = 50;
|
|
40385
40651
|
const DEFAULT_DETAIL_PAGES = 1;
|
|
40386
40652
|
const MAX_DETAIL_PAGES = 3;
|
|
40387
|
-
const DEFAULT_ROW_LIMIT$
|
|
40388
|
-
const MAX_ROW_LIMIT$
|
|
40653
|
+
const DEFAULT_ROW_LIMIT$3 = 500;
|
|
40654
|
+
const MAX_ROW_LIMIT$3 = 1e3;
|
|
40389
40655
|
const MAX_CONCURRENCY = 3;
|
|
40390
|
-
function integer(value, fallback, max, name) {
|
|
40656
|
+
function integer$1(value, fallback, max, name) {
|
|
40391
40657
|
const resolved = value ?? fallback;
|
|
40392
40658
|
if (!Number.isInteger(resolved) || resolved < 1 || resolved > max) throw new SeoError("INVALID_INPUT", `${name} must be between 1 and ${max}.`);
|
|
40393
40659
|
return resolved;
|
|
@@ -40448,9 +40714,9 @@ async function targetDetails(input) {
|
|
|
40448
40714
|
}
|
|
40449
40715
|
async function collectBingLinkEvidence(input) {
|
|
40450
40716
|
if (!input.site.trim()) throw new SeoError("INVALID_INPUT", "Pass a Bing Webmaster site URL.");
|
|
40451
|
-
const targetLimit = integer(input.targetLimit, DEFAULT_TARGET_LIMIT, MAX_TARGET_LIMIT, "Bing link target limit");
|
|
40452
|
-
const detailPages = integer(input.detailPagesPerTarget, DEFAULT_DETAIL_PAGES, MAX_DETAIL_PAGES, "Bing detail page limit");
|
|
40453
|
-
const rowLimit = integer(input.rowLimit, DEFAULT_ROW_LIMIT$
|
|
40717
|
+
const targetLimit = integer$1(input.targetLimit, DEFAULT_TARGET_LIMIT, MAX_TARGET_LIMIT, "Bing link target limit");
|
|
40718
|
+
const detailPages = integer$1(input.detailPagesPerTarget, DEFAULT_DETAIL_PAGES, MAX_DETAIL_PAGES, "Bing detail page limit");
|
|
40719
|
+
const rowLimit = integer$1(input.rowLimit, DEFAULT_ROW_LIMIT$3, MAX_ROW_LIMIT$3, "Bing link row limit");
|
|
40454
40720
|
const client = input.client ?? (await createBingWebmasterClient()).client;
|
|
40455
40721
|
const countRows = [];
|
|
40456
40722
|
let countPagesRequested = 0;
|
|
@@ -40571,6 +40837,884 @@ async function collectBingLinkEvidence(input) {
|
|
|
40571
40837
|
};
|
|
40572
40838
|
}
|
|
40573
40839
|
//#endregion
|
|
40840
|
+
//#region packages/core/src/links/context-sources.ts
|
|
40841
|
+
function urlKey(value) {
|
|
40842
|
+
try {
|
|
40843
|
+
const url = new URL(value);
|
|
40844
|
+
if (!["http:", "https:"].includes(url.protocol)) return null;
|
|
40845
|
+
url.hash = "";
|
|
40846
|
+
return url.toString();
|
|
40847
|
+
} catch {
|
|
40848
|
+
return null;
|
|
40849
|
+
}
|
|
40850
|
+
}
|
|
40851
|
+
function compareTargets(left, right) {
|
|
40852
|
+
return right.observedLinks - left.observedLinks || (left.targetUrl < right.targetUrl ? -1 : left.targetUrl > right.targetUrl ? 1 : 0);
|
|
40853
|
+
}
|
|
40854
|
+
function linkTargetCounts(evidence) {
|
|
40855
|
+
if (evidence.targetCounts.length) return [...evidence.targetCounts].sort(compareTargets);
|
|
40856
|
+
const counts = /* @__PURE__ */ new Map();
|
|
40857
|
+
for (const row of evidence.rows) counts.set(row.targetUrl, (counts.get(row.targetUrl) ?? 0) + 1);
|
|
40858
|
+
return [...counts].map(([targetUrl, observedLinks]) => ({
|
|
40859
|
+
targetUrl,
|
|
40860
|
+
observedLinks
|
|
40861
|
+
})).sort(compareTargets);
|
|
40862
|
+
}
|
|
40863
|
+
function crawlForLinkTargets(input) {
|
|
40864
|
+
const values = /* @__PURE__ */ new Map();
|
|
40865
|
+
if (!input.report) {
|
|
40866
|
+
for (const target of input.targets) values.set(target.targetUrl, {
|
|
40867
|
+
state: "unavailable",
|
|
40868
|
+
reason: "No matching saved crawl was available."
|
|
40869
|
+
});
|
|
40870
|
+
return {
|
|
40871
|
+
values,
|
|
40872
|
+
matched: 0
|
|
40873
|
+
};
|
|
40874
|
+
}
|
|
40875
|
+
const pages = /* @__PURE__ */ new Map();
|
|
40876
|
+
for (const page of input.report.pages) for (const value of [page.url, page.finalUrl]) {
|
|
40877
|
+
const key = urlKey(value);
|
|
40878
|
+
if (key && !pages.has(key)) pages.set(key, page);
|
|
40879
|
+
}
|
|
40880
|
+
const issues = /* @__PURE__ */ new Map();
|
|
40881
|
+
for (const issue of input.report.issues) {
|
|
40882
|
+
const key = urlKey(issue.url);
|
|
40883
|
+
if (!key) continue;
|
|
40884
|
+
const ids = issues.get(key) ?? /* @__PURE__ */ new Set();
|
|
40885
|
+
ids.add(issue.ruleId);
|
|
40886
|
+
issues.set(key, ids);
|
|
40887
|
+
}
|
|
40888
|
+
let matched = 0;
|
|
40889
|
+
for (const target of input.targets) {
|
|
40890
|
+
const key = urlKey(target.targetUrl);
|
|
40891
|
+
const page = key ? pages.get(key) : void 0;
|
|
40892
|
+
if (!page) {
|
|
40893
|
+
values.set(target.targetUrl, {
|
|
40894
|
+
state: "not-observed",
|
|
40895
|
+
reason: "The target URL was not present in the retained crawl pages."
|
|
40896
|
+
});
|
|
40897
|
+
continue;
|
|
40898
|
+
}
|
|
40899
|
+
matched += 1;
|
|
40900
|
+
values.set(target.targetUrl, {
|
|
40901
|
+
state: "observed",
|
|
40902
|
+
reportId: input.report.id,
|
|
40903
|
+
observedAt: input.report.generatedAt,
|
|
40904
|
+
status: page.status,
|
|
40905
|
+
finalUrl: page.finalUrl,
|
|
40906
|
+
indexable: page.indexable,
|
|
40907
|
+
canonical: page.canonical ?? null,
|
|
40908
|
+
issueIds: [...issues.get(key) ?? []].sort()
|
|
40909
|
+
});
|
|
40910
|
+
}
|
|
40911
|
+
return {
|
|
40912
|
+
values,
|
|
40913
|
+
matched
|
|
40914
|
+
};
|
|
40915
|
+
}
|
|
40916
|
+
function aggregateLinkSearchRows(rows) {
|
|
40917
|
+
const values = /* @__PURE__ */ new Map();
|
|
40918
|
+
for (const row of rows) {
|
|
40919
|
+
const page = row.keys[0];
|
|
40920
|
+
const key = page ? urlKey(page) : null;
|
|
40921
|
+
if (!key) continue;
|
|
40922
|
+
const current = values.get(key) ?? {
|
|
40923
|
+
clicks: 0,
|
|
40924
|
+
impressions: 0,
|
|
40925
|
+
positionWeight: 0
|
|
40926
|
+
};
|
|
40927
|
+
current.clicks += row.clicks;
|
|
40928
|
+
current.impressions += row.impressions;
|
|
40929
|
+
current.positionWeight += row.position * row.impressions;
|
|
40930
|
+
values.set(key, current);
|
|
40931
|
+
}
|
|
40932
|
+
return values;
|
|
40933
|
+
}
|
|
40934
|
+
//#endregion
|
|
40935
|
+
//#region packages/core/src/links/context-findings.ts
|
|
40936
|
+
const MAX_FINDINGS$1 = 50;
|
|
40937
|
+
function findingPriority(input) {
|
|
40938
|
+
const searchValue = input.search.state === "observed" && (input.search.clicks > 0 || input.search.impressions >= 100);
|
|
40939
|
+
if (input.code === "linked-broken-target" || searchValue) return "high";
|
|
40940
|
+
if (input.observedLinks >= 5) return "medium";
|
|
40941
|
+
return "low";
|
|
40942
|
+
}
|
|
40943
|
+
function finding(input) {
|
|
40944
|
+
const crawl = input.row.crawl;
|
|
40945
|
+
if (crawl.state !== "observed") throw new Error("A link finding requires observed crawl evidence.");
|
|
40946
|
+
const searchEvidence = input.row.searchConsole.state === "observed" ? ` Search Console retained ${input.row.searchConsole.clicks.toFixed(0)} clicks and ${input.row.searchConsole.impressions.toFixed(0)} impressions for this page in the selected window.` : "";
|
|
40947
|
+
const common = {
|
|
40948
|
+
priority: findingPriority({
|
|
40949
|
+
code: input.code,
|
|
40950
|
+
observedLinks: input.row.observedLinks,
|
|
40951
|
+
crawl,
|
|
40952
|
+
search: input.row.searchConsole
|
|
40953
|
+
}),
|
|
40954
|
+
heuristic: true,
|
|
40955
|
+
targetUrl: input.row.targetUrl,
|
|
40956
|
+
observedLinks: input.row.observedLinks,
|
|
40957
|
+
evidenceRefs: [input.row.targetUrl, crawl.reportId]
|
|
40958
|
+
};
|
|
40959
|
+
if (input.code === "linked-broken-target") return {
|
|
40960
|
+
...common,
|
|
40961
|
+
code: input.code,
|
|
40962
|
+
principle: "Linked target pages should resolve intentionally.",
|
|
40963
|
+
evidence: `The saved crawl observed status ${crawl.status} for a target with ${input.row.observedLinks} retained representative links.${searchEvidence}`,
|
|
40964
|
+
action: "Confirm whether the page should exist. Restore it or add one direct redirect to a genuinely equivalent live page when the missing URL is unintended.",
|
|
40965
|
+
verify: "Run redirect-trace for the target, then recrawl it and confirm a stable intended response."
|
|
40966
|
+
};
|
|
40967
|
+
if (input.code === "linked-redirect-target") return {
|
|
40968
|
+
...common,
|
|
40969
|
+
code: input.code,
|
|
40970
|
+
principle: "External links should reach a stable final destination.",
|
|
40971
|
+
evidence: `The saved crawl observed ${input.row.targetUrl} resolving to ${crawl.finalUrl}.${searchEvidence}`,
|
|
40972
|
+
action: "Check that the redirect is intentional, direct and semantically equivalent. Update links you control to the final URL and ask important external sources to update only when the change is worth the effort.",
|
|
40973
|
+
verify: "Run redirect-trace and confirm one stable hop to the intended indexable page."
|
|
40974
|
+
};
|
|
40975
|
+
if (input.code === "linked-canonical-conflict") return {
|
|
40976
|
+
...common,
|
|
40977
|
+
code: input.code,
|
|
40978
|
+
principle: "Canonical hints should agree with the intended linked page.",
|
|
40979
|
+
evidence: `The saved crawl observed canonical ${crawl.canonical} on a linked target that resolved to ${crawl.finalUrl}.${searchEvidence}`,
|
|
40980
|
+
action: "Confirm the preferred URL. Align the canonical and redirect only if the current disagreement is unintended.",
|
|
40981
|
+
verify: "Audit the final page and inspect the declared and Google-selected canonical before changing it."
|
|
40982
|
+
};
|
|
40983
|
+
return {
|
|
40984
|
+
...common,
|
|
40985
|
+
code: input.code,
|
|
40986
|
+
principle: "A linked page should be indexable when search visibility is intended.",
|
|
40987
|
+
evidence: `The saved crawl marked a linked target as non-indexable.${searchEvidence}`,
|
|
40988
|
+
action: "Confirm whether non-indexing is intentional. Remove the blocking signal or redirect to an equivalent indexable page only when this URL should appear in search.",
|
|
40989
|
+
verify: "Audit the page, then use URL Inspection when the intended state is indexable."
|
|
40990
|
+
};
|
|
40991
|
+
}
|
|
40992
|
+
function linkTargetFindings(rows) {
|
|
40993
|
+
return rows.flatMap((row) => {
|
|
40994
|
+
const crawl = row.crawl;
|
|
40995
|
+
if (crawl.state !== "observed") return [];
|
|
40996
|
+
if (crawl.status >= 400) return [finding({
|
|
40997
|
+
row,
|
|
40998
|
+
code: "linked-broken-target"
|
|
40999
|
+
})];
|
|
41000
|
+
if (urlKey(crawl.finalUrl) !== urlKey(row.targetUrl)) return [finding({
|
|
41001
|
+
row,
|
|
41002
|
+
code: "linked-redirect-target"
|
|
41003
|
+
})];
|
|
41004
|
+
if (crawl.canonical && urlKey(crawl.canonical) !== urlKey(crawl.finalUrl)) return [finding({
|
|
41005
|
+
row,
|
|
41006
|
+
code: "linked-canonical-conflict"
|
|
41007
|
+
})];
|
|
41008
|
+
if (!crawl.indexable) return [finding({
|
|
41009
|
+
row,
|
|
41010
|
+
code: "linked-non-indexable-target"
|
|
41011
|
+
})];
|
|
41012
|
+
return [];
|
|
41013
|
+
}).sort((left, right) => ({
|
|
41014
|
+
high: 0,
|
|
41015
|
+
medium: 1,
|
|
41016
|
+
low: 2
|
|
41017
|
+
})[left.priority] - {
|
|
41018
|
+
high: 0,
|
|
41019
|
+
medium: 1,
|
|
41020
|
+
low: 2
|
|
41021
|
+
}[right.priority] || right.observedLinks - left.observedLinks || (left.targetUrl < right.targetUrl ? -1 : left.targetUrl > right.targetUrl ? 1 : 0)).slice(0, MAX_FINDINGS$1);
|
|
41022
|
+
}
|
|
41023
|
+
//#endregion
|
|
41024
|
+
//#region packages/core/src/links/context.ts
|
|
41025
|
+
const DEFAULT_DAYS = 90;
|
|
41026
|
+
const MAX_DAYS = 548;
|
|
41027
|
+
const DEFAULT_CONTEXT_LIMIT = 100;
|
|
41028
|
+
const MAX_CONTEXT_LIMIT = 100;
|
|
41029
|
+
const MAX_GSC_ROWS = 25e3;
|
|
41030
|
+
const defaultDependencies = {
|
|
41031
|
+
latestCrawl: latestCrawlReport,
|
|
41032
|
+
searchAnalytics: querySearchAnalytics,
|
|
41033
|
+
now: () => /* @__PURE__ */ new Date()
|
|
41034
|
+
};
|
|
41035
|
+
function integer(input) {
|
|
41036
|
+
const value = input.value ?? input.fallback;
|
|
41037
|
+
if (!Number.isSafeInteger(value) || value < 1 || value > input.maximum) throw new SeoError("INVALID_INPUT", `${input.label} must be between 1 and ${input.maximum}.`);
|
|
41038
|
+
return value;
|
|
41039
|
+
}
|
|
41040
|
+
function searchEvidence(input) {
|
|
41041
|
+
if (!input.site) return {
|
|
41042
|
+
state: "unavailable",
|
|
41043
|
+
reason: "No Search Console property was selected for this report."
|
|
41044
|
+
};
|
|
41045
|
+
if (input.error) return {
|
|
41046
|
+
state: "unavailable",
|
|
41047
|
+
reason: input.error
|
|
41048
|
+
};
|
|
41049
|
+
if (!input.aggregate) return {
|
|
41050
|
+
state: "not-retained",
|
|
41051
|
+
reason: input.retainedLimitReached ? `The bounded Search Console response reached ${MAX_GSC_ROWS} rows and did not retain this page.` : "Search Console did not retain a page row for this URL in the selected window."
|
|
41052
|
+
};
|
|
41053
|
+
return {
|
|
41054
|
+
state: "observed",
|
|
41055
|
+
clicks: input.aggregate.clicks,
|
|
41056
|
+
impressions: input.aggregate.impressions,
|
|
41057
|
+
ctr: input.aggregate.impressions > 0 ? input.aggregate.clicks / input.aggregate.impressions : 0,
|
|
41058
|
+
position: input.aggregate.impressions > 0 ? input.aggregate.positionWeight / input.aggregate.impressions : 0
|
|
41059
|
+
};
|
|
41060
|
+
}
|
|
41061
|
+
async function linkTargetContext(input, dependencies = defaultDependencies) {
|
|
41062
|
+
const days = integer({
|
|
41063
|
+
value: input.days,
|
|
41064
|
+
fallback: DEFAULT_DAYS,
|
|
41065
|
+
maximum: MAX_DAYS,
|
|
41066
|
+
label: "Link context days"
|
|
41067
|
+
});
|
|
41068
|
+
const limit = integer({
|
|
41069
|
+
value: input.limit,
|
|
41070
|
+
fallback: DEFAULT_CONTEXT_LIMIT,
|
|
41071
|
+
maximum: MAX_CONTEXT_LIMIT,
|
|
41072
|
+
label: "Link context limit"
|
|
41073
|
+
});
|
|
41074
|
+
const available = linkTargetCounts(input.evidence);
|
|
41075
|
+
const selected = available.slice(0, limit);
|
|
41076
|
+
const crawlLookup = input.crawlSite ?? input.searchConsoleSite;
|
|
41077
|
+
const crawl = crawlLookup ? dependencies.latestCrawl(crawlLookup) : void 0;
|
|
41078
|
+
const crawlValues = crawlForLinkTargets({
|
|
41079
|
+
report: crawl,
|
|
41080
|
+
targets: selected
|
|
41081
|
+
});
|
|
41082
|
+
const warnings = [];
|
|
41083
|
+
const range = finalGscDateRange(days, dependencies.now());
|
|
41084
|
+
let searchRows = /* @__PURE__ */ new Map();
|
|
41085
|
+
let searchCalls = 0;
|
|
41086
|
+
let searchRowsFetched = 0;
|
|
41087
|
+
let searchError = null;
|
|
41088
|
+
if (input.searchConsoleSite) try {
|
|
41089
|
+
const result = await dependencies.searchAnalytics(input.searchConsoleSite, {
|
|
41090
|
+
...range,
|
|
41091
|
+
dimensions: ["page"],
|
|
41092
|
+
type: "web",
|
|
41093
|
+
dataState: "final",
|
|
41094
|
+
rowLimit: MAX_GSC_ROWS,
|
|
41095
|
+
maxRows: MAX_GSC_ROWS
|
|
41096
|
+
}, { refresh: input.refresh });
|
|
41097
|
+
searchRows = aggregateLinkSearchRows(result.rows);
|
|
41098
|
+
searchCalls = result.calls;
|
|
41099
|
+
searchRowsFetched = result.rowsFetched;
|
|
41100
|
+
} catch (error) {
|
|
41101
|
+
searchError = error instanceof Error ? error.message : "Search Console evidence could not be loaded.";
|
|
41102
|
+
warnings.push(`Search Console context was unavailable. ${searchError}`);
|
|
41103
|
+
}
|
|
41104
|
+
let searchMatches = 0;
|
|
41105
|
+
const retainedLimitReached = searchRowsFetched >= MAX_GSC_ROWS;
|
|
41106
|
+
const rows = selected.map((target) => {
|
|
41107
|
+
const aggregate = searchRows.get(urlKey(target.targetUrl) ?? "");
|
|
41108
|
+
if (aggregate) searchMatches += 1;
|
|
41109
|
+
return {
|
|
41110
|
+
...target,
|
|
41111
|
+
crawl: crawlValues.values.get(target.targetUrl) ?? {
|
|
41112
|
+
state: "not-observed",
|
|
41113
|
+
reason: "The target URL was not present in the retained crawl pages."
|
|
41114
|
+
},
|
|
41115
|
+
searchConsole: searchEvidence({
|
|
41116
|
+
site: input.searchConsoleSite,
|
|
41117
|
+
error: searchError,
|
|
41118
|
+
retainedLimitReached,
|
|
41119
|
+
aggregate
|
|
41120
|
+
})
|
|
41121
|
+
};
|
|
41122
|
+
});
|
|
41123
|
+
if (!crawl) warnings.push("No matching saved crawl was available, so target response and indexability checks were skipped.");
|
|
41124
|
+
if (retainedLimitReached) warnings.push(`Search Console reached the ${MAX_GSC_ROWS}-row acquisition limit. Missing target rows remain not retained rather than zero.`);
|
|
41125
|
+
const unavailableSources = Number(!crawl) + Number(!input.searchConsoleSite);
|
|
41126
|
+
return {
|
|
41127
|
+
schemaVersion: 1,
|
|
41128
|
+
dataStatus: unavailableSources === 2 ? "unavailable" : unavailableSources > 0 || searchError || retainedLimitReached ? "partial" : "complete",
|
|
41129
|
+
selection: {
|
|
41130
|
+
availableTargets: available.length,
|
|
41131
|
+
returnedTargets: rows.length,
|
|
41132
|
+
omittedTargets: Math.max(0, available.length - rows.length),
|
|
41133
|
+
limit
|
|
41134
|
+
},
|
|
41135
|
+
provenance: {
|
|
41136
|
+
crawl: {
|
|
41137
|
+
status: crawl ? "joined" : "unavailable",
|
|
41138
|
+
reportId: crawl?.id ?? null,
|
|
41139
|
+
observedAt: crawl?.generatedAt ?? null,
|
|
41140
|
+
availablePages: crawl?.pages.length ?? 0,
|
|
41141
|
+
matchedTargets: crawlValues.matched
|
|
41142
|
+
},
|
|
41143
|
+
searchConsole: {
|
|
41144
|
+
status: !input.searchConsoleSite || searchError ? "unavailable" : retainedLimitReached ? "partial" : "joined",
|
|
41145
|
+
site: input.searchConsoleSite ?? null,
|
|
41146
|
+
range: input.searchConsoleSite ? {
|
|
41147
|
+
...range,
|
|
41148
|
+
days
|
|
41149
|
+
} : null,
|
|
41150
|
+
calls: searchCalls,
|
|
41151
|
+
rowsFetched: searchRowsFetched,
|
|
41152
|
+
retainedRowLimit: MAX_GSC_ROWS,
|
|
41153
|
+
retainedRowLimitReached: retainedLimitReached,
|
|
41154
|
+
matchedTargets: searchMatches
|
|
41155
|
+
}
|
|
41156
|
+
},
|
|
41157
|
+
rows,
|
|
41158
|
+
findings: linkTargetFindings(rows),
|
|
41159
|
+
warnings
|
|
41160
|
+
};
|
|
41161
|
+
}
|
|
41162
|
+
//#endregion
|
|
41163
|
+
//#region packages/core/src/providers/dataforseo/link-research-shared.ts
|
|
41164
|
+
function linkTarget(value, requestedScope = "domain") {
|
|
41165
|
+
const raw = value.trim();
|
|
41166
|
+
if (!raw || raw.length > 2048) throw invalidTarget();
|
|
41167
|
+
if (requestedScope === "page") try {
|
|
41168
|
+
const url = new URL(raw);
|
|
41169
|
+
if (!["http:", "https:"].includes(url.protocol) || url.username || url.password) throw new Error();
|
|
41170
|
+
url.hash = "";
|
|
41171
|
+
return {
|
|
41172
|
+
target: url.toString(),
|
|
41173
|
+
scope: "page"
|
|
41174
|
+
};
|
|
41175
|
+
} catch {
|
|
41176
|
+
throw invalidTarget();
|
|
41177
|
+
}
|
|
41178
|
+
try {
|
|
41179
|
+
const hostname = new URL(raw.includes("://") ? raw : `https://${raw}`).hostname.toLowerCase().replace(/^www\./u, "").replace(/\.$/u, "");
|
|
41180
|
+
if (!hostname || hostname.length > 253 || hostname.includes("..") || !hostname.includes(".") || !/^[a-z0-9.-]+$/u.test(hostname)) throw new Error();
|
|
41181
|
+
return {
|
|
41182
|
+
target: hostname,
|
|
41183
|
+
scope: "domain"
|
|
41184
|
+
};
|
|
41185
|
+
} catch {
|
|
41186
|
+
throw invalidTarget();
|
|
41187
|
+
}
|
|
41188
|
+
}
|
|
41189
|
+
function invalidTarget() {
|
|
41190
|
+
return new ProviderError({
|
|
41191
|
+
provider: "dataforseo",
|
|
41192
|
+
operation: "link-evidence",
|
|
41193
|
+
code: "configuration",
|
|
41194
|
+
message: "Use a valid domain, or choose page scope and pass an absolute URL."
|
|
41195
|
+
});
|
|
41196
|
+
}
|
|
41197
|
+
function linkRowLimit(limit, offset = 0) {
|
|
41198
|
+
if (!Number.isSafeInteger(limit) || limit < 1 || limit > 1e3) throw new ProviderError({
|
|
41199
|
+
provider: "dataforseo",
|
|
41200
|
+
operation: "link-evidence",
|
|
41201
|
+
code: "configuration",
|
|
41202
|
+
message: `Link row limit must be from 1 to ${MAX_LINK_ROWS$1}.`
|
|
41203
|
+
});
|
|
41204
|
+
if (!Number.isSafeInteger(offset) || offset < 0 || offset > 2e4) throw new ProviderError({
|
|
41205
|
+
provider: "dataforseo",
|
|
41206
|
+
operation: "link-evidence",
|
|
41207
|
+
code: "configuration",
|
|
41208
|
+
message: `Link row offset must be from 0 to ${MAX_LINK_OFFSET}.`
|
|
41209
|
+
});
|
|
41210
|
+
}
|
|
41211
|
+
function requestContext(reportId, supplied) {
|
|
41212
|
+
return supplied ?? {
|
|
41213
|
+
reportId,
|
|
41214
|
+
reportRunId: randomUUID()
|
|
41215
|
+
};
|
|
41216
|
+
}
|
|
41217
|
+
function missing(field) {
|
|
41218
|
+
return unavailableValue("missing", `DataForSEO omitted ${field}.`);
|
|
41219
|
+
}
|
|
41220
|
+
function numberValue(value, field) {
|
|
41221
|
+
return value === null || value === void 0 ? missing(field) : observedValue(value);
|
|
41222
|
+
}
|
|
41223
|
+
function stringValue(value, field) {
|
|
41224
|
+
return value ? observedValue(value) : missing(field);
|
|
41225
|
+
}
|
|
41226
|
+
function metric(id, label, value) {
|
|
41227
|
+
return value === null || value === void 0 ? [] : [{
|
|
41228
|
+
provider: "dataforseo",
|
|
41229
|
+
id,
|
|
41230
|
+
label,
|
|
41231
|
+
value,
|
|
41232
|
+
scale: {
|
|
41233
|
+
minimum: 0,
|
|
41234
|
+
maximum: 100
|
|
41235
|
+
}
|
|
41236
|
+
}];
|
|
41237
|
+
}
|
|
41238
|
+
function safeUrl(value) {
|
|
41239
|
+
if (!value) return null;
|
|
41240
|
+
try {
|
|
41241
|
+
const url = new URL(value);
|
|
41242
|
+
if (!["http:", "https:"].includes(url.protocol)) return null;
|
|
41243
|
+
url.username = "";
|
|
41244
|
+
url.password = "";
|
|
41245
|
+
url.hash = "";
|
|
41246
|
+
return url.toString();
|
|
41247
|
+
} catch {
|
|
41248
|
+
return null;
|
|
41249
|
+
}
|
|
41250
|
+
}
|
|
41251
|
+
function normalizedDate(value) {
|
|
41252
|
+
if (!value) return null;
|
|
41253
|
+
const parsed = Date.parse(value);
|
|
41254
|
+
return Number.isFinite(parsed) ? new Date(parsed).toISOString() : null;
|
|
41255
|
+
}
|
|
41256
|
+
function uniqueSorted(values = []) {
|
|
41257
|
+
return [...new Set(values.map((value) => value.trim()).filter(Boolean))].sort(compareCodepoints$3);
|
|
41258
|
+
}
|
|
41259
|
+
function totalRows(values) {
|
|
41260
|
+
const present = values.filter((value) => value !== null && value !== void 0);
|
|
41261
|
+
return present.length ? Math.max(...present) : null;
|
|
41262
|
+
}
|
|
41263
|
+
function linkCoverage(input) {
|
|
41264
|
+
const hasMore = input.providerTotalComparable !== false && input.providerTotalRows !== null ? input.offset + input.returnedRows < input.providerTotalRows : input.returnedRows >= input.requestedRows;
|
|
41265
|
+
return {
|
|
41266
|
+
requestedRows: input.requestedRows,
|
|
41267
|
+
returnedRows: input.returnedRows,
|
|
41268
|
+
retainedRows: input.retainedRows,
|
|
41269
|
+
invalidRows: input.invalidRows,
|
|
41270
|
+
providerTotalRows: input.providerTotalRows,
|
|
41271
|
+
completeness: input.invalidRows > 0 ? "partial" : hasMore ? "capped" : input.filtered ? "filtered" : "complete",
|
|
41272
|
+
nextCursor: hasMore ? String(input.offset + input.returnedRows) : null
|
|
41273
|
+
};
|
|
41274
|
+
}
|
|
41275
|
+
function linkEvidence(input) {
|
|
41276
|
+
return {
|
|
41277
|
+
schemaVersion: 1,
|
|
41278
|
+
provider: "dataforseo",
|
|
41279
|
+
capability: input.capability,
|
|
41280
|
+
data: input.data,
|
|
41281
|
+
observedAt: input.snapshot.observedAt,
|
|
41282
|
+
market: null,
|
|
41283
|
+
coverage: input.coverage,
|
|
41284
|
+
cache: input.snapshot.cache,
|
|
41285
|
+
cost: input.snapshot.cost,
|
|
41286
|
+
request: {
|
|
41287
|
+
operation: input.capability,
|
|
41288
|
+
endpoint: input.endpoint,
|
|
41289
|
+
limit: input.limit,
|
|
41290
|
+
filters: input.filters,
|
|
41291
|
+
sort: input.sort
|
|
41292
|
+
},
|
|
41293
|
+
warnings: input.warnings
|
|
41294
|
+
};
|
|
41295
|
+
}
|
|
41296
|
+
function mappingWarnings(input) {
|
|
41297
|
+
return [
|
|
41298
|
+
...input.snapshotWarnings,
|
|
41299
|
+
...input.invalidRows ? [{
|
|
41300
|
+
code: `invalid-${input.label}-rows`,
|
|
41301
|
+
field: "data.rows",
|
|
41302
|
+
message: `${input.invalidRows} ${input.label} row${input.invalidRows === 1 ? "" : "s"} lacked required fields and were omitted.`
|
|
41303
|
+
}] : [],
|
|
41304
|
+
...input.duplicateRows ? [{
|
|
41305
|
+
code: `duplicate-${input.label}-rows`,
|
|
41306
|
+
field: "data.rows",
|
|
41307
|
+
message: `${input.duplicateRows} duplicate ${input.label} row${input.duplicateRows === 1 ? "" : "s"} were collapsed deterministically.`
|
|
41308
|
+
}] : []
|
|
41309
|
+
];
|
|
41310
|
+
}
|
|
41311
|
+
//#endregion
|
|
41312
|
+
//#region packages/core/src/providers/dataforseo/backlinks.ts
|
|
41313
|
+
function metricValue(row, id) {
|
|
41314
|
+
return row.metrics.find((item) => item.id === id)?.value ?? -1;
|
|
41315
|
+
}
|
|
41316
|
+
function compareRows(left, right) {
|
|
41317
|
+
return metricValue(right, "backlink-rank") - metricValue(left, "backlink-rank") || metricValue(right, "source-domain-rank") - metricValue(left, "source-domain-rank") || compareCodepoints$3(left.sourceDomain, right.sourceDomain) || compareCodepoints$3(left.sourceUrl, right.sourceUrl) || compareCodepoints$3(left.targetUrl, right.targetUrl) || compareCodepoints$3(left.anchorText ?? "", right.anchorText ?? "");
|
|
41318
|
+
}
|
|
41319
|
+
function dedupe(rows) {
|
|
41320
|
+
const sorted = [...rows].sort(compareRows);
|
|
41321
|
+
const seen = /* @__PURE__ */ new Set();
|
|
41322
|
+
return sorted.filter((row) => {
|
|
41323
|
+
const key = `${row.sourceUrl}\0${row.targetUrl}\0${row.anchorText ?? ""}`;
|
|
41324
|
+
if (seen.has(key)) return false;
|
|
41325
|
+
seen.add(key);
|
|
41326
|
+
return true;
|
|
41327
|
+
});
|
|
41328
|
+
}
|
|
41329
|
+
async function dataForSeoBacklinks(client, input) {
|
|
41330
|
+
const normalized = linkTarget(input.target, input.scope);
|
|
41331
|
+
const includeSubdomains = normalized.scope === "domain" ? input.includeSubdomains ?? true : false;
|
|
41332
|
+
const offset = input.offset ?? 0;
|
|
41333
|
+
linkRowLimit(input.limit, offset);
|
|
41334
|
+
const mode = input.mode ?? "representative";
|
|
41335
|
+
const status = input.status ?? "live";
|
|
41336
|
+
const providerMode = mode === "representative" ? "one_per_domain" : "as_is";
|
|
41337
|
+
const orderBy = [
|
|
41338
|
+
"rank,desc",
|
|
41339
|
+
"domain_from_rank,desc",
|
|
41340
|
+
"url_from,asc"
|
|
41341
|
+
];
|
|
41342
|
+
const snapshot = await client.backlinks({
|
|
41343
|
+
...normalized,
|
|
41344
|
+
includeSubdomains,
|
|
41345
|
+
mode: providerMode,
|
|
41346
|
+
status,
|
|
41347
|
+
limit: input.limit,
|
|
41348
|
+
offset,
|
|
41349
|
+
orderBy,
|
|
41350
|
+
refresh: input.refresh,
|
|
41351
|
+
context: requestContext("link-evidence", input.context)
|
|
41352
|
+
});
|
|
41353
|
+
const results = snapshot.response.tasks.flatMap((task) => task.result ?? []);
|
|
41354
|
+
const rawRows = results.flatMap((result) => result.items ?? []);
|
|
41355
|
+
let invalidRows = 0;
|
|
41356
|
+
const mapped = rawRows.flatMap((row) => {
|
|
41357
|
+
const sourceUrl = safeUrl(row.url_from);
|
|
41358
|
+
const targetUrl = safeUrl(row.url_to);
|
|
41359
|
+
if (!sourceUrl || !targetUrl) {
|
|
41360
|
+
invalidRows += 1;
|
|
41361
|
+
return [];
|
|
41362
|
+
}
|
|
41363
|
+
return [{
|
|
41364
|
+
sourceUrl,
|
|
41365
|
+
sourceDomain: new URL(sourceUrl).hostname.toLowerCase(),
|
|
41366
|
+
targetUrl,
|
|
41367
|
+
anchorText: row.anchor ?? null,
|
|
41368
|
+
linkType: row.item_type ?? null,
|
|
41369
|
+
dofollow: row.dofollow ?? null,
|
|
41370
|
+
attributes: uniqueSorted(row.rel_attributes ?? row.attributes ?? []),
|
|
41371
|
+
firstSeenAt: normalizedDate(row.first_seen),
|
|
41372
|
+
lastSeenAt: normalizedDate(row.lost_date ?? row.last_visited),
|
|
41373
|
+
state: row.is_lost || row.lost_date ? "lost" : "live",
|
|
41374
|
+
indirect: row.is_indirect_link ?? null,
|
|
41375
|
+
linksFromPage: row.links_count ?? null,
|
|
41376
|
+
linksFromDomain: row.group_count ?? null,
|
|
41377
|
+
metrics: [
|
|
41378
|
+
...metric("backlink-rank", "DataForSEO backlink rank", row.rank),
|
|
41379
|
+
...metric("source-domain-rank", "DataForSEO source domain rank", row.domain_from_rank),
|
|
41380
|
+
...metric("source-page-rank", "DataForSEO source page rank", row.page_from_rank),
|
|
41381
|
+
...metric("backlink-spam-score", "DataForSEO backlink spam score", row.backlink_spam_score ?? row.backlinks_spam_score)
|
|
41382
|
+
]
|
|
41383
|
+
}];
|
|
41384
|
+
});
|
|
41385
|
+
const rows = dedupe(mapped);
|
|
41386
|
+
const duplicateRows = mapped.length - rows.length;
|
|
41387
|
+
const providerTotalRows = totalRows(results.map((result) => result.total_count));
|
|
41388
|
+
return linkEvidence({
|
|
41389
|
+
capability: "backlinks",
|
|
41390
|
+
data: {
|
|
41391
|
+
target: normalized.target,
|
|
41392
|
+
mode,
|
|
41393
|
+
rows,
|
|
41394
|
+
totalRows: providerTotalRows
|
|
41395
|
+
},
|
|
41396
|
+
snapshot,
|
|
41397
|
+
coverage: linkCoverage({
|
|
41398
|
+
requestedRows: input.limit,
|
|
41399
|
+
returnedRows: rawRows.length,
|
|
41400
|
+
retainedRows: rows.length,
|
|
41401
|
+
invalidRows,
|
|
41402
|
+
providerTotalRows,
|
|
41403
|
+
offset,
|
|
41404
|
+
filtered: mode === "representative" || status !== "all",
|
|
41405
|
+
providerTotalComparable: mode !== "representative"
|
|
41406
|
+
}),
|
|
41407
|
+
endpoint: LINK_ENDPOINTS.backlinks,
|
|
41408
|
+
limit: input.limit,
|
|
41409
|
+
filters: {
|
|
41410
|
+
scope: normalized.scope,
|
|
41411
|
+
includeSubdomains,
|
|
41412
|
+
mode,
|
|
41413
|
+
status,
|
|
41414
|
+
includeIndirectLinks: true,
|
|
41415
|
+
excludeInternalBacklinks: true,
|
|
41416
|
+
offset
|
|
41417
|
+
},
|
|
41418
|
+
sort: orderBy,
|
|
41419
|
+
warnings: mappingWarnings({
|
|
41420
|
+
snapshotWarnings: snapshot.warnings,
|
|
41421
|
+
invalidRows,
|
|
41422
|
+
duplicateRows,
|
|
41423
|
+
label: "backlink"
|
|
41424
|
+
})
|
|
41425
|
+
});
|
|
41426
|
+
}
|
|
41427
|
+
//#endregion
|
|
41428
|
+
//#region packages/core/src/providers/dataforseo/link-summary.ts
|
|
41429
|
+
async function dataForSeoLinkSummary(client, input) {
|
|
41430
|
+
const normalized = linkTarget(input.target, input.scope);
|
|
41431
|
+
const includeSubdomains = normalized.scope === "domain" ? input.includeSubdomains ?? true : false;
|
|
41432
|
+
const snapshot = await client.linkSummary({
|
|
41433
|
+
...normalized,
|
|
41434
|
+
includeSubdomains,
|
|
41435
|
+
refresh: input.refresh,
|
|
41436
|
+
context: requestContext("link-evidence", input.context)
|
|
41437
|
+
});
|
|
41438
|
+
const rows = snapshot.response.tasks.flatMap((task) => task.result ?? []);
|
|
41439
|
+
const row = [...rows].sort((left, right) => compareCodepoints$3(left.target ?? "", right.target ?? ""))[0];
|
|
41440
|
+
const data = {
|
|
41441
|
+
target: normalized.target,
|
|
41442
|
+
scope: normalized.scope,
|
|
41443
|
+
backlinks: numberValue(row?.backlinks, "total backlinks"),
|
|
41444
|
+
referringDomains: numberValue(row?.referring_domains, "referring domains"),
|
|
41445
|
+
referringPages: numberValue(row?.referring_pages, "referring pages"),
|
|
41446
|
+
brokenBacklinks: numberValue(row?.broken_backlinks, "broken backlinks"),
|
|
41447
|
+
brokenPages: numberValue(row?.broken_pages, "broken referring pages"),
|
|
41448
|
+
metrics: [
|
|
41449
|
+
...metric("rank", "DataForSEO rank", row?.rank),
|
|
41450
|
+
...metric("backlinks-spam-score", "DataForSEO backlink spam score", row?.backlinks_spam_score),
|
|
41451
|
+
...metric("target-spam-score", "DataForSEO target spam score", row?.info?.target_spam_score)
|
|
41452
|
+
]
|
|
41453
|
+
};
|
|
41454
|
+
const retainedRows = row ? 1 : 0;
|
|
41455
|
+
return linkEvidence({
|
|
41456
|
+
capability: "link-summary",
|
|
41457
|
+
data,
|
|
41458
|
+
snapshot,
|
|
41459
|
+
coverage: {
|
|
41460
|
+
requestedRows: 1,
|
|
41461
|
+
returnedRows: rows.length,
|
|
41462
|
+
retainedRows,
|
|
41463
|
+
invalidRows: 0,
|
|
41464
|
+
providerTotalRows: rows.length,
|
|
41465
|
+
completeness: row ? "complete" : "unavailable",
|
|
41466
|
+
nextCursor: null
|
|
41467
|
+
},
|
|
41468
|
+
endpoint: LINK_ENDPOINTS.summary,
|
|
41469
|
+
limit: 1,
|
|
41470
|
+
filters: {
|
|
41471
|
+
scope: normalized.scope,
|
|
41472
|
+
includeSubdomains,
|
|
41473
|
+
status: "live",
|
|
41474
|
+
includeIndirectLinks: true,
|
|
41475
|
+
excludeInternalBacklinks: true
|
|
41476
|
+
},
|
|
41477
|
+
sort: [],
|
|
41478
|
+
warnings: [
|
|
41479
|
+
...snapshot.warnings,
|
|
41480
|
+
...rows.length > 1 ? [{
|
|
41481
|
+
code: "multiple-link-summary-rows",
|
|
41482
|
+
field: "data",
|
|
41483
|
+
message: "DataForSEO returned more than one summary row. One row was retained deterministically."
|
|
41484
|
+
}] : [],
|
|
41485
|
+
...!row ? [{
|
|
41486
|
+
code: "missing-link-summary-row",
|
|
41487
|
+
field: "data",
|
|
41488
|
+
message: "DataForSEO returned no summary row. Counts remain unavailable rather than zero."
|
|
41489
|
+
}] : []
|
|
41490
|
+
]
|
|
41491
|
+
});
|
|
41492
|
+
}
|
|
41493
|
+
//#endregion
|
|
41494
|
+
//#region packages/core/src/providers/dataforseo/referring-domains.ts
|
|
41495
|
+
function observedNumber(row) {
|
|
41496
|
+
return row.backlinks.state === "observed" ? row.backlinks.value : -1;
|
|
41497
|
+
}
|
|
41498
|
+
async function dataForSeoReferringDomains(client, input) {
|
|
41499
|
+
const normalized = linkTarget(input.target, input.scope);
|
|
41500
|
+
const includeSubdomains = normalized.scope === "domain" ? input.includeSubdomains ?? true : false;
|
|
41501
|
+
const offset = input.offset ?? 0;
|
|
41502
|
+
linkRowLimit(input.limit, offset);
|
|
41503
|
+
const orderBy = [
|
|
41504
|
+
"backlinks,desc",
|
|
41505
|
+
"rank,desc",
|
|
41506
|
+
"domain,asc"
|
|
41507
|
+
];
|
|
41508
|
+
const snapshot = await client.referringDomains({
|
|
41509
|
+
...normalized,
|
|
41510
|
+
includeSubdomains,
|
|
41511
|
+
limit: input.limit,
|
|
41512
|
+
offset,
|
|
41513
|
+
orderBy,
|
|
41514
|
+
refresh: input.refresh,
|
|
41515
|
+
context: requestContext("link-evidence", input.context)
|
|
41516
|
+
});
|
|
41517
|
+
const results = snapshot.response.tasks.flatMap((task) => task.result ?? []);
|
|
41518
|
+
const rawRows = results.flatMap((result) => result.items ?? []);
|
|
41519
|
+
let invalidRows = 0;
|
|
41520
|
+
const mapped = rawRows.flatMap((row) => {
|
|
41521
|
+
const domain = row.domain?.trim().toLowerCase();
|
|
41522
|
+
if (!domain) {
|
|
41523
|
+
invalidRows += 1;
|
|
41524
|
+
return [];
|
|
41525
|
+
}
|
|
41526
|
+
const firstSeenAt = normalizedDate(row.first_seen);
|
|
41527
|
+
return [{
|
|
41528
|
+
domain,
|
|
41529
|
+
backlinks: numberValue(row.backlinks, "domain backlinks"),
|
|
41530
|
+
referringPages: numberValue(row.referring_pages, "domain referring pages"),
|
|
41531
|
+
brokenBacklinks: numberValue(row.broken_backlinks, "domain broken backlinks"),
|
|
41532
|
+
brokenPages: numberValue(row.broken_pages, "domain broken pages"),
|
|
41533
|
+
firstSeenAt: stringValue(firstSeenAt, "domain first seen date"),
|
|
41534
|
+
metrics: [...metric("source-domain-rank", "DataForSEO source domain rank", row.rank), ...metric("domain-backlinks-spam-score", "DataForSEO domain backlink spam score", row.backlinks_spam_score)]
|
|
41535
|
+
}];
|
|
41536
|
+
});
|
|
41537
|
+
const byDomain = /* @__PURE__ */ new Map();
|
|
41538
|
+
for (const row of mapped.sort((left, right) => observedNumber(right) - observedNumber(left) || compareCodepoints$3(left.domain, right.domain))) if (!byDomain.has(row.domain)) byDomain.set(row.domain, row);
|
|
41539
|
+
const rows = [...byDomain.values()];
|
|
41540
|
+
const duplicateRows = mapped.length - rows.length;
|
|
41541
|
+
const providerTotalRows = totalRows(results.map((result) => result.total_count));
|
|
41542
|
+
return linkEvidence({
|
|
41543
|
+
capability: "referring-domains",
|
|
41544
|
+
data: {
|
|
41545
|
+
target: normalized.target,
|
|
41546
|
+
rows,
|
|
41547
|
+
totalRows: providerTotalRows
|
|
41548
|
+
},
|
|
41549
|
+
snapshot,
|
|
41550
|
+
coverage: linkCoverage({
|
|
41551
|
+
requestedRows: input.limit,
|
|
41552
|
+
returnedRows: rawRows.length,
|
|
41553
|
+
retainedRows: rows.length,
|
|
41554
|
+
invalidRows,
|
|
41555
|
+
providerTotalRows,
|
|
41556
|
+
offset,
|
|
41557
|
+
filtered: true
|
|
41558
|
+
}),
|
|
41559
|
+
endpoint: LINK_ENDPOINTS.referringDomains,
|
|
41560
|
+
limit: input.limit,
|
|
41561
|
+
filters: {
|
|
41562
|
+
scope: normalized.scope,
|
|
41563
|
+
includeSubdomains,
|
|
41564
|
+
status: "live",
|
|
41565
|
+
includeIndirectLinks: true,
|
|
41566
|
+
excludeInternalBacklinks: true,
|
|
41567
|
+
offset
|
|
41568
|
+
},
|
|
41569
|
+
sort: orderBy,
|
|
41570
|
+
warnings: mappingWarnings({
|
|
41571
|
+
snapshotWarnings: snapshot.warnings,
|
|
41572
|
+
invalidRows,
|
|
41573
|
+
duplicateRows,
|
|
41574
|
+
label: "referring-domain"
|
|
41575
|
+
})
|
|
41576
|
+
});
|
|
41577
|
+
}
|
|
41578
|
+
//#endregion
|
|
41579
|
+
//#region packages/core/src/providers/dataforseo/link-research.ts
|
|
41580
|
+
var DataForSeoLinkProvider = class {
|
|
41581
|
+
provider = "dataforseo";
|
|
41582
|
+
capabilitySupport = [
|
|
41583
|
+
"link-summary",
|
|
41584
|
+
"referring-domains",
|
|
41585
|
+
"backlinks"
|
|
41586
|
+
].map((capability) => ({
|
|
41587
|
+
capability,
|
|
41588
|
+
status: "available",
|
|
41589
|
+
markets: "all"
|
|
41590
|
+
}));
|
|
41591
|
+
client;
|
|
41592
|
+
constructor(options = {}) {
|
|
41593
|
+
this.client = options.client ?? new DataForSeoClient(options);
|
|
41594
|
+
}
|
|
41595
|
+
linkSummary(input) {
|
|
41596
|
+
return dataForSeoLinkSummary(this.client, input);
|
|
41597
|
+
}
|
|
41598
|
+
backlinks(input) {
|
|
41599
|
+
return dataForSeoBacklinks(this.client, input);
|
|
41600
|
+
}
|
|
41601
|
+
referringDomains(input) {
|
|
41602
|
+
return dataForSeoReferringDomains(this.client, input);
|
|
41603
|
+
}
|
|
41604
|
+
};
|
|
41605
|
+
//#endregion
|
|
41606
|
+
//#region packages/core/src/links/dataforseo.ts
|
|
41607
|
+
const DEFAULT_ROW_LIMIT$2 = 100;
|
|
41608
|
+
const MAX_ROW_LIMIT$2 = 500;
|
|
41609
|
+
function rowLimit(value) {
|
|
41610
|
+
const limit = value ?? DEFAULT_ROW_LIMIT$2;
|
|
41611
|
+
if (!Number.isSafeInteger(limit) || limit < 1 || limit > MAX_ROW_LIMIT$2) throw new SeoError("INVALID_INPUT", `DataForSEO link row limit must be between 1 and ${MAX_ROW_LIMIT$2}.`);
|
|
41612
|
+
return limit;
|
|
41613
|
+
}
|
|
41614
|
+
async function collectDataForSeoLinkEvidence(input) {
|
|
41615
|
+
const limit = rowLimit(input.rowLimit);
|
|
41616
|
+
const provider = input.provider ?? new DataForSeoLinkProvider();
|
|
41617
|
+
const context = input.context ?? {
|
|
41618
|
+
reportId: "link-evidence",
|
|
41619
|
+
reportRunId: randomUUID()
|
|
41620
|
+
};
|
|
41621
|
+
const summary = await provider.linkSummary({
|
|
41622
|
+
target: input.target,
|
|
41623
|
+
scope: input.scope,
|
|
41624
|
+
includeSubdomains: input.includeSubdomains,
|
|
41625
|
+
refresh: input.refresh,
|
|
41626
|
+
context
|
|
41627
|
+
});
|
|
41628
|
+
const backlinks = await provider.backlinks({
|
|
41629
|
+
target: summary.data.target,
|
|
41630
|
+
scope: summary.data.scope,
|
|
41631
|
+
includeSubdomains: input.includeSubdomains,
|
|
41632
|
+
mode: "representative",
|
|
41633
|
+
status: "live",
|
|
41634
|
+
limit,
|
|
41635
|
+
refresh: input.refresh,
|
|
41636
|
+
context
|
|
41637
|
+
});
|
|
41638
|
+
const rows = backlinks.data.rows.map((row) => ({
|
|
41639
|
+
sourceUrl: row.sourceUrl,
|
|
41640
|
+
sourceDomain: row.sourceDomain,
|
|
41641
|
+
targetUrl: row.targetUrl,
|
|
41642
|
+
anchorText: row.anchorText ?? void 0,
|
|
41643
|
+
firstSeenAt: row.firstSeenAt ?? void 0,
|
|
41644
|
+
lastSeenAt: row.lastSeenAt ?? void 0,
|
|
41645
|
+
nofollow: row.dofollow === null ? void 0 : !row.dofollow,
|
|
41646
|
+
linkType: row.linkType ?? void 0,
|
|
41647
|
+
attributes: row.attributes,
|
|
41648
|
+
state: row.state,
|
|
41649
|
+
indirect: row.indirect ?? void 0,
|
|
41650
|
+
linksFromPage: row.linksFromPage ?? void 0,
|
|
41651
|
+
linksFromDomain: row.linksFromDomain ?? void 0,
|
|
41652
|
+
providerMetrics: row.metrics
|
|
41653
|
+
}));
|
|
41654
|
+
const counts = /* @__PURE__ */ new Map();
|
|
41655
|
+
for (const row of rows) counts.set(row.targetUrl, (counts.get(row.targetUrl) ?? 0) + 1);
|
|
41656
|
+
const targetCounts = [...counts].map(([targetUrl, observedLinks]) => ({
|
|
41657
|
+
targetUrl,
|
|
41658
|
+
observedLinks
|
|
41659
|
+
})).sort((left, right) => right.observedLinks - left.observedLinks || (left.targetUrl < right.targetUrl ? -1 : left.targetUrl > right.targetUrl ? 1 : 0));
|
|
41660
|
+
const completeness = backlinks.coverage.completeness;
|
|
41661
|
+
const representative = backlinks.data.mode === "representative";
|
|
41662
|
+
const partial = completeness !== "complete" || representative;
|
|
41663
|
+
return {
|
|
41664
|
+
rows,
|
|
41665
|
+
targetCounts,
|
|
41666
|
+
provenance: {
|
|
41667
|
+
provider: "dataforseo",
|
|
41668
|
+
observedAt: backlinks.observedAt > summary.observedAt ? backlinks.observedAt : summary.observedAt,
|
|
41669
|
+
cached: summary.cache.status === "hit" && backlinks.cache.status === "hit",
|
|
41670
|
+
suppliedRows: backlinks.coverage.returnedRows ?? rows.length,
|
|
41671
|
+
validRows: rows.length,
|
|
41672
|
+
invalidRows: backlinks.coverage.invalidRows,
|
|
41673
|
+
duplicateRows: Math.max(0, (backlinks.coverage.returnedRows ?? rows.length) - backlinks.coverage.invalidRows - rows.length),
|
|
41674
|
+
capped: ["capped", "partial"].includes(completeness),
|
|
41675
|
+
rowLimit: limit,
|
|
41676
|
+
completeness: partial ? "partial" : "complete",
|
|
41677
|
+
providerRequests: {
|
|
41678
|
+
methods: [summary.request.endpoint, backlinks.request.endpoint],
|
|
41679
|
+
maxConcurrentRequests: 1
|
|
41680
|
+
},
|
|
41681
|
+
providerCoverage: {
|
|
41682
|
+
targetCountRows: {
|
|
41683
|
+
returnedRows: targetCounts.length,
|
|
41684
|
+
retainedRows: targetCounts.length,
|
|
41685
|
+
invalidRows: 0
|
|
41686
|
+
},
|
|
41687
|
+
detailRows: {
|
|
41688
|
+
returnedRows: backlinks.coverage.returnedRows ?? rows.length,
|
|
41689
|
+
retainedRows: rows.length,
|
|
41690
|
+
invalidRows: backlinks.coverage.invalidRows
|
|
41691
|
+
},
|
|
41692
|
+
summaryRows: {
|
|
41693
|
+
returnedRows: summary.coverage.returnedRows ?? 0,
|
|
41694
|
+
retainedRows: summary.coverage.retainedRows ?? 0,
|
|
41695
|
+
invalidRows: summary.coverage.invalidRows
|
|
41696
|
+
},
|
|
41697
|
+
backlinkRows: {
|
|
41698
|
+
returnedRows: backlinks.coverage.returnedRows ?? rows.length,
|
|
41699
|
+
retainedRows: rows.length,
|
|
41700
|
+
invalidRows: backlinks.coverage.invalidRows,
|
|
41701
|
+
providerTotalRows: backlinks.coverage.providerTotalRows
|
|
41702
|
+
}
|
|
41703
|
+
}
|
|
41704
|
+
},
|
|
41705
|
+
externalProvider: {
|
|
41706
|
+
summary,
|
|
41707
|
+
backlinks
|
|
41708
|
+
},
|
|
41709
|
+
warnings: [
|
|
41710
|
+
...summary.warnings.map((warning) => warning.message),
|
|
41711
|
+
...backlinks.warnings.map((warning) => warning.message),
|
|
41712
|
+
...representative ? ["The link list retains one representative backlink per referring domain. Provider summary counts remain separate from retained rows."] : [],
|
|
41713
|
+
...!representative && partial ? ["The link list is bounded or partial. Provider summary counts remain separate from retained rows."] : []
|
|
41714
|
+
]
|
|
41715
|
+
};
|
|
41716
|
+
}
|
|
41717
|
+
//#endregion
|
|
40574
41718
|
//#region packages/core/src/links/import.ts
|
|
40575
41719
|
const DEFAULT_ROW_LIMIT$1 = 1e4;
|
|
40576
41720
|
const MAX_ROW_LIMIT$1 = 1e5;
|
|
@@ -40759,6 +41903,10 @@ async function importLinkEvidence(input) {
|
|
|
40759
41903
|
//#region packages/core/src/links/report.ts
|
|
40760
41904
|
const DEFAULT_OUTPUT_LIMIT = 100;
|
|
40761
41905
|
const MAX_OUTPUT_LIMIT = 500;
|
|
41906
|
+
const MAX_TARGET_COUNTS = 100;
|
|
41907
|
+
const MAX_CONTEXT_ROWS = 100;
|
|
41908
|
+
const MAX_FINDINGS = 50;
|
|
41909
|
+
const MAX_STRUCTURED_DETAIL_ROWS = 750;
|
|
40762
41910
|
function boundedLimit(value) {
|
|
40763
41911
|
const limit = value ?? DEFAULT_OUTPUT_LIMIT;
|
|
40764
41912
|
if (!Number.isInteger(limit) || limit < 1 || limit > MAX_OUTPUT_LIMIT) throw new SeoError("INVALID_INPUT", `Link report limit must be between 1 and ${MAX_OUTPUT_LIMIT}.`);
|
|
@@ -40770,7 +41918,7 @@ function targetCounts(rows) {
|
|
|
40770
41918
|
return [...counts].map(([targetUrl, observedLinks]) => ({
|
|
40771
41919
|
targetUrl,
|
|
40772
41920
|
observedLinks
|
|
40773
|
-
})).sort((a, b) => b.observedLinks - a.observedLinks || a.targetUrl.
|
|
41921
|
+
})).sort((a, b) => b.observedLinks - a.observedLinks || (a.targetUrl < b.targetUrl ? -1 : a.targetUrl > b.targetUrl ? 1 : 0));
|
|
40774
41922
|
}
|
|
40775
41923
|
function linkEvidenceReport(input) {
|
|
40776
41924
|
const limit = boundedLimit(input.limit);
|
|
@@ -40778,8 +41926,24 @@ function linkEvidenceReport(input) {
|
|
|
40778
41926
|
const domains = new Set(input.evidence.rows.map((row) => row.sourceDomain));
|
|
40779
41927
|
const observedTargets = targetCounts(input.evidence.rows);
|
|
40780
41928
|
const counts = input.evidence.targetCounts.length ? input.evidence.targetCounts : observedTargets;
|
|
41929
|
+
const providerEvidence = input.evidence.externalProvider ? {
|
|
41930
|
+
summary: input.evidence.externalProvider.summary,
|
|
41931
|
+
backlinks: {
|
|
41932
|
+
...input.evidence.externalProvider.backlinks,
|
|
41933
|
+
data: {
|
|
41934
|
+
target: input.evidence.externalProvider.backlinks.data.target,
|
|
41935
|
+
mode: input.evidence.externalProvider.backlinks.data.mode,
|
|
41936
|
+
totalRows: input.evidence.externalProvider.backlinks.data.totalRows,
|
|
41937
|
+
retainedRows: input.evidence.externalProvider.backlinks.data.rows.length
|
|
41938
|
+
}
|
|
41939
|
+
}
|
|
41940
|
+
} : null;
|
|
41941
|
+
const targetCountsOutput = counts.slice(0, MAX_TARGET_COUNTS);
|
|
41942
|
+
const contextRows = input.targetContext?.rows.slice(0, MAX_CONTEXT_ROWS) ?? [];
|
|
41943
|
+
const findings = input.targetContext?.findings.slice(0, MAX_FINDINGS) ?? [];
|
|
41944
|
+
const returnedDetailRows = rows.length + targetCountsOutput.length + contextRows.length + findings.length;
|
|
40781
41945
|
return {
|
|
40782
|
-
schemaVersion:
|
|
41946
|
+
schemaVersion: 2,
|
|
40783
41947
|
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
40784
41948
|
dataStatus: input.evidence.provenance.completeness === "complete" ? "complete" : "partial",
|
|
40785
41949
|
summary: {
|
|
@@ -40788,6 +41952,8 @@ function linkEvidenceReport(input) {
|
|
|
40788
41952
|
targetPages: new Set(input.evidence.rows.map((row) => row.targetUrl)).size,
|
|
40789
41953
|
providerTargetPages: counts.length
|
|
40790
41954
|
},
|
|
41955
|
+
providerSummary: providerEvidence?.summary.data ?? null,
|
|
41956
|
+
providerEvidence,
|
|
40791
41957
|
provenance: input.evidence.provenance,
|
|
40792
41958
|
selection: {
|
|
40793
41959
|
availableRows: input.evidence.rows.length,
|
|
@@ -40795,13 +41961,45 @@ function linkEvidenceReport(input) {
|
|
|
40795
41961
|
omittedRows: Math.max(0, input.evidence.rows.length - rows.length),
|
|
40796
41962
|
limit
|
|
40797
41963
|
},
|
|
40798
|
-
|
|
41964
|
+
outputBudget: {
|
|
41965
|
+
unit: "structured-detail-rows",
|
|
41966
|
+
limit: MAX_STRUCTURED_DETAIL_ROWS,
|
|
41967
|
+
returned: returnedDetailRows,
|
|
41968
|
+
omitted: Math.max(0, input.evidence.rows.length - rows.length + Math.max(0, counts.length - targetCountsOutput.length) + Math.max(0, (input.targetContext?.rows.length ?? 0) - contextRows.length) + Math.max(0, (input.targetContext?.findings.length ?? 0) - findings.length)),
|
|
41969
|
+
sections: {
|
|
41970
|
+
links: {
|
|
41971
|
+
limit: MAX_OUTPUT_LIMIT,
|
|
41972
|
+
returned: rows.length
|
|
41973
|
+
},
|
|
41974
|
+
targetCounts: {
|
|
41975
|
+
limit: MAX_TARGET_COUNTS,
|
|
41976
|
+
returned: targetCountsOutput.length
|
|
41977
|
+
},
|
|
41978
|
+
targetContext: {
|
|
41979
|
+
limit: MAX_CONTEXT_ROWS,
|
|
41980
|
+
returned: contextRows.length
|
|
41981
|
+
},
|
|
41982
|
+
findings: {
|
|
41983
|
+
limit: MAX_FINDINGS,
|
|
41984
|
+
returned: findings.length
|
|
41985
|
+
}
|
|
41986
|
+
}
|
|
41987
|
+
},
|
|
41988
|
+
targetCounts: targetCountsOutput,
|
|
40799
41989
|
links: rows,
|
|
40800
|
-
|
|
41990
|
+
targetContext: input.targetContext ? {
|
|
41991
|
+
...input.targetContext,
|
|
41992
|
+
rows: contextRows,
|
|
41993
|
+
findings
|
|
41994
|
+
} : null,
|
|
41995
|
+
findings,
|
|
41996
|
+
warnings: [...input.evidence.warnings, ...input.targetContext?.warnings ?? []],
|
|
40801
41997
|
caveats: [
|
|
40802
41998
|
"This is bounded provider or imported evidence, not a complete backlink index.",
|
|
40803
41999
|
"A missing link is not proof that no link exists, and an observed link is not a quality or ranking verdict.",
|
|
40804
|
-
"Referring-domain counts describe the retained rows only."
|
|
42000
|
+
"Referring-domain counts describe the retained rows only.",
|
|
42001
|
+
...providerEvidence ? ["Provider profile counts describe its current index. The representative link rows are a separate bounded sample.", "Provider rank and spam metrics keep their provider names and scales. They are context, not ranking factors or universal authority scores."] : [],
|
|
42002
|
+
...input.targetContext ? ["Search Console page rows are retained first-party evidence. Missing or capped rows are never treated as zero.", "Saved crawl findings describe the recorded crawl time. Verify the live target before changing it."] : []
|
|
40805
42003
|
]
|
|
40806
42004
|
};
|
|
40807
42005
|
}
|
|
@@ -42133,6 +43331,6 @@ function isoDate(daysAgo = 0) {
|
|
|
42133
43331
|
return date.toISOString().slice(0, 10);
|
|
42134
43332
|
}
|
|
42135
43333
|
//#endregion
|
|
42136
|
-
export { AI_REFERRAL_SOURCES, AI_REFERRAL_SOURCES_VERSION, AI_SEARCH_SCORECARD_METHODOLOGY_ID, AI_SEARCH_SCORECARD_METHODOLOGY_VERSION, AUDIT_PAGE_RULE_IDS, AUTOMATIC_BASELINE_SITE_RETENTION, AUTOMATIC_BASELINE_TOTAL_RETENTION, BING_API_KEY_ENV, BING_API_KEY_SECRET, BROWSER_USER_AGENT, BingWebmasterClient, CANNIBAL_MAXIMUM_DOMINANT_SHARE, CANNIBAL_MINIMUM_PAGE_SHARE, CRAWL_REPORT_STORAGE_VERSION, CRAWL_RUN_RETENTION, CRAWL_SKIP_REASONS, CTR_DEFAULT_LIMIT, CTR_DEFAULT_MIN_IMPRESSIONS, CTR_MAX_LIMIT, CTR_MAX_MIN_IMPRESSIONS, DATAFORSEO_CREDENTIAL_SECRET, DATAFORSEO_LOGIN_ENV, DATAFORSEO_PASSWORD_ENV, DEFAULT_PROVIDER_SPEND_LIMITS, DataForSeoClient, DataForSeoKeywordDiscoveryProvider, DataForSeoKeywordMetricsProvider, DataForSeoProvider, DataForSeoRankTrackingCollector, DataForSeoSerpSnapshotProvider, GSC_FINAL_DATA_LAG_DAYS, GSC_TIME_ZONE, INDEXNOW_ENDPOINT, INDEXNOW_KEYS_SECRET, INDEXNOW_KEY_ENV, INDEXNOW_MAX_URLS, INDEX_WATCH_ATTEMPT_RETENTION, INTERNAL_LINK_LEXICAL_TARGET_LIMIT, INTERNAL_LINK_MATCH_EVIDENCE_LIMIT, JsonFileStorageAdapter, KEYWORD_SET_FIELD_LIMITS, KEYWORD_SET_LIMITS, KEYWORD_SET_SCHEMA_SQL, LINK_RECOVER_RUN_RETENTION, LOG_MAX_AGE_MS, LOG_MAX_FILE_BYTES, LOG_MAX_TOTAL_BYTES, LocalCredentialsProvider, MAX_CRAWL_CONCURRENCY, MAX_CRAWL_DEPTH, MAX_CRAWL_PAGES, MAX_CRAWL_TIMEOUT_MS, OKF_DEFAULT_CONCEPTS, OKF_MAX_CONCEPTS, PROVIDER_SPEND_MAX_BYTES, PROVIDER_SPEND_MAX_ROWS, PROVIDER_SPEND_RETENTION_DAYS, ProviderError, RANK_TRACKING_LIMITS, RANK_TRACKING_SCHEMA_SQL, REPORT_BASELINE_MAX_AGE_MS, REPORT_BASELINE_MAX_DEPTH, REPORT_BASELINE_MAX_PAGES, ResponseSizeLimitError, SCORECARD_CHECK_WEIGHTS, SCORECARD_STATUS_CREDIT, SEO_CRAWLER_IDENTITY, SEO_CRAWLER_TOKEN, SEO_CRAWLER_USER_AGENT, SEO_VERSION, SERP_TITLE_REFERENCE_WIDTH_PX, SERP_TITLE_WIDTH_PROFILE, SemrushProvider, SeoError, ServiceAccountAccessTokenClient, SessionLedger, TELEMETRY_AGENTS, TELEMETRY_ENDPOINT, TELEMETRY_ERROR_CATEGORIES, TELEMETRY_EVENTS, TELEMETRY_NOTICE, TELEMETRY_REPORTS, TELEMETRY_SCHEMA_VERSION, TELEMETRY_TIMEOUT_MS, acquirePseoAuditEvidence, activeRankTrackingRun, addKeywordsToSet, addStatus, affectedUrls, agentReadiness, aiPromptsForQuery, aiReadiness, aiReferralSourceForValue, aiReferralsReport, aiSearchScorecard, allocateIndexUrlsToProperties, analyticsConnectionsSchema, analyzeAiReferralRows, analyzeBingCrawl, analyzeBingDimensions, analyzeBingTraffic, analyzeCannibalRows, analyzeCtrUnderperformersFromRows, analyzeDecay, analyzeIndexCoverageSignals, analyzeInternalLinksFromRows, analyzeKeywordTrend, analyzePageOpportunitiesFromRows, analyzeQueryClustersFromRows, analyzeQuickWinsFromRows, analyzeSecondPageRows, analyzeSegmentRows, analyzeStrikingDistanceRows, analyzeTrafficAnomalyRows, assertCrawlConfigLimits, assertUrlMatchesGscProperty, attachCrawlRecommendations, auditCrawlPages, auditCrawlRequests, auditLlmsTxt, auditPage, authStatus, bingAnalysisDefaults, bingWebmasterOverview, bingWebmasterSiteUrl, boundedSitemapInventory, buildOkfBundle, buildPseoAuditFromAcquisition, buildPseoAuditReportFromRows, buildQueryClusterReportFromRows, buildTelemetryPayload, cannibalReport, changeMeasurementCsvRows, checkDatabaseReadiness, classifyCommunityIntent, classifyCrawler, clearCache, clientProfileSchema, clusterPseoTemplates, clusterQueryRows, collectAgentDiscovery, collectBingLinkEvidence, combineRobotsValues, communityIntentReport, compareCrawlPages, compareCrawlReports, compareLinkEvidence, compareSegmentRows, competitorKeywordGapReport, configSchema, contentCoverageRecommendation, contentCoverageType, contentOptimizationFromPageOpportunities, contentOptimizationReport, countLabel, crawlConfigHash, crawlConfigSchema, crawlDefinitionId, crawlDiff, crawlFixToQueueItem, crawlImplementationQueueWorkflow, crawlIssueGroupSchema, crawlIssueSchema, crawlOne, crawlPageSnapshotSchema, crawlReportSchema, crawlReportStore, crawlReportSummarySchema, crawlRequestObservationSchema, crawlRunId, crawlSite, crawlSkipImpact, crawlSkipReasonCountsFromRecord, crawlStatusOnly, crawlTopFixSchema, crawlerJsonSchemas, crawlerRuleCategorySchema, crawlerRuleIdSchema, crawlerRuleInfoSchema, crawlerRuleRecommendationSchema, crawlerRuleSeveritySchema, crawlerSchemas, createAuthorizedClient, createBingWebmasterClient, createContentGroup, createCrawlReport, createCtrBenchmarkContext, createGoogleAccessTokenClient, createIndexNowKey, createIndexNowKeyRecord, createKeywordSet, createLogger, createPageRenderer, ctrUnderperformersReport, decayClusterDrafts, decayComparisonRange, decayingReport, deleteChange, deleteClient, deleteContentGroup, deleteCrawlReport, deleteDataForSeoCredentials, deleteKeywordSet, deleteProviderSecret, deleteTokens, deriveBrandTerms, detectBrandTerms, detectTelemetryAgent, diagnoseCsvFiles, diagnoseProperty, diagnosePropertyWorkflow, domainOverviewReport, effectiveRobotsDirectives, effectiveSnippetControl, emptyStatusBreakdown, enforceRankTrackingLogicalBytes, ensurePrivateDatabaseFiles, ensureSeoCliDirs, entityReadiness, estimateSerpTitleWidth, executeRankTracking, expectedCtrForPosition, explainOkfValidation, explainRule, failRankTrackingTask, fetchCruxFieldData, fetchPage, fetchPageStatus, fetchSearchStatusIncidents, fetchSitemapUrls, fetchText, fileSize, finalGscDateRange, finalizeProviderSpend, findOverlappingSearchUpdates, formatRelativeExpiry, ga4MatchReason, ga4PropertyIdFromName, ga4ReportQualityWarnings, ga4RequestCanUseCache, ga4RowsToObjects, generateLlmsTxt, geoGaps, geoGapsReport, getAuthModeStatus, getCacheStats, getChange, getClient, getClientConfig, getContentGroup, getDb, getKeywordProvider, getKeywordSet, getOrCreateRankTrackingConfiguration, getPreviousRun, getPrivacySnapshot, getProviderSpendLimits, getProviderSpendSummary, getRankTrackingRun, getRepeatedLinkRecoverUrls, getRunPages, getSeoCliPaths, getServiceAccountConfig, getServiceAccountStatus, getTelemetryStatus, getTokenStorageStatus, googleAnalyticsPropertyId, groupCrawlIssues, hasMetaRobotsDirective, hasRule, hasXRobotsDirective, hashKey, importLinkEvidence, importServerLog, indexCoveragePlan, indexCoverageSignals, indexMonitor, indexWatch, inferPseoTemplate, inferTemplateMovement, initializeTelemetry, insertCrawlRun, insertLinkRecoverRun, inspectUrl, internalLinksReport, interpretUpdateCorrelation, isBrandQuery, isCompatibleTechnicalBaseline, isCurrentTechnicalBaseline, isEntityEvidenceSchemaType, isSiteIdentitySchemaType, isSkippableReportError, isTelemetryCi, isTelemetryReport, isoDate, isoWeek, keywordDiscoverySourceSchema, keywordMetricsReport, keywordOpportunitiesReport, keywordResearchReport, keywordSetLogicalBytes, latestCrawlReport, latestCrawlSummaries, latestFinalGscDate, latestIndexWatchSummary, latestLinkRecoverSummary, latestRankTrackingRun, linkEntries, linkEvidenceKey, linkEvidenceReport, linkRecover, linkRecoverRecommendation, listChanges, listClients, listContentGroups, listCrawlReports, listGa4AccountSummaries, listGa4DataStreams, listIndexNowKeys, listKeywordSets, listRules, listSearchUpdates, listSites, loadCrawlReport, localCredentialsProvider, loginWithLoopback, makeRunId, mapDataForSeoSerpSnapshot, markRankTasksPosted, markRankTasksPosting, matchGa4WebStreams, measureChange, measureCoverage, metaRobotsDirectives, migrateLegacyMacConfig, missingOAuthClientMessage, missingSharedClientLoginMessage, monitoringStatus, monthlyReport, monthlyReportWorkflow, narrativeCsvFiles, normalizeCrawlConfig, normalizeCrawlSkipReasonCounts, normalizeForCoverage, normalizeHttpUrl, normalizeJavaScriptRenderingMode, normalizeLinkEvidenceRow, normalizeLoadedCrawlReport, normalizeSavedKeyword, noteCacheWrite, observedValue, okfConceptLimit, pageEvidenceRecommendation, pageOpportunitiesReport, parseCombinedLogLine, parseIndexNowSite, parseJsonLogLine, parseOlderThan, parsePseoPath, performanceAudit, performanceReportIsCacheable, planDueIndexUrls, planIndexCoverageFromUrls, plural, priorComparableRankTrackingRun, propertyMatchesUrl, providerCapabilitySchema, providerIdSchema, providerPreferenceSchema, providerRequestJson, providerRequestText, providerSpendLimitOverridesSchema, pruneIndexWatchSnapshots, pruneLogs, pseoAuditOptions, pseoAuditReport, pseoCsvFiles, pseoIndexStatus, pseoOpportunitiesReport, pseoPresentation, publicHttpFetch, queryClusterReport, queryClusterTokens, queryContentCoverageFromPage, queryContentFieldsFromPage, queryFieldCoverage, queryOpportunityRecommendation, queryPageMetrics, queryPageTopQuery, queryPagesMetrics, queryPagesMetricsBatch, queryPagesTopQueries, queryPagesTopQueriesBatch, querySearchAnalytics, quickWinsCsvRows, quickWinsReport, rankObservations, rankTrackingLogicalBytes, rankTrackingReport, rankTrackingTasks, rankedKeywordsReport, rankingPagesReport, readBoundedResponseText, readConfig, readDataForSeoCredentials, readOauthClient, readProviderSecret, readTokens, recommendCrawlDiffItem, recommendationForRule, recordChange, recoverRankTaskReceipt, redirectTrace, refreshAuthToken, refreshKeywordSet, refreshPrioritiesCsvFiles, refreshPrioritiesWorkflow, refreshRankTrackingRun, removeIndexNowKey, removeKeywordsFromSet, renderCrawlCsv, renderCrawlHtml, renderCrawlJunit, renderCrawlMarkdownTickets, renderCrawlPagesCsv, renderCrawlPretty, renderCsv, renderPresentationTablesMarkdown, renderPseoMarkdown, renderReportHtml, renderWorkflowMarkdown, reportNarrative, reportPresentation, requestHeaders, reserveProviderSpend, resolveIndexNowKey, resolveProvider, resolveSegmentRanges, resolveSeoCliPaths, resolveTechnicalBaseline, reviewObservations, roundedPosition, runDoctor, runGa4Report, safeError, saveClient, saveCrawlReport, saveIndexNowKey, saveRankObservation, saveRankObservations, savedKeywordSetReport, searchMarketSchema, secondPage, segmentComparisonRange, segmentImpact, segmentRangeDays, selectAffectedUrls, selectDueIndexUrls, seoErrorEnvelope, seoToAiQueryReport, serpCompetitorsReport, serpResultsReport, serverLogReport, sessionSourceInListFilter, setClientBingSite, setDefaultClient, setKeywordSetRefreshTime, setProviderSpendLimits, setTelemetryEnabled, setTokenStorageMode, shiftIsoDate, shouldExcludeBrandQuery, siteSchema, sqliteCrawlReportStore, startRankTrackingRun, strikingDistance, submitIndexNow, summarizeCrawlReport, targetMatchesDomain, pageTechnicalSignals as technicalPageSignals, technicalWatchWorkflow, telemetryErrorCategory, templateForUrl, toSeoError, tokenSchema, topCrawlRecommendations, topFixes, trackTelemetryReportComplete, trackTelemetryReportFailed, trackTelemetryReportStart, trackTelemetrySetupComplete, trafficAnomaly, unavailableSegmentImpactReport, unavailableValue, unicodeTokens, updateCorrelation, updatePostmortemCsvFiles, updatePostmortemWorkflow, validateIndexNowKey, validateIndexNowKeyRecord, validateOkfFiles, verifyIndexNowKey, verifyQueryContent, workflowPresentation, writeConfig, writeDataForSeoCredentials, writeOauthClient, writeProviderSecret, writeTokens, xRobotsDirectives };
|
|
43334
|
+
export { AI_REFERRAL_SOURCES, AI_REFERRAL_SOURCES_VERSION, AI_SEARCH_SCORECARD_METHODOLOGY_ID, AI_SEARCH_SCORECARD_METHODOLOGY_VERSION, AUDIT_PAGE_RULE_IDS, AUTOMATIC_BASELINE_SITE_RETENTION, AUTOMATIC_BASELINE_TOTAL_RETENTION, BING_API_KEY_ENV, BING_API_KEY_SECRET, BROWSER_USER_AGENT, BingWebmasterClient, CANNIBAL_MAXIMUM_DOMINANT_SHARE, CANNIBAL_MINIMUM_PAGE_SHARE, CRAWL_REPORT_STORAGE_VERSION, CRAWL_RUN_RETENTION, CRAWL_SKIP_REASONS, CTR_DEFAULT_LIMIT, CTR_DEFAULT_MIN_IMPRESSIONS, CTR_MAX_LIMIT, CTR_MAX_MIN_IMPRESSIONS, DATAFORSEO_CREDENTIAL_SECRET, DATAFORSEO_LOGIN_ENV, DATAFORSEO_PASSWORD_ENV, DEFAULT_PROVIDER_SPEND_LIMITS, DataForSeoClient, DataForSeoKeywordDiscoveryProvider, DataForSeoKeywordMetricsProvider, DataForSeoLinkProvider, DataForSeoProvider, DataForSeoRankTrackingCollector, DataForSeoSerpSnapshotProvider, GSC_FINAL_DATA_LAG_DAYS, GSC_TIME_ZONE, INDEXNOW_ENDPOINT, INDEXNOW_KEYS_SECRET, INDEXNOW_KEY_ENV, INDEXNOW_MAX_URLS, INDEX_WATCH_ATTEMPT_RETENTION, INTERNAL_LINK_LEXICAL_TARGET_LIMIT, INTERNAL_LINK_MATCH_EVIDENCE_LIMIT, JsonFileStorageAdapter, KEYWORD_SET_FIELD_LIMITS, KEYWORD_SET_LIMITS, KEYWORD_SET_SCHEMA_SQL, LINK_RECOVER_RUN_RETENTION, LOG_MAX_AGE_MS, LOG_MAX_FILE_BYTES, LOG_MAX_TOTAL_BYTES, LocalCredentialsProvider, MAX_CRAWL_CONCURRENCY, MAX_CRAWL_DEPTH, MAX_CRAWL_PAGES, MAX_CRAWL_TIMEOUT_MS, OKF_DEFAULT_CONCEPTS, OKF_MAX_CONCEPTS, PROVIDER_SPEND_MAX_BYTES, PROVIDER_SPEND_MAX_ROWS, PROVIDER_SPEND_RETENTION_DAYS, ProviderError, RANK_TRACKING_LIMITS, RANK_TRACKING_SCHEMA_SQL, REPORT_BASELINE_MAX_AGE_MS, REPORT_BASELINE_MAX_DEPTH, REPORT_BASELINE_MAX_PAGES, ResponseSizeLimitError, SCORECARD_CHECK_WEIGHTS, SCORECARD_STATUS_CREDIT, SEO_CRAWLER_IDENTITY, SEO_CRAWLER_TOKEN, SEO_CRAWLER_USER_AGENT, SEO_VERSION, SERP_TITLE_REFERENCE_WIDTH_PX, SERP_TITLE_WIDTH_PROFILE, SemrushProvider, SeoError, ServiceAccountAccessTokenClient, SessionLedger, TELEMETRY_AGENTS, TELEMETRY_ENDPOINT, TELEMETRY_ERROR_CATEGORIES, TELEMETRY_EVENTS, TELEMETRY_NOTICE, TELEMETRY_REPORTS, TELEMETRY_SCHEMA_VERSION, TELEMETRY_TIMEOUT_MS, acquirePseoAuditEvidence, activeRankTrackingRun, addKeywordsToSet, addStatus, affectedUrls, agentReadiness, aiPromptsForQuery, aiReadiness, aiReferralSourceForValue, aiReferralsReport, aiSearchScorecard, allocateIndexUrlsToProperties, analyticsConnectionsSchema, analyzeAiReferralRows, analyzeBingCrawl, analyzeBingDimensions, analyzeBingTraffic, analyzeCannibalRows, analyzeCtrUnderperformersFromRows, analyzeDecay, analyzeIndexCoverageSignals, analyzeInternalLinksFromRows, analyzeKeywordTrend, analyzePageOpportunitiesFromRows, analyzeQueryClustersFromRows, analyzeQuickWinsFromRows, analyzeSecondPageRows, analyzeSegmentRows, analyzeStrikingDistanceRows, analyzeTrafficAnomalyRows, assertCrawlConfigLimits, assertUrlMatchesGscProperty, attachCrawlRecommendations, auditCrawlPages, auditCrawlRequests, auditLlmsTxt, auditPage, authStatus, bingAnalysisDefaults, bingWebmasterOverview, bingWebmasterSiteUrl, boundedSitemapInventory, buildOkfBundle, buildPseoAuditFromAcquisition, buildPseoAuditReportFromRows, buildQueryClusterReportFromRows, buildTelemetryPayload, cannibalReport, changeMeasurementCsvRows, checkDatabaseReadiness, classifyCommunityIntent, classifyCrawler, clearCache, clientProfileSchema, clusterPseoTemplates, clusterQueryRows, collectAgentDiscovery, collectBingLinkEvidence, collectDataForSeoLinkEvidence, combineRobotsValues, communityIntentReport, compareCrawlPages, compareCrawlReports, compareLinkEvidence, compareSegmentRows, competitorKeywordGapReport, configSchema, contentCoverageRecommendation, contentCoverageType, contentOptimizationFromPageOpportunities, contentOptimizationReport, countLabel, crawlConfigHash, crawlConfigSchema, crawlDefinitionId, crawlDiff, crawlFixToQueueItem, crawlImplementationQueueWorkflow, crawlIssueGroupSchema, crawlIssueSchema, crawlOne, crawlPageSnapshotSchema, crawlReportSchema, crawlReportStore, crawlReportSummarySchema, crawlRequestObservationSchema, crawlRunId, crawlSite, crawlSkipImpact, crawlSkipReasonCountsFromRecord, crawlStatusOnly, crawlTopFixSchema, crawlerJsonSchemas, crawlerRuleCategorySchema, crawlerRuleIdSchema, crawlerRuleInfoSchema, crawlerRuleRecommendationSchema, crawlerRuleSeveritySchema, crawlerSchemas, createAuthorizedClient, createBingWebmasterClient, createContentGroup, createCrawlReport, createCtrBenchmarkContext, createGoogleAccessTokenClient, createIndexNowKey, createIndexNowKeyRecord, createKeywordSet, createLogger, createPageRenderer, ctrUnderperformersReport, decayClusterDrafts, decayComparisonRange, decayingReport, deleteChange, deleteClient, deleteContentGroup, deleteCrawlReport, deleteDataForSeoCredentials, deleteKeywordSet, deleteProviderSecret, deleteTokens, deriveBrandTerms, detectBrandTerms, detectTelemetryAgent, diagnoseCsvFiles, diagnoseProperty, diagnosePropertyWorkflow, domainOverviewReport, effectiveRobotsDirectives, effectiveSnippetControl, emptyStatusBreakdown, enforceRankTrackingLogicalBytes, ensurePrivateDatabaseFiles, ensureSeoCliDirs, entityReadiness, estimateSerpTitleWidth, executeRankTracking, expectedCtrForPosition, explainOkfValidation, explainRule, failRankTrackingTask, fetchCruxFieldData, fetchPage, fetchPageStatus, fetchSearchStatusIncidents, fetchSitemapUrls, fetchText, fileSize, finalGscDateRange, finalizeProviderSpend, findOverlappingSearchUpdates, formatRelativeExpiry, ga4MatchReason, ga4PropertyIdFromName, ga4ReportQualityWarnings, ga4RequestCanUseCache, ga4RowsToObjects, generateLlmsTxt, geoGaps, geoGapsReport, getAuthModeStatus, getCacheStats, getChange, getClient, getClientConfig, getContentGroup, getDb, getKeywordProvider, getKeywordSet, getOrCreateRankTrackingConfiguration, getPreviousRun, getPrivacySnapshot, getProviderSpendLimits, getProviderSpendSummary, getRankTrackingRun, getRepeatedLinkRecoverUrls, getRunPages, getSeoCliPaths, getServiceAccountConfig, getServiceAccountStatus, getTelemetryStatus, getTokenStorageStatus, googleAnalyticsPropertyId, groupCrawlIssues, hasMetaRobotsDirective, hasRule, hasXRobotsDirective, hashKey, importLinkEvidence, importServerLog, indexCoveragePlan, indexCoverageSignals, indexMonitor, indexWatch, inferPseoTemplate, inferTemplateMovement, initializeTelemetry, insertCrawlRun, insertLinkRecoverRun, inspectUrl, internalLinksReport, interpretUpdateCorrelation, isBrandQuery, isCompatibleTechnicalBaseline, isCurrentTechnicalBaseline, isEntityEvidenceSchemaType, isSiteIdentitySchemaType, isSkippableReportError, isTelemetryCi, isTelemetryReport, isoDate, isoWeek, keywordDiscoverySourceSchema, keywordMetricsReport, keywordOpportunitiesReport, keywordResearchReport, keywordSetLogicalBytes, latestCrawlReport, latestCrawlSummaries, latestFinalGscDate, latestIndexWatchSummary, latestLinkRecoverSummary, latestRankTrackingRun, linkEntries, linkEvidenceKey, linkEvidenceReport, linkRecover, linkRecoverRecommendation, linkTargetContext, listChanges, listClients, listContentGroups, listCrawlReports, listGa4AccountSummaries, listGa4DataStreams, listIndexNowKeys, listKeywordSets, listRules, listSearchUpdates, listSites, loadCrawlReport, localCredentialsProvider, loginWithLoopback, makeRunId, mapDataForSeoSerpSnapshot, markRankTasksPosted, markRankTasksPosting, matchGa4WebStreams, measureChange, measureCoverage, metaRobotsDirectives, migrateLegacyMacConfig, missingOAuthClientMessage, missingSharedClientLoginMessage, monitoringStatus, monthlyReport, monthlyReportWorkflow, narrativeCsvFiles, normalizeCrawlConfig, normalizeCrawlSkipReasonCounts, normalizeForCoverage, normalizeHttpUrl, normalizeJavaScriptRenderingMode, normalizeLinkEvidenceRow, normalizeLoadedCrawlReport, normalizeSavedKeyword, noteCacheWrite, observedValue, okfConceptLimit, pageEvidenceRecommendation, pageOpportunitiesReport, parseCombinedLogLine, parseIndexNowSite, parseJsonLogLine, parseOlderThan, parsePseoPath, performanceAudit, performanceReportIsCacheable, planDueIndexUrls, planIndexCoverageFromUrls, plural, priorComparableRankTrackingRun, propertyMatchesUrl, providerCapabilitySchema, providerIdSchema, providerPreferenceSchema, providerRequestJson, providerRequestText, providerSpendLimitOverridesSchema, pruneIndexWatchSnapshots, pruneLogs, pseoAuditOptions, pseoAuditReport, pseoCsvFiles, pseoIndexStatus, pseoOpportunitiesReport, pseoPresentation, publicHttpFetch, queryClusterReport, queryClusterTokens, queryContentCoverageFromPage, queryContentFieldsFromPage, queryFieldCoverage, queryOpportunityRecommendation, queryPageMetrics, queryPageTopQuery, queryPagesMetrics, queryPagesMetricsBatch, queryPagesTopQueries, queryPagesTopQueriesBatch, querySearchAnalytics, quickWinsCsvRows, quickWinsReport, rankObservations, rankTrackingLogicalBytes, rankTrackingReport, rankTrackingTasks, rankedKeywordsReport, rankingPagesReport, readBoundedResponseText, readConfig, readDataForSeoCredentials, readOauthClient, readProviderSecret, readTokens, recommendCrawlDiffItem, recommendationForRule, recordChange, recoverRankTaskReceipt, redirectTrace, refreshAuthToken, refreshKeywordSet, refreshPrioritiesCsvFiles, refreshPrioritiesWorkflow, refreshRankTrackingRun, removeIndexNowKey, removeKeywordsFromSet, renderCrawlCsv, renderCrawlHtml, renderCrawlJunit, renderCrawlMarkdownTickets, renderCrawlPagesCsv, renderCrawlPretty, renderCsv, renderPresentationTablesMarkdown, renderPseoMarkdown, renderReportHtml, renderWorkflowMarkdown, reportNarrative, reportPresentation, requestHeaders, reserveProviderSpend, resolveIndexNowKey, resolveProvider, resolveSegmentRanges, resolveSeoCliPaths, resolveTechnicalBaseline, reviewObservations, roundedPosition, runDoctor, runGa4Report, safeError, saveClient, saveCrawlReport, saveIndexNowKey, saveRankObservation, saveRankObservations, savedKeywordSetReport, searchMarketSchema, secondPage, segmentComparisonRange, segmentImpact, segmentRangeDays, selectAffectedUrls, selectDueIndexUrls, seoErrorEnvelope, seoToAiQueryReport, serpCompetitorsReport, serpResultsReport, serverLogReport, sessionSourceInListFilter, setClientBingSite, setDefaultClient, setKeywordSetRefreshTime, setProviderSpendLimits, setTelemetryEnabled, setTokenStorageMode, shiftIsoDate, shouldExcludeBrandQuery, siteSchema, sqliteCrawlReportStore, startRankTrackingRun, strikingDistance, submitIndexNow, summarizeCrawlReport, targetMatchesDomain, pageTechnicalSignals as technicalPageSignals, technicalWatchWorkflow, telemetryErrorCategory, templateForUrl, toSeoError, tokenSchema, topCrawlRecommendations, topFixes, trackTelemetryReportComplete, trackTelemetryReportFailed, trackTelemetryReportStart, trackTelemetrySetupComplete, trafficAnomaly, unavailableSegmentImpactReport, unavailableValue, unicodeTokens, updateCorrelation, updatePostmortemCsvFiles, updatePostmortemWorkflow, validateIndexNowKey, validateIndexNowKeyRecord, validateOkfFiles, verifyIndexNowKey, verifyQueryContent, workflowPresentation, writeConfig, writeDataForSeoCredentials, writeOauthClient, writeProviderSecret, writeTokens, xRobotsDirectives };
|
|
42137
43335
|
|
|
42138
43336
|
//# sourceMappingURL=index.js.map
|