@orion-studios/payload-seo-audit 1.0.0 → 1.1.0

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 (50) hide show
  1. package/README.md +48 -45
  2. package/dist/api/cron.d.ts.map +1 -1
  3. package/dist/api/cron.js +3 -23
  4. package/dist/api/run-stream.d.ts.map +1 -1
  5. package/dist/api/run-stream.js +19 -215
  6. package/dist/api/run.d.ts.map +1 -1
  7. package/dist/api/run.js +4 -25
  8. package/dist/collections/SeoSnapshots.d.ts.map +1 -1
  9. package/dist/collections/SeoSnapshots.js +26 -0
  10. package/dist/components/types.d.ts +10 -0
  11. package/dist/components/types.d.ts.map +1 -1
  12. package/dist/components/views/SeoDashboard.js +29 -17
  13. package/dist/config.d.ts +1 -0
  14. package/dist/config.d.ts.map +1 -1
  15. package/dist/config.js +1 -0
  16. package/dist/globals/SeoIntegrations.d.ts +3 -0
  17. package/dist/globals/SeoIntegrations.d.ts.map +1 -0
  18. package/dist/globals/SeoIntegrations.js +305 -0
  19. package/dist/index.d.ts.map +1 -1
  20. package/dist/index.js +2 -4
  21. package/dist/utilities/crux.d.ts +6 -0
  22. package/dist/utilities/crux.d.ts.map +1 -0
  23. package/dist/utilities/crux.js +244 -0
  24. package/dist/utilities/dataforseo.d.ts +12 -0
  25. package/dist/utilities/dataforseo.d.ts.map +1 -0
  26. package/dist/utilities/dataforseo.js +169 -0
  27. package/dist/utilities/gsc.d.ts +4 -11
  28. package/dist/utilities/gsc.d.ts.map +1 -1
  29. package/dist/utilities/gsc.js +58 -22
  30. package/dist/utilities/integrationSettings.d.ts +10 -0
  31. package/dist/utilities/integrationSettings.d.ts.map +1 -0
  32. package/dist/utilities/integrationSettings.js +198 -0
  33. package/dist/utilities/opsWebhook.d.ts +15 -0
  34. package/dist/utilities/opsWebhook.d.ts.map +1 -0
  35. package/dist/utilities/opsWebhook.js +130 -0
  36. package/dist/utilities/pagespeed.d.ts +1 -1
  37. package/dist/utilities/pagespeed.d.ts.map +1 -1
  38. package/dist/utilities/pagespeed.js +11 -5
  39. package/dist/utilities/providers.d.ts +2 -2
  40. package/dist/utilities/providers.d.ts.map +1 -1
  41. package/dist/utilities/providers.js +12 -7
  42. package/dist/utilities/runAudit.d.ts +4 -1
  43. package/dist/utilities/runAudit.d.ts.map +1 -1
  44. package/dist/utilities/runAudit.js +112 -11
  45. package/dist/utilities/secrets.d.ts +23 -0
  46. package/dist/utilities/secrets.d.ts.map +1 -0
  47. package/dist/utilities/secrets.js +108 -0
  48. package/dist/utilities/types.d.ts +85 -0
  49. package/dist/utilities/types.d.ts.map +1 -1
  50. package/package.json +1 -1
package/README.md CHANGED
@@ -5,14 +5,15 @@ Professional SEO audit system for Payload CMS 3.0 + Next.js 15 projects.
5
5
  ## Features
6
6
 
7
7
  - 🔍 **Comprehensive SEO Analysis** - Crawls your site and checks 50+ SEO factors
8
- - 📊 **Visual Dashboard** - Beautiful admin UI with scores, trends, and issue tracking
8
+ - 📊 **Visual Dashboard** - Admin UI with scores, trends, issues, and CrUX metrics
9
9
  - 🎯 **Category Scoring** - Metadata, indexability, structure, links, media, structured data, performance
