@prenta/core 7.7.0 → 7.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/dist/api/routes/seo/handlers/analysis.d.ts +4 -0
  3. package/dist/api/routes/seo/handlers/analysis.d.ts.map +1 -0
  4. package/dist/api/routes/seo/handlers/analysis.js +131 -0
  5. package/dist/api/routes/seo/handlers/analysis.js.map +1 -0
  6. package/dist/api/routes/seo/handlers/audits.d.ts +5 -0
  7. package/dist/api/routes/seo/handlers/audits.d.ts.map +1 -0
  8. package/dist/api/routes/seo/handlers/audits.js +121 -0
  9. package/dist/api/routes/seo/handlers/audits.js.map +1 -0
  10. package/dist/api/routes/seo/handlers/content.d.ts +4 -0
  11. package/dist/api/routes/seo/handlers/content.d.ts.map +1 -0
  12. package/dist/api/routes/seo/handlers/content.js +330 -0
  13. package/dist/api/routes/seo/handlers/content.js.map +1 -0
  14. package/dist/api/routes/seo/handlers/issue-helpers.d.ts +37 -0
  15. package/dist/api/routes/seo/handlers/issue-helpers.d.ts.map +1 -0
  16. package/dist/api/routes/seo/handlers/issue-helpers.js +72 -0
  17. package/dist/api/routes/seo/handlers/issue-helpers.js.map +1 -0
  18. package/dist/api/routes/seo/handlers/issues-briefs.d.ts +7 -0
  19. package/dist/api/routes/seo/handlers/issues-briefs.d.ts.map +1 -0
  20. package/dist/api/routes/seo/handlers/issues-briefs.js +341 -0
  21. package/dist/api/routes/seo/handlers/issues-briefs.js.map +1 -0
  22. package/dist/api/routes/seo/handlers/issues-fixes.d.ts +4 -0
  23. package/dist/api/routes/seo/handlers/issues-fixes.d.ts.map +1 -0
  24. package/dist/api/routes/seo/handlers/issues-fixes.js +233 -0
  25. package/dist/api/routes/seo/handlers/issues-fixes.js.map +1 -0
  26. package/dist/api/routes/seo/handlers/issues-list.d.ts +7 -0
  27. package/dist/api/routes/seo/handlers/issues-list.d.ts.map +1 -0
  28. package/dist/api/routes/seo/handlers/issues-list.js +191 -0
  29. package/dist/api/routes/seo/handlers/issues-list.js.map +1 -0
  30. package/dist/api/routes/seo/handlers/links.d.ts +6 -0
  31. package/dist/api/routes/seo/handlers/links.d.ts.map +1 -0
  32. package/dist/api/routes/seo/handlers/links.js +383 -0
  33. package/dist/api/routes/seo/handlers/links.js.map +1 -0
  34. package/dist/api/routes/seo/handlers/overview.d.ts +4 -0
  35. package/dist/api/routes/seo/handlers/overview.d.ts.map +1 -0
  36. package/dist/api/routes/seo/handlers/overview.js +348 -0
  37. package/dist/api/routes/seo/handlers/overview.js.map +1 -0
  38. package/dist/api/routes/seo/handlers/pages.d.ts +2 -0
  39. package/dist/api/routes/seo/handlers/pages.d.ts.map +1 -0
  40. package/dist/api/routes/seo/handlers/pages.js +38 -0
  41. package/dist/api/routes/seo/handlers/pages.js.map +1 -0
  42. package/dist/api/routes/seo/handlers/proposals.d.ts +4 -0
  43. package/dist/api/routes/seo/handlers/proposals.d.ts.map +1 -0
  44. package/dist/api/routes/seo/handlers/proposals.js +93 -0
  45. package/dist/api/routes/seo/handlers/proposals.js.map +1 -0
  46. package/dist/api/routes/seo/handlers/public-files.d.ts +6 -0
  47. package/dist/api/routes/seo/handlers/public-files.d.ts.map +1 -0
  48. package/dist/api/routes/seo/handlers/public-files.js +328 -0
  49. package/dist/api/routes/seo/handlers/public-files.js.map +1 -0
  50. package/dist/api/routes/seo/handlers/shared.d.ts +24 -0
  51. package/dist/api/routes/seo/handlers/shared.d.ts.map +1 -0
  52. package/dist/api/routes/seo/handlers/shared.js +67 -0
  53. package/dist/api/routes/seo/handlers/shared.js.map +1 -0
  54. package/dist/api/routes/seo.d.ts +5 -5
  55. package/dist/api/routes/seo.d.ts.map +1 -1
  56. package/dist/api/routes/seo.js +56 -2610
  57. package/dist/api/routes/seo.js.map +1 -1
  58. package/package.json +1 -1
