@rankcli/agent-runtime 0.0.1

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.
Files changed (178) hide show
  1. package/README.md +242 -0
  2. package/dist/analyzer-2CSWIQGD.mjs +6 -0
  3. package/dist/chunk-YNZYHEYM.mjs +774 -0
  4. package/dist/index.d.mts +4012 -0
  5. package/dist/index.d.ts +4012 -0
  6. package/dist/index.js +29672 -0
  7. package/dist/index.mjs +28602 -0
  8. package/package.json +53 -0
  9. package/scripts/build-deno.ts +134 -0
  10. package/src/audit/ai/analyzer.ts +347 -0
  11. package/src/audit/ai/index.ts +29 -0
  12. package/src/audit/ai/prompts/content-analysis.ts +271 -0
  13. package/src/audit/ai/types.ts +179 -0
  14. package/src/audit/checks/additional-checks.ts +439 -0
  15. package/src/audit/checks/ai-citation-worthiness.ts +399 -0
  16. package/src/audit/checks/ai-content-structure.ts +325 -0
  17. package/src/audit/checks/ai-readiness.ts +339 -0
  18. package/src/audit/checks/anchor-text.ts +179 -0
  19. package/src/audit/checks/answer-conciseness.ts +322 -0
  20. package/src/audit/checks/asset-minification.ts +270 -0
  21. package/src/audit/checks/bing-optimization.ts +206 -0
  22. package/src/audit/checks/brand-mention-optimization.ts +349 -0
  23. package/src/audit/checks/caching-headers.ts +305 -0
  24. package/src/audit/checks/canonical-advanced.ts +150 -0
  25. package/src/audit/checks/canonical-domain.ts +196 -0
  26. package/src/audit/checks/citation-quality.ts +358 -0
  27. package/src/audit/checks/client-rendering.ts +542 -0
  28. package/src/audit/checks/color-contrast.ts +342 -0
  29. package/src/audit/checks/content-freshness.ts +170 -0
  30. package/src/audit/checks/content-science.ts +589 -0
  31. package/src/audit/checks/conversion-elements.ts +526 -0
  32. package/src/audit/checks/crawlability.ts +220 -0
  33. package/src/audit/checks/directory-listing.ts +172 -0
  34. package/src/audit/checks/dom-analysis.ts +191 -0
  35. package/src/audit/checks/dom-size.ts +246 -0
  36. package/src/audit/checks/duplicate-content.ts +194 -0
  37. package/src/audit/checks/eeat-signals.ts +990 -0
  38. package/src/audit/checks/entity-seo.ts +396 -0
  39. package/src/audit/checks/featured-snippet.ts +473 -0
  40. package/src/audit/checks/freshness-signals.ts +443 -0
  41. package/src/audit/checks/funnel-intent.ts +463 -0
  42. package/src/audit/checks/hreflang.ts +174 -0
  43. package/src/audit/checks/html-compliance.ts +302 -0
  44. package/src/audit/checks/image-dimensions.ts +167 -0
  45. package/src/audit/checks/images.ts +160 -0
  46. package/src/audit/checks/indexnow.ts +275 -0
  47. package/src/audit/checks/interactive-tools.ts +475 -0
  48. package/src/audit/checks/internal-link-graph.ts +436 -0
  49. package/src/audit/checks/keyword-analysis.ts +239 -0
  50. package/src/audit/checks/keyword-cannibalization.ts +385 -0
  51. package/src/audit/checks/keyword-placement.ts +471 -0
  52. package/src/audit/checks/links.ts +203 -0
  53. package/src/audit/checks/llms-txt.ts +224 -0
  54. package/src/audit/checks/local-seo.ts +296 -0
  55. package/src/audit/checks/mobile.ts +167 -0
  56. package/src/audit/checks/modern-images.ts +226 -0
  57. package/src/audit/checks/navboost-signals.ts +395 -0
  58. package/src/audit/checks/on-page.ts +209 -0
  59. package/src/audit/checks/page-resources.ts +285 -0
  60. package/src/audit/checks/pagination.ts +180 -0
  61. package/src/audit/checks/performance.ts +153 -0
  62. package/src/audit/checks/platform-presence.ts +580 -0
  63. package/src/audit/checks/redirect-analysis.ts +153 -0
  64. package/src/audit/checks/redirect-chain.ts +389 -0
  65. package/src/audit/checks/resource-hints.ts +420 -0
  66. package/src/audit/checks/responsive-css.ts +247 -0
  67. package/src/audit/checks/responsive-images.ts +396 -0
  68. package/src/audit/checks/review-ecosystem.ts +415 -0
  69. package/src/audit/checks/robots-validation.ts +373 -0
  70. package/src/audit/checks/security-headers.ts +172 -0
  71. package/src/audit/checks/security.ts +144 -0
  72. package/src/audit/checks/serp-preview.ts +251 -0
  73. package/src/audit/checks/site-maturity.ts +444 -0
  74. package/src/audit/checks/social-meta.test.ts +275 -0
  75. package/src/audit/checks/social-meta.ts +134 -0
  76. package/src/audit/checks/soft-404.ts +151 -0
  77. package/src/audit/checks/structured-data.ts +238 -0
  78. package/src/audit/checks/tech-detection.ts +496 -0
  79. package/src/audit/checks/topical-clusters.ts +435 -0
  80. package/src/audit/checks/tracker-bloat.ts +462 -0
  81. package/src/audit/checks/tracking-verification.test.ts +371 -0
  82. package/src/audit/checks/tracking-verification.ts +636 -0
  83. package/src/audit/checks/url-safety.ts +682 -0
  84. package/src/audit/deno-entry.ts +66 -0
  85. package/src/audit/discovery/index.ts +15 -0
  86. package/src/audit/discovery/link-crawler.ts +232 -0
  87. package/src/audit/discovery/repo-routes.ts +347 -0
  88. package/src/audit/engine.ts +620 -0
  89. package/src/audit/fixes/index.ts +209 -0
  90. package/src/audit/fixes/social-meta-fixes.test.ts +329 -0
  91. package/src/audit/fixes/social-meta-fixes.ts +463 -0
  92. package/src/audit/index.ts +74 -0
  93. package/src/audit/runner.test.ts +299 -0
  94. package/src/audit/runner.ts +130 -0
  95. package/src/audit/types.ts +1953 -0
  96. package/src/content/featured-snippet.ts +367 -0
  97. package/src/content/generator.test.ts +534 -0
  98. package/src/content/generator.ts +501 -0
  99. package/src/content/headline.ts +317 -0
  100. package/src/content/index.ts +62 -0
  101. package/src/content/intent.ts +258 -0
  102. package/src/content/keyword-density.ts +349 -0
  103. package/src/content/readability.ts +262 -0
  104. package/src/executor.ts +336 -0
  105. package/src/fixer.ts +416 -0
  106. package/src/frameworks/detector.test.ts +248 -0
  107. package/src/frameworks/detector.ts +371 -0
  108. package/src/frameworks/index.ts +68 -0
  109. package/src/frameworks/recipes/angular.yaml +171 -0
  110. package/src/frameworks/recipes/astro.yaml +206 -0
  111. package/src/frameworks/recipes/django.yaml +180 -0
  112. package/src/frameworks/recipes/laravel.yaml +137 -0
  113. package/src/frameworks/recipes/nextjs.yaml +268 -0
  114. package/src/frameworks/recipes/nuxt.yaml +175 -0
  115. package/src/frameworks/recipes/rails.yaml +188 -0
  116. package/src/frameworks/recipes/react.yaml +202 -0
  117. package/src/frameworks/recipes/sveltekit.yaml +154 -0
  118. package/src/frameworks/recipes/vue.yaml +137 -0
  119. package/src/frameworks/recipes/wordpress.yaml +209 -0
  120. package/src/frameworks/suggestion-engine.ts +320 -0
  121. package/src/geo/geo-content.test.ts +305 -0
  122. package/src/geo/geo-content.ts +266 -0
  123. package/src/geo/geo-history.test.ts +473 -0
  124. package/src/geo/geo-history.ts +433 -0
  125. package/src/geo/geo-tracker.test.ts +359 -0
  126. package/src/geo/geo-tracker.ts +411 -0
  127. package/src/geo/index.ts +10 -0
  128. package/src/git/commit-helper.test.ts +261 -0
  129. package/src/git/commit-helper.ts +329 -0
  130. package/src/git/index.ts +12 -0
  131. package/src/git/pr-helper.test.ts +284 -0
  132. package/src/git/pr-helper.ts +307 -0
  133. package/src/index.ts +66 -0
  134. package/src/keywords/ai-keyword-engine.ts +1062 -0
  135. package/src/keywords/ai-summarizer.ts +387 -0
  136. package/src/keywords/ci-mode.ts +555 -0
  137. package/src/keywords/engine.ts +359 -0
  138. package/src/keywords/index.ts +151 -0
  139. package/src/keywords/llm-judge.ts +357 -0
  140. package/src/keywords/nlp-analysis.ts +706 -0
  141. package/src/keywords/prioritizer.ts +295 -0
  142. package/src/keywords/site-crawler.ts +342 -0
  143. package/src/keywords/sources/autocomplete.ts +139 -0
  144. package/src/keywords/sources/competitive-search.ts +450 -0
  145. package/src/keywords/sources/competitor-analysis.ts +374 -0
  146. package/src/keywords/sources/dataforseo.ts +206 -0
  147. package/src/keywords/sources/free-sources.ts +294 -0
  148. package/src/keywords/sources/gsc.ts +123 -0
  149. package/src/keywords/topic-grouping.ts +327 -0
  150. package/src/keywords/types.ts +144 -0
  151. package/src/keywords/wizard.ts +457 -0
  152. package/src/loader.ts +40 -0
  153. package/src/reports/index.ts +7 -0
  154. package/src/reports/report-generator.test.ts +293 -0
  155. package/src/reports/report-generator.ts +713 -0
  156. package/src/scheduler/alerts.test.ts +458 -0
  157. package/src/scheduler/alerts.ts +328 -0
  158. package/src/scheduler/index.ts +8 -0
  159. package/src/scheduler/scheduled-audit.test.ts +377 -0
  160. package/src/scheduler/scheduled-audit.ts +149 -0
  161. package/src/test/integration-test.ts +325 -0
  162. package/src/tools/analyzer.ts +373 -0
  163. package/src/tools/crawl.ts +293 -0
  164. package/src/tools/files.ts +301 -0
  165. package/src/tools/h1-fixer.ts +249 -0
  166. package/src/tools/index.ts +67 -0
  167. package/src/tracking/github-action.ts +326 -0
  168. package/src/tracking/google-analytics.ts +265 -0
  169. package/src/tracking/index.ts +45 -0
  170. package/src/tracking/report-generator.ts +386 -0
  171. package/src/tracking/search-console.ts +335 -0
  172. package/src/types.ts +134 -0
  173. package/src/utils/http.ts +302 -0
  174. package/src/wasm-adapter.ts +297 -0
  175. package/src/wasm-entry.ts +14 -0
  176. package/tsconfig.json +17 -0
  177. package/tsup.wasm.config.ts +26 -0
  178. package/vitest.config.ts +15 -0