10
- - 📈 **Trend Tracking** - Monitor your SEO improvements over time
11
- - ⚡ **Performance Metrics** - Integrates with Google PageSpeed Insights for Core Web Vitals
10
+ - 📈 **Trend Tracking** - Monitor SEO performance over time
11
+ - ⚡ **Performance Integrations** - Google PageSpeed + Chrome UX Report (CrUX)
12
+ - 🔎 **Search Visibility Sync** - Google Search Console keyword visibility imports
13
+ - 🔗 **Authority Snapshots** - DataForSEO authority/backlink snapshots with run policy controls
12
14
  - 🔄 **Auto-Trigger** - Optionally run audits when content is published
13
- - 🌙 **Dark Mode** - Full dark mode support for comfortable viewing
14
- - 📄 **PDF Export** - Download professional audit reports
15
- - 🔌 **Easy Integration** - Simple plugin system with automated setup
15
+ - 🔐 **Encrypted Integration Settings** - Credentials managed in Payload admin (with env fallback)
16
+ - 📄 **PDF Export** - Download snapshot reports
16
17
 
17
18
  ## Quick Start
18
19
 
@@ -28,7 +29,7 @@ npm install @orion-studios/payload-seo-audit
28
29
  # 1. Run the automated setup tool
29
30
  npx payload-seo-audit init
30
31
 
31
- # 2. Configure your environment variables (.env.local)
32
+ # 2. Configure required environment variables (.env.local)
32
33
  SEO_AUDIT_SECRET=<random-secret-key>
33
34
  NEXT_PUBLIC_SERVER_URL=https://your-site.com
34
35
 
@@ -54,10 +55,7 @@ export default buildConfig({
54
55
  domain: 'www.yoursite.com',
55
56
  canonicalHost: 'https://www.yoursite.com',
56
57
  sitemapURL: 'https://www.yoursite.com/sitemap.xml',
57
- keyURLs: [
58
- 'https://www.yoursite.com',
59
- 'https://www.yoursite.com/about',
60
- ],
58
+ keyURLs: ['https://www.yoursite.com', 'https://www.yoursite.com/about'],
61
59
  },
62
60
  crawl: {
63
61
  maxPages: 120,
@@ -69,54 +67,59 @@ export default buildConfig({
69
67
  globals: ['home'],
70
68
  },
71
69
  access: (user) => user?.role === 'admin',
70
+ integrations: {
71
+ enablePageSpeed: true,
72
+ enableSearchConsole: false,
73
+ enableCrUX: false,
74
+ },
72
75
  }),
73
76
  ],
74
77
  })
