recker 1.0.73 → 1.0.75-next.a400152
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 +5 -18
- package/dist/browser/core/client.d.ts +14 -8
- package/dist/browser/core/client.js +199 -17
- package/dist/browser/core/errors.d.ts +15 -1
- package/dist/browser/core/errors.js +140 -9
- package/dist/browser/core/request.d.ts +5 -0
- package/dist/browser/core/request.js +33 -2
- package/dist/browser/core-runtime/plugin-manifest.d.ts +24 -0
- package/dist/browser/core-runtime/plugin-manifest.js +159 -0
- package/dist/browser/core-runtime/request-context.d.ts +13 -0
- package/dist/browser/core-runtime/request-context.js +24 -0
- package/dist/browser/core-runtime/typed-events.d.ts +89 -0
- package/dist/browser/core-runtime/typed-events.js +34 -0
- package/dist/browser/index.iife.min.js +79 -79
- package/dist/browser/index.min.js +79 -79
- package/dist/browser/index.mini.iife.js +913 -97
- package/dist/browser/index.mini.iife.min.js +46 -46
- package/dist/browser/index.mini.min.js +46 -46
- package/dist/browser/index.mini.umd.js +913 -97
- package/dist/browser/index.mini.umd.min.js +46 -46
- package/dist/browser/index.umd.min.js +79 -79
- package/dist/browser/plugins/auth/aws-sigv4.d.ts +1 -0
- package/dist/browser/plugins/auth/aws-sigv4.js +19 -2
- package/dist/browser/plugins/retry.js +29 -1
- package/dist/browser/presets/aws.d.ts +1 -0
- package/dist/browser/presets/aws.js +62 -1
- package/dist/browser/runner/request-runner.d.ts +15 -5
- package/dist/browser/runner/request-runner.js +164 -30
- package/dist/browser/scrape/parser/nodes/html.d.ts +6 -0
- package/dist/browser/scrape/parser/nodes/html.js +70 -18
- package/dist/browser/scrape/parser/nodes/node.d.ts +1 -0
- package/dist/browser/scrape/parser/nodes/node.js +5 -0
- package/dist/browser/scrape/spider.d.ts +1 -0
- package/dist/browser/scrape/spider.js +39 -26
- package/dist/browser/search/google.d.ts +70 -0
- package/dist/browser/search/google.js +617 -0
- package/dist/browser/seo/analyzer.d.ts +1 -1
- package/dist/browser/seo/analyzer.js +73 -42
- package/dist/browser/seo/index.d.ts +3 -1
- package/dist/browser/seo/index.js +1 -0
- package/dist/browser/seo/keyword-campaign.d.ts +107 -0
- package/dist/browser/seo/keyword-campaign.js +380 -0
- package/dist/browser/seo/rules/types.d.ts +2 -0
- package/dist/browser/seo/seo-spider.d.ts +2 -3
- package/dist/browser/seo/seo-spider.js +26 -202
- package/dist/browser/seo/types.d.ts +4 -0
- package/dist/browser/seo/validators/sitemap.js +9 -2
- package/dist/browser/transport/fetch.js +38 -5
- package/dist/browser/transport/undici.js +73 -11
- package/dist/browser/transport/worker.d.ts +0 -1
- package/dist/browser/transport/worker.js +1 -3
- package/dist/browser/types/index.d.ts +24 -0
- package/dist/cli/commands/mcp.js +5 -3
- package/dist/core/client.d.ts +14 -8
- package/dist/core/client.js +199 -17
- package/dist/core/errors.d.ts +15 -1
- package/dist/core/errors.js +140 -9
- package/dist/core/request.d.ts +5 -0
- package/dist/core/request.js +33 -2
- package/dist/core-runtime/plugin-manifest.d.ts +24 -0
- package/dist/core-runtime/plugin-manifest.js +159 -0
- package/dist/core-runtime/request-context.d.ts +13 -0
- package/dist/core-runtime/request-context.js +24 -0
- package/dist/core-runtime/typed-events.d.ts +89 -0
- package/dist/core-runtime/typed-events.js +34 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/mcp/cli.js +10 -8
- package/dist/mcp/profiles.d.ts +1 -1
- package/dist/mcp/profiles.js +31 -6
- package/dist/mcp/tools/categories.js +0 -1
- package/dist/plugins/auth/aws-sigv4.d.ts +1 -0
- package/dist/plugins/auth/aws-sigv4.js +19 -2
- package/dist/plugins/retry.js +29 -1
- package/dist/presets/aws.d.ts +1 -0
- package/dist/presets/aws.js +62 -1
- package/dist/recker.d.ts +3 -0
- package/dist/recker.js +5 -0
- package/dist/runner/request-runner.d.ts +15 -5
- package/dist/runner/request-runner.js +164 -30
- package/dist/scrape/parser/nodes/html.d.ts +6 -0
- package/dist/scrape/parser/nodes/html.js +70 -18
- package/dist/scrape/parser/nodes/node.d.ts +1 -0
- package/dist/scrape/parser/nodes/node.js +5 -0
- package/dist/scrape/spider.d.ts +1 -0
- package/dist/scrape/spider.js +39 -26
- package/dist/search/google.d.ts +70 -0
- package/dist/search/google.js +617 -0
- package/dist/search/index.d.ts +3 -0
- package/dist/search/index.js +1 -0
- package/dist/seo/analyzer.d.ts +1 -1
- package/dist/seo/analyzer.js +73 -42
- package/dist/seo/index.d.ts +3 -1
- package/dist/seo/index.js +1 -0
- package/dist/seo/keyword-campaign.d.ts +107 -0
- package/dist/seo/keyword-campaign.js +380 -0
- package/dist/seo/rules/types.d.ts +2 -0
- package/dist/seo/seo-spider.d.ts +2 -3
- package/dist/seo/seo-spider.js +26 -202
- package/dist/seo/types.d.ts +4 -0
- package/dist/seo/validators/sitemap.js +9 -2
- package/dist/transport/fetch.js +38 -5
- package/dist/transport/undici.js +73 -11
- package/dist/transport/worker.d.ts +0 -1
- package/dist/transport/worker.js +1 -3
- package/dist/types/index.d.ts +24 -0
- package/dist/version.js +1 -1
- package/package.json +9 -1
package/dist/seo/analyzer.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { parse } from '../scrape/parser/index.js';
|
|
2
2
|
import { extractMeta, extractOpenGraph, extractTwitterCard, extractJsonLd, extractLinks, extractImages, } from '../scrape/extractors.js';
|
|
3
3
|
import { generateKeywordCloud } from './keywords.js';
|
|
4
|
-
import { createRulesEngine, SEO_THRESHOLDS, } from './rules/index.js';
|
|
4
|
+
import { createRulesEngine, SEO_THRESHOLDS, calculateWeightedScore, } from './rules/index.js';
|
|
5
5
|
export class SeoAnalyzer {
|
|
6
6
|
root;
|
|
7
7
|
options;
|
|
@@ -47,7 +47,9 @@ export class SeoAnalyzer {
|
|
|
47
47
|
const analytics = this.analyzeAnalytics();
|
|
48
48
|
const feeds = this.analyzeFeeds();
|
|
49
49
|
const conversion = this.analyzeConversionElements(links, visibleText);
|
|
50
|
+
const pageType = this.detectPageType(jsonLd);
|
|
50
51
|
const context = this.buildRuleContext({
|
|
52
|
+
pageType,
|
|
51
53
|
meta,
|
|
52
54
|
og,
|
|
53
55
|
twitter,
|
|
@@ -68,7 +70,7 @@ export class SeoAnalyzer {
|
|
|
68
70
|
});
|
|
69
71
|
const ruleResults = this.rulesEngine.evaluate(context);
|
|
70
72
|
const checks = this.convertToCheckResults(ruleResults);
|
|
71
|
-
const { score, grade } = this.calculateScore(
|
|
73
|
+
const { score, grade } = this.calculateScore(ruleResults);
|
|
72
74
|
const summary = this.buildSummary(ruleResults, checks, {
|
|
73
75
|
content,
|
|
74
76
|
imageAnalysis,
|
|
@@ -77,13 +79,17 @@ export class SeoAnalyzer {
|
|
|
77
79
|
og,
|
|
78
80
|
twitter,
|
|
79
81
|
technical,
|
|
82
|
+
pageType,
|
|
83
|
+
timings: this.options.timings,
|
|
80
84
|
});
|
|
81
85
|
return {
|
|
82
86
|
url,
|
|
83
87
|
timestamp: new Date(),
|
|
84
88
|
grade,
|
|
85
89
|
score,
|
|
90
|
+
timing: this.options.timings,
|
|
86
91
|
summary,
|
|
92
|
+
pageType,
|
|
87
93
|
checks,
|
|
88
94
|
title: meta.title
|
|
89
95
|
? { text: meta.title, length: meta.title.length }
|
|
@@ -134,6 +140,47 @@ export class SeoAnalyzer {
|
|
|
134
140
|
return bodies[0];
|
|
135
141
|
return bodies.reduce((prev, curr) => curr.text.length > prev.text.length ? curr : prev);
|
|
136
142
|
}
|
|
143
|
+
detectPageType(jsonLd) {
|
|
144
|
+
if (!this.options.baseUrl) {
|
|
145
|
+
return 'other';
|
|
146
|
+
}
|
|
147
|
+
try {
|
|
148
|
+
const parsed = new URL(this.options.baseUrl);
|
|
149
|
+
const pathname = parsed.pathname.toLowerCase();
|
|
150
|
+
const hasQueryKeyword = (value) => parsed.searchParams.has(value);
|
|
151
|
+
if (pathname === '/' || pathname === '') {
|
|
152
|
+
return 'homepage';
|
|
153
|
+
}
|
|
154
|
+
if (/(^|\/)(search|busca|s|results|query)\b/.test(pathname) ||
|
|
155
|
+
hasQueryKeyword('q') ||
|
|
156
|
+
hasQueryKeyword('query') ||
|
|
157
|
+
hasQueryKeyword('search')) {
|
|
158
|
+
return 'search';
|
|
159
|
+
}
|
|
160
|
+
const productSignals = ['product', 'produto', 'item', 'sku', 'shop'];
|
|
161
|
+
if (productSignals.some((segment) => pathname.includes(`/${segment}/`))) {
|
|
162
|
+
return 'product';
|
|
163
|
+
}
|
|
164
|
+
const articleSignals = ['article', 'post', 'blog', 'noticia', 'news'];
|
|
165
|
+
if (articleSignals.some((segment) => pathname.includes(`/${segment}/`)) ||
|
|
166
|
+
this.root.querySelectorAll('article').length > 0) {
|
|
167
|
+
return 'article';
|
|
168
|
+
}
|
|
169
|
+
if (/(^|\/)(categoria|category|tag|section|topic)\b/.test(pathname)) {
|
|
170
|
+
return 'category';
|
|
171
|
+
}
|
|
172
|
+
const hasProductJsonLd = jsonLd
|
|
173
|
+
.map((node) => node['@type'])
|
|
174
|
+
.some((type) => typeof type === 'string' && type.toLowerCase() === 'product');
|
|
175
|
+
if (hasProductJsonLd) {
|
|
176
|
+
return 'product';
|
|
177
|
+
}
|
|
178
|
+
return 'other';
|
|
179
|
+
}
|
|
180
|
+
catch {
|
|
181
|
+
return 'other';
|
|
182
|
+
}
|
|
183
|
+
}
|
|
137
184
|
getVisibleText() {
|
|
138
185
|
const body = this.getMainBody();
|
|
139
186
|
if (!body)
|
|
@@ -159,7 +206,7 @@ export class SeoAnalyzer {
|
|
|
159
206
|
return clone.text.replace(/\s+/g, ' ').trim();
|
|
160
207
|
}
|
|
161
208
|
buildRuleContext(data) {
|
|
162
|
-
const { meta, og, twitter, jsonLd, headings, content, linkAnalysis, imageAnalysis, links, keywords, resources, emailsFound, socialLinksFound, socialLinkDetails, analytics, feeds, conversion, } = data;
|
|
209
|
+
const { meta, og, twitter, jsonLd, headings, content, pageType, linkAnalysis, imageAnalysis, links, keywords, resources, emailsFound, socialLinksFound, socialLinkDetails, analytics, feeds, conversion, } = data;
|
|
163
210
|
const html = this.root.querySelector('html');
|
|
164
211
|
const htmlLang = html ? html.getAttribute('lang') : undefined;
|
|
165
212
|
const hreflangTags = [];
|
|
@@ -198,7 +245,6 @@ export class SeoAnalyzer {
|
|
|
198
245
|
const hasMixedContent = this.checkMixedContent();
|
|
199
246
|
const h1Elements = this.root.querySelectorAll('h1');
|
|
200
247
|
const h1Text = h1Elements.length > 0 ? h1Elements[0].text.trim() : '';
|
|
201
|
-
const iframeCount = this.root.querySelectorAll('iframe').length;
|
|
202
248
|
const topKeywords = keywords.topKeywords.slice(0, 5).map(k => k.word);
|
|
203
249
|
const mainKeyword = topKeywords.length > 0 ? topKeywords[0] : undefined;
|
|
204
250
|
const keywordsInTitle = topKeywords.some(kw => meta.title?.toLowerCase().includes(kw));
|
|
@@ -234,7 +280,6 @@ export class SeoAnalyzer {
|
|
|
234
280
|
const structuralHtml = this.analyzeStructuralHtml();
|
|
235
281
|
const breadcrumbs = this.analyzeBreadcrumbs(jsonLd.map((j) => j['@type']).filter(Boolean));
|
|
236
282
|
const multimedia = this.analyzeMultimedia();
|
|
237
|
-
const advancedImages = this.analyzeAdvancedImages();
|
|
238
283
|
const responsiveImages = this.analyzeResponsiveImages();
|
|
239
284
|
const inlineImages = this.analyzeInlineImages();
|
|
240
285
|
const trustSignals = this.analyzeTrustSignals(links);
|
|
@@ -245,6 +290,7 @@ export class SeoAnalyzer {
|
|
|
245
290
|
: 0;
|
|
246
291
|
const textHtmlRatio = this.calculateTextHtmlRatio(content.characterCount);
|
|
247
292
|
return {
|
|
293
|
+
pageType,
|
|
248
294
|
jsFilesCount: resources.jsFilesCount,
|
|
249
295
|
cssFilesCount: resources.cssFilesCount,
|
|
250
296
|
unminifiedResources: resources.unminifiedResources,
|
|
@@ -774,7 +820,6 @@ export class SeoAnalyzer {
|
|
|
774
820
|
}
|
|
775
821
|
analyzeAnalytics() {
|
|
776
822
|
const providers = [];
|
|
777
|
-
const html = this.root.innerHTML || '';
|
|
778
823
|
const scripts = this.root.querySelectorAll('script');
|
|
779
824
|
const scriptSources = [];
|
|
780
825
|
const scriptContents = [];
|
|
@@ -899,21 +944,6 @@ export class SeoAnalyzer {
|
|
|
899
944
|
hasPhoneOnPage,
|
|
900
945
|
};
|
|
901
946
|
}
|
|
902
|
-
analyzeAdvancedImages() {
|
|
903
|
-
let imagesWithSrcset = 0;
|
|
904
|
-
let largeBase64ImagesCount = 0;
|
|
905
|
-
const imgs = this.root.querySelectorAll('img');
|
|
906
|
-
imgs.forEach((img) => {
|
|
907
|
-
if (img.getAttribute('srcset') || (img.parentNode && img.parentNode.tagName === 'PICTURE')) {
|
|
908
|
-
imagesWithSrcset++;
|
|
909
|
-
}
|
|
910
|
-
const src = img.getAttribute('src') || '';
|
|
911
|
-
if (src.startsWith('data:image') && src.length > 5 * 1024) {
|
|
912
|
-
largeBase64ImagesCount++;
|
|
913
|
-
}
|
|
914
|
-
});
|
|
915
|
-
return { imagesWithSrcset, largeBase64ImagesCount };
|
|
916
|
-
}
|
|
917
947
|
calculateTextHtmlRatio(bodyTextLength) {
|
|
918
948
|
const htmlSize = this.root.innerHTML?.length;
|
|
919
949
|
if (htmlSize && htmlSize > 0) {
|
|
@@ -926,6 +956,7 @@ export class SeoAnalyzer {
|
|
|
926
956
|
id: r.id,
|
|
927
957
|
name: r.name,
|
|
928
958
|
category: r.category,
|
|
959
|
+
severity: r.severity,
|
|
929
960
|
status: r.status,
|
|
930
961
|
message: r.message,
|
|
931
962
|
value: r.value,
|
|
@@ -934,6 +965,8 @@ export class SeoAnalyzer {
|
|
|
934
965
|
}));
|
|
935
966
|
}
|
|
936
967
|
buildSummary(ruleResults, checks, data) {
|
|
968
|
+
const pageType = data.pageType;
|
|
969
|
+
const timings = data.timings;
|
|
937
970
|
const passed = checks.filter((c) => c.status === 'pass').length;
|
|
938
971
|
const warnings = checks.filter((c) => c.status === 'warn').length;
|
|
939
972
|
const errors = checks.filter((c) => c.status === 'fail').length;
|
|
@@ -954,21 +987,25 @@ export class SeoAnalyzer {
|
|
|
954
987
|
else if (result.status === 'fail')
|
|
955
988
|
issuesByCategory[cat].errors++;
|
|
956
989
|
}
|
|
957
|
-
const topIssues =
|
|
958
|
-
.filter((
|
|
990
|
+
const topIssues = checks
|
|
991
|
+
.filter((c) => c.status === 'fail' || c.status === 'warn')
|
|
959
992
|
.sort((a, b) => {
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
if (
|
|
963
|
-
return
|
|
964
|
-
|
|
993
|
+
const severityOrder = (status) => status === 'fail' ? 2 : 1;
|
|
994
|
+
const statusDiff = severityOrder(b.status) - severityOrder(a.status);
|
|
995
|
+
if (statusDiff !== 0)
|
|
996
|
+
return statusDiff;
|
|
997
|
+
const aSeverity = a.severity || (a.status === 'fail' ? 'error' : 'warning');
|
|
998
|
+
const bSeverity = b.severity || (b.status === 'fail' ? 'error' : 'warning');
|
|
999
|
+
if (aSeverity === bSeverity)
|
|
1000
|
+
return 0;
|
|
1001
|
+
return aSeverity === 'error' ? -1 : 1;
|
|
965
1002
|
})
|
|
966
1003
|
.slice(0, 5)
|
|
967
1004
|
.map((r) => ({
|
|
968
1005
|
name: r.name,
|
|
969
1006
|
message: r.message,
|
|
970
1007
|
category: r.category,
|
|
971
|
-
severity: (r.status === 'fail' ? 'error' : 'warning'),
|
|
1008
|
+
severity: (r.severity || (r.status === 'fail' ? 'error' : 'warning')),
|
|
972
1009
|
}));
|
|
973
1010
|
const quickWins = [];
|
|
974
1011
|
if (!data.meta.title)
|
|
@@ -993,8 +1030,8 @@ export class SeoAnalyzer {
|
|
|
993
1030
|
const vitals = {
|
|
994
1031
|
htmlSize,
|
|
995
1032
|
domElements,
|
|
996
|
-
ttfb:
|
|
997
|
-
totalTime:
|
|
1033
|
+
ttfb: timings?.ttfb,
|
|
1034
|
+
totalTime: timings?.total,
|
|
998
1035
|
wordCount: data.content.wordCount,
|
|
999
1036
|
totalWordCount: data.content.totalWordCount,
|
|
1000
1037
|
readingTime: data.content.readingTimeMinutes,
|
|
@@ -1017,6 +1054,7 @@ export class SeoAnalyzer {
|
|
|
1017
1054
|
infos,
|
|
1018
1055
|
passRate,
|
|
1019
1056
|
issuesByCategory,
|
|
1057
|
+
pageType: pageType,
|
|
1020
1058
|
topIssues,
|
|
1021
1059
|
quickWins: limitedQuickWins,
|
|
1022
1060
|
vitals,
|
|
@@ -1387,18 +1425,11 @@ export class SeoAnalyzer {
|
|
|
1387
1425
|
unminifiedResourceUrls: unminified
|
|
1388
1426
|
};
|
|
1389
1427
|
}
|
|
1390
|
-
calculateScore(
|
|
1391
|
-
|
|
1392
|
-
pass: 100,
|
|
1393
|
-
warn: 50,
|
|
1394
|
-
fail: 0,
|
|
1395
|
-
info: 100,
|
|
1396
|
-
};
|
|
1397
|
-
const scoringChecks = checks.filter((c) => c.status !== 'info');
|
|
1398
|
-
if (scoringChecks.length === 0)
|
|
1428
|
+
calculateScore(results) {
|
|
1429
|
+
if (results.length === 0)
|
|
1399
1430
|
return { score: 100, grade: 'A' };
|
|
1400
|
-
const
|
|
1401
|
-
const score =
|
|
1431
|
+
const { score: weightedScore } = calculateWeightedScore(results);
|
|
1432
|
+
const score = weightedScore;
|
|
1402
1433
|
let grade;
|
|
1403
1434
|
if (score >= 90)
|
|
1404
1435
|
grade = 'A';
|
package/dist/seo/index.d.ts
CHANGED
|
@@ -6,7 +6,7 @@ export type { SeoSpiderOptions, SeoPageResult, SiteWideIssue, SeoSpiderResult, }
|
|
|
6
6
|
export { SeoRulesEngine, createRulesEngine, SEO_THRESHOLDS, ALL_SEO_RULES, } from './rules/index.js';
|
|
7
7
|
export { generateSeoFilename, resolveOutputPath, writeReport, formatReportForJson, } from './output.js';
|
|
8
8
|
export type { SeoOutputType, OutputOptions, WriteOptions } from './output.js';
|
|
9
|
-
export type { SeoReport, SeoCheckResult, SeoStatus, SeoTiming, HeadingAnalysis, HeadingInfo, ContentMetrics, LinkAnalysis, ImageAnalysis, SocialMetaAnalysis, TechnicalSeo, SeoAnalyzerOptions, } from './types.js';
|
|
9
|
+
export type { SeoReport, SeoCheckResult, SeoStatus, SeoPageType, SeoTiming, HeadingAnalysis, HeadingInfo, ContentMetrics, LinkAnalysis, ImageAnalysis, SocialMetaAnalysis, TechnicalSeo, SeoAnalyzerOptions, } from './types.js';
|
|
10
10
|
export type { SeoRule, RuleContext, RuleResult, RuleEvidence, RuleCategory, RuleSeverity, RulesEngineOptions, } from './rules/index.js';
|
|
11
11
|
export type { SeoAnalyzerFullOptions } from './analyzer.js';
|
|
12
12
|
export { parseRobotsTxt, validateRobotsTxt, isPathAllowed, fetchAndValidateRobotsTxt, } from './validators/robots.js';
|
|
@@ -15,3 +15,5 @@ export { parseSitemap, validateSitemap, discoverSitemaps, fetchAndValidateSitema
|
|
|
15
15
|
export type { SitemapUrl, SitemapIndex, SitemapParseResult, SitemapValidationIssue, SitemapValidationResult, } from './validators/sitemap.js';
|
|
16
16
|
export { parseLlmsTxt, validateLlmsTxt, fetchAndValidateLlmsTxt, generateLlmsTxtTemplate, } from './validators/llms-txt.js';
|
|
17
17
|
export type { LlmsTxtLink, LlmsTxtSection, LlmsTxtParseResult, LlmsTxtValidationIssue, LlmsTxtValidationResult, } from './validators/llms-txt.js';
|
|
18
|
+
export { analyzeKeywordCampaign, extractKeywordCampaignSeedsFromReport, } from './keyword-campaign.js';
|
|
19
|
+
export type { CampaignActivitySignal, CampaignResultPlacement, KeywordCampaignCompetitorResult, KeywordCampaignCompetitorSummary, KeywordCampaignExtractionOptions, KeywordCampaignOptions, KeywordCampaignPageStats, KeywordCampaignReport, KeywordCampaignResult, KeywordCampaignSeed, KeywordCampaignSeedInput, KeywordCampaignSource, KeywordCampaignSummary, } from './keyword-campaign.js';
|
package/dist/seo/index.js
CHANGED
|
@@ -6,3 +6,4 @@ export { generateSeoFilename, resolveOutputPath, writeReport, formatReportForJso
|
|
|
6
6
|
export { parseRobotsTxt, validateRobotsTxt, isPathAllowed, fetchAndValidateRobotsTxt, } from './validators/robots.js';
|
|
7
7
|
export { parseSitemap, validateSitemap, discoverSitemaps, fetchAndValidateSitemap, } from './validators/sitemap.js';
|
|
8
8
|
export { parseLlmsTxt, validateLlmsTxt, fetchAndValidateLlmsTxt, generateLlmsTxtTemplate, } from './validators/llms-txt.js';
|
|
9
|
+
export { analyzeKeywordCampaign, extractKeywordCampaignSeedsFromReport, } from './keyword-campaign.js';
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import type { SearchTransport } from '../search/google.js';
|
|
2
|
+
import type { SeoReport } from './types.js';
|
|
3
|
+
export type KeywordCampaignSource = 'discovered' | 'preset';
|
|
4
|
+
export type CampaignResultPlacement = 'ad' | 'organic' | 'unknown';
|
|
5
|
+
export interface KeywordCampaignSeedInput {
|
|
6
|
+
keyword: string;
|
|
7
|
+
source?: KeywordCampaignSource;
|
|
8
|
+
sourcePage?: string;
|
|
9
|
+
weight?: number;
|
|
10
|
+
}
|
|
11
|
+
export interface KeywordCampaignSeed {
|
|
12
|
+
keyword: string;
|
|
13
|
+
normalizedKeyword: string;
|
|
14
|
+
source: KeywordCampaignSource;
|
|
15
|
+
sourcePage?: string;
|
|
16
|
+
weight: number;
|
|
17
|
+
}
|
|
18
|
+
export interface KeywordCampaignOptions {
|
|
19
|
+
targetUrl: string;
|
|
20
|
+
discoveredKeywords?: KeywordCampaignSeedInput[] | string[];
|
|
21
|
+
presetKeywords?: string[];
|
|
22
|
+
minKeywordLength?: number;
|
|
23
|
+
maxQueries?: number;
|
|
24
|
+
maxResultsPerQuery?: number;
|
|
25
|
+
transport?: SearchTransport;
|
|
26
|
+
timeout?: number;
|
|
27
|
+
country?: string;
|
|
28
|
+
gl?: string;
|
|
29
|
+
hl?: string;
|
|
30
|
+
minWeight?: number;
|
|
31
|
+
}
|
|
32
|
+
export interface KeywordCampaignCompetitorResult {
|
|
33
|
+
domain: string;
|
|
34
|
+
rank: number;
|
|
35
|
+
placement: CampaignResultPlacement;
|
|
36
|
+
placementHint?: string;
|
|
37
|
+
url: string;
|
|
38
|
+
title: string;
|
|
39
|
+
}
|
|
40
|
+
export interface KeywordCampaignResult {
|
|
41
|
+
keyword: string;
|
|
42
|
+
source: KeywordCampaignSource;
|
|
43
|
+
sourcePage?: string;
|
|
44
|
+
sourceWeight: number;
|
|
45
|
+
found: boolean;
|
|
46
|
+
bestPosition: number | null;
|
|
47
|
+
totalChecked: number;
|
|
48
|
+
matchedUrl?: string;
|
|
49
|
+
matchedTitle?: string;
|
|
50
|
+
matchedDisplayUrl?: string;
|
|
51
|
+
placement: CampaignResultPlacement;
|
|
52
|
+
placementHint?: string;
|
|
53
|
+
searchUrl: string;
|
|
54
|
+
searchTransport: SearchTransport;
|
|
55
|
+
competitors: KeywordCampaignCompetitorResult[];
|
|
56
|
+
}
|
|
57
|
+
export interface KeywordCampaignPageStats {
|
|
58
|
+
pageUrl: string;
|
|
59
|
+
tracked: number;
|
|
60
|
+
found: number;
|
|
61
|
+
avgPosition: number | null;
|
|
62
|
+
top3: number;
|
|
63
|
+
top10: number;
|
|
64
|
+
}
|
|
65
|
+
export interface KeywordCampaignSummary {
|
|
66
|
+
queriesRequested: number;
|
|
67
|
+
queriesExecuted: number;
|
|
68
|
+
queriesFound: number;
|
|
69
|
+
avgTopPosition: number | null;
|
|
70
|
+
top3Count: number;
|
|
71
|
+
top10Count: 0 | number;
|
|
72
|
+
topOrganicCompetitors: KeywordCampaignCompetitorSummary[];
|
|
73
|
+
topPaidCompetitors: KeywordCampaignCompetitorSummary[];
|
|
74
|
+
competitorCoverage: {
|
|
75
|
+
organicUniqueDomains: number;
|
|
76
|
+
paidUniqueDomains: number;
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
export interface KeywordCampaignCompetitorSummary {
|
|
80
|
+
domain: string;
|
|
81
|
+
organicQueries: number;
|
|
82
|
+
paidQueries: number;
|
|
83
|
+
bestOrganicRank: number | null;
|
|
84
|
+
bestPaidRank: number | null;
|
|
85
|
+
matchedKeywords: number;
|
|
86
|
+
}
|
|
87
|
+
export interface CampaignActivitySignal {
|
|
88
|
+
active: boolean;
|
|
89
|
+
confidence: 'high' | 'medium' | 'low';
|
|
90
|
+
evidence: string[];
|
|
91
|
+
}
|
|
92
|
+
export interface KeywordCampaignReport {
|
|
93
|
+
targetUrl: string;
|
|
94
|
+
targetDomain: string;
|
|
95
|
+
results: KeywordCampaignResult[];
|
|
96
|
+
summary: KeywordCampaignSummary;
|
|
97
|
+
pageComparison: KeywordCampaignPageStats[];
|
|
98
|
+
campaign: CampaignActivitySignal;
|
|
99
|
+
}
|
|
100
|
+
export interface KeywordCampaignExtractionOptions {
|
|
101
|
+
maxKeywords?: number;
|
|
102
|
+
minKeywordLength?: number;
|
|
103
|
+
}
|
|
104
|
+
export declare function extractKeywordCampaignSeedsFromReport(report: SeoReport, options?: KeywordCampaignExtractionOptions & {
|
|
105
|
+
sourcePage?: string;
|
|
106
|
+
}): KeywordCampaignSeed[];
|
|
107
|
+
export declare function analyzeKeywordCampaign(options: KeywordCampaignOptions): Promise<KeywordCampaignReport>;
|