@orion-studios/payload-seo-audit 1.0.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 (165) hide show
  1. package/README.md +127 -0
  2. package/bin/init.js +267 -0
  3. package/dist/api/backlinks-import.d.ts +4 -0
  4. package/dist/api/backlinks-import.d.ts.map +1 -0
  5. package/dist/api/backlinks-import.js +182 -0
  6. package/dist/api/cron.d.ts +4 -0
  7. package/dist/api/cron.d.ts.map +1 -0
  8. package/dist/api/cron.js +89 -0
  9. package/dist/api/index.d.ts +10 -0
  10. package/dist/api/index.d.ts.map +1 -0
  11. package/dist/api/index.js +21 -0
  12. package/dist/api/page-result.d.ts +4 -0
  13. package/dist/api/page-result.d.ts.map +1 -0
  14. package/dist/api/page-result.js +93 -0
  15. package/dist/api/page-results.d.ts +4 -0
  16. package/dist/api/page-results.d.ts.map +1 -0
  17. package/dist/api/page-results.js +83 -0
  18. package/dist/api/run-stream.d.ts +4 -0
  19. package/dist/api/run-stream.d.ts.map +1 -0
  20. package/dist/api/run-stream.js +273 -0
  21. package/dist/api/run.d.ts +4 -0
  22. package/dist/api/run.d.ts.map +1 -0
  23. package/dist/api/run.js +102 -0
  24. package/dist/api/snapshot-report.d.ts +4 -0
  25. package/dist/api/snapshot-report.d.ts.map +1 -0
  26. package/dist/api/snapshot-report.js +130 -0
  27. package/dist/api/snapshots.d.ts +4 -0
  28. package/dist/api/snapshots.d.ts.map +1 -0
  29. package/dist/api/snapshots.js +138 -0
  30. package/dist/api/trend.d.ts +4 -0
  31. package/dist/api/trend.d.ts.map +1 -0
  32. package/dist/api/trend.js +71 -0
  33. package/dist/collections/SeoAuthoritySnapshots.d.ts +3 -0
  34. package/dist/collections/SeoAuthoritySnapshots.d.ts.map +1 -0
  35. package/dist/collections/SeoAuthoritySnapshots.js +83 -0
  36. package/dist/collections/SeoKeywordVisibility.d.ts +3 -0
  37. package/dist/collections/SeoKeywordVisibility.d.ts.map +1 -0
  38. package/dist/collections/SeoKeywordVisibility.js +65 -0
  39. package/dist/collections/SeoPageResults.d.ts +3 -0
  40. package/dist/collections/SeoPageResults.d.ts.map +1 -0
  41. package/dist/collections/SeoPageResults.js +170 -0
  42. package/dist/collections/SeoSnapshots.d.ts +3 -0
  43. package/dist/collections/SeoSnapshots.d.ts.map +1 -0
  44. package/dist/collections/SeoSnapshots.js +131 -0
  45. package/dist/components/hooks/useSeoApi.d.ts +7 -0
  46. package/dist/components/hooks/useSeoApi.d.ts.map +1 -0
  47. package/dist/components/hooks/useSeoApi.js +31 -0
  48. package/dist/components/hooks/useSeoPageResults.d.ts +19 -0
  49. package/dist/components/hooks/useSeoPageResults.d.ts.map +1 -0
  50. package/dist/components/hooks/useSeoPageResults.js +62 -0
  51. package/dist/components/hooks/useSeoSnapshot.d.ts +8 -0
  52. package/dist/components/hooks/useSeoSnapshot.d.ts.map +1 -0
  53. package/dist/components/hooks/useSeoSnapshot.js +39 -0
  54. package/dist/components/hooks/useSeoTrend.d.ts +8 -0
  55. package/dist/components/hooks/useSeoTrend.d.ts.map +1 -0
  56. package/dist/components/hooks/useSeoTrend.js +38 -0
  57. package/dist/components/layout/SeoReportHeader.d.ts +10 -0
  58. package/dist/components/layout/SeoReportHeader.d.ts.map +1 -0
  59. package/dist/components/layout/SeoReportHeader.js +18 -0
  60. package/dist/components/layout/SeoReportShell.d.ts +9 -0
  61. package/dist/components/layout/SeoReportShell.d.ts.map +1 -0
  62. package/dist/components/layout/SeoReportShell.js +17 -0
  63. package/dist/components/pdf/PdfDownloadButton.d.ts +9 -0
  64. package/dist/components/pdf/PdfDownloadButton.d.ts.map +1 -0
  65. package/dist/components/pdf/PdfDownloadButton.js +80 -0
  66. package/dist/components/tables/IssueTable.d.ts +11 -0
  67. package/dist/components/tables/IssueTable.d.ts.map +1 -0
  68. package/dist/components/tables/IssueTable.js +121 -0
  69. package/dist/components/tables/PageResultsTable.d.ts +18 -0
  70. package/dist/components/tables/PageResultsTable.d.ts.map +1 -0
  71. package/dist/components/tables/PageResultsTable.js +96 -0
  72. package/dist/components/types.d.ts +107 -0
  73. package/dist/components/types.d.ts.map +1 -0
  74. package/dist/components/types.js +22 -0
  75. package/dist/components/utils/formatters.d.ts +15 -0
  76. package/dist/components/utils/formatters.d.ts.map +1 -0
  77. package/dist/components/utils/formatters.js +98 -0
  78. package/dist/components/utils/scoreHelpers.d.ts +17 -0
  79. package/dist/components/utils/scoreHelpers.d.ts.map +1 -0
  80. package/dist/components/utils/scoreHelpers.js +139 -0
  81. package/dist/components/views/SeoDashboard.d.ts +3 -0
  82. package/dist/components/views/SeoDashboard.d.ts.map +1 -0
  83. package/dist/components/views/SeoDashboard.js +239 -0
  84. package/dist/components/views/SeoPageReport.d.ts +3 -0
  85. package/dist/components/views/SeoPageReport.d.ts.map +1 -0
  86. package/dist/components/views/SeoPageReport.js +234 -0
  87. package/dist/components/views/SeoSnapshotReport.d.ts +3 -0
  88. package/dist/components/views/SeoSnapshotReport.d.ts.map +1 -0
  89. package/dist/components/views/SeoSnapshotReport.js +224 -0
  90. package/dist/components/visualization/CategoryScoreCard.d.ts +11 -0
  91. package/dist/components/visualization/CategoryScoreCard.d.ts.map +1 -0
  92. package/dist/components/visualization/CategoryScoreCard.js +17 -0
  93. package/dist/components/visualization/CategoryScoreGrid.d.ts +9 -0
  94. package/dist/components/visualization/CategoryScoreGrid.d.ts.map +1 -0
  95. package/dist/components/visualization/CategoryScoreGrid.js +32 -0
  96. package/dist/components/visualization/IssueCategoryChart.d.ts +8 -0
  97. package/dist/components/visualization/IssueCategoryChart.d.ts.map +1 -0
  98. package/dist/components/visualization/IssueCategoryChart.js +47 -0
  99. package/dist/components/visualization/MetricCard.d.ts +11 -0
  100. package/dist/components/visualization/MetricCard.d.ts.map +1 -0
  101. package/dist/components/visualization/MetricCard.js +17 -0
  102. package/dist/components/visualization/MetricCardRow.d.ts +7 -0
  103. package/dist/components/visualization/MetricCardRow.d.ts.map +1 -0
  104. package/dist/components/visualization/MetricCardRow.js +12 -0
  105. package/dist/components/visualization/ScoreBar.d.ts +11 -0
  106. package/dist/components/visualization/ScoreBar.d.ts.map +1 -0
  107. package/dist/components/visualization/ScoreBar.js +34 -0
  108. package/dist/components/visualization/ScoreGauge.d.ts +11 -0
  109. package/dist/components/visualization/ScoreGauge.d.ts.map +1 -0
  110. package/dist/components/visualization/ScoreGauge.js +28 -0
  111. package/dist/components/visualization/ScoreTrendChart.d.ts +9 -0
  112. package/dist/components/visualization/ScoreTrendChart.d.ts.map +1 -0
  113. package/dist/components/visualization/ScoreTrendChart.js +43 -0
  114. package/dist/components/visualization/SeverityBadge.d.ts +8 -0
  115. package/dist/components/visualization/SeverityBadge.d.ts.map +1 -0
  116. package/dist/components/visualization/SeverityBadge.js +14 -0
  117. package/dist/config.d.ts +38 -0
  118. package/dist/config.d.ts.map +1 -0
  119. package/dist/config.js +36 -0
  120. package/dist/exports/components.d.ts +4 -0
  121. package/dist/exports/components.d.ts.map +1 -0
  122. package/dist/exports/components.js +9 -0
  123. package/dist/globals/SeoDashboard.d.ts +3 -0
  124. package/dist/globals/SeoDashboard.d.ts.map +1 -0
  125. package/dist/globals/SeoDashboard.js +25 -0
  126. package/dist/index.d.ts +6 -0
  127. package/dist/index.d.ts.map +1 -0
  128. package/dist/index.js +39 -0
  129. package/dist/utilities/access.d.ts +8 -0
  130. package/dist/utilities/access.d.ts.map +1 -0
  131. package/dist/utilities/access.js +11 -0
  132. package/dist/utilities/auth.d.ts +7 -0
  133. package/dist/utilities/auth.d.ts.map +1 -0
  134. package/dist/utilities/auth.js +28 -0
  135. package/dist/utilities/checks.d.ts +3 -0
  136. package/dist/utilities/checks.d.ts.map +1 -0
  137. package/dist/utilities/checks.js +255 -0
  138. package/dist/utilities/crawler.d.ts +14 -0
  139. package/dist/utilities/crawler.d.ts.map +1 -0
  140. package/dist/utilities/crawler.js +152 -0
  141. package/dist/utilities/gsc.d.ts +15 -0
  142. package/dist/utilities/gsc.d.ts.map +1 -0
  143. package/dist/utilities/gsc.js +69 -0
  144. package/dist/utilities/helpers.d.ts +7 -0
  145. package/dist/utilities/helpers.d.ts.map +1 -0
  146. package/dist/utilities/helpers.js +44 -0
  147. package/dist/utilities/pagespeed.d.ts +3 -0
  148. package/dist/utilities/pagespeed.d.ts.map +1 -0
  149. package/dist/utilities/pagespeed.js +49 -0
  150. package/dist/utilities/providers.d.ts +3 -0
  151. package/dist/utilities/providers.d.ts.map +1 -0
  152. package/dist/utilities/providers.js +18 -0
  153. package/dist/utilities/runAudit.d.ts +14 -0
  154. package/dist/utilities/runAudit.d.ts.map +1 -0
  155. package/dist/utilities/runAudit.js +224 -0
  156. package/dist/utilities/scoring.d.ts +3 -0
  157. package/dist/utilities/scoring.d.ts.map +1 -0
  158. package/dist/utilities/scoring.js +45 -0
  159. package/dist/utilities/triggers.d.ts +3 -0
  160. package/dist/utilities/triggers.d.ts.map +1 -0
  161. package/dist/utilities/triggers.js +39 -0
  162. package/dist/utilities/types.d.ts +87 -0
  163. package/dist/utilities/types.d.ts.map +1 -0
  164. package/dist/utilities/types.js +2 -0
  165. package/package.json +63 -0