75
78
  ```
76
79
 
77
- ### Usage
78
-
79
- 1. Visit `/admin/globals/seo-dashboard`
80
- 2. Click **"Run Audit Now"**
81
- 3. View comprehensive SEO analysis
82
- 4. Click on snapshots to see detailed reports
83
- 5. Track your improvements over time
84
-
85
- ## Documentation
80
+ ### Configure API Integrations in Admin
86
81
 
87
- - **[Integration Guide](./INTEGRATION.md)** - Complete setup instructions with troubleshooting
88
- - **[Configuration Options](./INTEGRATION.md#step-2-configure-payload-plugin)** - All plugin config options
89
- - **[Troubleshooting](./INTEGRATION.md#troubleshooting)** - Common issues and solutions
82
+ After startup, open:
90
83
 
91
- ## Troubleshooting
84
+ - `/admin/globals/seo-integrations`
92
85
 
93
- ### Dark Mode Not Working (White Cards)
86
+ From there you can securely configure:
94
87
 
95
- Ensure your `tailwind.config.ts` has BOTH:
88
+ - Google Search Console (OAuth or service account)
89
+ - PageSpeed API key
90
+ - CrUX API key and query scope
91
+ - DataForSEO credentials + run policy
92
+ - Private operator webhook settings
96
93
 
97
- 1. **Plugin path in content array:**
98
- ```typescript
99
- content: [
100
- './src/**/*.{js,ts,jsx,tsx}',
101
- './node_modules/@orion-studios/payload-seo-audit/dist/**/*.js',
102
- ]
103
- ```
94
+ Secrets are encrypted at rest and masked in the admin form.
104
95
 
105
- 2. **Correct darkMode configuration:**
106
- ```typescript
107
- darkMode: ['selector', '[data-theme="dark"]'],
108
- ```
96
+ ### Usage
109
97
 
110
- **If you have a custom theme toggle:** Update it to use `data-theme` attribute instead of classes:
111
- ```typescript
112
- // Correct
113
- document.documentElement.setAttribute('data-theme', 'dark')
98
+ 1. Visit `/admin/globals/seo-dashboard`
99
+ 2. Click **Run Audit Now**
100
+ 3. Review scores, issues, trends, and CrUX field data
101
+ 4. Open snapshots for detailed reports and exports
102
+
103
+ ## Environment Variable Fallbacks
104
+
105
+ If `seo-integrations` is not configured yet, these env vars are used as fallback:
106
+
107
+ - `SEO_GSC_CLIENT_ID`
108
+ - `SEO_GSC_CLIENT_SECRET`
109
+ - `SEO_GSC_REDIRECT_URI`
110
+ - `SEO_GSC_REFRESH_TOKEN`
111
+ - `GOOGLE_SERVICE_ACCOUNT_EMAIL`
112
+ - `GOOGLE_SERVICE_ACCOUNT_PRIVATE_KEY`
113
+ - `SEO_PAGESPEED_API_KEY`
114
+ - `SEO_CRUX_API_KEY`
115
+ - `SEO_DATAFORSEO_LOGIN`
116
+ - `SEO_DATAFORSEO_PASSWORD`
117
+ - `SEO_DATAFORSEO_BASE_URL`
114
118
 
