@rankcli/agent-runtime 0.0.8 → 0.0.11

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 (49) hide show
  1. package/README.md +90 -196
  2. package/dist/analyzer-GMURJADU.mjs +7 -0
  3. package/dist/chunk-2JADKV3Z.mjs +244 -0
  4. package/dist/chunk-3ZSCLNTW.mjs +557 -0
  5. package/dist/chunk-4E4MQOSP.mjs +374 -0
  6. package/dist/chunk-6BWS3CLP.mjs +16 -0
  7. package/dist/chunk-AK2IC22C.mjs +206 -0
  8. package/dist/chunk-K6VSXDD6.mjs +293 -0
  9. package/dist/chunk-M27NQCWW.mjs +303 -0
  10. package/dist/{chunk-YNZYHEYM.mjs → chunk-PJLNXOLN.mjs} +0 -14
  11. package/dist/chunk-VSQD74I7.mjs +474 -0
  12. package/dist/core-web-vitals-analyzer-TE6LQJMS.mjs +7 -0
  13. package/dist/geo-analyzer-D47LTMMA.mjs +25 -0
  14. package/dist/image-optimization-analyzer-XP4OQGRP.mjs +9 -0
  15. package/dist/index.d.mts +1523 -17
  16. package/dist/index.d.ts +1523 -17
  17. package/dist/index.js +9582 -2664
  18. package/dist/index.mjs +4812 -380
  19. package/dist/internal-linking-analyzer-MRMBV7NM.mjs +9 -0
  20. package/dist/mobile-seo-analyzer-67HNQ7IO.mjs +7 -0
  21. package/dist/security-headers-analyzer-3ZUQARS5.mjs +9 -0
  22. package/dist/structured-data-analyzer-2I4NQAUP.mjs +9 -0
  23. package/package.json +2 -2
  24. package/src/analyzers/core-web-vitals-analyzer.test.ts +236 -0
  25. package/src/analyzers/core-web-vitals-analyzer.ts +557 -0
  26. package/src/analyzers/geo-analyzer.test.ts +310 -0
  27. package/src/analyzers/geo-analyzer.ts +814 -0
  28. package/src/analyzers/image-optimization-analyzer.test.ts +145 -0
  29. package/src/analyzers/image-optimization-analyzer.ts +348 -0
  30. package/src/analyzers/index.ts +233 -0
  31. package/src/analyzers/internal-linking-analyzer.test.ts +141 -0
  32. package/src/analyzers/internal-linking-analyzer.ts +419 -0
  33. package/src/analyzers/mobile-seo-analyzer.test.ts +140 -0
  34. package/src/analyzers/mobile-seo-analyzer.ts +455 -0
  35. package/src/analyzers/security-headers-analyzer.test.ts +115 -0
  36. package/src/analyzers/security-headers-analyzer.ts +318 -0
  37. package/src/analyzers/structured-data-analyzer.test.ts +210 -0
  38. package/src/analyzers/structured-data-analyzer.ts +590 -0
  39. package/src/audit/engine.ts +3 -3
  40. package/src/audit/types.ts +3 -2
  41. package/src/fixer/framework-fixes.test.ts +489 -0
  42. package/src/fixer/framework-fixes.ts +3418 -0
  43. package/src/fixer/index.ts +1 -0
  44. package/src/fixer/schemas.ts +971 -0
  45. package/src/frameworks/detector.ts +642 -114
  46. package/src/frameworks/suggestion-engine.ts +38 -1
  47. package/src/index.ts +6 -0
  48. package/src/types.ts +15 -1
  49. package/dist/analyzer-2CSWIQGD.mjs +0 -6
