n8n-nodes-seo-scanner 1.2.21 → 1.2.22

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.
@@ -23,28 +23,42 @@ export interface GeoBotAccess {
23
23
  allowed: boolean | null;
24
24
  blocked: boolean | null;
25
25
  }
26
+ export interface GeoSummary {
27
+ criticalCount: number;
28
+ importantCount: number;
29
+ warningCount: number;
30
+ infoCount: number;
31
+ passedCount: number;
32
+ }
33
+ export interface GeoBotAccessReport {
34
+ robotsTxtUrl: string | null;
35
+ robotsTxtFetched: boolean;
36
+ robotsTxtStatusCode: number | null;
37
+ robotsTxtError: string | null;
38
+ bots: GeoBotAccess[];
39
+ }
40
+ export interface GeoPageReport {
41
+ url: string;
42
+ finalUrl: string | null;
43
+ title: string | null;
44
+ score: number;
45
+ summary: GeoSummary;
46
+ checks: GeoCheck[];
47
+ problemsBySeverity: Record<GeoSeverity, GeoIssue[]>;
48
+ passed: string[];
49
+ botAccess: GeoBotAccessReport;
50
+ }
26
51
  export interface GeoReport {
27
52
  version: string;
28
53
  source: 'n8n-node';
29
54
  generatedAt: string;
30
55
  score: number;
31
- summary: {
32
- criticalCount: number;
33
- importantCount: number;
34
- warningCount: number;
35
- infoCount: number;
36
- passedCount: number;
37
- };
56
+ summary: GeoSummary;
38
57
  checks: GeoCheck[];
39
58
  problemsBySeverity: Record<GeoSeverity, GeoIssue[]>;
40
59
  passed: string[];
41
- botAccess: {
42
- robotsTxtUrl: string | null;
43
- robotsTxtFetched: boolean;
44
- robotsTxtStatusCode: number | null;
45
- robotsTxtError: string | null;
46
- bots: GeoBotAccess[];
47
- };
60
+ botAccess: GeoBotAccessReport;
61
+ pages: GeoPageReport[];
48
62
  }
49
63
  export declare function buildGeoReport(params: {
50
64
  mainPage: SeoResult;
package/dist/geoUtils.js CHANGED
@@ -36,7 +36,10 @@ function textFrom(value) {
36
36
  return '';
37
37
  }
38
38
  function getAllPages(mainPage, internalPages) {
39
- return [mainPage, ...(internalPages ?? [])].filter((page) => Boolean(page && page.finalUrl));
39
+ return [mainPage, ...(internalPages ?? [])].filter((page) => Boolean(page && (page.finalUrl || page.url)));
40
+ }
41
+ function getPageUrl(page) {
42
+ return page.finalUrl || page.url || 'Pagina sin URL';
40
43
  }
41
44
  function getHeader(headers, name) {
42
45
  if (!headers)
@@ -57,70 +60,95 @@ function hasQuestionContent(pages) {
57
60
  }))));
58
61
  return /\b(que|como|cuando|donde|por que|cuanto|faq|preguntas|questions|how|what|why|where|when)\b/.test(text);
59
62
  }