@@ -0,0 +1,233 @@
1
+ import { logEvent } from '../../../../security/audit.js';
2
+ import { hasPlanFeature } from '../../../../plan/features.js';
3
+ import { json, errorResponse, internalError, asRecord, hasModel, modelNotAvailable, requireAuth, WRITE_ROLES, ADMIN_ROLES, requireRole, aiGenerateLimiter, checkRateLimitAsync, } from '../../../route-helpers.js';
4
+ import { seoApplyFixBodySchema, validateBody } from '../../../validate-body.js';
5
+ import { db, seoLogger, planRequiredResponse, contentWriteGate } from './shared.js';
6
+ import { seoIssueToApi, loadIssueFixContext } from './issue-helpers.js';
7
+ export async function postSeoIssueSuggestFix(request, params) {
8
+ try {
9
+ const auth = await requireAuth(request);
10
+ if (auth.error)
11
+ return auth.error;
12
+ if (!hasModel(db(), 'seoIssue'))
13
+ return modelNotAvailable('SeoIssue');
14
+ const issue = await db().seoIssue.findUnique({ where: { id: params.id } });
15
+ if (!issue)
16
+ return errorResponse('Issue not found', 404);
17
+ const loaded = await loadIssueFixContext(issue);
18
+ if ('error' in loaded)
19
+ return loaded.error;
20
+ const issueInput = {
21
+ type: issue.type,
22
+ title: issue.title,
23
+ recommendation: issue.recommendation,
24
+ entityType: issue.entityType,
25
+ entityId: issue.entityId,
26
+ };
27
+ const fixCtx = {
28
+ entity: loaded.entity,
29
+ siteSeo: loaded.siteSeo,
30
+ updatedAt: loaded.updatedAt,
31
+ metadata: asRecord(issue.metadata),
32
+ };
33
+ let aiDeps;
34
+ const { REDIRECT_FIX_TYPES } = await import('../../../../seo/issue-fix-redirect.js');
35
+ const { INSERT_LINK_FIX_TYPES } = await import('../../../../seo/issue-fix-link-insert.js');
36
+ if (REDIRECT_FIX_TYPES.has(issue.type) || INSERT_LINK_FIX_TYPES.has(issue.type)) {
37
+ aiDeps = {
38
+ db: db(),
39
+ userId: auth.session.userId,
40
+ collection: loaded.collection,
41
+ };
42
+ }
43
+ else {
44
+ const adminErr = requireRole(auth.session.role, ADMIN_ROLES);
45
+ if (!adminErr &&
46
+ hasPlanFeature('seo.inlineApply') &&
47
+ (await checkRateLimitAsync(aiGenerateLimiter, `ai-seo-fix-suggest:${auth.session.userId}`))) {
48
+ aiDeps = {
49
+ db: db(),
50
+ userId: auth.session.userId,
51
+ collection: loaded.collection,
52
+ };
53
+ }
54
+ }
55
+ const { suggestIssueFix } = await import('../../../../seo/issue-fix.js');
56
+ const { pendingFixToMetadata, scoreFixBrandAlignment } = await import('../../../../seo/issue-fix-ai.js');
57
+ const result = await suggestIssueFix(issueInput, fixCtx, aiDeps);
58
+ const existingMeta = asRecord(issue.metadata);
59
+ let nextMetadata;
60
+ if (result.cacheForApply) {
61
+ // Deterministic brand-voice score stamped at generation (no LLM call)
62
+ // so the proposals inbox can badge it without re-scoring.
63
+ const { getAIConfig } = await import('../../../../ai/config-store.js');
64
+ const brandVoice = await getAIConfig(db())
65
+ .then((c) => c.settings.brandVoice)
66
+ .catch((err) => {
67
+ // Fail open: an unreadable AI config must not cost a working suggestion.
68
+ seoLogger.warn('AI config unavailable for brand alignment', {
69
+ error: err instanceof Error ? err.message : String(err),
70
+ });
71
+ return undefined;
72
+ });
73
+ nextMetadata = {
74
+ ...existingMeta,
75
+ ...pendingFixToMetadata(result.suggestion, {
76
+ brandAlignment: scoreFixBrandAlignment(result.suggestion.changes, brandVoice),
77
+ }),
78
+ };
79
+ }
80
+ else {
81
+ nextMetadata = { ...existingMeta, pendingFix: null };
82
+ }
83
+ await db().seoIssue.update({
84
+ where: { id: issue.id },
85
+ data: { metadata: nextMetadata },
86
+ });
87
+ return json({ data: { suggestion: result.suggestion } });
88
+ }
89
+ catch (err) {
90
+ return internalError(err, 'seo/issues/:id/suggest-fix');
91
+ }
92
+ }
93
+ export async function postSeoIssueApplyFix(request, params) {
94
+ try {
95
+ const auth = await requireAuth(request);
96
+ if (auth.error)
97
+ return auth.error;
98
+ const roleErr = requireRole(auth.session.role, WRITE_ROLES);
99
+ if (roleErr)
100
+ return roleErr;
101
+ if (!hasModel(db(), 'seoIssue'))
102
+ return modelNotAvailable('SeoIssue');
103
+ const parsed = await validateBody(request, seoApplyFixBodySchema);
104
+ if (!parsed.ok)
105
+ return parsed.error;
106
+ const body = parsed.data;
107
+ const [{ applyIssueFix, VERIFY_FAILED_MESSAGE }, { FAQ_HEADING_MAX, FAQ_MAX_ITEMS }] = await Promise.all([
108
+ import('../../../../seo/issue-fix-apply.js'),
109
+ import('../../../../seo/issue-fix-faq.js'),
110
+ ]);
111
+ const fingerprint = typeof body?.fingerprint === 'string' ? body.fingerprint : undefined;
112
+ // `includeItems` / `headingOverride` only mean something for `add-section`
113
+ // fixes; they are validated for shape here and ignored by other branches.
114
+ let includeItems;
115
+ if (body?.includeItems !== undefined) {
116
+ const raw = body.includeItems;
117
+ if (!Array.isArray(raw) ||
118
+ raw.length > FAQ_MAX_ITEMS ||
119
+ !raw.every((n) => typeof n === 'number' && Number.isInteger(n) && n >= 0) ||
120
+ new Set(raw).size !== raw.length) {
121
+ return errorResponse(`includeItems must be an array of at most ${FAQ_MAX_ITEMS} distinct non-negative integers`, 400);
122
+ }
123
+ includeItems = raw;
124
+ }
125
+ let headingOverride;
126
+ if (body?.headingOverride !== undefined) {
127
+ // Trimmed length is the one that lands in the section, so it is the one measured.
128
+ const trimmed = typeof body.headingOverride === 'string' ? body.headingOverride.trim() : null;
129
+ if (trimmed === null || trimmed.length > FAQ_HEADING_MAX) {
130
+ return errorResponse(`headingOverride must be a string of at most ${FAQ_HEADING_MAX} characters`, 400);
131
+ }
132
+ headingOverride = trimmed;
133
+ }
134
+ const result = await applyIssueFix(db(), {
135
+ issueId: params.id,
136
+ fingerprint,
137
+ includeItems,
138
+ headingOverride,
139
+ actor: { userId: auth.session.userId, role: auth.session.role },
140
+ authorizeContentWrite: contentWriteGate(auth.session),
141
+ });
142
+ switch (result.status) {
143
+ case 'applied':
144
+ return json({
145
+ data: {
146
+ issue: seoIssueToApi(result.issue),
147
+ applied: result.applied,
148
+ ...(result.sectionId ? { sectionId: result.sectionId } : {}),
149
+ },
150
+ });
151
+ case 'stale':
152
+ return errorResponse(result.reason, 409);
153
+ case 'verify-failed':
154
+ return json({ error: VERIFY_FAILED_MESSAGE, reason: result.reason }, 409);
155
+ case 'plan-required':
156
+ return planRequiredResponse(result.denial);
157
+ case 'not-found':
158
+ return errorResponse(result.reason, 404);
159
+ case 'not-allowed':
160
+ return errorResponse(result.reason, result.httpStatus);
161
+ case 'not-fixable':
162
+ return errorResponse(result.reason, result.httpStatus);
163
+ default: {
164
+ const _exhaustive = result;
165
+ return _exhaustive;
166
+ }
167
+ }
168
+ }
169
+ catch (err) {
170
+ return internalError(err, 'seo/issues/:id/apply-fix');
171
+ }
172
+ }
173
+ export async function postSeoIssueDismissFix(request, params) {
174
+ try {
175
+ const auth = await requireAuth(request);
176
+ if (auth.error)
177
+ return auth.error;
178
+ const roleErr = requireRole(auth.session.role, WRITE_ROLES);
179
+ if (roleErr)
180
+ return roleErr;
181
+ if (!hasModel(db(), 'seoIssue'))
182
+ return modelNotAvailable('SeoIssue');
183
+ const issue = await db().seoIssue.findUnique({ where: { id: params.id } });
184
+ if (!issue)
185
+ return errorResponse('Issue not found', 404);
186
+ const { pendingFixFromMetadata } = await import('../../../../seo/issue-fix-ai.js');
187
+ const cached = pendingFixFromMetadata(issue.metadata);
188
+ if (!cached)
189
+ return json({ data: { dismissed: false } });
190
+ // Sticky: remember which document state was rejected so batch
191
+ // generation does not recreate it until the document changes. The
192
+ // marker must match the entity-based live fingerprint the no-cache
193
+ // path computes, which differs from the cached one for insert-link.
194
+ const { dismissalFingerprintFor } = await import('../../../../seo/proposals.js');
195
+ const entityDoc = typeof issue.entityId === 'string'
196
+ ? await db()
197
+ .document.findUnique({ where: { id: issue.entityId }, select: { updatedAt: true } })
198
+ .catch(() => null)
199
+ : null;
200
+ const dismissedFingerprint = dismissalFingerprintFor(issue, cached, entityDoc?.updatedAt ?? null);
201
+ await db().seoIssue.update({
202
+ where: { id: issue.id },
203
+ data: {
204
+ metadata: {
205
+ ...asRecord(issue.metadata),
206
+ pendingFix: null,
207
+ dismissedFingerprint,
208
+ },
209
+ },
210
+ });
211
+ try {
212
+ await logEvent({
213
+ event: 'seo_fix_dismissed',
214
+ userId: auth.session.userId,
215
+ details: {
216
+ issueId: issue.id,
217
+ issueType: issue.type,
218
+ entityId: issue.entityId ?? null,
219
+ fingerprint: dismissedFingerprint,
220
+ source: cached.source,
221
+ },
222
+ });
223
+ }
224
+ catch {
225
+ /* audit-log failures never block */
226
+ }
227
+ return json({ data: { dismissed: true } });
228
+ }
229
+ catch (err) {
230
+ return internalError(err, 'seo/issues/:id/dismiss-fix');
231
+ }
232
+ }
233
+ //# sourceMappingURL=issues-fixes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"issues-fixes.js","sourceRoot":"","sources":["../../../../../src/api/routes/seo/handlers/issues-fixes.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ export declare function getSeoIssues(request: Request): Promise<Response>;
2
+ export declare function getSeoIssuesExportBrief(request: Request): Promise<Response>;
3
+ export declare function getSeoIssue(request: Request, params: Record<string, string>): Promise<Response>;
4
+ export declare function postSeoIssueResolve(request: Request, params: Record<string, string>): Promise<Response>;
5
+ export declare function postSeoIssueIgnore(request: Request, params: Record<string, string>): Promise<Response>;
6
+ export declare function postSeoIssueReopen(request: Request, params: Record<string, string>): Promise<Response>;
7
+ //# sourceMappingURL=issues-list.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"issues-list.d.ts","sourceRoot":"","sources":["../../../../../src/api/routes/seo/handlers/issues-list.ts"],"names":[],"mappings":"AAYA,wBAAsB,YAAY,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,CA2BtE;AAED,wBAAsB,uBAAuB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,CA6IjF;AAED,wBAAsB,WAAW,CAC/B,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC7B,OAAO,CAAC,QAAQ,CAAC,CAWnB;AAED,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC7B,OAAO,CAAC,QAAQ,CAAC,CAEnB;AAED,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC7B,OAAO,CAAC,QAAQ,CAAC,CAEnB;AAED,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC7B,OAAO,CAAC,QAAQ,CAAC,CAEnB"}
@@ -0,0 +1,191 @@
1
+ import { getPrentaConfig } from '../../../../config/runtime.js';
2
+ import { json, errorResponse, internalError, hasModel, modelNotAvailable, requireAuth, } from '../../../route-helpers.js';
3
+ import { db, sortIssuesBySeverity } from './shared.js';
4
+ import { seoIssueToApi, setIssueStatus } from './issue-helpers.js';
5
+ export async function getSeoIssues(request) {
6
+ try {
7
+ const auth = await requireAuth(request);
8
+ if (auth.error)
9
+ return auth.error;
10
+ if (!hasModel(db(), 'seoIssue'))
11
+ return json({ data: { issues: [] } });
12
+ const url = new URL(request.url);
13
+ const where = {};
14
+ const severity = url.searchParams.get('severity');
15
+ const category = url.searchParams.get('category');
16
+ const status = url.searchParams.get('status');
17
+ const auditRunId = url.searchParams.get('auditRunId');
18
+ if (severity)
19
+ where.severity = severity;
20
+ if (category)
21
+ where.category = category;
22
+ if (status)
23
+ where.status = status;
24
+ else
25
+ where.status = { in: ['open', 'recurring'] };
26
+ if (auditRunId)
27
+ where.auditRunId = auditRunId;
28
+ const issues = await db().seoIssue.findMany({
29
+ where,
30
+ orderBy: { lastDetectedAt: 'desc' },
31
+ take: 500,
32
+ });
33
+ return json({ data: { issues: sortIssuesBySeverity(issues).map(seoIssueToApi) } });
34
+ }
35
+ catch (err) {
36
+ return internalError(err, 'seo/issues');
37
+ }
38
+ }
39
+ export async function getSeoIssuesExportBrief(request) {
40
+ try {
41
+ const auth = await requireAuth(request);
42
+ if (auth.error)
43
+ return auth.error;
44
+ if (!hasModel(db(), 'seoIssue')) {
45
+ const { buildSeoFixBriefMarkdown, fixBriefFilename } = await import('../../../../seo/fix-brief-export.js');
46
+ return json({
47
+ data: {
48
+ markdown: buildSeoFixBriefMarkdown({ issues: [], manualOnly: true }),
49
+ filename: fixBriefFilename(),
50
+ issueCount: 0,
51
+ },
52
+ });
53
+ }
54
+ const url = new URL(request.url);
55
+ const severity = url.searchParams.get('severity');
56
+ const status = url.searchParams.get('status');
57
+ const auditRunId = url.searchParams.get('auditRunId');
58
+ const manualOnly = url.searchParams.get('manualOnly') !== 'false';
59
+ const includeContentBriefs = url.searchParams.get('includeContentBriefs') !== 'false';
60
+ const includeContentResearch = url.searchParams.get('includeContentResearch') !== 'false';
61
+ const where = {};
62
+ if (severity)
63
+ where.severity = severity;
64
+ if (status)
65
+ where.status = status;
66
+ else
67
+ where.status = { in: ['open', 'recurring'] };
68
+ if (auditRunId)
69
+ where.auditRunId = auditRunId;
70
+ const issues = sortIssuesBySeverity(await db().seoIssue.findMany({
71
+ where,
72
+ orderBy: { lastDetectedAt: 'desc' },
73
+ take: 500,
74
+ }));
75
+ let runAuditDate = null;
76
+ let runId = auditRunId;
77
+ if (auditRunId && hasModel(db(), 'seoAuditRun')) {
78
+ const run = await db().seoAuditRun.findUnique({ where: { id: auditRunId } });
79
+ runAuditDate = run?.finishedAt ?? run?.startedAt ?? null;
80
+ }
81
+ else if (hasModel(db(), 'seoAuditRun')) {
82
+ const lastRun = await db().seoAuditRun.findFirst({
83
+ where: { status: 'COMPLETED' },
84
+ orderBy: { startedAt: 'desc' },
85
+ });
86
+ runId = lastRun?.id ?? null;
87
+ runAuditDate = lastRun?.finishedAt ?? lastRun?.startedAt ?? null;
88
+ }
89
+ const { applySeoOverrides, getSeoOverrides } = await import('../../../../seo/config-store.js');
90
+ const overrides = await getSeoOverrides(db()).catch(() => null);
91
+ const mergedConfig = applySeoOverrides(getPrentaConfig(), overrides);
92
+ const siteSeo = mergedConfig?.seo;
93
+ const { buildSeoFixBriefMarkdown, filterFixBriefIssues, fixBriefFilename } = await import('../../../../seo/fix-brief-export.js');
94
+ const entityIds = [
95
+ ...new Set(issues
96
+ .map((i) => i.entityId)
97
+ .filter((id) => typeof id === 'string' && id.length > 0)),
98
+ ];
99
+ const updatedAtByEntity = new Map();
100
+ if ((includeContentBriefs || includeContentResearch) && entityIds.length > 0) {
101
+ const docs = await db().document.findMany({
102
+ where: { id: { in: entityIds }, deletedAt: null },
103
+ select: { id: true, updatedAt: true },
104
+ });
105
+ for (const doc of docs) {
106
+ updatedAtByEntity.set(doc.id, doc.updatedAt instanceof Date ? doc.updatedAt : new Date(doc.updatedAt));
107
+ }
108
+ }
109
+ const { contentBriefFromMetadata } = await import('../../../../seo/issue-content-brief.js');
110
+ const { contentResearchFromMetadata } = await import('../../../../seo/issue-content-research.js');
111
+ const briefIssues = issues.map((i) => {
112
+ let contentBrief = null;
113
+ let contentResearch = null;
114
+ if (i.entityId) {
115
+ const updatedAt = updatedAtByEntity.get(i.entityId);
116
+ if (updatedAt) {
117
+ if (includeContentBriefs) {
118
+ contentBrief = contentBriefFromMetadata(i.metadata, i.type, i.entityId, updatedAt);
119
+ }
120
+ if (includeContentResearch) {
121
+ contentResearch = contentResearchFromMetadata(i.metadata, i.type, i.entityId, updatedAt);
122
+ }
123
+ }
124
+ }
125
+ return {
126
+ id: i.id,
127
+ type: i.type,
128
+ title: i.title,
129
+ description: i.description ?? null,
130
+ impact: i.impact ?? null,
131
+ recommendation: i.recommendation ?? null,
132
+ severity: i.severity,
133
+ category: i.category,
134
+ status: i.status,
135
+ entityType: i.entityType ?? null,
136
+ entityId: i.entityId ?? null,
137
+ entityTitle: i.entityTitle ?? null,
138
+ url: i.url ?? null,
139
+ fixActionType: i.fixActionType ?? null,
140
+ fixable: i.fixable ?? false,
141
+ contentBrief,
142
+ contentResearch,
143
+ };
144
+ });
145
+ const markdown = buildSeoFixBriefMarkdown({
146
+ siteName: siteSeo?.siteName ?? null,
147
+ siteUrl: siteSeo?.siteUrl ?? null,
148
+ auditRunId: runId,
149
+ auditDate: runAuditDate,
150
+ issues: briefIssues,
151
+ manualOnly,
152
+ });
153
+ const issueCount = filterFixBriefIssues(briefIssues, manualOnly).length;
154
+ return json({
155
+ data: {
156
+ markdown,
157
+ filename: fixBriefFilename(siteSeo?.siteName, runAuditDate ?? undefined),
158
+ issueCount,
159
+ },
160
+ });
161
+ }
162
+ catch (err) {
163
+ return internalError(err, 'seo/issues/export-brief');
164
+ }
165
+ }
166
+ export async function getSeoIssue(request, params) {
167
+ try {
168
+ const auth = await requireAuth(request);
169
+ if (auth.error)
170
+ return auth.error;
171
+ if (!hasModel(db(), 'seoIssue'))
172
+ return modelNotAvailable('SeoIssue');
173
+ const issue = await db().seoIssue.findUnique({ where: { id: params.id } });
174
+ if (!issue)
175
+ return errorResponse('Issue not found', 404);
176
+ return json({ data: seoIssueToApi(issue) });
177
+ }
178
+ catch (err) {
179
+ return internalError(err, 'seo/issues/:id');
180
+ }
181
+ }
182
+ export function postSeoIssueResolve(request, params) {
183
+ return setIssueStatus(request, params.id, 'resolved').catch((e) => internalError(e));
184
+ }
185
+ export function postSeoIssueIgnore(request, params) {
186
+ return setIssueStatus(request, params.id, 'ignored').catch((e) => internalError(e));
187
+ }
188
+ export function postSeoIssueReopen(request, params) {
189
+ return setIssueStatus(request, params.id, 'open').catch((e) => internalError(e));
190
+ }
191
+ //# sourceMappingURL=issues-list.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"issues-list.js","sourceRoot":"","sources":["../../../../../src/api/routes/seo/handlers/issues-list.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ export declare function getSeoLinkHealth(request: Request): Promise<Response>;
2
+ export declare function getSeoLinkSnapshot(request: Request): Promise<Response>;
3
+ export declare function postSeoLinkAiIndex(request: Request): Promise<Response>;
4
+ export declare function postSeoLinkSuggest(request: Request): Promise<Response>;
5
+ export declare function postSeoLinkApply(request: Request): Promise<Response>;
6
+ //# sourceMappingURL=links.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"links.d.ts","sourceRoot":"","sources":["../../../../../src/api/routes/seo/handlers/links.ts"],"names":[],"mappings":"AAkCA,wBAAsB,gBAAgB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,CAuH1E;AAED,wBAAsB,kBAAkB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,CAgE5E;AAED,wBAAsB,kBAAkB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,CAuD5E;AAED,wBAAsB,kBAAkB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,CA8C5E;AAED,wBAAsB,gBAAgB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,CA6H1E"}