@@ -0,0 +1,474 @@
1
+ // src/analyzers/structured-data-analyzer.ts
2
+ import * as cheerio from "cheerio";
3
+ var SCHEMA_REQUIREMENTS = {
4
+ "Organization": {
5
+ required: ["name", "url"],
6
+ recommended: ["logo", "sameAs", "contactPoint", "address"]
7
+ },
8
+ "WebSite": {
9
+ required: ["name", "url"],
10
+ recommended: ["potentialAction", "publisher"]
11
+ },
12
+ "WebPage": {
13
+ required: ["name"],
14
+ recommended: ["description", "url", "breadcrumb", "mainEntity"]
15
+ },
16
+ "Article": {
17
+ required: ["headline", "author", "datePublished"],
18
+ recommended: ["image", "dateModified", "publisher", "description", "mainEntityOfPage"]
19
+ },
20
+ "BlogPosting": {
21
+ required: ["headline", "author", "datePublished"],
22
+ recommended: ["image", "dateModified", "publisher", "description"]
23
+ },
24
+ "NewsArticle": {
25
+ required: ["headline", "author", "datePublished", "image"],
26
+ recommended: ["dateModified", "publisher", "description"]
27
+ },
28
+ "Product": {
29
+ required: ["name"],
30
+ recommended: ["image", "description", "offers", "brand", "sku", "aggregateRating", "review"]
31
+ },
32
+ "Offer": {
33
+ required: ["price", "priceCurrency"],
34
+ recommended: ["availability", "url", "priceValidUntil"]
35
+ },
36
+ "FAQPage": {
37
+ required: ["mainEntity"],
38
+ recommended: []
39
+ },
40
+ "Question": {
41
+ required: ["name", "acceptedAnswer"],
42
+ recommended: []
43
+ },
44
+ "HowTo": {
45
+ required: ["name", "step"],
46
+ recommended: ["image", "totalTime", "estimatedCost", "supply", "tool"]
47
+ },
48
+ "BreadcrumbList": {
49
+ required: ["itemListElement"],
50
+ recommended: []
51
+ },
52
+ "LocalBusiness": {
53
+ required: ["name", "address"],
54
+ recommended: ["telephone", "openingHours", "geo", "image", "priceRange"]
55
+ },
56
+ "Event": {
57
+ required: ["name", "startDate", "location"],
58
+ recommended: ["endDate", "description", "image", "offers", "performer", "organizer"]
59
+ },
60
+ "Review": {
61
+ required: ["itemReviewed", "reviewRating", "author"],
62
+ recommended: ["reviewBody", "datePublished"]
63
+ },
64
+ "AggregateRating": {
65
+ required: ["ratingValue", "reviewCount"],
66
+ recommended: ["bestRating", "worstRating"]
67
+ },
68
+ "Person": {
69
+ required: ["name"],
70
+ recommended: ["url", "image", "jobTitle", "sameAs"]
71
+ },
72
+ "VideoObject": {
73
+ required: ["name", "thumbnailUrl", "uploadDate"],
74
+ recommended: ["description", "contentUrl", "duration", "embedUrl"]
75
+ },
76
+ "ImageObject": {
77
+ required: ["contentUrl"],
78
+ recommended: ["caption", "creditText", "creator"]
79
+ },
80
+ "SoftwareApplication": {
81
+ required: ["name"],
82
+ recommended: ["operatingSystem", "applicationCategory", "offers", "aggregateRating"]
83
+ },
84
+ "Recipe": {
85
+ required: ["name", "recipeIngredient", "recipeInstructions"],
86
+ recommended: ["image", "author", "prepTime", "cookTime", "totalTime", "nutrition"]
87
+ },
88
+ "Course": {
89
+ required: ["name", "provider"],
90
+ recommended: ["description", "offers"]
91
+ }
92
+ };
93
+ function parseJsonLd(script) {
94
+ try {
95
+ const data = JSON.parse(script);
96
+ return { data };
97
+ } catch (e) {
98
+ return { data: null, error: `Invalid JSON: ${e.message}` };
99
+ }
100
+ }
101
+ function extractTypes(data) {
102
+ const types = [];
103
+ if (!data) return types;
104
+ if (Array.isArray(data)) {
105
+ for (const item of data) {
106
+ types.push(...extractTypes(item));
107
+ }
108
+ } else if (typeof data === "object") {
109
+ if (data["@type"]) {
110
+ const schemaType = Array.isArray(data["@type"]) ? data["@type"] : [data["@type"]];
111
+ types.push(...schemaType);
112
+ }
113
+ if (data["@graph"]) {
114
+ types.push(...extractTypes(data["@graph"]));
115
+ }
116
+ }
117
+ return types;
118
+ }
119
+ function validateSchema(data, type) {
120
+ const errors = [];
121
+ const warnings = [];
122
+ const properties = [];
123
+ if (!data || typeof data !== "object") {
124
+ return { type, isValid: false, errors: ["Invalid schema object"], warnings, properties };
125
+ }
126
+ for (const key of Object.keys(data)) {
127
+ if (!key.startsWith("@")) {
128
+ properties.push(key);
129
+ }
130
+ }
131
+ const requirements = SCHEMA_REQUIREMENTS[type];
132
+ if (requirements) {
133
+ for (const prop of requirements.required) {
134
+ if (!data[prop]) {
135
+ errors.push(`Missing required property: ${prop}`);
136
+ }
137
+ }
138
+ for (const prop of requirements.recommended) {
139
+ if (!data[prop]) {
140
+ warnings.push(`Missing recommended property: ${prop}`);
141
+ }
142
+ }
143
+ }
144
+ if (type === "Article" || type === "BlogPosting" || type === "NewsArticle") {
145
+ if (data.author && typeof data.author === "string") {
146
+ warnings.push("author should be a Person or Organization object, not a string");
147
+ }
148
+ if (data.publisher && typeof data.publisher === "string") {
149
+ warnings.push("publisher should be an Organization object, not a string");
150
+ }
151
+ if (data.datePublished && !/^\d{4}-\d{2}-\d{2}/.test(data.datePublished)) {
152
+ warnings.push("datePublished should be in ISO 8601 format (YYYY-MM-DD)");
153
+ }
154
+ }
155
+ if (type === "Product") {
156
+ if (!data.offers) {
157
+ warnings.push("Product without offers/price - may not show rich results");
158
+ }
159
+ }
160
+ if (type === "FAQPage") {
161
+ if (data.mainEntity) {
162
+ const questions = Array.isArray(data.mainEntity) ? data.mainEntity : [data.mainEntity];
163
+ for (let i = 0; i < questions.length; i++) {
164
+ const q = questions[i];
165
+ if (!q.name && !q["@type"]?.includes("Question")) {
166
+ errors.push(`FAQ item ${i + 1} is not a valid Question`);
167
+ }
168
+ if (!q.acceptedAnswer) {
169
+ errors.push(`FAQ item ${i + 1} missing acceptedAnswer`);
170
+ }
171
+ }
172
+ }
173
+ }
174
+ if (type === "BreadcrumbList") {
175
+ if (data.itemListElement) {
176
+ const items = Array.isArray(data.itemListElement) ? data.itemListElement : [data.itemListElement];
177
+ items.forEach((item, i) => {
178
+ if (!item.position) {
179
+ errors.push(`Breadcrumb item ${i + 1} missing position`);
180
+ }
181
+ if (!item.name && !item.item?.name) {
182
+ errors.push(`Breadcrumb item ${i + 1} missing name`);
183
+ }
184
+ });
185
+ }
186
+ }
187
+ if (type === "LocalBusiness") {
188
+ if (data.geo) {
189
+ if (!data.geo.latitude || !data.geo.longitude) {
190
+ warnings.push("geo should include latitude and longitude");
191
+ }
192
+ }
193
+ if (data.openingHours && typeof data.openingHours === "string") {
194
+ warnings.push("openingHours should be an array of OpeningHoursSpecification objects for rich results");
195
+ }
196
+ }
197
+ return {
198
+ type,
199
+ isValid: errors.length === 0,
200
+ errors,
201
+ warnings,
202
+ properties
203
+ };
204
+ }
205
+ function analyzeStructuredData(html, url) {
206
+ const $ = cheerio.load(html);
207
+ const schemas = [];
208
+ const issues = [];
209
+ const recommendations = [];
210
+ let score = 100;
211
+ const foundTypes = /* @__PURE__ */ new Set();
212
+ $('script[type="application/ld+json"]').each((_, el) => {
213
+ const content = $(el).html();
214
+ if (!content) return;
215
+ const { data, error } = parseJsonLd(content);
216
+ if (error) {
217
+ issues.push({
218
+ code: "SCHEMA_INVALID_JSON",
219
+ severity: "critical",
220
+ category: "technical",
221
+ title: "Invalid JSON-LD syntax",
222
+ description: error,
223
+ impact: "Schema will not be parsed by search engines",
224
+ howToFix: "Fix JSON syntax errors. Use a JSON validator.",
225
+ affectedUrls: [url]
226
+ });
227
+ score -= 20;
228
+ return;
229
+ }
230
+ const types = extractTypes(data);
231
+ const processItem = (item) => {
232
+ if (!item || typeof item !== "object") return;
233
+ let itemType = item["@type"];
234
+ if (Array.isArray(itemType)) itemType = itemType[0];
235
+ if (itemType) {
236
+ foundTypes.add(itemType);
237
+ const validation = validateSchema(item, itemType);
238
+ schemas.push(validation);
239
+ if (!validation.isValid) {
240
+ for (const err of validation.errors) {
241
+ issues.push({
242
+ code: "SCHEMA_VALIDATION_ERROR",
243
+ severity: "warning",
244
+ category: "technical",
245
+ title: `${itemType} schema error: ${err}`,
246
+ description: `The ${itemType} schema is missing required properties or has invalid data.`,
247
+ impact: "May not qualify for rich results",
248
+ howToFix: `Add the missing property: ${err.replace("Missing required property: ", "")}`,
249
+ affectedUrls: [url]
250
+ });
251
+ score -= 5;
252
+ }
253
+ }
254
+ }
255
+ if (item["@graph"] && Array.isArray(item["@graph"])) {
256
+ item["@graph"].forEach(processItem);
257
+ }
258
+ };
259
+ if (Array.isArray(data)) {
260
+ data.forEach(processItem);
261
+ } else {
262
+ processItem(data);
263
+ }
264
+ });
265
+ const hasOrganization = foundTypes.has("Organization");
266
+ const hasWebSite = foundTypes.has("WebSite");
267
+ const hasWebPage = foundTypes.has("WebPage");
268
+ const hasBreadcrumb = foundTypes.has("BreadcrumbList");
269
+ const hasArticle = foundTypes.has("Article") || foundTypes.has("BlogPosting") || foundTypes.has("NewsArticle");
270
+ const hasProduct = foundTypes.has("Product");
271
+ const hasFAQ = foundTypes.has("FAQPage");
272
+ const hasHowTo = foundTypes.has("HowTo");
273
+ const hasLocalBusiness = foundTypes.has("LocalBusiness");
274
+ const hasEvent = foundTypes.has("Event");
275
+ const hasReview = foundTypes.has("Review") || foundTypes.has("AggregateRating");
276
+ if (!hasOrganization) {
277
+ recommendations.push("Add Organization schema for brand knowledge panel");
278
+ score -= 5;
279
+ }
280
+ if (!hasWebSite) {
281
+ recommendations.push("Add WebSite schema with SearchAction for sitelinks search box");
282
+ score -= 3;
283
+ }
284
+ if (!hasBreadcrumb) {
285
+ recommendations.push("Add BreadcrumbList schema for breadcrumb rich results");
286
+ score -= 3;
287
+ }
288
+ if (!hasArticle && !hasProduct && !hasFAQ && !hasHowTo && !hasLocalBusiness && !hasEvent) {
289
+ recommendations.push("Add page-specific schema (Article, Product, FAQ, HowTo, etc.)");
290
+ score -= 10;
291
+ issues.push({
292
+ code: "SCHEMA_NO_RICH_RESULT_TYPE",
293
+ severity: "warning",
294
+ category: "technical",
295
+ title: "No rich result schema found",
296
+ description: "Page lacks schema types that enable rich results (Article, Product, FAQ, etc.)",
297
+ impact: "Missing opportunity for enhanced search results",
298
+ howToFix: "Add appropriate schema type for your content (e.g., Article for blog posts, Product for products, FAQ for Q&A)",
299
+ affectedUrls: [url]
300
+ });
301
+ }
302
+ if (schemas.length === 0) {
303
+ score -= 20;
304
+ issues.push({
305
+ code: "SCHEMA_NONE_FOUND",
306
+ severity: "warning",
307
+ category: "technical",
308
+ title: "No structured data found",
309
+ description: "No JSON-LD structured data detected on the page.",
310
+ impact: "Missing rich results, reduced AI understanding, lower search visibility",
311
+ howToFix: "Add JSON-LD structured data. At minimum, include Organization and WebPage schemas.",
312
+ affectedUrls: [url]
313
+ });
314
+ }
315
+ if (schemas.length > 0 && !hasFAQ) {
316
+ recommendations.push("Consider adding FAQPage schema - excellent for AI search citations");
317
+ }
318
+ if (!foundTypes.has("Person") && hasArticle) {
319
+ recommendations.push("Use Person schema for authors to improve E-E-A-T signals");
320
+ }
321
+ return {
322
+ score: Math.max(0, Math.min(100, score)),
323
+ schemas,
324
+ hasOrganization,
325
+ hasWebSite,
326
+ hasWebPage,
327
+ hasBreadcrumb,
328
+ hasArticle,
329
+ hasProduct,
330
+ hasFAQ,
331
+ hasHowTo,
332
+ hasLocalBusiness,
333
+ hasEvent,
334
+ hasReview,
335
+ issues,
336
+ recommendations
337
+ };
338
+ }
339
+ function generateSchemaTemplate(pageType, options) {
340
+ const { siteName, siteUrl, authorName, organizationName } = options;
341
+ const baseSchemas = [
342
+ {
343
+ "@context": "https://schema.org",
344
+ "@type": "Organization",
345
+ name: organizationName || siteName,
346
+ url: siteUrl,
347
+ logo: `${siteUrl}/logo.png`
348
+ },
349
+ {
350
+ "@context": "https://schema.org",
351
+ "@type": "WebSite",
352
+ name: siteName,
353
+ url: siteUrl,
354
+ potentialAction: {
355
+ "@type": "SearchAction",
356
+ target: {
357
+ "@type": "EntryPoint",
358
+ urlTemplate: `${siteUrl}/search?q={search_term_string}`
359
+ },
360
+ "query-input": "required name=search_term_string"
361
+ }
362
+ }
363
+ ];
364
+ const pageSchemas = {
365
+ article: {
366
+ "@context": "https://schema.org",
367
+ "@type": "Article",
368
+ headline: "{{title}}",
369
+ description: "{{description}}",
370
+ image: "{{image_url}}",
371
+ datePublished: "{{date_published}}",
372
+ dateModified: "{{date_modified}}",
373
+ author: {
374
+ "@type": "Person",
375
+ name: authorName || "{{author_name}}",
376
+ url: "{{author_url}}"
377
+ },
378
+ publisher: {
379
+ "@type": "Organization",
380
+ name: organizationName || siteName,
381
+ logo: {
382
+ "@type": "ImageObject",
383
+ url: `${siteUrl}/logo.png`
384
+ }
385
+ }
386
+ },
387
+ product: {
388
+ "@context": "https://schema.org",
389
+ "@type": "Product",
390
+ name: "{{product_name}}",
391
+ description: "{{product_description}}",
392
+ image: "{{product_image}}",
393
+ brand: {
394
+ "@type": "Brand",
395
+ name: "{{brand_name}}"
396
+ },
397
+ sku: "{{sku}}",
398
+ offers: {
399
+ "@type": "Offer",
400
+ price: "{{price}}",
401
+ priceCurrency: "USD",
402
+ availability: "https://schema.org/InStock",
403
+ url: "{{product_url}}"
404
+ },
405
+ aggregateRating: {
406
+ "@type": "AggregateRating",
407
+ ratingValue: "{{rating}}",
408
+ reviewCount: "{{review_count}}"
409
+ }
410
+ },
411
+ faq: {
412
+ "@context": "https://schema.org",
413
+ "@type": "FAQPage",
414
+ mainEntity: [
415
+ {
416
+ "@type": "Question",
417
+ name: "{{question_1}}",
418
+ acceptedAnswer: {
419
+ "@type": "Answer",
420
+ text: "{{answer_1}}"
421
+ }
422
+ },
423
+ {
424
+ "@type": "Question",
425
+ name: "{{question_2}}",
426
+ acceptedAnswer: {
427
+ "@type": "Answer",
428
+ text: "{{answer_2}}"
429
+ }
430
+ }
431
+ ]
432
+ },
433
+ "local-business": {
434
+ "@context": "https://schema.org",
435
+ "@type": "LocalBusiness",
436
+ name: "{{business_name}}",
437
+ description: "{{description}}",
438
+ url: siteUrl,
439
+ telephone: "{{phone}}",
440
+ address: {
441
+ "@type": "PostalAddress",
442
+ streetAddress: "{{street}}",
443
+ addressLocality: "{{city}}",
444
+ addressRegion: "{{state}}",
445
+ postalCode: "{{zip}}",
446
+ addressCountry: "{{country}}"
447
+ },
448
+ geo: {
449
+ "@type": "GeoCoordinates",
450
+ latitude: "{{latitude}}",
451
+ longitude: "{{longitude}}"
452
+ },
453
+ openingHoursSpecification: [
454
+ {
455
+ "@type": "OpeningHoursSpecification",
456
+ dayOfWeek: ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"],
457
+ opens: "09:00",
458
+ closes: "17:00"
459
+ }
460
+ ]
461
+ },
462
+ website: baseSchemas[1]
463
+ };
464
+ const result = [...baseSchemas];
465
+ if (pageType !== "website" && pageSchemas[pageType]) {
466
+ result.push(pageSchemas[pageType]);
467
+ }
468
+ return JSON.stringify(result, null, 2);
469
+ }
470
+
471
+ export {
472
+ analyzeStructuredData,
473
+ generateSchemaTemplate
474
+ };
@@ -0,0 +1,7 @@
1
+ import {
2
+ analyzeCoreWebVitals
3
+ } from "./chunk-4E4MQOSP.mjs";
4
+ import "./chunk-6BWS3CLP.mjs";
5
+ export {
6
+ analyzeCoreWebVitals
7
+ };
@@ -0,0 +1,25 @@
1
+ import {
2
+ AI_CRAWLERS_INFO,
3
+ analyzeCitationReadiness,
4
+ analyzeContentStructure,
5
+ analyzeEntityExtraction,
6
+ analyzeGEO,
7
+ analyzeRobotsTxtForAI,
8
+ calculateLLMSignals,
9
+ detectRenderingMode,
10
+ generateAIFriendlyRobotsTxt,
11
+ generateGEOIssues
12
+ } from "./chunk-3ZSCLNTW.mjs";
13
+ import "./chunk-6BWS3CLP.mjs";
14
+ export {
15
+ AI_CRAWLERS_INFO,
16
+ analyzeCitationReadiness,
17
+ analyzeContentStructure,
18
+ analyzeEntityExtraction,
19
+ analyzeGEO,
20
+ analyzeRobotsTxtForAI,
21
+ calculateLLMSignals,
22
+ detectRenderingMode,
23
+ generateAIFriendlyRobotsTxt,
24
+ generateGEOIssues
25
+ };
@@ -0,0 +1,9 @@
1
+ import {
2
+ analyzeImages,
3
+ generateResponsiveImage
4
+ } from "./chunk-2JADKV3Z.mjs";
5
+ import "./chunk-6BWS3CLP.mjs";
6
+ export {
7
+ analyzeImages,
8
+ generateResponsiveImage
9
+ };