115
- // ❌ Wrong
116
- document.documentElement.classList.add('dark')
117
- ```
119
+ ## Documentation
118
120
 
119
- Then restart dev server and hard refresh. See [full troubleshooting guide](./INTEGRATION.md#troubleshooting).
121
+ - **[Integration Guide](./INTEGRATION.md)** - Full setup and troubleshooting
122
+ - **[Troubleshooting](./INTEGRATION.md#troubleshooting)** - Common issues and fixes
120
123
 
121
124
  ## License
122
125
 
@@ -1 +1 @@
1
- {"version":3,"file":"cron.d.ts","sourceRoot":"","sources":["../../src/api/cron.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AACtC,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAS5D,wBAAsB,aAAa,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC,CA6DjG"}
1
+ {"version":3,"file":"cron.d.ts","sourceRoot":"","sources":["../../src/api/cron.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AACtC,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAM5D,wBAAsB,aAAa,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC,CAmCjG"}
package/dist/api/cron.js CHANGED
@@ -36,6 +36,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.handleSeoCron = handleSeoCron;
37
37
  const auth_1 = require("../utilities/auth");
38
38
  const index_1 = require("../index");
39
+ const integrationSettings_1 = require("../utilities/integrationSettings");
39
40
  const runAudit_1 = require("../utilities/runAudit");
40
41
  async function handleSeoCron(payload, request) {
41
42
  const { NextResponse } = await Promise.resolve().then(() => __importStar(require('next/server')));
@@ -47,32 +48,11 @@ async function handleSeoCron(payload, request) {
47
48
  if (!seoConfig) {
48
49
  return NextResponse.json({ error: 'SEO Audit plugin not configured' }, { status: 500 });
49
50
  }
50
- const site = {
51
- id: 1,
52
- name: seoConfig.site.name,
53
- domain: seoConfig.site.domain,
54
- canonicalHost: seoConfig.site.canonicalHost,
55
- sitemapURL: seoConfig.site.sitemapURL,
56
- keyURLs: seoConfig.site.keyURLs.map((url) => ({ url })),
57
- crawlSettings: {
58
- maxPages: seoConfig.crawl.maxPages,
59
- maxDepth: seoConfig.crawl.maxDepth,
60
- requestTimeoutMs: seoConfig.crawl.requestTimeoutMs,
61
- includePatterns: seoConfig.crawl.includePatterns.map((pattern) => ({ pattern })),
62
- excludePatterns: seoConfig.crawl.excludePatterns.map((pattern) => ({ pattern })),
63
- },
64
- integrations: {
65
- enablePageSpeed: seoConfig.integrations.enablePageSpeed,
66
- enableSearchConsole: seoConfig.integrations.enableSearchConsole,
67
- },
68
- thresholds: {
69
- targetLCPMs: seoConfig.thresholds.targetLCPMs,
70
- targetCLS: seoConfig.thresholds.targetCLS,
71
- },
72
- };
51
+ const site = (0, integrationSettings_1.siteFromSeoConfig)(seoConfig);
73
52
  const result = await (0, runAudit_1.runSEOSnapshot)({
74
53
  payload,
75
54
  site,
55
+ seoConfig,
76
56
  runType: 'scheduled',
77
57
  });
78
58
  return NextResponse.json({
@@ -1 +1 @@
1
- {"version":3,"file":"run-stream.d.ts","sourceRoot":"","sources":["../../src/api/run-stream.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AACtC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAuE9C,wBAAsB,kBAAkB,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,QAAQ,CAAC,CAmQlG"}
1
+ {"version":3,"file":"run-stream.d.ts","sourceRoot":"","sources":["../../src/api/run-stream.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AACtC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAY9C,wBAAsB,kBAAkB,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,QAAQ,CAAC,CA4ElG"}
@@ -3,61 +3,13 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.handleSeoRunStream = handleSeoRunStream;
4
4
  const auth_1 = require("../utilities/auth");
5
5
  const index_1 = require("../index");
6
- const checks_1 = require("../utilities/checks");
7
- const crawler_1 = require("../utilities/crawler");
8
- const helpers_1 = require("../utilities/helpers");
9
- const gsc_1 = require("../utilities/gsc");
10
- const pagespeed_1 = require("../utilities/pagespeed");
11
- const scoring_1 = require("../utilities/scoring");
12
- const providers_1 = require("../utilities/providers");
6
+ const integrationSettings_1 = require("../utilities/integrationSettings");
7
+ const runAudit_1 = require("../utilities/runAudit");
13
8
  const resolveRunType = (value) => {
14
9
  if (value === 'scheduled' || value === 'publish-triggered')
15
10
  return value;
16
11
  return 'manual';
17
12
  };
18
- const average = (values) => {
19
- if (!values.length)
20
- return 0;
21
- return Math.round(values.reduce((sum, value) => sum + value, 0) / values.length);
22
- };
23
- const applyPerformanceIssues = (issues, pageSpeed, site) => {
24
- if (!pageSpeed)
25
- return issues;
26
- const nextIssues = [...issues];
27
- if (typeof pageSpeed.averagePerformanceScore === 'number' && pageSpeed.averagePerformanceScore < 70) {
28
- nextIssues.push({
29
- fingerprint: `perf-score-${pageSpeed.averagePerformanceScore}`,
30
- ruleID: 'pagespeed-performance-low',
31
- category: 'performance',
32
- severity: pageSpeed.averagePerformanceScore < 50 ? 'high' : 'medium',
33
- message: `Average Lighthouse performance score is ${pageSpeed.averagePerformanceScore}.`,
34
- recommendation: 'Optimize render-blocking assets, image delivery, and JS execution.',
35
- });
36
- }
37
- const targetLCP = Number(site.thresholds?.targetLCPMs || 2500);
38
- if (typeof pageSpeed.averageLCPMs === 'number' && pageSpeed.averageLCPMs > targetLCP) {
39
- nextIssues.push({
40
- fingerprint: `perf-lcp-${pageSpeed.averageLCPMs}`,
41
- ruleID: 'pagespeed-lcp-high',
42
- category: 'performance',
43
- severity: pageSpeed.averageLCPMs > targetLCP * 1.5 ? 'high' : 'medium',
44
- message: `Average LCP is ${pageSpeed.averageLCPMs}ms.`,
45
- recommendation: 'Improve server response times, preload key assets, and optimize hero content.',
46
- });
47
- }
48
- const targetCLS = Number(site.thresholds?.targetCLS || 0.1);
49
- if (typeof pageSpeed.averageCLS === 'number' && pageSpeed.averageCLS > targetCLS) {
50
- nextIssues.push({
51
- fingerprint: `perf-cls-${pageSpeed.averageCLS}`,
52
- ruleID: 'pagespeed-cls-high',
53
- category: 'performance',
54
- severity: pageSpeed.averageCLS > targetCLS * 2 ? 'high' : 'medium',
55
- message: `Average CLS is ${pageSpeed.averageCLS}.`,
56
- recommendation: 'Set explicit media dimensions and reduce layout shifts from dynamic UI elements.',
57
- });
58
- }
59
- return nextIssues;
60
- };
61
13
  async function handleSeoRunStream(payload, request) {
62
14
  const body = (await request.json().catch(() => ({})));
63
15
  const encoder = new TextEncoder();
@@ -84,173 +36,25 @@ async function handleSeoRunStream(payload, request) {
84
36
  controller.close();
85
37
  return;
86
38
  }
87
- const site = {
88
- id: 1,
89
- name: seoConfig.site.name,
90
- domain: seoConfig.site.domain,
91
- canonicalHost: seoConfig.site.canonicalHost,
92
- sitemapURL: seoConfig.site.sitemapURL,
93
- keyURLs: seoConfig.site.keyURLs.map((url) => ({ url })),
94
- crawlSettings: {
95
- maxPages: seoConfig.crawl.maxPages,
96
- maxDepth: seoConfig.crawl.maxDepth,
97
- requestTimeoutMs: seoConfig.crawl.requestTimeoutMs,
98
- includePatterns: seoConfig.crawl.includePatterns.map((pattern) => ({ pattern })),
99
- excludePatterns: seoConfig.crawl.excludePatterns.map((pattern) => ({ pattern })),
100
- },
101
- integrations: {
102
- enablePageSpeed: seoConfig.integrations.enablePageSpeed,
103
- enableSearchConsole: seoConfig.integrations.enableSearchConsole,
104
- },
105
- thresholds: {
106
- targetLCPMs: seoConfig.thresholds.targetLCPMs,
107
- targetCLS: seoConfig.thresholds.targetCLS,
108
- },
109
- };
110
- const runLabel = `${site.name} SEO Snapshot ${new Date().toISOString()}`;
111
39
  send('progress', { step: 'snapshot', message: 'Creating snapshot record...' });
112
- const snapshot = await payload.create({
113
- collection: 'seo-snapshots',
114
- data: {
115
- runLabel,
116
- runType: resolveRunType(body.runType),
117
- status: 'pending',
118
- startedAt: new Date().toISOString(),
119
- },
120
- overrideAccess: true,
121
- });
122
- send('progress', { step: 'crawl', message: 'Crawling site pages...' });
123
- const crawl = await (0, crawler_1.crawlSiteForSEO)(site);
124
- send('progress', {
125
- step: 'crawl-complete',
126
- message: `Found ${crawl.pages.length} pages`,
127
- data: { pagesFound: crawl.pages.length },
128
- });
129
- send('progress', { step: 'checks', message: 'Running SEO checks on all pages...' });
130
- const pageResults = crawl.pages.map((page) => {
131
- const check = (0, checks_1.runSEOChecks)(page.url, page.html);
132
- const score = (0, scoring_1.scoreSEOIssues)(check.issues);
133
- return {
134
- url: page.url,
135
- path: page.path,
136
- statusCode: page.statusCode,
137
- check,
138
- score,
139
- };
140
- });
141
- send('progress', { step: 'checks-complete', message: 'SEO checks complete' });
142
- send('progress', { step: 'pagespeed', message: 'Analyzing page performance...' });
143
- const pageSpeedSummary = site.integrations?.enablePageSpeed !== false
144
- ? await (0, pagespeed_1.getPageSpeedSummary)(pageResults.map((page) => page.url))
145
- : null;
146
- if (pageSpeedSummary) {
147
- send('progress', {
148
- step: 'pagespeed-complete',
149
- message: `Performance analysis complete (avg: ${pageSpeedSummary.averagePerformanceScore})`,
150
- });
151
- }
152
- else {
153
- send('progress', { step: 'pagespeed-skipped', message: 'PageSpeed analysis disabled' });
154
- }
155
- send('progress', { step: 'gsc', message: 'Syncing Google Search Console data...' });
156
- const keywordVisibilitySync = await (0, gsc_1.syncGSCKeywordVisibility)({
40
+ await (0, runAudit_1.runSEOSnapshot)({
157
41
  payload,
158
- site,
159
- });
160
- if (keywordVisibilitySync.enabled) {
161
- send('progress', {
162
- step: 'gsc-complete',
163
- message: `Imported ${keywordVisibilitySync.imported} GSC keywords`,
164
- });
165
- }
166
- else {
167
- send('progress', { step: 'gsc-skipped', message: 'GSC sync disabled' });
168
- }
169
- const allIssues = applyPerformanceIssues(pageResults.flatMap((result) => result.check.issues), pageSpeedSummary, site);
170
- const issueCounts = (0, helpers_1.countIssuesBySeverity)(allIssues);
171
- const providerAdapter = (0, providers_1.getSEOProviderAdapter)();
172
- const summaryText = keywordVisibilitySync.enabled
173
- ? `Automated audit completed using ${providerAdapter.name} authority adapter. GSC rows imported: ${keywordVisibilitySync.imported}.`
174
- : `Automated audit completed using ${providerAdapter.name} authority adapter.`;
175
- const scores = {
176
- metadata: average(pageResults.map((result) => result.score.metadata)),
177
- indexability: average(pageResults.map((result) => result.score.indexability)),
178
- structure: average(pageResults.map((result) => result.score.structure)),
179
- links: average(pageResults.map((result) => result.score.links)),
180
- media: average(pageResults.map((result) => result.score.media)),
181
- structuredData: average(pageResults.map((result) => result.score.structuredData)),
182
- performance: typeof pageSpeedSummary?.averagePerformanceScore === 'number'
183
- ? pageSpeedSummary.averagePerformanceScore
184
- : average(pageResults.map((result) => result.score.performance)),
185
- };
186
- const overallScore = Math.round(scores.metadata * 0.2 +
187
- scores.indexability * 0.2 +
188
- scores.structure * 0.15 +
189
- scores.links * 0.1 +
190
- scores.media * 0.1 +
191
- scores.structuredData * 0.1 +
192
- scores.performance * 0.15);
193
- send('progress', { step: 'saving', message: 'Saving results to database...' });
194
- const batchSize = 10;
195
- for (let i = 0; i < pageResults.length; i += batchSize) {
196
- const batch = pageResults.slice(i, i + batchSize);
197
- await Promise.all(batch.map((result) => payload.create({
198
- collection: 'seo-page-results',
199
- data: {
200
- snapshot: snapshot.id,
201
- url: result.url,
202
- path: result.path,
203
- statusCode: result.statusCode,
204
- title: result.check.title,
205
- metaDescription: result.check.metaDescription,
206
- canonical: result.check.canonical,
207
- robotsMeta: result.check.robotsMeta,
208
- h1Count: result.check.h1Count,
209
- internalLinks: result.check.internalLinks,
210
- externalLinks: result.check.externalLinks,
211
- imagesTotal: result.check.imagesTotal,
212
- imagesMissingAlt: result.check.imagesMissingAlt,
213
- structuredDataBlocks: result.check.structuredDataBlocks,
214
- headingOrderIssues: result.check.headingOrderIssues,
215
- scoreBreakdown: result.score,
216
- overallScore: Math.round(result.score.metadata * 0.2 +
217
- result.score.indexability * 0.2 +
218
- result.score.structure * 0.15 +
219
- result.score.links * 0.1 +
220
- result.score.media * 0.1 +
221
- result.score.structuredData * 0.1 +
222
- result.score.performance * 0.15),
223
- issues: result.check.issues,
224
- checkedAt: new Date().toISOString(),
225
- },
226
- overrideAccess: true,
227
- })));
228
- }
229
- await payload.update({
230
- collection: 'seo-snapshots',
231
- id: snapshot.id,
232
- data: {
233
- status: 'completed',
234
- completedAt: new Date().toISOString(),
235
- scores: { ...scores, overall: overallScore },
236
- metrics: {
237
- pagesCrawled: crawl.pages.length,
238
- pagesChecked: pageResults.length,
239
- avgLighthousePerformance: pageSpeedSummary?.averagePerformanceScore,
240
- avgLCPMs: pageSpeedSummary?.averageLCPMs,
241
- avgCLS: pageSpeedSummary?.averageCLS,
242
- },
243
- issueCounts,
244
- summary: summaryText,
245
- },
246
- overrideAccess: true,
247
- });
248
- send('complete', {
249
- message: 'Audit complete!',
250
- data: {
251
- pagesChecked: pageResults.length,
252
- overallScore,
253
- snapshotId: snapshot.id,
42
+ site: (0, integrationSettings_1.siteFromSeoConfig)(seoConfig),
43
+ seoConfig,
44
+ runType: resolveRunType(body.runType),
45
+ onProgress: async (step, message, data) => {
46
+ if (step === 'complete') {
47
+ send('complete', {
48
+ message,
49
+ data,
50
+ });
51
+ return;
52
+ }
53
+ send('progress', {
54
+ step,
55
+ message,
56
+ data,
57
+ });
254
58
  },
255
59
  });
256
60
  controller.close();
@@ -1 +1 @@
1
- {"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../src/api/run.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AACtC,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAc5D,wBAAsB,YAAY,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC,CA4EhG"}
1
+ {"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../src/api/run.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AACtC,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAY5D,wBAAsB,YAAY,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC,CA6ChG"}
package/dist/api/run.js CHANGED
@@ -35,8 +35,9 @@ var __importStar = (this && this.__importStar) || (function () {
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.handleSeoRun = handleSeoRun;
37
37
  const auth_1 = require("../utilities/auth");
38
- const runAudit_1 = require("../utilities/runAudit");
39
38
  const index_1 = require("../index");
39
+ const integrationSettings_1 = require("../utilities/integrationSettings");
40
+ const runAudit_1 = require("../utilities/runAudit");
40
41
  const resolveRunType = (value) => {
41
42
  if (value === 'scheduled' || value === 'publish-triggered')
42
43
  return value;
@@ -57,32 +58,10 @@ async function handleSeoRun(payload, request) {
57
58
  return NextResponse.json({ error: 'SEO Audit plugin not configured' }, { status: 500 });
58
59
  }
59
60
  const body = (await request.json().catch(() => ({})));
60
- const site = {
61
- id: 1,
62
- name: seoConfig.site.name,
63
- domain: seoConfig.site.domain,
64
- canonicalHost: seoConfig.site.canonicalHost,
65
- sitemapURL: seoConfig.site.sitemapURL,
66
- keyURLs: seoConfig.site.keyURLs.map(url => ({ url })),
67
- crawlSettings: {
68
- maxPages: seoConfig.crawl.maxPages,
69
- maxDepth: seoConfig.crawl.maxDepth,
70
- requestTimeoutMs: seoConfig.crawl.requestTimeoutMs,
71
- includePatterns: seoConfig.crawl.includePatterns.map(pattern => ({ pattern })),
72
- excludePatterns: seoConfig.crawl.excludePatterns.map(pattern => ({ pattern })),
73
- },
74
- integrations: {
75
- enablePageSpeed: seoConfig.integrations.enablePageSpeed,
76
- enableSearchConsole: seoConfig.integrations.enableSearchConsole,
77
- },
78
- thresholds: {
79
- targetLCPMs: seoConfig.thresholds.targetLCPMs,
80
- targetCLS: seoConfig.thresholds.targetCLS,
81
- },
82
- };
83
61
  const result = await (0, runAudit_1.runSEOSnapshot)({
84
62
  payload,
85
- site,
63
+ site: (0, integrationSettings_1.siteFromSeoConfig)(seoConfig),
64
+ seoConfig,
86
65
  runType: resolveRunType(body.runType),
87
66
  });
88
67
  return NextResponse.json({
@@ -1 +1 @@
1
- {"version":3,"file":"SeoSnapshots.d.ts","sourceRoot":"","sources":["../../src/collections/SeoSnapshots.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAA;AAG/C,eAAO,MAAM,YAAY,EAAE,gBAqI1B,CAAA"}
1
+ {"version":3,"file":"SeoSnapshots.d.ts","sourceRoot":"","sources":["../../src/collections/SeoSnapshots.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAA;AAG/C,eAAO,MAAM,YAAY,EAAE,gBA6J1B,CAAA"}
@@ -106,6 +106,25 @@ exports.SeoSnapshots = {
106
106
  { name: 'avgLighthousePerformance', type: 'number' },
107
107
  { name: 'avgLCPMs', type: 'number' },
108
108
  { name: 'avgCLS', type: 'number' },
109
+ { name: 'cruxAvailable', type: 'checkbox' },
110
+ {
111
+ name: 'cruxSource',
112
+ type: 'select',
113
+ options: [
114
+ { label: 'Origin', value: 'origin' },
115
+ { label: 'URL', value: 'url' },
116
+ { label: 'Mixed', value: 'mixed' },
117
+ { label: 'None', value: 'none' },
118
+ ],
119
+ },
120
+ { name: 'cruxGoodLCPPct', type: 'number' },
121
+ { name: 'cruxGoodINPPct', type: 'number' },
122
+ { name: 'cruxGoodCLSPct', type: 'number' },
123
+ { name: 'cruxP75LCPMs', type: 'number' },
124
+ { name: 'cruxP75INPMs', type: 'number' },
125
+ { name: 'cruxP75CLS', type: 'number' },
126
+ { name: 'cruxSampleUrlsChecked', type: 'number' },
127
+ { name: 'cruxSampleUrlsWithData', type: 'number' },
109
128
  ],
110
129
  },
111
130
  {
@@ -123,6 +142,13 @@ exports.SeoSnapshots = {
123
142
  name: 'summary',
124
143
  type: 'textarea',
125
144
  },
145
+ {
146
+ name: 'integrationStatus',
147
+ type: 'json',
148
+ admin: {
149
+ readOnly: true,
150
+ },
151
+ },
126
152
  {
127
153
  name: 'errorMessage',
128
154
  type: 'textarea',
@@ -32,6 +32,16 @@ export type SEOMetrics = {
32
32
  avgLighthousePerformance?: number | null;
33
33
  avgLCPMs?: number | null;
34
34
  avgCLS?: number | null;
35
+ cruxAvailable?: boolean | null;
36
+ cruxSource?: 'origin' | 'url' | 'mixed' | 'none' | null;
37
+ cruxGoodLCPPct?: number | null;
38
+ cruxGoodINPPct?: number | null;
39
+ cruxGoodCLSPct?: number | null;
40
+ cruxP75LCPMs?: number | null;
41
+ cruxP75INPMs?: number | null;
42
+ cruxP75CLS?: number | null;
43
+ cruxSampleUrlsChecked?: number | null;
44
+ cruxSampleUrlsWithData?: number | null;
35
45
  };
36
46
  export type SEOSnapshot = {
37
47
  id: number | string;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/components/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/components/types.ts"],"names":[],"mappings":"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"}