@@ -0,0 +1,238 @@
1
+ import * as cheerio from 'cheerio';
2
+ import type { AuditIssue } from '../types.js';
3
+ import { ISSUE_DEFINITIONS } from '../types.js';
4
+
5
+ export interface SchemaItem {
6
+ type: string;
7
+ data: Record<string, unknown>;
8
+ errors: string[];
9
+ warnings: string[];
10
+ }
11
+
12
+ export interface StructuredDataData {
13
+ schemas: SchemaItem[];
14
+ hasSchema: boolean;
15
+ schemaTypes: string[];
16
+ }
17
+
18
+ // Required properties for common schema types
19
+ const SCHEMA_REQUIRED_PROPERTIES: Record<string, string[]> = {
20
+ 'Organization': ['name', 'url'],
21
+ 'WebSite': ['name', 'url'],
22
+ 'WebPage': ['name'],
23
+ 'Article': ['headline', 'author', 'datePublished'],
24
+ 'BlogPosting': ['headline', 'author', 'datePublished'],
25
+ 'NewsArticle': ['headline', 'author', 'datePublished'],
26
+ 'Product': ['name', 'image'],
27
+ 'LocalBusiness': ['name', 'address'],
28
+ 'Person': ['name'],
29
+ 'Event': ['name', 'startDate', 'location'],
30
+ 'Recipe': ['name', 'image', 'recipeIngredient'],
31
+ 'FAQPage': ['mainEntity'],
32
+ 'HowTo': ['name', 'step'],
33
+ 'BreadcrumbList': ['itemListElement'],
34
+ 'SoftwareApplication': ['name', 'operatingSystem'],
35
+ 'VideoObject': ['name', 'description', 'thumbnailUrl', 'uploadDate'],
36
+ 'ImageObject': ['contentUrl'],
37
+ 'Review': ['itemReviewed', 'author'],
38
+ 'AggregateRating': ['ratingValue', 'reviewCount'],
39
+ 'Offer': ['price', 'priceCurrency'],
40
+ };
41
+
42
+ // Recommended properties for common schema types
43
+ const SCHEMA_RECOMMENDED_PROPERTIES: Record<string, string[]> = {
44
+ 'Organization': ['logo', 'sameAs', 'contactPoint'],
45
+ 'Article': ['image', 'publisher', 'dateModified'],
46
+ 'Product': ['description', 'offers', 'brand', 'review', 'aggregateRating'],
47
+ 'LocalBusiness': ['telephone', 'openingHours', 'geo'],
48
+ 'SoftwareApplication': ['applicationCategory', 'offers', 'aggregateRating'],
49
+ 'VideoObject': ['duration', 'embedUrl'],
50
+ };
51
+
52
+ export function analyzeStructuredData(html: string, url: string): { issues: AuditIssue[]; data: StructuredDataData } {
53
+ const issues: AuditIssue[] = [];
54
+ const $ = cheerio.load(html);
55
+ const schemas: SchemaItem[] = [];
56
+
57
+ // Find all JSON-LD scripts
58
+ $('script[type="application/ld+json"]').each((_, el) => {
59
+ const content = $(el).html();
60
+ if (!content) return;
61
+
62
+ try {
63
+ const parsed = JSON.parse(content);
64
+ const items = Array.isArray(parsed) ? parsed : [parsed];
65
+
66
+ for (const item of items) {
67
+ if (item['@graph']) {
68
+ // Handle @graph format
69
+ for (const graphItem of item['@graph']) {
70
+ const schemaItem = validateSchemaItem(graphItem);
71
+ schemas.push(schemaItem);
72
+ }
73
+ } else {
74
+ const schemaItem = validateSchemaItem(item);
75
+ schemas.push(schemaItem);
76
+ }
77
+ }
78
+ } catch (e) {
79
+ issues.push({
80
+ ...ISSUE_DEFINITIONS.SCHEMA_INVALID,
81
+ affectedUrls: [url],
82
+ details: {
83
+ error: e instanceof Error ? e.message : 'Invalid JSON',
84
+ content: content.substring(0, 200),
85
+ },
86
+ });
87
+ }
88
+ });
89
+
90
+ // Check if any schema exists
91
+ if (schemas.length === 0) {
92
+ issues.push({
93
+ ...ISSUE_DEFINITIONS.SCHEMA_MISSING,
94
+ affectedUrls: [url],
95
+ });
96
+ }
97
+
98
+ // Check for required properties
99
+ for (const schema of schemas) {
100
+ if (schema.errors.length > 0) {
101
+ issues.push({
102
+ ...ISSUE_DEFINITIONS.SCHEMA_MISSING_REQUIRED,
103
+ affectedUrls: [url],
104
+ details: {
105
+ type: schema.type,
106
+ missingProperties: schema.errors,
107
+ },
108
+ });
109
+ }
110
+ }
111
+
112
+ const schemaTypes = schemas.map(s => s.type).filter(Boolean);
113
+
114
+ return {
115
+ issues,
116
+ data: {
117
+ schemas,
118
+ hasSchema: schemas.length > 0,
119
+ schemaTypes,
120
+ }
121
+ };
122
+ }
123
+
124
+ function validateSchemaItem(item: Record<string, unknown>): SchemaItem {
125
+ const type = (item['@type'] as string) || 'Unknown';
126
+ const errors: string[] = [];
127
+ const warnings: string[] = [];
128
+
129
+ // Check required properties
130
+ const required = SCHEMA_REQUIRED_PROPERTIES[type] || [];
131
+ for (const prop of required) {
132
+ if (!item[prop]) {
133
+ errors.push(`Missing required property: ${prop}`);
134
+ }
135
+ }
136
+
137
+ // Check recommended properties
138
+ const recommended = SCHEMA_RECOMMENDED_PROPERTIES[type] || [];
139
+ for (const prop of recommended) {
140
+ if (!item[prop]) {
141
+ warnings.push(`Missing recommended property: ${prop}`);
142
+ }
143
+ }
144
+
145
+ // Validate specific types
146
+ if (type === 'BreadcrumbList') {
147
+ const items = item['itemListElement'] as unknown[];
148
+ if (items && Array.isArray(items)) {
149
+ for (let i = 0; i < items.length; i++) {
150
+ const crumb = items[i] as Record<string, unknown>;
151
+ if (!crumb['position']) {
152
+ errors.push(`Breadcrumb item ${i + 1} missing position`);
153
+ }
154
+ if (!crumb['name'] && !crumb['item']) {
155
+ errors.push(`Breadcrumb item ${i + 1} missing name or item`);
156
+ }
157
+ }
158
+ }
159
+ }
160
+
161
+ if (type === 'FAQPage') {
162
+ const mainEntity = item['mainEntity'] as unknown[];
163
+ if (!mainEntity || !Array.isArray(mainEntity) || mainEntity.length === 0) {
164
+ errors.push('FAQPage must have at least one question in mainEntity');
165
+ } else {
166
+ for (let i = 0; i < mainEntity.length; i++) {
167
+ const qa = mainEntity[i] as Record<string, unknown>;
168
+ if (!qa['name']) {
169
+ errors.push(`FAQ item ${i + 1} missing question (name)`);
170
+ }
171
+ if (!qa['acceptedAnswer']) {
172
+ errors.push(`FAQ item ${i + 1} missing answer (acceptedAnswer)`);
173
+ }
174
+ }
175
+ }
176
+ }
177
+
178
+ if (type === 'Product' && item['offers']) {
179
+ const offers = item['offers'] as Record<string, unknown>;
180
+ if (!offers['price'] && !offers['lowPrice']) {
181
+ warnings.push('Product offers should include price');
182
+ }
183
+ if (!offers['availability']) {
184
+ warnings.push('Product offers should include availability');
185
+ }
186
+ }
187
+
188
+ return {
189
+ type,
190
+ data: item,
191
+ errors,
192
+ warnings,
193
+ };
194
+ }
195
+
196
+ // Suggest appropriate schema types based on page content
197
+ export function suggestSchemaTypes(html: string, url: string): string[] {
198
+ const $ = cheerio.load(html);
199
+ const suggestions: string[] = [];
200
+ const path = new URL(url).pathname.toLowerCase();
201
+
202
+ // Always suggest Organization and WebSite for homepage
203
+ if (path === '/' || path === '') {
204
+ suggestions.push('Organization', 'WebSite');
205
+ }
206
+
207
+ // Check for blog/article patterns
208
+ if (path.includes('/blog') || path.includes('/article') || path.includes('/post') || path.includes('/news')) {
209
+ suggestions.push('Article', 'BlogPosting');
210
+ }
211
+
212
+ // Check for product patterns
213
+ if (path.includes('/product') || path.includes('/shop') || path.includes('/item')) {
214
+ suggestions.push('Product');
215
+ }
216
+
217
+ // Check for FAQ patterns
218
+ if (path.includes('/faq') || path.includes('/help') || $('h2:contains("FAQ"), h3:contains("FAQ")').length > 0) {
219
+ suggestions.push('FAQPage');
220
+ }
221
+
222
+ // Check for contact/about patterns
223
+ if (path.includes('/contact') || path.includes('/about')) {
224
+ suggestions.push('Organization', 'LocalBusiness');
225
+ }
226
+
227
+ // Check for SaaS/software patterns
228
+ if (path.includes('/pricing') || $('meta[name="application-name"]').length > 0) {
229
+ suggestions.push('SoftwareApplication');
230
+ }
231
+
232
+ // Check for breadcrumbs
233
+ if ($('[class*="breadcrumb"], nav[aria-label*="breadcrumb"]').length > 0) {
234
+ suggestions.push('BreadcrumbList');
235
+ }
236
+
237
+ return [...new Set(suggestions)];
238
+ }