@@ -0,0 +1,170 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SeoPageResults = void 0;
4
+ const access_1 = require("../utilities/access");
5
+ exports.SeoPageResults = {
6
+ slug: 'seo-page-results',
7
+ admin: {
8
+ useAsTitle: 'url',
9
+ defaultColumns: ['url', 'snapshot', 'overallScore', 'checkedAt'],
10
+ group: 'SEO',
11
+ components: {
12
+ views: {
13
+ edit: {
14
+ root: {
15
+ Component: '@orion-studios/payload-seo-audit/components#SeoPageReport',
16
+ },
17
+ },
18
+ },
19
+ },
20
+ },
21
+ access: {
22
+ read: access_1.seoAdminAccess,
23
+ create: access_1.seoAdminAccess,
24
+ update: access_1.seoAdminAccess,
25
+ delete: access_1.seoAdminAccess,
26
+ },
27
+ fields: [
28
+ {
29
+ name: 'snapshot',
30
+ type: 'relationship',
31
+ relationTo: 'seo-snapshots',
32
+ required: true,
33
+ index: true,
34
+ },
35
+ {
36
+ name: 'url',
37
+ type: 'text',
38
+ required: true,
39
+ index: true,
40
+ },
41
+ {
42
+ name: 'path',
43
+ type: 'text',
44
+ },
45
+ {
46
+ name: 'statusCode',
47
+ type: 'number',
48
+ },
49
+ {
50
+ name: 'title',
51
+ type: 'text',
52
+ },
53
+ {
54
+ name: 'metaDescription',
55
+ type: 'textarea',
56
+ },
57
+ {
58
+ name: 'canonical',
59
+ type: 'text',
60
+ },
61
+ {
62
+ name: 'robotsMeta',
63
+ type: 'text',
64
+ },
65
+ {
66
+ name: 'h1Count',
67
+ type: 'number',
68
+ },
69
+ {
70
+ name: 'headingOrderIssues',
71
+ type: 'number',
72
+ },
73
+ {
74
+ name: 'internalLinks',
75
+ type: 'number',
76
+ },
77
+ {
78
+ name: 'externalLinks',
79
+ type: 'number',
80
+ },
81
+ {
82
+ name: 'imagesTotal',
83
+ type: 'number',
84
+ },
85
+ {
86
+ name: 'imagesMissingAlt',
87
+ type: 'number',
88
+ },
89
+ {
90
+ name: 'structuredDataBlocks',
91
+ type: 'number',
92
+ },
93
+ {
94
+ name: 'scoreBreakdown',
95
+ type: 'group',
96
+ fields: [
97
+ { name: 'metadata', type: 'number' },
98
+ { name: 'indexability', type: 'number' },
99
+ { name: 'structure', type: 'number' },
100
+ { name: 'links', type: 'number' },
101
+ { name: 'media', type: 'number' },
102
+ { name: 'structuredData', type: 'number' },
103
+ ],
104
+ },
105
+ {
106
+ name: 'overallScore',
107
+ type: 'number',
108
+ },
109
+ {
110
+ name: 'issues',
111
+ type: 'array',
112
+ fields: [
113
+ {
114
+ name: 'fingerprint',
115
+ type: 'text',
116
+ required: true,
117
+ index: true,
118
+ },
119
+ {
120
+ name: 'ruleID',
121
+ type: 'text',
122
+ required: true,
123
+ },
124
+ {
125
+ name: 'category',
126
+ type: 'select',
127
+ required: true,
128
+ options: [
129
+ { label: 'Metadata', value: 'metadata' },
130
+ { label: 'Indexability', value: 'indexability' },
131
+ { label: 'Structure', value: 'structure' },
132
+ { label: 'Links', value: 'links' },
133
+ { label: 'Media', value: 'media' },
134
+ { label: 'Structured Data', value: 'structuredData' },
135
+ { label: 'Performance', value: 'performance' },
136
+ ],
137
+ },
138
+ {
139
+ name: 'severity',
140
+ type: 'select',
141
+ required: true,
142
+ options: [
143
+ { label: 'Critical', value: 'critical' },
144
+ { label: 'High', value: 'high' },
145
+ { label: 'Medium', value: 'medium' },
146
+ { label: 'Low', value: 'low' },
147
+ { label: 'Info', value: 'info' },
148
+ ],
149
+ },
150
+ {
151
+ name: 'message',
152
+ type: 'text',
153
+ required: true,
154
+ },
155
+ {
156
+ name: 'recommendation',
157
+ type: 'textarea',
158
+ },
159
+ ],
160
+ },
161
+ {
162
+ name: 'checkedAt',
163
+ type: 'date',
164
+ required: true,
165
+ admin: {
166
+ date: { pickerAppearance: 'dayAndTime' },
167
+ },
168
+ },
169
+ ],
170
+ };
@@ -0,0 +1,3 @@
1
+ import type { CollectionConfig } from 'payload';
2
+ export declare const SeoSnapshots: CollectionConfig;
3
+ //# sourceMappingURL=SeoSnapshots.d.ts.map
@@ -0,0 +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"}
@@ -0,0 +1,131 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SeoSnapshots = void 0;
4
+ const access_1 = require("../utilities/access");
5
+ exports.SeoSnapshots = {
6
+ slug: 'seo-snapshots',
7
+ admin: {
8
+ useAsTitle: 'runLabel',
9
+ defaultColumns: ['runLabel', 'status', 'startedAt', 'completedAt'],
10
+ group: 'SEO',
11
+ components: {
12
+ views: {
13
+ edit: {
14
+ root: {
15
+ Component: '@orion-studios/payload-seo-audit/components#SeoSnapshotReport',
16
+ },
17
+ },
18
+ },
19
+ },
20
+ },
21
+ access: {
22
+ read: access_1.seoAdminAccess,
23
+ create: access_1.seoAdminAccess,
24
+ update: access_1.seoAdminAccess,
25
+ delete: access_1.seoAdminAccess,
26
+ },
27
+ hooks: {
28
+ beforeDelete: [
29
+ async ({ req, id }) => {
30
+ const pageResults = await req.payload.find({
31
+ collection: 'seo-page-results',
32
+ where: {
33
+ snapshot: { equals: id },
34
+ },
35
+ limit: 1000,
36
+ });
37
+ await Promise.all(pageResults.docs.map((doc) => req.payload.delete({
38
+ collection: 'seo-page-results',
39
+ id: doc.id,
40
+ })));
41
+ },
42
+ ],
43
+ },
44
+ fields: [
45
+ {
46
+ name: 'runLabel',
47
+ type: 'text',
48
+ required: true,
49
+ },
50
+ {
51
+ name: 'runType',
52
+ type: 'select',
53
+ required: true,
54
+ options: [
55
+ { label: 'Scheduled', value: 'scheduled' },
56
+ { label: 'Manual', value: 'manual' },
57
+ { label: 'Publish Triggered', value: 'publish-triggered' },
58
+ ],
59
+ },
60
+ {
61
+ name: 'status',
62
+ type: 'select',
63
+ defaultValue: 'pending',
64
+ options: [
65
+ { label: 'Pending', value: 'pending' },
66
+ { label: 'Completed', value: 'completed' },
67
+ { label: 'Failed', value: 'failed' },
68
+ ],
69
+ required: true,
70
+ },
71
+ {
72
+ name: 'startedAt',
73
+ type: 'date',
74
+ required: true,
75
+ admin: {
76
+ date: { pickerAppearance: 'dayAndTime' },
77
+ },
78
+ },
79
+ {
80
+ name: 'completedAt',
81
+ type: 'date',
82
+ admin: {
83
+ date: { pickerAppearance: 'dayAndTime' },
84
+ },
85
+ },
86
+ {
87
+ name: 'scores',
88
+ type: 'group',
89
+ fields: [
90
+ { name: 'metadata', type: 'number' },
91
+ { name: 'indexability', type: 'number' },
92
+ { name: 'structure', type: 'number' },
93
+ { name: 'links', type: 'number' },
94
+ { name: 'media', type: 'number' },
95
+ { name: 'structuredData', type: 'number' },
96
+ { name: 'performance', type: 'number' },
97
+ { name: 'overall', type: 'number' },
98
+ ],
99
+ },
100
+ {
101
+ name: 'metrics',
102
+ type: 'group',
103
+ fields: [
104
+ { name: 'pagesCrawled', type: 'number' },
105
+ { name: 'pagesChecked', type: 'number' },
106
+ { name: 'avgLighthousePerformance', type: 'number' },
107
+ { name: 'avgLCPMs', type: 'number' },
108
+ { name: 'avgCLS', type: 'number' },
109
+ ],
110
+ },
111
+ {
112
+ name: 'issueCounts',
113
+ type: 'group',
114
+ fields: [
115
+ { name: 'critical', type: 'number' },
116
+ { name: 'high', type: 'number' },
117
+ { name: 'medium', type: 'number' },
118
+ { name: 'low', type: 'number' },
119
+ { name: 'info', type: 'number' },
120
+ ],
121
+ },
122
+ {
123
+ name: 'summary',
124
+ type: 'textarea',
125
+ },
126
+ {
127
+ name: 'errorMessage',
128
+ type: 'textarea',
129
+ },
130
+ ],
131
+ };
@@ -0,0 +1,7 @@
1
+ export declare function useSeoApi<T>(): {
2
+ fetchData: (url: string) => Promise<T | null>;
3
+ data: T | null;
4
+ loading: boolean;
5
+ error: string | null;
6
+ };
7
+ //# sourceMappingURL=useSeoApi.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useSeoApi.d.ts","sourceRoot":"","sources":["../../../src/components/hooks/useSeoApi.ts"],"names":[],"mappings":"AAUA,wBAAgB,SAAS,CAAC,CAAC;qBAOiB,MAAM;;aAXvC,OAAO;WACT,MAAM,GAAG,IAAI;EAgCrB"}
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+ 'use client';
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.useSeoApi = useSeoApi;
5
+ const react_1 = require("react");
6
+ function useSeoApi() {
7
+ const [state, setState] = (0, react_1.useState)({
8
+ data: null,
9
+ loading: false,
10
+ error: null,
11
+ });
12
+ const fetchData = (0, react_1.useCallback)(async (url) => {
13
+ setState((prev) => ({ ...prev, loading: true, error: null }));
14
+ try {
15
+ const response = await fetch(url, { credentials: 'include' });
16
+ if (!response.ok) {
17
+ const body = (await response.json().catch(() => ({})));
18
+ throw new Error(body.error || `Request failed with ${response.status}`);
19
+ }
20
+ const data = (await response.json());
21
+ setState({ data, loading: false, error: null });
22
+ return data;
23
+ }
24
+ catch (err) {
25
+ const message = err instanceof Error ? err.message : 'An error occurred';
26
+ setState((prev) => ({ ...prev, loading: false, error: message }));
27
+ return null;
28
+ }
29
+ }, []);
30
+ return { ...state, fetchData };
31
+ }
@@ -0,0 +1,19 @@
1
+ import type { SEOPageResult } from '../types';
2
+ export declare function useSeoPageResults(snapshotId?: number | string | null, options?: {
3
+ sort?: string;
4
+ order?: 'asc' | 'desc';
5
+ limit?: number;
6
+ }): {
7
+ docs: SEOPageResult[];
8
+ pagination: {
9
+ totalDocs: number;
10
+ totalPages: number;
11
+ page: number;
12
+ hasNextPage: boolean;
13
+ hasPrevPage: boolean;
14
+ };
15
+ loading: boolean;
16
+ error: string | null;
17
+ fetchPage: (page?: number) => Promise<void>;
18
+ };
19
+ //# sourceMappingURL=useSeoPageResults.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useSeoPageResults.d.ts","sourceRoot":"","sources":["../../../src/components/hooks/useSeoPageResults.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAW7C,wBAAgB,iBAAiB,CAC/B,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,EACnC,OAAO,CAAC,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,KAAK,GAAG,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE;;;;;;;;;;;;EAgEpE"}
@@ -0,0 +1,62 @@
1
+ "use strict";
2
+ 'use client';
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.useSeoPageResults = useSeoPageResults;
5
+ const react_1 = require("react");
6
+ function useSeoPageResults(snapshotId, options) {
7
+ const [docs, setDocs] = (0, react_1.useState)([]);
8
+ const [pagination, setPagination] = (0, react_1.useState)({
9
+ totalDocs: 0,
10
+ totalPages: 0,
11
+ page: 1,
12
+ hasNextPage: false,
13
+ hasPrevPage: false,
14
+ });
15
+ const [loading, setLoading] = (0, react_1.useState)(true);
16
+ const [error, setError] = (0, react_1.useState)(null);
17
+ const fetchPage = (0, react_1.useCallback)(async (page = 1) => {
18
+ if (!snapshotId) {
19
+ setLoading(false);
20
+ return;
21
+ }
22
+ setLoading(true);
23
+ setError(null);
24
+ try {
25
+ const params = new URLSearchParams({
26
+ snapshot: String(snapshotId),
27
+ page: String(page),
28
+ limit: String(options?.limit ?? 50),
29
+ });
30
+ if (options?.sort)
31
+ params.set('sort', options.sort);
32
+ if (options?.order)
33
+ params.set('order', options.order);
34
+ const response = await fetch(`/api/seo/page-results?${params.toString()}`, {
35
+ credentials: 'include',
36
+ });
37
+ if (!response.ok) {
38
+ const body = (await response.json().catch(() => ({})));
39
+ throw new Error(body.error || `Request failed with ${response.status}`);
40
+ }
41
+ const data = (await response.json());
42
+ setDocs(data.docs);
43
+ setPagination({
44
+ totalDocs: data.totalDocs,
45
+ totalPages: data.totalPages,
46
+ page: data.page,
47
+ hasNextPage: data.hasNextPage,
48
+ hasPrevPage: data.hasPrevPage,
49
+ });
50
+ }
51
+ catch (err) {
52
+ setError(err instanceof Error ? err.message : 'Failed to load page results');
53
+ }
54
+ finally {
55
+ setLoading(false);
56
+ }
57
+ }, [snapshotId, options?.sort, options?.order, options?.limit]);
58
+ (0, react_1.useEffect)(() => {
59
+ void fetchPage(1);
60
+ }, [fetchPage]);
61
+ return { docs, pagination, loading, error, fetchPage };
62
+ }
@@ -0,0 +1,8 @@
1
+ import type { SEOSnapshotReportData } from '../types';
2
+ export declare function useSeoSnapshot(snapshotId?: number | string | null): {
3
+ data: SEOSnapshotReportData | null;
4
+ loading: boolean;
5
+ error: string | null;
6
+ refresh: () => Promise<void>;
7
+ };
8
+ //# sourceMappingURL=useSeoSnapshot.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useSeoSnapshot.d.ts","sourceRoot":"","sources":["../../../src/components/hooks/useSeoSnapshot.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAA;AAErD,wBAAgB,cAAc,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;;;;;EAsCjE"}
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+ 'use client';
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.useSeoSnapshot = useSeoSnapshot;
5
+ const react_1 = require("react");
6
+ function useSeoSnapshot(snapshotId) {
7
+ const [data, setData] = (0, react_1.useState)(null);
8
+ const [loading, setLoading] = (0, react_1.useState)(true);
9
+ const [error, setError] = (0, react_1.useState)(null);
10
+ const fetchReport = (0, react_1.useCallback)(async () => {
11
+ if (!snapshotId) {
12
+ setLoading(false);
13
+ return;
14
+ }
15
+ setLoading(true);
16
+ setError(null);
17
+ try {
18
+ const response = await fetch(`/api/seo/snapshot-report?snapshot=${snapshotId}`, {
19
+ credentials: 'include',
20
+ });
21
+ if (!response.ok) {
22
+ const body = (await response.json().catch(() => ({})));
23
+ throw new Error(body.error || `Request failed with ${response.status}`);
24
+ }
25
+ const result = (await response.json());
26
+ setData(result);
27
+ }
28
+ catch (err) {
29
+ setError(err instanceof Error ? err.message : 'Failed to load snapshot report');
30
+ }
31
+ finally {
32
+ setLoading(false);
33
+ }
34
+ }, [snapshotId]);
35
+ (0, react_1.useEffect)(() => {
36
+ void fetchReport();
37
+ }, [fetchReport]);
38
+ return { data, loading, error, refresh: fetchReport };
39
+ }
@@ -0,0 +1,8 @@
1
+ import type { SEOTrendPoint } from '../types';
2
+ export declare function useSeoTrend(siteId?: number | string, limit?: number): {
3
+ points: SEOTrendPoint[];
4
+ loading: boolean;
5
+ error: string | null;
6
+ refresh: () => Promise<void>;
7
+ };
8
+ //# sourceMappingURL=useSeoTrend.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useSeoTrend.d.ts","sourceRoot":"","sources":["../../../src/components/hooks/useSeoTrend.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAI7C,wBAAgB,WAAW,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,KAAK,SAAK;;;;;EAoC/D"}
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+ 'use client';
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.useSeoTrend = useSeoTrend;
5
+ const react_1 = require("react");
6
+ function useSeoTrend(siteId, limit = 12) {
7
+ const [points, setPoints] = (0, react_1.useState)([]);
8
+ const [loading, setLoading] = (0, react_1.useState)(true);
9
+ const [error, setError] = (0, react_1.useState)(null);
10
+ const fetchTrend = (0, react_1.useCallback)(async () => {
11
+ setLoading(true);
12
+ setError(null);
13
+ try {
14
+ const params = new URLSearchParams({ limit: String(limit) });
15
+ if (siteId)
16
+ params.set('site', String(siteId));
17
+ const response = await fetch(`/api/seo/trend?${params.toString()}`, {
18
+ credentials: 'include',
19
+ });
20
+ if (!response.ok) {
21
+ const body = (await response.json().catch(() => ({})));
22
+ throw new Error(body.error || `Request failed with ${response.status}`);
23
+ }
24
+ const data = (await response.json());
25
+ setPoints(data.points || []);
26
+ }
27
+ catch (err) {
28
+ setError(err instanceof Error ? err.message : 'Failed to load trend data');
29
+ }
30
+ finally {
31
+ setLoading(false);
32
+ }
33
+ }, [siteId, limit]);
34
+ (0, react_1.useEffect)(() => {
35
+ void fetchTrend();
36
+ }, [fetchTrend]);
37
+ return { points, loading, error, refresh: fetchTrend };
38
+ }
@@ -0,0 +1,10 @@
1
+ import React from 'react';
2
+ type SeoReportHeaderProps = {
3
+ title: string;
4
+ subtitle?: string;
5
+ actions?: React.ReactNode;
6
+ badges?: React.ReactNode;
7
+ };
8
+ export declare const SeoReportHeader: React.FC<SeoReportHeaderProps>;
9
+ export {};
10
+ //# sourceMappingURL=SeoReportHeader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SeoReportHeader.d.ts","sourceRoot":"","sources":["../../../src/components/layout/SeoReportHeader.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB,KAAK,oBAAoB,GAAG;IAC1B,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,OAAO,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IACzB,MAAM,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;CACzB,CAAA;AAED,eAAO,MAAM,eAAe,EAAE,KAAK,CAAC,EAAE,CAAC,oBAAoB,CAkB1D,CAAA"}
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ 'use client';
3
+ var __importDefault = (this && this.__importDefault) || function (mod) {
4
+ return (mod && mod.__esModule) ? mod : { "default": mod };
5
+ };
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.SeoReportHeader = void 0;
8
+ const react_1 = __importDefault(require("react"));
9
+ const SeoReportHeader = ({ title, subtitle, actions, badges, }) => {
10
+ return (react_1.default.createElement("div", { className: "flex flex-wrap items-start justify-between gap-4" },
11
+ react_1.default.createElement("div", null,
12
+ react_1.default.createElement("div", { className: "flex flex-wrap items-center gap-2" },
13
+ react_1.default.createElement("h1", { className: "text-xl font-semibold text-slate-900 dark:text-slate-100" }, title),
14
+ badges),
15
+ subtitle && react_1.default.createElement("p", { className: "mt-1 text-sm text-slate-500 dark:text-slate-400" }, subtitle)),
16
+ actions && react_1.default.createElement("div", { className: "flex items-center gap-2" }, actions)));
17
+ };
18
+ exports.SeoReportHeader = SeoReportHeader;
@@ -0,0 +1,9 @@
1
+ import React from 'react';
2
+ type SeoReportShellProps = {
3
+ children: React.ReactNode;
4
+ onBack?: () => void;
5
+ backLabel?: string;
6
+ };
7
+ export declare const SeoReportShell: React.FC<SeoReportShellProps>;
8
+ export {};
9
+ //# sourceMappingURL=SeoReportShell.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SeoReportShell.d.ts","sourceRoot":"","sources":["../../../src/components/layout/SeoReportShell.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB,KAAK,mBAAmB,GAAG;IACzB,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;IACzB,MAAM,CAAC,EAAE,MAAM,IAAI,CAAA;IACnB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,CAAA;AAED,eAAO,MAAM,cAAc,EAAE,KAAK,CAAC,EAAE,CAAC,mBAAmB,CAsBxD,CAAA"}
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ 'use client';
3
+ var __importDefault = (this && this.__importDefault) || function (mod) {
4
+ return (mod && mod.__esModule) ? mod : { "default": mod };
5
+ };
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.SeoReportShell = void 0;
8
+ const react_1 = __importDefault(require("react"));
9
+ const SeoReportShell = ({ children, onBack, backLabel = 'Back', }) => {
10
+ return (react_1.default.createElement("div", { className: "seo-report mx-auto max-w-7xl space-y-6 p-6" },
11
+ onBack && (react_1.default.createElement("button", { type: "button", onClick: onBack, className: "flex items-center gap-1 text-sm text-slate-500 hover:text-slate-700" },
12
+ react_1.default.createElement("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", className: "inline" },
13
+ react_1.default.createElement("path", { d: "M10 12L6 8l4-4", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" })),
14
+ backLabel)),
15
+ children));
16
+ };
17
+ exports.SeoReportShell = SeoReportShell;
@@ -0,0 +1,9 @@
1
+ import React from 'react';
2
+ type PdfDownloadButtonProps = {
3
+ targetId: string;
4
+ filename: string;
5
+ label?: string;
6
+ };
7
+ export declare const PdfDownloadButton: React.FC<PdfDownloadButtonProps>;
8
+ export {};
9
+ //# sourceMappingURL=PdfDownloadButton.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PdfDownloadButton.d.ts","sourceRoot":"","sources":["../../../src/components/pdf/PdfDownloadButton.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAgC,MAAM,OAAO,CAAA;AAEpD,KAAK,sBAAsB,GAAG;IAC5B,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,MAAM,CAAA;IAChB,KAAK,CAAC,EAAE,MAAM,CAAA;CACf,CAAA;AAED,eAAO,MAAM,iBAAiB,EAAE,KAAK,CAAC,EAAE,CAAC,sBAAsB,CA4D9D,CAAA"}