60
- function hasEntitySignal(mainPage) {
61
- const types = (mainPage.jsonLdTypes ?? []).map((type) => normalizeText(type));
63
+ function hasEntitySignal(page) {
64
+ const types = (page.jsonLdTypes ?? []).map((type) => normalizeText(type));
62
65
  const entityTypes = ['organization', 'localbusiness', 'person', 'product', 'service', 'article', 'webpage', 'website'];
63
66
  if (types.some((type) => entityTypes.some((entityType) => type.includes(entityType))))
64
67
  return true;
65
- if (mainPage.ogSiteName && mainPage.ogSiteName.trim().length > 1)
68
+ if (page.ogSiteName && page.ogSiteName.trim().length > 1)
66
69
  return true;
67
- if (mainPage.cmsDetected && mainPage.title && mainPage.title.trim().length > 5)
70
+ if (page.cmsDetected && page.title && page.title.trim().length > 5)
68
71
  return true;
69
72
  return false;
70
73
  }
71
- function hasUsefulSchema(mainPage) {
72
- if ((mainPage.jsonLdCount ?? 0) <= 0)
74
+ function hasUsefulSchema(page) {
75
+ if ((page.jsonLdCount ?? 0) <= 0)
73
76
  return false;
74
- const types = (mainPage.jsonLdTypes ?? []).map((type) => normalizeText(type));
77
+ const types = (page.jsonLdTypes ?? []).map((type) => normalizeText(type));
75
78
  if (types.length === 0)
76
79
  return true;
77
80
  const usefulTypes = ['organization', 'localbusiness', 'product', 'service', 'article', 'faqpage', 'breadcrumblist', 'person', 'webpage', 'website'];
78
81
  return types.some((type) => usefulTypes.some((usefulType) => type.includes(usefulType)));
79
82
  }
80
- function hasFreshnessSignal(mainPage) {
81
- const metaText = normalizeText(textFrom(mainPage.allMetaTags ?? []));
83
+ function hasFreshnessSignal(page) {
84
+ const metaText = normalizeText(textFrom(page.allMetaTags ?? []));
82
85
  const headerText = [
83
- getHeader(mainPage.responseHeaders, 'last-modified'),
84
- getHeader(mainPage.responseHeaders, 'etag'),
85
- mainPage.crawlExtras?.lastModified,
86
- mainPage.crawlExtras?.expires,
86
+ getHeader(page.responseHeaders, 'last-modified'),
87
+ getHeader(page.responseHeaders, 'etag'),
88
+ page.crawlExtras?.lastModified,
89
+ page.crawlExtras?.expires,
87
90
  ].filter(Boolean).join(' ');
88
91
  return Boolean(headerText.trim()) || /datepublished|datemodified|article:published_time|article:modified_time|updated|published/.test(metaText);
89
92
  }
90
- async function getAiBotAccess(pageUrl, timeoutMs, userAgent) {
91
- let robotsTxtUrl = null;
92
- let path = '/';
93
- try {
94
- const parsed = new URL(pageUrl);
95
- robotsTxtUrl = `${parsed.origin}/robots.txt`;
96
- path = parsed.pathname || '/';
97
- }
98
- catch {
99
- return {
100
- robotsTxtUrl: null,
101
- robotsTxtFetched: false,
102
- robotsTxtStatusCode: null,
103
- robotsTxtError: 'URL no valida para comprobar robots.txt',
104
- bots: AI_BOTS.map((bot) => ({ ...bot })),
105
- };
106
- }
93
+ function getInvalidBotAccess(pageUrl) {
94
+ return {
95
+ robotsTxtUrl: null,
96
+ robotsTxtFetched: false,
97
+ robotsTxtStatusCode: null,
98
+ robotsTxtError: `URL no valida para comprobar robots.txt: ${pageUrl}`,
99
+ bots: AI_BOTS.map((bot) => ({ ...bot })),
100
+ };
101
+ }
102
+ async function fetchRobotsForOrigin(origin, timeoutMs, userAgent, cache) {
103
+ const cached = cache.get(origin);
104
+ if (cached)
105
+ return cached;
106
+ const robotsTxtUrl = `${origin}/robots.txt`;
107
107
  const response = await (0, networkUtils_1.fetchText)(robotsTxtUrl, timeoutMs, userAgent);
108
- if (!response.ok || !response.text.trim()) {
109
- return {
108
+ const entry = response.ok && response.text.trim()
109
+ ? {
110
+ robotsTxtUrl,
111
+ robotsTxtFetched: true,
112
+ robotsTxtStatusCode: response.statusCode,
113
+ robotsTxtError: null,
114
+ robotsText: response.text,
115
+ }
116
+ : {
110
117
  robotsTxtUrl,
111
118
  robotsTxtFetched: false,
112
119
  robotsTxtStatusCode: response.statusCode || null,
113
120
  robotsTxtError: response.text ? 'No se pudo leer robots.txt' : 'robots.txt vacio o no existe',
121
+ robotsText: '',
122
+ };
123
+ cache.set(origin, entry);
124
+ return entry;
125
+ }
126
+ async function getAiBotAccess(pageUrl, timeoutMs, userAgent, cache) {
127
+ let parsed;
128
+ try {
129
+ parsed = new URL(pageUrl);
130
+ }
131
+ catch {
132
+ return getInvalidBotAccess(pageUrl);
133
+ }
134
+ const robots = await fetchRobotsForOrigin(parsed.origin, timeoutMs, userAgent, cache);
135
+ if (!robots.robotsTxtFetched || !robots.robotsText) {
136
+ return {
137
+ robotsTxtUrl: robots.robotsTxtUrl,
138
+ robotsTxtFetched: robots.robotsTxtFetched,
139
+ robotsTxtStatusCode: robots.robotsTxtStatusCode,
140
+ robotsTxtError: robots.robotsTxtError,
114
141
  bots: AI_BOTS.map((bot) => ({ ...bot })),
115
142
  };
116
143
  }
144
+ const path = parsed.pathname || '/';
117
145
  return {
118
- robotsTxtUrl,
146
+ robotsTxtUrl: robots.robotsTxtUrl,
119
147
  robotsTxtFetched: true,
120
- robotsTxtStatusCode: response.statusCode,
148
+ robotsTxtStatusCode: robots.robotsTxtStatusCode,
121
149
  robotsTxtError: null,
122
150
  bots: AI_BOTS.map((bot) => {
123
- const blocked = (0, robotsUtils_1.parseRobotsTxtBlocked)(response.text, path, bot.name);
151
+ const blocked = (0, robotsUtils_1.parseRobotsTxtBlocked)(robots.robotsText, path, bot.name);
124
152
  return { ...bot, blocked, allowed: !blocked };
125
153
  }),
126
154
  };
@@ -163,29 +191,46 @@ function buildChecks(issues) {
163
191
  };
164
192
  });
165
193
  }
166
- async function buildGeoReport(params) {
167
- const pages = getAllPages(params.mainPage, params.internalPages);
194
+ function buildProblemsBySeverity(issues) {
195
+ return {
196
+ critical: issues.filter((issue) => issue.severity === 'critical'),
197
+ important: issues.filter((issue) => issue.severity === 'important'),
198
+ warning: issues.filter((issue) => issue.severity === 'warning'),
199
+ info: issues.filter((issue) => issue.severity === 'info'),
200
+ };
201
+ }
202
+ function buildSummary(problemsBySeverity, passed) {
203
+ return {
204
+ criticalCount: problemsBySeverity.critical.length,
205
+ importantCount: problemsBySeverity.important.length,
206
+ warningCount: problemsBySeverity.warning.length,
207
+ infoCount: problemsBySeverity.info.length,
208
+ passedCount: passed.length,
209
+ };
210
+ }
211
+ function buildGeoAnalysis(params) {
168
212
  const issues = [];
169
213
  const passed = [];
170
- const botAccess = await getAiBotAccess(params.mainPage.finalUrl || params.mainPage.url, params.timeoutMs, params.userAgent);
214
+ const focusPage = params.focusPage;
215
+ const pages = params.pages.length > 0 ? params.pages : [focusPage];
171
216
  const totalWords = pages.reduce((total, page) => total + (Number.isFinite(page.wordCount) ? page.wordCount : 0), 0);
172
- if (params.mainPage.noindex || params.mainPage.robotsTxtBlocked || normalizeText(params.mainPage.metaRobots).includes('noindex')) {
217
+ if (focusPage.noindex || focusPage.robotsTxtBlocked || normalizeText(focusPage.metaRobots).includes('noindex')) {
173
218
  pushIssue(issues, {
174
219
  category: 'aiBotAccess',
175
220
  severity: 'critical',
176
221
  message: 'La pagina puede estar bloqueada para indexacion o rastreo.',
177
222
  why: 'Si los buscadores o sistemas de IA no pueden rastrear la pagina, es menos probable que la usen como fuente en respuestas generativas.',
178
- where: 'Meta robots, robots.txt o directivas de indexacion de la URL principal.',
223
+ where: 'Meta robots, robots.txt o directivas de indexacion de la URL analizada.',
179
224
  recommendation: 'Permite indexacion y rastreo en las URLs publicas que deban aparecer en buscadores e IAs.',
180
- evidence: params.mainPage.metaRobots || (params.mainPage.robotsTxtBlocked ? 'robots.txt bloquea la URL' : undefined),
225
+ evidence: focusPage.metaRobots || (focusPage.robotsTxtBlocked ? 'robots.txt bloquea la URL' : undefined),
181
226
  });
182
227
  }
183
228
  else {
184
- passed.push('La URL principal no esta marcada como noindex ni bloqueada por robots en el escaneo base.');
229
+ passed.push('La URL no esta marcada como noindex ni bloqueada por robots en el escaneo base.');
185
230
  }
186
- const blockedSearchBots = botAccess.bots.filter((bot) => bot.blocked === true && (bot.purpose === 'search' || bot.purpose === 'userFetch'));
187
- const blockedTrainingBots = botAccess.bots.filter((bot) => bot.blocked === true && bot.purpose === 'training');
188
- if (!botAccess.robotsTxtFetched) {
231
+ const blockedSearchBots = params.botAccess.bots.filter((bot) => bot.blocked === true && (bot.purpose === 'search' || bot.purpose === 'userFetch'));
232
+ const blockedTrainingBots = params.botAccess.bots.filter((bot) => bot.blocked === true && bot.purpose === 'training');
233
+ if (!params.botAccess.robotsTxtFetched) {
189
234
  pushIssue(issues, {
190
235
  category: 'aiBotAccess',
191
236
  severity: 'warning',
@@ -193,7 +238,7 @@ async function buildGeoReport(params) {
193
238
  why: 'ChatGPT y Claude usan crawlers propios para busqueda o recuperacion. Sin robots.txt no se puede confirmar si tienen acceso.',
194
239
  where: 'Archivo robots.txt del dominio analizado.',
195
240
  recommendation: 'Haz accesible robots.txt y evita bloquear OAI-SearchBot, ChatGPT-User, Claude-SearchBot o Claude-User si buscas visibilidad en IA.',
196
- evidence: botAccess.robotsTxtError || undefined,
241
+ evidence: params.botAccess.robotsTxtError || undefined,
197
242
  });
198
243
  }
199
244
  else if (blockedSearchBots.length > 0) {
@@ -202,13 +247,13 @@ async function buildGeoReport(params) {
202
247
  severity: 'important',
203
248
  message: 'robots.txt bloquea crawlers de busqueda o recuperacion de IA.',
204
249
  why: 'Bloquear bots de busqueda o fetch bajo demanda puede reducir la probabilidad de que ChatGPT o Claude recuperen y citen el contenido.',
205
- where: 'Reglas User-agent/Disallow del robots.txt.',
250
+ where: 'Reglas User-agent/Disallow del robots.txt aplicadas a esta URL.',
206
251
  recommendation: 'Permite OAI-SearchBot, ChatGPT-User, Claude-SearchBot y Claude-User en contenido publico que quieras posicionar en IA.',
207
252
  evidence: blockedSearchBots.map((bot) => bot.name).join(', '),
208
253
  });
209
254
  }
210
255
  else {
211
- passed.push('No se detecta bloqueo explicito para crawlers IA de busqueda o recuperacion.');
256
+ passed.push('No se detecta bloqueo explicito para crawlers IA de busqueda o recuperacion en esta URL.');
212
257
  }
213
258
  if (blockedTrainingBots.length > 0) {
214
259
  pushIssue(issues, {
@@ -227,7 +272,7 @@ async function buildGeoReport(params) {
227
272
  severity: 'important',
228
273
  message: 'Falta contenido con formato de respuesta directa o preguntas frecuentes.',
229
274
  why: 'Las IAs suelen extraer respuestas de bloques claros, autocontenidos y orientados a preguntas reales de usuarios.',
230
- where: 'Contenido visible, headings, FAQs y secciones explicativas.',
275
+ where: 'Contenido visible, headings, FAQs y secciones explicativas de la URL.',
231
276
  recommendation: 'Anade secciones con preguntas y respuestas claras: que es, como funciona, para quien es, precios, pasos, comparativas o casos de uso.',
232
277
  });
233
278
  }
@@ -240,12 +285,12 @@ async function buildGeoReport(params) {
240
285
  severity: 'warning',
241
286
  message: 'El contenido textual parece escaso para respuestas generativas.',
242
287
  why: 'Con poco texto, una IA tiene menos contexto para entender matices, servicios, ventajas y casos de uso.',
243
- where: 'Contenido visible de las paginas analizadas.',
244
- recommendation: 'Amplia las paginas clave con explicaciones utiles, ejemplos, entidades, FAQs y detalles que resuelvan dudas concretas.',
245
- evidence: `${totalWords} palabras detectadas en el conjunto analizado.`,
288
+ where: 'Contenido visible de la URL analizada.',
289
+ recommendation: 'Amplia la pagina con explicaciones utiles, ejemplos, entidades, FAQs y detalles que resuelvan dudas concretas.',
290
+ evidence: `${totalWords} palabras detectadas.`,
246
291
  });
247
292
  }
248
- if (!hasEntitySignal(params.mainPage)) {
293
+ if (!hasEntitySignal(focusPage)) {
249
294
  pushIssue(issues, {
250
295
  category: 'entityClarity',
251
296
  severity: 'important',
@@ -256,15 +301,15 @@ async function buildGeoReport(params) {
256
301
  });
257
302
  }
258
303
  else {
259
- passed.push('Se detectan senales de entidad, marca, autor o tecnologia en los datos del reporte.');
304
+ passed.push('Se detectan senales de entidad, marca, autor o tecnologia en los datos de la URL.');
260
305
  }
261
- if (!hasUsefulSchema(params.mainPage)) {
306
+ if (!hasUsefulSchema(focusPage)) {
262
307
  pushIssue(issues, {
263
308
  category: 'structuredData',
264
309
  severity: 'important',
265
310
  message: 'Faltan datos estructurados utiles para entidades.',
266
311
  why: 'Schema ayuda a buscadores e IAs a interpretar productos, organizaciones, articulos, servicios, FAQs y breadcrumbs.',
267
- where: 'JSON-LD, microdatos o schema.org en el HTML.',
312
+ where: 'JSON-LD, microdatos o schema.org en el HTML de la URL.',
268
313
  recommendation: 'Anade schema Organization, LocalBusiness, Product, Service, Article, FAQPage o BreadcrumbList segun el tipo de pagina.',
269
314
  });
270
315
  }
@@ -285,7 +330,7 @@ async function buildGeoReport(params) {
285
330
  else {
286
331
  passed.push('Se detectan enlaces externos que pueden apoyar confianza o contexto.');
287
332
  }
288
- if (!hasFreshnessSignal(params.mainPage)) {
333
+ if (!hasFreshnessSignal(focusPage)) {
289
334
  pushIssue(issues, {
290
335
  category: 'freshness',
291
336
  severity: 'warning',
@@ -298,22 +343,22 @@ async function buildGeoReport(params) {
298
343
  else {
299
344
  passed.push('Se detectan senales de fecha, actualizacion o cabeceras temporales.');
300
345
  }
301
- const responseTime = params.mainPage.responseTimeMs || params.mainPage.timeToFirstByteMs;
302
- if (params.mainPage.statusCode >= 400 || responseTime > 2500) {
346
+ const responseTime = focusPage.responseTimeMs || focusPage.timeToFirstByteMs;
347
+ if (focusPage.statusCode >= 400 || responseTime > 2500) {
303
348
  pushIssue(issues, {
304
349
  category: 'retrievability',
305
- severity: params.mainPage.statusCode >= 400 ? 'critical' : 'warning',
350
+ severity: focusPage.statusCode >= 400 ? 'critical' : 'warning',
306
351
  message: 'La pagina puede ser dificil de recuperar de forma fiable.',
307
352
  why: 'Si la URL falla o responde muy lento, los sistemas de busqueda con IA pueden descartarla o no usarla como fuente.',
308
353
  where: 'Estado HTTP, tiempo de respuesta y disponibilidad de la URL.',
309
354
  recommendation: 'Corrige errores HTTP y reduce tiempos de respuesta para que la pagina sea recuperable de forma estable.',
310
- evidence: `HTTP ${params.mainPage.statusCode || '-'} / ${responseTime || '-'}ms`,
355
+ evidence: `HTTP ${focusPage.statusCode || '-'} / ${responseTime || '-'}ms`,
311
356
  });
312
357
  }
313
358
  else {
314
- passed.push('La URL principal parece recuperable por estado HTTP y tiempo de respuesta.');
359
+ passed.push('La URL parece recuperable por estado HTTP y tiempo de respuesta.');
315
360
  }
316
- if (params.mainPage.crawlExtras?.waf || params.mainPage.crawlExtras?.rateLimit) {
361
+ if (focusPage.crawlExtras?.waf || focusPage.crawlExtras?.rateLimit) {
317
362
  pushIssue(issues, {
318
363
  category: 'retrievability',
319
364
  severity: 'info',
@@ -321,31 +366,53 @@ async function buildGeoReport(params) {
321
366
  why: 'Un firewall o limite agresivo puede bloquear crawlers de IA aunque robots.txt permita el acceso.',
322
367
  where: 'Cabeceras, infraestructura, WAF/CDN o protecciones anti-bot.',
323
368
  recommendation: 'Revisa reglas del CDN/WAF para permitir crawlers de busqueda IA verificados en contenido publico.',
324
- evidence: textFrom({ waf: params.mainPage.crawlExtras.waf, rateLimit: params.mainPage.crawlExtras.rateLimit }).slice(0, 180),
369
+ evidence: textFrom({ waf: focusPage.crawlExtras.waf, rateLimit: focusPage.crawlExtras.rateLimit }).slice(0, 180),
325
370
  });
326
371
  }
327
- const problemsBySeverity = {
328
- critical: issues.filter((issue) => issue.severity === 'critical'),
329
- important: issues.filter((issue) => issue.severity === 'important'),
330
- warning: issues.filter((issue) => issue.severity === 'warning'),
331
- info: issues.filter((issue) => issue.severity === 'info'),
372
+ return { issues, passed };
373
+ }
374
+ function buildGeoPayload(analysis) {
375
+ const problemsBySeverity = buildProblemsBySeverity(analysis.issues);
376
+ return {
377
+ score: scoreGeoReport(analysis.issues, analysis.passed),
378
+ summary: buildSummary(problemsBySeverity, analysis.passed),
379
+ checks: buildChecks(analysis.issues),
380
+ problemsBySeverity,
381
+ passed: analysis.passed,
382
+ };
383
+ }
384
+ async function buildGeoPageReport(page, timeoutMs, userAgent, cache) {
385
+ const pageUrl = getPageUrl(page);
386
+ const botAccess = await getAiBotAccess(pageUrl, timeoutMs, userAgent, cache);
387
+ const payload = buildGeoPayload(buildGeoAnalysis({ focusPage: page, pages: [page], botAccess }));
388
+ return {
389
+ url: page.url || pageUrl,
390
+ finalUrl: page.finalUrl || null,
391
+ title: page.title || null,
392
+ ...payload,
393
+ botAccess,
332
394
  };
395
+ }
396
+ async function buildGeoReport(params) {
397
+ const pages = getAllPages(params.mainPage, params.internalPages);
398
+ const robotsCache = new Map();
399
+ const mainBotAccess = await getAiBotAccess(getPageUrl(params.mainPage), params.timeoutMs, params.userAgent, robotsCache);
400
+ const sitePayload = buildGeoPayload(buildGeoAnalysis({
401
+ focusPage: params.mainPage,
402
+ pages,
403
+ botAccess: mainBotAccess,
404
+ }));
405
+ const pageReports = [];
406
+ for (const page of pages) {
407
+ pageReports.push(await buildGeoPageReport(page, params.timeoutMs, params.userAgent, robotsCache));
408
+ }
333
409
  return {
334
410
  version: '2026-05-geo-v1',
335
411
  source: 'n8n-node',
336
412
  generatedAt: new Date().toISOString(),
337
- score: scoreGeoReport(issues, passed),
338
- summary: {
339
- criticalCount: problemsBySeverity.critical.length,
340
- importantCount: problemsBySeverity.important.length,
341
- warningCount: problemsBySeverity.warning.length,
342
- infoCount: problemsBySeverity.info.length,
343
- passedCount: passed.length,
344
- },
345
- checks: buildChecks(issues),
346
- problemsBySeverity,
347
- passed,
348
- botAccess,
413
+ ...sitePayload,
414
+ botAccess: mainBotAccess,
415
+ pages: pageReports,
349
416
  };
350
417
  }
351
418
  //# sourceMappingURL=geoUtils.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"geoUtils.js","sourceRoot":"","sources":["../nodes/SeoScanner/geoUtils.ts"],"names":[],"mappings":";;AAwNA,wCAiMC;AAzZD,iDAA2C;AAC3C,+CAAsD;AAuDtD,MAAM,OAAO,GAAmB;IAC/B,EAAE,IAAI,EAAE,eAAe,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE;IAC1E,EAAE,IAAI,EAAE,cAAc,EAAE,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE;IAC5E,EAAE,IAAI,EAAE,kBAAkB,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE;IAC7E,EAAE,IAAI,EAAE,aAAa,EAAE,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE;IAC3E,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE;IACrE,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE;CACxE,CAAC;AAEF,SAAS,SAAS,CAAC,MAAkB,EAAE,KAA2B;IACjE,MAAM,CAAC,IAAI,CAAC;QACX,EAAE,EAAE,OAAO,KAAK,CAAC,QAAQ,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE;QAChD,GAAG,KAAK;KACR,CAAC,CAAC;AACJ,CAAC;AAED,SAAS,aAAa,CAAC,KAAc;IACpC,OAAO,MAAM,CAAC,KAAK,IAAI,EAAE,CAAC;SACxB,SAAS,CAAC,KAAK,CAAC;SAChB,OAAO,CAAC,kBAAkB,EAAE,EAAE,CAAC;SAC/B,IAAI,EAAE;SACN,WAAW,EAAE,CAAC;AACjB,CAAC;AAED,SAAS,QAAQ,CAAC,KAAc;IAC/B,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,EAAE,CAAC;IACrD,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,OAAO,KAAK,KAAK,SAAS;QAAE,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC;IAC/G,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC/D,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,MAAM,CAAC,MAAM,CAAC,KAAgC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC9G,OAAO,EAAE,CAAC;AACX,CAAC;AAED,SAAS,WAAW,CAAC,QAAmB,EAAE,aAAsC;IAC/E,OAAO,CAAC,QAAQ,EAAE,GAAG,CAAC,aAAa,IAAI,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,IAAI,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;AAC9F,CAAC;AAED,SAAS,SAAS,CAAC,OAA2C,EAAE,IAAY;IAC3E,IAAI,CAAC,OAAO;QAAE,OAAO,EAAE,CAAC;IACxB,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;IAC5D,IAAI,MAAM;QAAE,OAAO,MAAM,CAAC;IAC1B,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,UAAU,CAAC,WAAW,EAAE,KAAK,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;IACvG,OAAO,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;AAChC,CAAC;AAED,SAAS,kBAAkB,CAAC,KAAkB;IAC7C,MAAM,IAAI,GAAG,aAAa,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QACxD,KAAK,EAAE,IAAI,CAAC,KAAK;QACjB,eAAe,EAAE,IAAI,CAAC,eAAe;QACrC,OAAO,EAAE,IAAI,CAAC,OAAO;QACrB,QAAQ,EAAE,IAAI,CAAC,QAAQ;QACvB,eAAe,EAAE,IAAI,CAAC,eAAe;KACrC,CAAC,CAAC,CAAC,CAAC,CAAC;IACN,OAAO,4FAA4F,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAChH,CAAC;AAED,SAAS,eAAe,CAAC,QAAmB;IAC3C,MAAM,KAAK,GAAG,CAAC,QAAQ,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC;IAC9E,MAAM,WAAW,GAAG,CAAC,cAAc,EAAE,eAAe,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC;IACvH,IAAI,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IACnG,IAAI,QAAQ,CAAC,UAAU,IAAI,QAAQ,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IAC9E,IAAI,QAAQ,CAAC,WAAW,IAAI,QAAQ,CAAC,KAAK,IAAI,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IAC5F,OAAO,KAAK,CAAC;AACd,CAAC;AAED,SAAS,eAAe,CAAC,QAAmB;IAC3C,IAAI,CAAC,QAAQ,CAAC,WAAW,IAAI,CAAC,CAAC,IAAI,CAAC;QAAE,OAAO,KAAK,CAAC;IACnD,MAAM,KAAK,GAAG,CAAC,QAAQ,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC;IAC9E,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACpC,MAAM,WAAW,GAAG,CAAC,cAAc,EAAE,eAAe,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,gBAAgB,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC;IACpJ,OAAO,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;AAC1F,CAAC;AAED,SAAS,kBAAkB,CAAC,QAAmB;IAC9C,MAAM,QAAQ,GAAG,aAAa,CAAC,QAAQ,CAAC,QAAQ,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC,CAAC;IACrE,MAAM,UAAU,GAAG;QAClB,SAAS,CAAC,QAAQ,CAAC,eAAe,EAAE,eAAe,CAAC;QACpD,SAAS,CAAC,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;QAC3C,QAAQ,CAAC,WAAW,EAAE,YAAY;QAClC,QAAQ,CAAC,WAAW,EAAE,OAAO;KAC7B,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC5B,OAAO,OAAO,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC,IAAI,2FAA2F,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;AACjJ,CAAC;AAED,KAAK,UAAU,cAAc,CAAC,OAAe,EAAE,SAAiB,EAAE,SAAiB;IAClF,IAAI,YAAY,GAAkB,IAAI,CAAC;IACvC,IAAI,IAAI,GAAG,GAAG,CAAC;IACf,IAAI,CAAC;QACJ,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC;QAChC,YAAY,GAAG,GAAG,MAAM,CAAC,MAAM,aAAa,CAAC;QAC7C,IAAI,GAAG,MAAM,CAAC,QAAQ,IAAI,GAAG,CAAC;IAC/B,CAAC;IAAC,MAAM,CAAC;QACR,OAAO;YACN,YAAY,EAAE,IAAI;YAClB,gBAAgB,EAAE,KAAK;YACvB,mBAAmB,EAAE,IAAI;YACzB,cAAc,EAAE,yCAAyC;YACzD,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,GAAG,EAAE,CAAC,CAAC;SACxC,CAAC;IACH,CAAC;IAED,MAAM,QAAQ,GAAG,MAAM,IAAA,wBAAS,EAAC,YAAY,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC;IACrE,IAAI,CAAC,QAAQ,CAAC,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC;QAC3C,OAAO;YACN,YAAY;YACZ,gBAAgB,EAAE,KAAK;YACvB,mBAAmB,EAAE,QAAQ,CAAC,UAAU,IAAI,IAAI;YAChD,cAAc,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,4BAA4B,CAAC,CAAC,CAAC,8BAA8B;YAC7F,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,GAAG,EAAE,CAAC,CAAC;SACxC,CAAC;IACH,CAAC;IAED,OAAO;QACN,YAAY;QACZ,gBAAgB,EAAE,IAAI;QACtB,mBAAmB,EAAE,QAAQ,CAAC,UAAU;QACxC,cAAc,EAAE,IAAI;QACpB,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE;YACzB,MAAM,OAAO,GAAG,IAAA,mCAAqB,EAAC,QAAQ,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC;YACrE,OAAO,EAAE,GAAG,GAAG,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,OAAO,EAAE,CAAC;QAC/C,CAAC,CAAC;KACF,CAAC;AACH,CAAC;AAED,SAAS,cAAc,CAAC,MAAkB,EAAE,MAAgB;IAC3D,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE;QAC9C,IAAI,KAAK,CAAC,QAAQ,KAAK,UAAU;YAAE,OAAO,KAAK,GAAG,EAAE,CAAC;QACrD,IAAI,KAAK,CAAC,QAAQ,KAAK,WAAW;YAAE,OAAO,KAAK,GAAG,EAAE,CAAC;QACtD,IAAI,KAAK,CAAC,QAAQ,KAAK,SAAS;YAAE,OAAO,KAAK,GAAG,CAAC,CAAC;QACnD,OAAO,KAAK,GAAG,CAAC,CAAC;IAClB,CAAC,EAAE,CAAC,CAAC,CAAC;IACN,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAC9C,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,GAAG,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC;AAC1D,CAAC;AAED,SAAS,WAAW,CAAC,MAAkB;IACtC,MAAM,MAAM,GAAgC;QAC3C,WAAW,EAAE,mBAAmB;QAChC,eAAe,EAAE,uBAAuB;QACxC,aAAa,EAAE,qBAAqB;QACpC,aAAa,EAAE,mBAAmB;QAClC,cAAc,EAAE,qBAAqB;QACrC,SAAS,EAAE,YAAY;QACvB,cAAc,EAAE,iBAAiB;KACjC,CAAC;IACF,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAkB,CAAC;IACxD,OAAO,UAAU,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE;QAClC,MAAM,cAAc,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC;QAC7E,MAAM,KAAK,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,QAAQ,KAAK,UAAU,CAAC;eACvE,cAAc,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,QAAQ,KAAK,WAAW,CAAC;eAC9D,cAAc,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,QAAQ,KAAK,SAAS,CAAC;eAC5D,cAAc,CAAC,CAAC,CAAC,CAAC;QACtB,OAAO;YACN,EAAE,EAAE,QAAQ;YACZ,KAAK,EAAE,MAAM,CAAC,QAAQ,CAAC;YACvB,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,KAAK,UAAU,IAAI,KAAK,CAAC,QAAQ,KAAK,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,QAAQ;YACnH,MAAM,EAAE,KAAK,EAAE,OAAO,IAAI,iDAAiD;SAC3E,CAAC;IACH,CAAC,CAAC,CAAC;AACJ,CAAC;AAEM,KAAK,UAAU,cAAc,CAAC,MAKpC;IACA,MAAM,KAAK,GAAG,WAAW,CAAC,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,aAAa,CAAC,CAAC;IACjE,MAAM,MAAM,GAAe,EAAE,CAAC;IAC9B,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,MAAM,SAAS,GAAG,MAAM,cAAc,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,SAAS,CAAC,CAAC;IAC5H,MAAM,UAAU,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,CAAC,KAAK,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAEpH,IAAI,MAAM,CAAC,QAAQ,CAAC,OAAO,IAAI,MAAM,CAAC,QAAQ,CAAC,gBAAgB,IAAI,aAAa,CAAC,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;QAClI,SAAS,CAAC,MAAM,EAAE;YACjB,QAAQ,EAAE,aAAa;YACvB,QAAQ,EAAE,UAAU;YACpB,OAAO,EAAE,4DAA4D;YACrE,GAAG,EAAE,uIAAuI;YAC5I,KAAK,EAAE,yEAAyE;YAChF,cAAc,EAAE,2FAA2F;YAC3G,QAAQ,EAAE,MAAM,CAAC,QAAQ,CAAC,UAAU,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,gBAAgB,CAAC,CAAC,CAAC,2BAA2B,CAAC,CAAC,CAAC,SAAS,CAAC;SACpH,CAAC,CAAC;IACJ,CAAC;SAAM,CAAC;QACP,MAAM,CAAC,IAAI,CAAC,2FAA2F,CAAC,CAAC;IAC1G,CAAC;IAED,MAAM,iBAAiB,GAAG,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,OAAO,KAAK,IAAI,IAAI,CAAC,GAAG,CAAC,OAAO,KAAK,QAAQ,IAAI,GAAG,CAAC,OAAO,KAAK,WAAW,CAAC,CAAC,CAAC;IAC5I,MAAM,mBAAmB,GAAG,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,OAAO,KAAK,IAAI,IAAI,GAAG,CAAC,OAAO,KAAK,UAAU,CAAC,CAAC;IAC/G,IAAI,CAAC,SAAS,CAAC,gBAAgB,EAAE,CAAC;QACjC,SAAS,CAAC,MAAM,EAAE;YACjB,QAAQ,EAAE,aAAa;YACvB,QAAQ,EAAE,SAAS;YACnB,OAAO,EAAE,sDAAsD;YAC/D,GAAG,EAAE,6HAA6H;YAClI,KAAK,EAAE,2CAA2C;YAClD,cAAc,EAAE,oIAAoI;YACpJ,QAAQ,EAAE,SAAS,CAAC,cAAc,IAAI,SAAS;SAC/C,CAAC,CAAC;IACJ,CAAC;SAAM,IAAI,iBAAiB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACzC,SAAS,CAAC,MAAM,EAAE;YACjB,QAAQ,EAAE,aAAa;YACvB,QAAQ,EAAE,WAAW;YACrB,OAAO,EAAE,+DAA+D;YACxE,GAAG,EAAE,sIAAsI;YAC3I,KAAK,EAAE,4CAA4C;YACnD,cAAc,EAAE,wHAAwH;YACxI,QAAQ,EAAE,iBAAiB,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;SAC7D,CAAC,CAAC;IACJ,CAAC;SAAM,CAAC;QACP,MAAM,CAAC,IAAI,CAAC,8EAA8E,CAAC,CAAC;IAC7F,CAAC;IAED,IAAI,mBAAmB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACpC,SAAS,CAAC,MAAM,EAAE;YACjB,QAAQ,EAAE,aAAa;YACvB,QAAQ,EAAE,MAAM;YAChB,OAAO,EAAE,kDAAkD;YAC3D,GAAG,EAAE,wHAAwH;YAC7H,KAAK,EAAE,+CAA+C;YACtD,cAAc,EAAE,iIAAiI;YACjJ,QAAQ,EAAE,mBAAmB,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;SAC/D,CAAC,CAAC;IACJ,CAAC;IAED,IAAI,CAAC,kBAAkB,CAAC,KAAK,CAAC,EAAE,CAAC;QAChC,SAAS,CAAC,MAAM,EAAE;YACjB,QAAQ,EAAE,iBAAiB;YAC3B,QAAQ,EAAE,WAAW;YACrB,OAAO,EAAE,0EAA0E;YACnF,GAAG,EAAE,kHAAkH;YACvH,KAAK,EAAE,6DAA6D;YACpE,cAAc,EAAE,uIAAuI;SACvJ,CAAC,CAAC;IACJ,CAAC;SAAM,CAAC;QACP,MAAM,CAAC,IAAI,CAAC,4EAA4E,CAAC,CAAC;IAC3F,CAAC;IAED,IAAI,UAAU,GAAG,CAAC,IAAI,UAAU,GAAG,GAAG,EAAE,CAAC;QACxC,SAAS,CAAC,MAAM,EAAE;YACjB,QAAQ,EAAE,iBAAiB;YAC3B,QAAQ,EAAE,SAAS;YACnB,OAAO,EAAE,iEAAiE;YAC1E,GAAG,EAAE,wGAAwG;YAC7G,KAAK,EAAE,8CAA8C;YACrD,cAAc,EAAE,wHAAwH;YACxI,QAAQ,EAAE,GAAG,UAAU,gDAAgD;SACvE,CAAC,CAAC;IACJ,CAAC;IAED,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC;QACvC,SAAS,CAAC,MAAM,EAAE;YACjB,QAAQ,EAAE,eAAe;YACzB,QAAQ,EAAE,WAAW;YACrB,OAAO,EAAE,2DAA2D;YACpE,GAAG,EAAE,8IAA8I;YACnJ,KAAK,EAAE,qFAAqF;YAC5F,cAAc,EAAE,oHAAoH;SACpI,CAAC,CAAC;IACJ,CAAC;SAAM,CAAC;QACP,MAAM,CAAC,IAAI,CAAC,qFAAqF,CAAC,CAAC;IACpG,CAAC;IAED,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC;QACvC,SAAS,CAAC,MAAM,EAAE;YACjB,QAAQ,EAAE,gBAAgB;YAC1B,QAAQ,EAAE,WAAW;YACrB,OAAO,EAAE,mDAAmD;YAC5D,GAAG,EAAE,oHAAoH;YACzH,KAAK,EAAE,8CAA8C;YACrD,cAAc,EAAE,wHAAwH;SACxI,CAAC,CAAC;IACJ,CAAC;SAAM,CAAC;QACP,MAAM,CAAC,IAAI,CAAC,8DAA8D,CAAC,CAAC;IAC7E,CAAC;IAED,MAAM,aAAa,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,CAAC,KAAK,GAAG,CAAC,IAAI,CAAC,aAAa,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAC1F,IAAI,aAAa,KAAK,CAAC,EAAE,CAAC;QACzB,SAAS,CAAC,MAAM,EAAE;YACjB,QAAQ,EAAE,eAAe;YACzB,QAAQ,EAAE,SAAS;YACnB,OAAO,EAAE,yDAAyD;YAClE,GAAG,EAAE,yHAAyH;YAC9H,KAAK,EAAE,iFAAiF;YACxF,cAAc,EAAE,sIAAsI;SACtJ,CAAC,CAAC;IACJ,CAAC;SAAM,CAAC;QACP,MAAM,CAAC,IAAI,CAAC,sEAAsE,CAAC,CAAC;IACrF,CAAC;IAED,IAAI,CAAC,kBAAkB,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC1C,SAAS,CAAC,MAAM,EAAE;YACjB,QAAQ,EAAE,WAAW;YACrB,QAAQ,EAAE,SAAS;YACnB,OAAO,EAAE,iDAAiD;YAC1D,GAAG,EAAE,qGAAqG;YAC1G,KAAK,EAAE,sGAAsG;YAC7G,cAAc,EAAE,uGAAuG;SACvH,CAAC,CAAC;IACJ,CAAC;SAAM,CAAC;QACP,MAAM,CAAC,IAAI,CAAC,qEAAqE,CAAC,CAAC;IACpF,CAAC;IAED,MAAM,YAAY,GAAG,MAAM,CAAC,QAAQ,CAAC,cAAc,IAAI,MAAM,CAAC,QAAQ,CAAC,iBAAiB,CAAC;IACzF,IAAI,MAAM,CAAC,QAAQ,CAAC,UAAU,IAAI,GAAG,IAAI,YAAY,GAAG,IAAI,EAAE,CAAC;QAC9D,SAAS,CAAC,MAAM,EAAE;YACjB,QAAQ,EAAE,gBAAgB;YAC1B,QAAQ,EAAE,MAAM,CAAC,QAAQ,CAAC,UAAU,IAAI,GAAG,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS;YACpE,OAAO,EAAE,2DAA2D;YACpE,GAAG,EAAE,mHAAmH;YACxH,KAAK,EAAE,8DAA8D;YACrE,cAAc,EAAE,yGAAyG;YACzH,QAAQ,EAAE,QAAQ,MAAM,CAAC,QAAQ,CAAC,UAAU,IAAI,GAAG,MAAM,YAAY,IAAI,GAAG,IAAI;SAChF,CAAC,CAAC;IACJ,CAAC;SAAM,CAAC;QACP,MAAM,CAAC,IAAI,CAAC,4EAA4E,CAAC,CAAC;IAC3F,CAAC;IAED,IAAI,MAAM,CAAC,QAAQ,CAAC,WAAW,EAAE,GAAG,IAAI,MAAM,CAAC,QAAQ,CAAC,WAAW,EAAE,SAAS,EAAE,CAAC;QAChF,SAAS,CAAC,MAAM,EAAE;YACjB,QAAQ,EAAE,gBAAgB;YAC1B,QAAQ,EAAE,MAAM;YAChB,OAAO,EAAE,2DAA2D;YACpE,GAAG,EAAE,kGAAkG;YACvG,KAAK,EAAE,8DAA8D;YACrE,cAAc,EAAE,mGAAmG;YACnH,QAAQ,EAAE,QAAQ,CAAC,EAAE,GAAG,EAAE,MAAM,CAAC,QAAQ,CAAC,WAAW,CAAC,GAAG,EAAE,SAAS,EAAE,MAAM,CAAC,QAAQ,CAAC,WAAW,CAAC,SAAS,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC;SAC5H,CAAC,CAAC;IACJ,CAAC;IAED,MAAM,kBAAkB,GAAoC;QAC3D,QAAQ,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,QAAQ,KAAK,UAAU,CAAC;QACjE,SAAS,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,QAAQ,KAAK,WAAW,CAAC;QACnE,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,QAAQ,KAAK,SAAS,CAAC;QAC/D,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,QAAQ,KAAK,MAAM,CAAC;KACzD,CAAC;IAEF,OAAO;QACN,OAAO,EAAE,gBAAgB;QACzB,MAAM,EAAE,UAAU;QAClB,WAAW,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACrC,KAAK,EAAE,cAAc,CAAC,MAAM,EAAE,MAAM,CAAC;QACrC,OAAO,EAAE;YACR,aAAa,EAAE,kBAAkB,CAAC,QAAQ,CAAC,MAAM;YACjD,cAAc,EAAE,kBAAkB,CAAC,SAAS,CAAC,MAAM;YACnD,YAAY,EAAE,kBAAkB,CAAC,OAAO,CAAC,MAAM;YAC/C,SAAS,EAAE,kBAAkB,CAAC,IAAI,CAAC,MAAM;YACzC,WAAW,EAAE,MAAM,CAAC,MAAM;SAC1B;QACD,MAAM,EAAE,WAAW,CAAC,MAAM,CAAC;QAC3B,kBAAkB;QAClB,MAAM;QACN,SAAS;KACT,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"geoUtils.js","sourceRoot":"","sources":["../nodes/SeoScanner/geoUtils.ts"],"names":[],"mappings":"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"}
@@ -36,7 +36,10 @@ function textFrom(value) {
36
36
  return '';
37
37
  }
38
38
  function getAllPages(mainPage, internalPages) {
39
- return [mainPage, ...(internalPages ?? [])].filter((page) => Boolean(page && page.finalUrl));
39
+ return [mainPage, ...(internalPages ?? [])].filter((page) => Boolean(page && (page.finalUrl || page.url)));
40
+ }
41
+ function getPageUrl(page) {
42
+ return page.finalUrl || page.url || 'Pagina sin URL';
40
43
  }
41
44
  function getHeader(headers, name) {
42
45
  if (!headers)
@@ -57,70 +60,95 @@ function hasQuestionContent(pages) {
57
60
  }))));
58
61
  return /\b(que|como|cuando|donde|por que|cuanto|faq|preguntas|questions|how|what|why|where|when)\b/.test(text);
59
62
  }
60
- function hasEntitySignal(mainPage) {
61
- const types = (mainPage.jsonLdTypes ?? []).map((type) => normalizeText(type));
63
+ function hasEntitySignal(page) {
64
+ const types = (page.jsonLdTypes ?? []).map((type) => normalizeText(type));
62
65
  const entityTypes = ['organization', 'localbusiness', 'person', 'product', 'service', 'article', 'webpage', 'website'];
63
66
  if (types.some((type) => entityTypes.some((entityType) => type.includes(entityType))))
64
67
  return true;
65
- if (mainPage.ogSiteName && mainPage.ogSiteName.trim().length > 1)
68
+ if (page.ogSiteName && page.ogSiteName.trim().length > 1)
66
69
  return true;
67
- if (mainPage.cmsDetected && mainPage.title && mainPage.title.trim().length > 5)
70
+ if (page.cmsDetected && page.title && page.title.trim().length > 5)
68
71
  return true;
69
72
  return false;
70
73
  }
71
- function hasUsefulSchema(mainPage) {
72
- if ((mainPage.jsonLdCount ?? 0) <= 0)
74
+ function hasUsefulSchema(page) {
75
+ if ((page.jsonLdCount ?? 0) <= 0)
73
76
  return false;
74
- const types = (mainPage.jsonLdTypes ?? []).map((type) => normalizeText(type));
77
+ const types = (page.jsonLdTypes ?? []).map((type) => normalizeText(type));
75
78
  if (types.length === 0)
76
79
  return true;
77
80
  const usefulTypes = ['organization', 'localbusiness', 'product', 'service', 'article', 'faqpage', 'breadcrumblist', 'person', 'webpage', 'website'];
78
81
  return types.some((type) => usefulTypes.some((usefulType) => type.includes(usefulType)));
79
82
  }
80
- function hasFreshnessSignal(mainPage) {
81
- const metaText = normalizeText(textFrom(mainPage.allMetaTags ?? []));
83
+ function hasFreshnessSignal(page) {
84
+ const metaText = normalizeText(textFrom(page.allMetaTags ?? []));
82
85
  const headerText = [
83
- getHeader(mainPage.responseHeaders, 'last-modified'),
84
- getHeader(mainPage.responseHeaders, 'etag'),
85
- mainPage.crawlExtras?.lastModified,
86
- mainPage.crawlExtras?.expires,
86
+ getHeader(page.responseHeaders, 'last-modified'),
87
+ getHeader(page.responseHeaders, 'etag'),
88
+ page.crawlExtras?.lastModified,
89
+ page.crawlExtras?.expires,
87
90
  ].filter(Boolean).join(' ');
88
91
  return Boolean(headerText.trim()) || /datepublished|datemodified|article:published_time|article:modified_time|updated|published/.test(metaText);
89
92
  }
90
- async function getAiBotAccess(pageUrl, timeoutMs, userAgent) {
91
- let robotsTxtUrl = null;
92
- let path = '/';
93
- try {
94
- const parsed = new URL(pageUrl);
95
- robotsTxtUrl = `${parsed.origin}/robots.txt`;
96
- path = parsed.pathname || '/';
97
- }
98
- catch {
99
- return {
100
- robotsTxtUrl: null,
101
- robotsTxtFetched: false,
102
- robotsTxtStatusCode: null,
103
- robotsTxtError: 'URL no valida para comprobar robots.txt',
104
- bots: AI_BOTS.map((bot) => ({ ...bot })),
105
- };
106
- }
93
+ function getInvalidBotAccess(pageUrl) {
94
+ return {
95
+ robotsTxtUrl: null,
96
+ robotsTxtFetched: false,
97
+ robotsTxtStatusCode: null,
98
+ robotsTxtError: `URL no valida para comprobar robots.txt: ${pageUrl}`,
99
+ bots: AI_BOTS.map((bot) => ({ ...bot })),
100
+ };
101
+ }
102
+ async function fetchRobotsForOrigin(origin, timeoutMs, userAgent, cache) {
103
+ const cached = cache.get(origin);
104
+ if (cached)
105
+ return cached;
106
+ const robotsTxtUrl = `${origin}/robots.txt`;
107
107
  const response = await (0, networkUtils_1.fetchText)(robotsTxtUrl, timeoutMs, userAgent);
108
- if (!response.ok || !response.text.trim()) {
109
- return {
108
+ const entry = response.ok && response.text.trim()
109
+ ? {
110
+ robotsTxtUrl,
111
+ robotsTxtFetched: true,
112
+ robotsTxtStatusCode: response.statusCode,
113
+ robotsTxtError: null,
114
+ robotsText: response.text,
115
+ }
116
+ : {
110
117
  robotsTxtUrl,
111
118
  robotsTxtFetched: false,
112
119
  robotsTxtStatusCode: response.statusCode || null,
113
120
  robotsTxtError: response.text ? 'No se pudo leer robots.txt' : 'robots.txt vacio o no existe',
121
+ robotsText: '',
122
+ };
123
+ cache.set(origin, entry);
124
+ return entry;
125
+ }
126
+ async function getAiBotAccess(pageUrl, timeoutMs, userAgent, cache) {
127
+ let parsed;
128
+ try {
129
+ parsed = new URL(pageUrl);
130
+ }
131
+ catch {
132
+ return getInvalidBotAccess(pageUrl);
133
+ }
134
+ const robots = await fetchRobotsForOrigin(parsed.origin, timeoutMs, userAgent, cache);
135
+ if (!robots.robotsTxtFetched || !robots.robotsText) {
136
+ return {
137
+ robotsTxtUrl: robots.robotsTxtUrl,
138
+ robotsTxtFetched: robots.robotsTxtFetched,
139
+ robotsTxtStatusCode: robots.robotsTxtStatusCode,
140
+ robotsTxtError: robots.robotsTxtError,
114
141
  bots: AI_BOTS.map((bot) => ({ ...bot })),
115
142
  };
116
143
  }
144
+ const path = parsed.pathname || '/';
117
145
  return {
118
- robotsTxtUrl,
146
+ robotsTxtUrl: robots.robotsTxtUrl,
119
147
  robotsTxtFetched: true,
120
- robotsTxtStatusCode: response.statusCode,
148
+ robotsTxtStatusCode: robots.robotsTxtStatusCode,
121
149
  robotsTxtError: null,
122
150
  bots: AI_BOTS.map((bot) => {
123
- const blocked = (0, robotsUtils_1.parseRobotsTxtBlocked)(response.text, path, bot.name);
151
+ const blocked = (0, robotsUtils_1.parseRobotsTxtBlocked)(robots.robotsText, path, bot.name);
124
152
  return { ...bot, blocked, allowed: !blocked };
125
153
  }),
126
154
  };
@@ -163,29 +191,46 @@ function buildChecks(issues) {
163
191
  };
164
192
  });
165
193
  }
166
- async function buildGeoReport(params) {
167
- const pages = getAllPages(params.mainPage, params.internalPages);
194
+ function buildProblemsBySeverity(issues) {
195
+ return {
196
+ critical: issues.filter((issue) => issue.severity === 'critical'),
197
+ important: issues.filter((issue) => issue.severity === 'important'),
198
+ warning: issues.filter((issue) => issue.severity === 'warning'),
199
+ info: issues.filter((issue) => issue.severity === 'info'),
200
+ };
201
+ }
202
+ function buildSummary(problemsBySeverity, passed) {
203
+ return {
204
+ criticalCount: problemsBySeverity.critical.length,
205
+ importantCount: problemsBySeverity.important.length,
206
+ warningCount: problemsBySeverity.warning.length,
207
+ infoCount: problemsBySeverity.info.length,
208
+ passedCount: passed.length,
209
+ };
210
+ }
211
+ function buildGeoAnalysis(params) {
168
212
  const issues = [];
169
213
  const passed = [];
170
- const botAccess = await getAiBotAccess(params.mainPage.finalUrl || params.mainPage.url, params.timeoutMs, params.userAgent);
214
+ const focusPage = params.focusPage;
215
+ const pages = params.pages.length > 0 ? params.pages : [focusPage];
171
216
  const totalWords = pages.reduce((total, page) => total + (Number.isFinite(page.wordCount) ? page.wordCount : 0), 0);
172
- if (params.mainPage.noindex || params.mainPage.robotsTxtBlocked || normalizeText(params.mainPage.metaRobots).includes('noindex')) {
217
+ if (focusPage.noindex || focusPage.robotsTxtBlocked || normalizeText(focusPage.metaRobots).includes('noindex')) {
173
218
  pushIssue(issues, {
174
219
  category: 'aiBotAccess',
175
220
  severity: 'critical',
176
221
  message: 'La pagina puede estar bloqueada para indexacion o rastreo.',
177
222
  why: 'Si los buscadores o sistemas de IA no pueden rastrear la pagina, es menos probable que la usen como fuente en respuestas generativas.',
178
- where: 'Meta robots, robots.txt o directivas de indexacion de la URL principal.',
223
+ where: 'Meta robots, robots.txt o directivas de indexacion de la URL analizada.',
179
224
  recommendation: 'Permite indexacion y rastreo en las URLs publicas que deban aparecer en buscadores e IAs.',
180
- evidence: params.mainPage.metaRobots || (params.mainPage.robotsTxtBlocked ? 'robots.txt bloquea la URL' : undefined),
225
+ evidence: focusPage.metaRobots || (focusPage.robotsTxtBlocked ? 'robots.txt bloquea la URL' : undefined),
181
226
  });
182
227
  }
183
228
  else {
184
- passed.push('La URL principal no esta marcada como noindex ni bloqueada por robots en el escaneo base.');
229
+ passed.push('La URL no esta marcada como noindex ni bloqueada por robots en el escaneo base.');
185
230
  }
186
- const blockedSearchBots = botAccess.bots.filter((bot) => bot.blocked === true && (bot.purpose === 'search' || bot.purpose === 'userFetch'));
187
- const blockedTrainingBots = botAccess.bots.filter((bot) => bot.blocked === true && bot.purpose === 'training');
188
- if (!botAccess.robotsTxtFetched) {
231
+ const blockedSearchBots = params.botAccess.bots.filter((bot) => bot.blocked === true && (bot.purpose === 'search' || bot.purpose === 'userFetch'));
232
+ const blockedTrainingBots = params.botAccess.bots.filter((bot) => bot.blocked === true && bot.purpose === 'training');
233
+ if (!params.botAccess.robotsTxtFetched) {
189
234
  pushIssue(issues, {
190
235
  category: 'aiBotAccess',
191
236
  severity: 'warning',
@@ -193,7 +238,7 @@ async function buildGeoReport(params) {
193
238
  why: 'ChatGPT y Claude usan crawlers propios para busqueda o recuperacion. Sin robots.txt no se puede confirmar si tienen acceso.',
194
239
  where: 'Archivo robots.txt del dominio analizado.',
195
240
  recommendation: 'Haz accesible robots.txt y evita bloquear OAI-SearchBot, ChatGPT-User, Claude-SearchBot o Claude-User si buscas visibilidad en IA.',
196
- evidence: botAccess.robotsTxtError || undefined,
241
+ evidence: params.botAccess.robotsTxtError || undefined,
197
242
  });
198
243
  }
199
244
  else if (blockedSearchBots.length > 0) {
@@ -202,13 +247,13 @@ async function buildGeoReport(params) {
202
247
  severity: 'important',
203
248
  message: 'robots.txt bloquea crawlers de busqueda o recuperacion de IA.',
204
249
  why: 'Bloquear bots de busqueda o fetch bajo demanda puede reducir la probabilidad de que ChatGPT o Claude recuperen y citen el contenido.',
205
- where: 'Reglas User-agent/Disallow del robots.txt.',
250
+ where: 'Reglas User-agent/Disallow del robots.txt aplicadas a esta URL.',
206
251
  recommendation: 'Permite OAI-SearchBot, ChatGPT-User, Claude-SearchBot y Claude-User en contenido publico que quieras posicionar en IA.',
207
252
  evidence: blockedSearchBots.map((bot) => bot.name).join(', '),
208
253
  });
209
254
  }
210
255
  else {
211
- passed.push('No se detecta bloqueo explicito para crawlers IA de busqueda o recuperacion.');
256
+ passed.push('No se detecta bloqueo explicito para crawlers IA de busqueda o recuperacion en esta URL.');
212
257
  }
213
258
  if (blockedTrainingBots.length > 0) {
214
259
  pushIssue(issues, {
@@ -227,7 +272,7 @@ async function buildGeoReport(params) {
227
272
  severity: 'important',
228
273
  message: 'Falta contenido con formato de respuesta directa o preguntas frecuentes.',
229
274
  why: 'Las IAs suelen extraer respuestas de bloques claros, autocontenidos y orientados a preguntas reales de usuarios.',
230
- where: 'Contenido visible, headings, FAQs y secciones explicativas.',
275
+ where: 'Contenido visible, headings, FAQs y secciones explicativas de la URL.',
231
276
  recommendation: 'Anade secciones con preguntas y respuestas claras: que es, como funciona, para quien es, precios, pasos, comparativas o casos de uso.',
232
277
  });
233
278
  }
@@ -240,12 +285,12 @@ async function buildGeoReport(params) {
240
285
  severity: 'warning',
241
286
  message: 'El contenido textual parece escaso para respuestas generativas.',
242
287
  why: 'Con poco texto, una IA tiene menos contexto para entender matices, servicios, ventajas y casos de uso.',
243
- where: 'Contenido visible de las paginas analizadas.',
244
- recommendation: 'Amplia las paginas clave con explicaciones utiles, ejemplos, entidades, FAQs y detalles que resuelvan dudas concretas.',
245
- evidence: `${totalWords} palabras detectadas en el conjunto analizado.`,
288
+ where: 'Contenido visible de la URL analizada.',
289
+ recommendation: 'Amplia la pagina con explicaciones utiles, ejemplos, entidades, FAQs y detalles que resuelvan dudas concretas.',
290
+ evidence: `${totalWords} palabras detectadas.`,
246
291
  });
247
292
  }
248
- if (!hasEntitySignal(params.mainPage)) {
293
+ if (!hasEntitySignal(focusPage)) {
249
294
  pushIssue(issues, {
250
295
  category: 'entityClarity',
251
296
  severity: 'important',
@@ -256,15 +301,15 @@ async function buildGeoReport(params) {
256
301
  });
257
302
  }
258
303
  else {
259
- passed.push('Se detectan senales de entidad, marca, autor o tecnologia en los datos del reporte.');
304
+ passed.push('Se detectan senales de entidad, marca, autor o tecnologia en los datos de la URL.');
260
305
  }
261
- if (!hasUsefulSchema(params.mainPage)) {
306
+ if (!hasUsefulSchema(focusPage)) {
262
307
  pushIssue(issues, {
263
308
  category: 'structuredData',
264
309
  severity: 'important',
265
310
  message: 'Faltan datos estructurados utiles para entidades.',
266
311
  why: 'Schema ayuda a buscadores e IAs a interpretar productos, organizaciones, articulos, servicios, FAQs y breadcrumbs.',
267
- where: 'JSON-LD, microdatos o schema.org en el HTML.',
312
+ where: 'JSON-LD, microdatos o schema.org en el HTML de la URL.',
268
313
  recommendation: 'Anade schema Organization, LocalBusiness, Product, Service, Article, FAQPage o BreadcrumbList segun el tipo de pagina.',
269
314
  });
270
315
  }
@@ -285,7 +330,7 @@ async function buildGeoReport(params) {
285
330
  else {
286
331
  passed.push('Se detectan enlaces externos que pueden apoyar confianza o contexto.');
287
332
  }
288
- if (!hasFreshnessSignal(params.mainPage)) {
333
+ if (!hasFreshnessSignal(focusPage)) {
289
334
  pushIssue(issues, {
290
335
  category: 'freshness',
291
336
  severity: 'warning',
@@ -298,22 +343,22 @@ async function buildGeoReport(params) {
298
343
  else {
299
344
  passed.push('Se detectan senales de fecha, actualizacion o cabeceras temporales.');
300
345
  }
301
- const responseTime = params.mainPage.responseTimeMs || params.mainPage.timeToFirstByteMs;
302
- if (params.mainPage.statusCode >= 400 || responseTime > 2500) {
346
+ const responseTime = focusPage.responseTimeMs || focusPage.timeToFirstByteMs;
347
+ if (focusPage.statusCode >= 400 || responseTime > 2500) {
303
348
  pushIssue(issues, {
304
349
  category: 'retrievability',
305
- severity: params.mainPage.statusCode >= 400 ? 'critical' : 'warning',
350
+ severity: focusPage.statusCode >= 400 ? 'critical' : 'warning',
306
351
  message: 'La pagina puede ser dificil de recuperar de forma fiable.',
307
352
  why: 'Si la URL falla o responde muy lento, los sistemas de busqueda con IA pueden descartarla o no usarla como fuente.',
308
353
  where: 'Estado HTTP, tiempo de respuesta y disponibilidad de la URL.',
309
354
  recommendation: 'Corrige errores HTTP y reduce tiempos de respuesta para que la pagina sea recuperable de forma estable.',
310
- evidence: `HTTP ${params.mainPage.statusCode || '-'} / ${responseTime || '-'}ms`,
355
+ evidence: `HTTP ${focusPage.statusCode || '-'} / ${responseTime || '-'}ms`,
311
356
  });
312
357
  }
313
358
  else {
314
- passed.push('La URL principal parece recuperable por estado HTTP y tiempo de respuesta.');
359
+ passed.push('La URL parece recuperable por estado HTTP y tiempo de respuesta.');
315
360
  }
316
- if (params.mainPage.crawlExtras?.waf || params.mainPage.crawlExtras?.rateLimit) {
361
+ if (focusPage.crawlExtras?.waf || focusPage.crawlExtras?.rateLimit) {
317
362
  pushIssue(issues, {
318
363
  category: 'retrievability',
319
364
  severity: 'info',
@@ -321,31 +366,53 @@ async function buildGeoReport(params) {
321
366
  why: 'Un firewall o limite agresivo puede bloquear crawlers de IA aunque robots.txt permita el acceso.',
322
367
  where: 'Cabeceras, infraestructura, WAF/CDN o protecciones anti-bot.',
323
368
  recommendation: 'Revisa reglas del CDN/WAF para permitir crawlers de busqueda IA verificados en contenido publico.',
324
- evidence: textFrom({ waf: params.mainPage.crawlExtras.waf, rateLimit: params.mainPage.crawlExtras.rateLimit }).slice(0, 180),
369
+ evidence: textFrom({ waf: focusPage.crawlExtras.waf, rateLimit: focusPage.crawlExtras.rateLimit }).slice(0, 180),
325
370
  });
326
371
  }
327
- const problemsBySeverity = {
328
- critical: issues.filter((issue) => issue.severity === 'critical'),
329
- important: issues.filter((issue) => issue.severity === 'important'),
330
- warning: issues.filter((issue) => issue.severity === 'warning'),
331
- info: issues.filter((issue) => issue.severity === 'info'),
372
+ return { issues, passed };
373
+ }
374
+ function buildGeoPayload(analysis) {
375
+ const problemsBySeverity = buildProblemsBySeverity(analysis.issues);
376
+ return {
377
+ score: scoreGeoReport(analysis.issues, analysis.passed),
378
+ summary: buildSummary(problemsBySeverity, analysis.passed),
379
+ checks: buildChecks(analysis.issues),
380
+ problemsBySeverity,
381
+ passed: analysis.passed,
382
+ };
383
+ }
384
+ async function buildGeoPageReport(page, timeoutMs, userAgent, cache) {
385
+ const pageUrl = getPageUrl(page);
386
+ const botAccess = await getAiBotAccess(pageUrl, timeoutMs, userAgent, cache);
387
+ const payload = buildGeoPayload(buildGeoAnalysis({ focusPage: page, pages: [page], botAccess }));
388
+ return {
389
+ url: page.url || pageUrl,
390
+ finalUrl: page.finalUrl || null,
391
+ title: page.title || null,
392
+ ...payload,
393
+ botAccess,
332
394
  };
395
+ }
396
+ async function buildGeoReport(params) {
397
+ const pages = getAllPages(params.mainPage, params.internalPages);
398
+ const robotsCache = new Map();
399
+ const mainBotAccess = await getAiBotAccess(getPageUrl(params.mainPage), params.timeoutMs, params.userAgent, robotsCache);
400
+ const sitePayload = buildGeoPayload(buildGeoAnalysis({
401
+ focusPage: params.mainPage,
402
+ pages,
403
+ botAccess: mainBotAccess,
404
+ }));
405
+ const pageReports = [];
406
+ for (const page of pages) {
407
+ pageReports.push(await buildGeoPageReport(page, params.timeoutMs, params.userAgent, robotsCache));
408
+ }
333
409
  return {
334
410
  version: '2026-05-geo-v1',
335
411
  source: 'n8n-node',
336
412
  generatedAt: new Date().toISOString(),
337
- score: scoreGeoReport(issues, passed),
338
- summary: {
339
- criticalCount: problemsBySeverity.critical.length,
340
- importantCount: problemsBySeverity.important.length,
341
- warningCount: problemsBySeverity.warning.length,
342
- infoCount: problemsBySeverity.info.length,
343
- passedCount: passed.length,
344
- },
345
- checks: buildChecks(issues),
346
- problemsBySeverity,
347
- passed,
348
- botAccess,
413
+ ...sitePayload,
414
+ botAccess: mainBotAccess,
415
+ pages: pageReports,
349
416
  };
350
417
  }
351
418
  //# sourceMappingURL=geoUtils.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "n8n-nodes-seo-scanner",
3
- "version": "1.2.21",
3
+ "version": "1.2.22",
4
4
  "description": "Nodo n8n: escaneo SEO técnico completo de una página web, con opción de escanear enlaces internos, informe HTML tipo dashboard, detección de CMS/plugins, crawl extendido (DNS, CDN, SSL, analytics).",
5
5
  "license": "MIT",
6
6
  "keywords": [