@prenta/core 7.7.0 → 7.7.2

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 (106) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/api/route-helpers/auth.d.ts +131 -0
  3. package/dist/api/route-helpers/auth.d.ts.map +1 -0
  4. package/dist/api/route-helpers/auth.js +505 -0
  5. package/dist/api/route-helpers/auth.js.map +1 -0
  6. package/dist/api/route-helpers/authoring.d.ts +32 -0
  7. package/dist/api/route-helpers/authoring.d.ts.map +1 -0
  8. package/dist/api/route-helpers/authoring.js +99 -0
  9. package/dist/api/route-helpers/authoring.js.map +1 -0
  10. package/dist/api/route-helpers/forms.d.ts +46 -0
  11. package/dist/api/route-helpers/forms.d.ts.map +1 -0
  12. package/dist/api/route-helpers/forms.js +435 -0
  13. package/dist/api/route-helpers/forms.js.map +1 -0
  14. package/dist/api/route-helpers/http.d.ts +87 -0
  15. package/dist/api/route-helpers/http.d.ts.map +1 -0
  16. package/dist/api/route-helpers/http.js +286 -0
  17. package/dist/api/route-helpers/http.js.map +1 -0
  18. package/dist/api/route-helpers/media.d.ts +37 -0
  19. package/dist/api/route-helpers/media.d.ts.map +1 -0
  20. package/dist/api/route-helpers/media.js +189 -0
  21. package/dist/api/route-helpers/media.js.map +1 -0
  22. package/dist/api/route-helpers/page-shape.d.ts +31 -0
  23. package/dist/api/route-helpers/page-shape.d.ts.map +1 -0
  24. package/dist/api/route-helpers/page-shape.js +98 -0
  25. package/dist/api/route-helpers/page-shape.js.map +1 -0
  26. package/dist/api/route-helpers.d.ts +8 -358
  27. package/dist/api/route-helpers.d.ts.map +1 -1
  28. package/dist/api/route-helpers.js +7 -1592
  29. package/dist/api/route-helpers.js.map +1 -1
  30. package/dist/api/routes/seo/handlers/analysis.d.ts +4 -0
  31. package/dist/api/routes/seo/handlers/analysis.d.ts.map +1 -0
  32. package/dist/api/routes/seo/handlers/analysis.js +131 -0
  33. package/dist/api/routes/seo/handlers/analysis.js.map +1 -0
  34. package/dist/api/routes/seo/handlers/audits.d.ts +5 -0
  35. package/dist/api/routes/seo/handlers/audits.d.ts.map +1 -0
  36. package/dist/api/routes/seo/handlers/audits.js +121 -0
  37. package/dist/api/routes/seo/handlers/audits.js.map +1 -0
  38. package/dist/api/routes/seo/handlers/content.d.ts +4 -0
  39. package/dist/api/routes/seo/handlers/content.d.ts.map +1 -0
  40. package/dist/api/routes/seo/handlers/content.js +330 -0
  41. package/dist/api/routes/seo/handlers/content.js.map +1 -0
  42. package/dist/api/routes/seo/handlers/issue-helpers.d.ts +37 -0
  43. package/dist/api/routes/seo/handlers/issue-helpers.d.ts.map +1 -0
  44. package/dist/api/routes/seo/handlers/issue-helpers.js +72 -0
  45. package/dist/api/routes/seo/handlers/issue-helpers.js.map +1 -0
  46. package/dist/api/routes/seo/handlers/issues-briefs.d.ts +7 -0
  47. package/dist/api/routes/seo/handlers/issues-briefs.d.ts.map +1 -0
  48. package/dist/api/routes/seo/handlers/issues-briefs.js +341 -0
  49. package/dist/api/routes/seo/handlers/issues-briefs.js.map +1 -0
  50. package/dist/api/routes/seo/handlers/issues-fixes.d.ts +4 -0
  51. package/dist/api/routes/seo/handlers/issues-fixes.d.ts.map +1 -0
  52. package/dist/api/routes/seo/handlers/issues-fixes.js +233 -0
  53. package/dist/api/routes/seo/handlers/issues-fixes.js.map +1 -0
  54. package/dist/api/routes/seo/handlers/issues-list.d.ts +7 -0
  55. package/dist/api/routes/seo/handlers/issues-list.d.ts.map +1 -0
  56. package/dist/api/routes/seo/handlers/issues-list.js +191 -0
  57. package/dist/api/routes/seo/handlers/issues-list.js.map +1 -0
  58. package/dist/api/routes/seo/handlers/links.d.ts +6 -0
  59. package/dist/api/routes/seo/handlers/links.d.ts.map +1 -0
  60. package/dist/api/routes/seo/handlers/links.js +383 -0
  61. package/dist/api/routes/seo/handlers/links.js.map +1 -0
  62. package/dist/api/routes/seo/handlers/overview.d.ts +4 -0
  63. package/dist/api/routes/seo/handlers/overview.d.ts.map +1 -0
  64. package/dist/api/routes/seo/handlers/overview.js +348 -0
  65. package/dist/api/routes/seo/handlers/overview.js.map +1 -0
  66. package/dist/api/routes/seo/handlers/pages.d.ts +2 -0
  67. package/dist/api/routes/seo/handlers/pages.d.ts.map +1 -0
  68. package/dist/api/routes/seo/handlers/pages.js +38 -0
  69. package/dist/api/routes/seo/handlers/pages.js.map +1 -0
  70. package/dist/api/routes/seo/handlers/proposals.d.ts +4 -0
  71. package/dist/api/routes/seo/handlers/proposals.d.ts.map +1 -0
  72. package/dist/api/routes/seo/handlers/proposals.js +93 -0
  73. package/dist/api/routes/seo/handlers/proposals.js.map +1 -0
  74. package/dist/api/routes/seo/handlers/public-files.d.ts +6 -0
  75. package/dist/api/routes/seo/handlers/public-files.d.ts.map +1 -0
  76. package/dist/api/routes/seo/handlers/public-files.js +328 -0
  77. package/dist/api/routes/seo/handlers/public-files.js.map +1 -0
  78. package/dist/api/routes/seo/handlers/shared.d.ts +24 -0
  79. package/dist/api/routes/seo/handlers/shared.d.ts.map +1 -0
  80. package/dist/api/routes/seo/handlers/shared.js +67 -0
  81. package/dist/api/routes/seo/handlers/shared.js.map +1 -0
  82. package/dist/api/routes/seo.d.ts +5 -5
  83. package/dist/api/routes/seo.d.ts.map +1 -1
  84. package/dist/api/routes/seo.js +56 -2610
  85. package/dist/api/routes/seo.js.map +1 -1
  86. package/dist/api/routes/users/handlers/api-keys.d.ts +4 -0
  87. package/dist/api/routes/users/handlers/api-keys.d.ts.map +1 -0
  88. package/dist/api/routes/users/handlers/api-keys.js +164 -0
  89. package/dist/api/routes/users/handlers/api-keys.js.map +1 -0
  90. package/dist/api/routes/users/handlers/invites.d.ts +7 -0
  91. package/dist/api/routes/users/handlers/invites.d.ts.map +1 -0
  92. package/dist/api/routes/users/handlers/invites.js +201 -0
  93. package/dist/api/routes/users/handlers/invites.js.map +1 -0
  94. package/dist/api/routes/users/handlers/users-admin.d.ts +7 -0
  95. package/dist/api/routes/users/handlers/users-admin.d.ts.map +1 -0
  96. package/dist/api/routes/users/handlers/users-admin.js +310 -0
  97. package/dist/api/routes/users/handlers/users-admin.js.map +1 -0
  98. package/dist/api/routes/users/handlers/users-detail.d.ts +16 -0
  99. package/dist/api/routes/users/handlers/users-detail.d.ts.map +1 -0
  100. package/dist/api/routes/users/handlers/users-detail.js +525 -0
  101. package/dist/api/routes/users/handlers/users-detail.js.map +1 -0
  102. package/dist/api/routes/users.d.ts +4 -0
  103. package/dist/api/routes/users.d.ts.map +1 -1
  104. package/dist/api/routes/users.js +38 -1177
  105. package/dist/api/routes/users.js.map +1 -1
  106. package/package.json +1 -1
@@ -0,0 +1,330 @@
1
+ import { updateDocumentSeoFields } from '../../../../actions.js';
2
+ import { logEvent } from '../../../../security/audit.js';
3
+ import { DEFAULT_DIRECTIVES, coerceMaxImagePreview } from '../../../../seo/robots-directives.js';
4
+ import { getPrentaConfig } from '../../../../config/runtime.js';
5
+ import { syncSchemaTypeFields } from '../../../../seo/schema-sync.js';
6
+ import { json, errorResponse, internalError, asRecord, requireAuth, buildActionContext, WRITE_ROLES, requireRole, enforceDocumentReadAccess, clampPage, clampPageSize, } from '../../../route-helpers.js';
7
+ import { db } from './shared.js';
8
+ /**
9
+ * Compute the set of front-end content collections the caller may read.
10
+ * Mirrors the per-document `enforceDocumentReadAccess` check the sibling
11
+ * `/seo/analysis|readability|…` endpoints run, but resolved once for the
12
+ * collection list so the aggregate `/seo/content` view can never surface SEO
13
+ * fields for a collection the caller's scope/role forbids.
14
+ */
15
+ async function readableSeoCollections(session) {
16
+ const { frontEndContentCollectionTypes } = await import('../../../../seo/audit-runner.js');
17
+ const collectionTypes = frontEndContentCollectionTypes(getPrentaConfig());
18
+ const allowed = new Set();
19
+ for (const slug of Object.keys(collectionTypes)) {
20
+ const err = await enforceDocumentReadAccess(session, slug);
21
+ if (!err)
22
+ allowed.add(slug);
23
+ }
24
+ return allowed;
25
+ }
26
+ async function buildSeoContentRecords(allowedCollections,
27
+ /**
28
+ * Restrict to specific documents, regardless of publication status. Used by
29
+ * the per-document GET, which must answer for a saved draft — the list
30
+ * endpoints deliberately stay published-only.
31
+ */
32
+ documentIds, page) {
33
+ const { gatherAuditEntities, countAuditEntities, frontEndContentCollectionTypes } = await import('../../../../seo/audit-runner.js');
34
+ const { applySeoOverrides, getSeoOverrides } = await import('../../../../seo/config-store.js');
35
+ const { calculatePageSeoScore } = await import('../../../../seo/score.js');
36
+ const allTypes = frontEndContentCollectionTypes(getPrentaConfig());
37
+ // When a readable-collection allow-list is supplied, scope the gather to it
38
+ // so records for forbidden collections are never even built.
39
+ const collectionTypes = allowedCollections
40
+ ? Object.fromEntries(Object.entries(allTypes).filter(([slug]) => allowedCollections.has(slug)))
41
+ : allTypes;
42
+ const overrides = await getSeoOverrides(db()).catch(() => null);
43
+ const siteSeo = applySeoOverrides(getPrentaConfig(), overrides)?.seo;
44
+ const [entities, total] = await Promise.all([
45
+ gatherAuditEntities(db(), {
46
+ collectionTypes,
47
+ documentIds,
48
+ skip: page?.skip,
49
+ take: page?.take,
50
+ }),
51
+ documentIds
52
+ ? Promise.resolve(documentIds.length)
53
+ : countAuditEntities(db(), { collectionTypes }),
54
+ ]);
55
+ const records = entities.map((e) => {
56
+ const score = calculatePageSeoScore(e);
57
+ return {
58
+ id: `${e.entityType}:${e.entityId}`,
59
+ entityType: e.entityType,
60
+ entityId: e.entityId,
61
+ title: e.title,
62
+ url: e.url,
63
+ canonicalUrl: e.canonicalUrl ?? null,
64
+ /** Rendered public title (after site title template). */
65
+ metaTitle: e.metaTitle ?? null,
66
+ /** Stored page-specific portion (`%page%` token). */
67
+ metaTitlePage: e.metaTitlePage ?? null,
68
+ siteName: siteSeo?.siteName ?? null,
69
+ titleTemplate: siteSeo?.titleTemplate ?? null,
70
+ metaDescription: e.metaDescription ?? null,
71
+ focusKeyword: e.focusKeyword ?? null,
72
+ keyTakeaway: e.keyTakeaway ?? null,
73
+ ogTitle: e.ogTitle ?? null,
74
+ ogDescription: e.ogDescription ?? null,
75
+ ogImageId: null,
76
+ ogImage: e.ogImage ?? null,
77
+ twitterTitle: null,
78
+ twitterDescription: null,
79
+ twitterImageId: null,
80
+ noindex: e.noindex ?? false,
81
+ nofollow: false,
82
+ // Permissive defaults; the single-record GET overlays what is stored.
83
+ nosnippet: false,
84
+ noarchive: false,
85
+ maxImagePreview: DEFAULT_DIRECTIVES.maxImagePreview,
86
+ structuredDataType: e.structuredDataType ?? null,
87
+ structuredData: null,
88
+ // llms.txt curation defaults; the single-record GET overlays the real
89
+ // stored values (the list endpoint doesn't surface these).
90
+ llmsInclude: 'AUTO',
91
+ llmsDescription: null,
92
+ llmsSection: null,
93
+ llmsOptional: false,
94
+ seoScore: score.score,
95
+ seoGrade: score.grade,
96
+ updatedAt: e.updatedAt instanceof Date
97
+ ? e.updatedAt.toISOString()
98
+ : typeof e.updatedAt === 'string'
99
+ ? e.updatedAt
100
+ : null,
101
+ };
102
+ });
103
+ return {
104
+ records,
105
+ total,
106
+ truncated: !documentIds && total > records.length,
107
+ };
108
+ }
109
+ export async function getSeoContent(request) {
110
+ try {
111
+ const auth = await requireAuth(request);
112
+ if (auth.error)
113
+ return auth.error;
114
+ // Scope the list to the collections this caller may read — otherwise a
115
+ // collection-scoped API key (or a collection-restricted role) could pull
116
+ // metaTitle/description/canonical/OG for every collection, the exact
117
+ // bypass the sibling document-level SEO endpoints already prevent.
118
+ const allowed = await readableSeoCollections(auth.session);
119
+ const url = new URL(request.url);
120
+ const page = clampPage(url.searchParams.get('page'));
121
+ const pageSize = clampPageSize(url.searchParams.get('pageSize'), 100, 50);
122
+ const result = await buildSeoContentRecords(allowed, undefined, {
123
+ skip: (page - 1) * pageSize,
124
+ take: pageSize,
125
+ });
126
+ return json({
127
+ data: {
128
+ records: result.records,
129
+ total: result.total,
130
+ page,
131
+ pageSize,
132
+ truncated: result.truncated,
133
+ },
134
+ });
135
+ }
136
+ catch (err) {
137
+ return internalError(err, 'seo/content');
138
+ }
139
+ }
140
+ export async function getSeoContentRecord(request, params) {
141
+ try {
142
+ const auth = await requireAuth(request);
143
+ if (auth.error)
144
+ return auth.error;
145
+ // Load the target first so we can enforce the collection's read-access
146
+ // rule (requireCollectionScope + assertCollectionAccess) before returning
147
+ // any SEO fields — parity with /seo/analysis and friends.
148
+ const doc = await db().document.findFirst({
149
+ where: { id: params.entityId, deletedAt: null },
150
+ select: { data: true, collection: true },
151
+ });
152
+ if (!doc)
153
+ return errorResponse('Content record not found', 404);
154
+ const accessErr = await enforceDocumentReadAccess(auth.session, doc.collection);
155
+ if (accessErr)
156
+ return accessErr;
157
+ // Scoped to THIS document and not filtered by publication status: a saved
158
+ // draft has SEO worth editing, and the matching PUT accepts one. Resolving
159
+ // through the published-only gather made drafts 404 here while remaining
160
+ // writable — so an editor could save SEO and never read it back.
161
+ const { records } = await buildSeoContentRecords(null, [params.entityId]);
162
+ const record = records.find((r) => r.entityType === params.entityType && r.entityId === params.entityId);
163
+ if (!record)
164
+ return errorResponse('Content record not found', 404);
165
+ // Overlay the real llms.txt curation values from the stored document
166
+ // (the audit-entity pipeline that builds the base record doesn't carry
167
+ // these convention keys).
168
+ const data = asRecord(doc.data);
169
+ const includeRaw = String(data.llmsInclude ?? '').toUpperCase();
170
+ const merged = {
171
+ ...record,
172
+ llmsInclude: includeRaw === 'ALWAYS' || includeRaw === 'NEVER'
173
+ ? includeRaw
174
+ : 'AUTO',
175
+ llmsDescription: typeof data.llmsDescription === 'string' ? data.llmsDescription : null,
176
+ llmsSection: typeof data.llmsSection === 'string' ? data.llmsSection : null,
177
+ llmsOptional: data.llmsOptional === true,
178
+ // Robots directives live in the same content JSON. Overlaid here for
179
+ // the same reason as the llms.txt keys: the audit-entity pipeline that
180
+ // builds the base record does not carry them, so without this the
181
+ // editor would read every page back as fully permissive and silently
182
+ // overwrite a real restriction on the next save.
183
+ nosnippet: data.nosnippet === true,
184
+ noarchive: data.noarchive === true,
185
+ maxImagePreview: coerceMaxImagePreview(data.maxImagePreview),
186
+ };
187
+ return json({ data: merged });
188
+ }
189
+ catch (err) {
190
+ return internalError(err, 'seo/content/:id');
191
+ }
192
+ }
193
+ export async function putSeoContentRecord(request, params) {
194
+ try {
195
+ const auth = await requireAuth(request);
196
+ if (auth.error)
197
+ return auth.error;
198
+ const roleErr = requireRole(auth.session.role, WRITE_ROLES);
199
+ if (roleErr)
200
+ return roleErr;
201
+ const body = (await request.json().catch(() => null));
202
+ if (!body || typeof body !== 'object') {
203
+ return errorResponse('Request body must be an object', 400);
204
+ }
205
+ const doc = await db().document.findFirst({
206
+ where: { id: params.entityId, deletedAt: null },
207
+ select: { id: true, collection: true },
208
+ });
209
+ if (!doc)
210
+ return errorResponse('Document not found', 404);
211
+ // String SEO fields: payload key -> stored data key, each with a max
212
+ // length so we never persist unbounded/megabyte values into the content
213
+ // JSON. Canonical is stored as `canonical` to match normalizeSeoPage.
214
+ const TEXT_FIELDS = {
215
+ metaTitle: { target: 'metaTitle', max: 300 },
216
+ metaDescription: { target: 'metaDescription', max: 1000 },
217
+ canonicalUrl: { target: 'canonical', max: 2000 },
218
+ focusKeyword: { target: 'focusKeyword', max: 200 },
219
+ keyTakeaway: { target: 'keyTakeaway', max: 500 },
220
+ ogTitle: { target: 'ogTitle', max: 300 },
221
+ ogDescription: { target: 'ogDescription', max: 1000 },
222
+ ogImage: { target: 'ogImage', max: 2000 },
223
+ twitterTitle: { target: 'twitterTitle', max: 300 },
224
+ twitterDescription: { target: 'twitterDescription', max: 1000 },
225
+ twitterImage: { target: 'twitterImage', max: 2000 },
226
+ structuredDataType: { target: 'structuredDataType', max: 100 },
227
+ schemaType: { target: 'schemaType', max: 100 },
228
+ llmsDescription: { target: 'llmsDescription', max: 500 },
229
+ llmsSection: { target: 'llmsSection', max: 100 },
230
+ };
231
+ const patch = {};
232
+ for (const [key, { target, max }] of Object.entries(TEXT_FIELDS)) {
233
+ if (!(key in body))
234
+ continue;
235
+ const value = body[key];
236
+ if (value === null || value === '') {
237
+ patch[target] = '';
238
+ continue;
239
+ }
240
+ if (typeof value !== 'string') {
241
+ return errorResponse(`Field "${key}" must be a string`, 400);
242
+ }
243
+ if (value.length > max) {
244
+ return errorResponse(`Field "${key}" exceeds the ${max}-character limit`, 400);
245
+ }
246
+ patch[target] = value;
247
+ }
248
+ if ('noindex' in body)
249
+ patch.noindex = body.noindex === true;
250
+ if ('nofollow' in body)
251
+ patch.nofollow = body.nofollow === true;
252
+ if ('nosnippet' in body)
253
+ patch.nosnippet = body.nosnippet === true;
254
+ if ('noarchive' in body)
255
+ patch.noarchive = body.noarchive === true;
256
+ if ('maxImagePreview' in body) {
257
+ // Coerced rather than rejected: the field is an enum with a permissive
258
+ // default, and refusing the write would block an otherwise valid patch
259
+ // over a value the composer already knows how to fall back from.
260
+ patch.maxImagePreview = coerceMaxImagePreview(body.maxImagePreview);
261
+ }
262
+ if ('llmsOptional' in body)
263
+ patch.llmsOptional = body.llmsOptional === true;
264
+ if ('llmsInclude' in body) {
265
+ const v = String(body.llmsInclude ?? '').toUpperCase();
266
+ if (v !== 'AUTO' && v !== 'ALWAYS' && v !== 'NEVER') {
267
+ return errorResponse('llmsInclude must be one of AUTO, ALWAYS, NEVER', 400);
268
+ }
269
+ // AUTO is the default — store empty so the field falls back cleanly.
270
+ patch.llmsInclude = v === 'AUTO' ? '' : v;
271
+ }
272
+ if ('llmsPriority' in body) {
273
+ const n = body.llmsPriority;
274
+ if (n !== null && typeof n !== 'number') {
275
+ return errorResponse('llmsPriority must be a number', 400);
276
+ }
277
+ patch.llmsPriority = n ?? 0;
278
+ }
279
+ if ('structuredData' in body) {
280
+ const sd = body.structuredData;
281
+ if (sd !== null && (typeof sd !== 'object' || Array.isArray(sd))) {
282
+ return errorResponse('structuredData must be a JSON object', 400);
283
+ }
284
+ if (sd && JSON.stringify(sd).length > 50_000) {
285
+ return errorResponse('structuredData payload is too large', 400);
286
+ }
287
+ patch.structuredData = sd;
288
+ }
289
+ if (Object.keys(patch).length === 0) {
290
+ return errorResponse('No recognized SEO fields in request body', 400);
291
+ }
292
+ if ('structuredDataType' in patch || 'schemaType' in patch) {
293
+ Object.assign(patch, syncSchemaTypeFields(patch));
294
+ }
295
+ // Route through the data layer so the edit gets per-collection access
296
+ // control, a Version snapshot, search re-indexing and the afterUpdate
297
+ // hook — never write document.data directly. (updateDocumentSeoFields
298
+ // preserves the undeclared SEO convention keys that the generic
299
+ // updateDocument field-access layer would strip.)
300
+ const ctx = buildActionContext(auth.session, db());
301
+ try {
302
+ await updateDocumentSeoFields(doc.collection, doc.id, patch, ctx);
303
+ }
304
+ catch (err) {
305
+ const msg = err instanceof Error ? err.message : '';
306
+ if (msg.includes('Access denied'))
307
+ return errorResponse('Insufficient permissions', 403);
308
+ if (msg.includes('not found'))
309
+ return errorResponse('Document not found', 404);
310
+ throw err;
311
+ }
312
+ try {
313
+ await logEvent({
314
+ event: 'document_updated',
315
+ userId: auth.session.userId,
316
+ details: { action: 'seo_fields_update', documentId: doc.id },
317
+ });
318
+ }
319
+ catch {
320
+ /* noop */
321
+ }
322
+ const { records } = await buildSeoContentRecords(null, [doc.id]);
323
+ const record = records.find((r) => r.entityId === doc.id);
324
+ return json({ data: record ?? { ok: true } });
325
+ }
326
+ catch (err) {
327
+ return internalError(err, 'seo/content PUT');
328
+ }
329
+ }
330
+ //# sourceMappingURL=content.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"content.js","sourceRoot":"","sources":["../../../../../src/api/routes/seo/handlers/content.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,37 @@
1
+ export declare function seoIssueToApi(i: any): {
2
+ id: any;
3
+ auditRunId: any;
4
+ entityType: any;
5
+ entityId: any;
6
+ entityTitle: any;
7
+ url: any;
8
+ severity: any;
9
+ category: any;
10
+ type: any;
11
+ title: any;
12
+ description: any;
13
+ impact: any;
14
+ recommendation: any;
15
+ status: any;
16
+ fixable: any;
17
+ fixActionType: any;
18
+ relatedEntityIds: any;
19
+ source: any;
20
+ firstDetectedAt: any;
21
+ lastDetectedAt: any;
22
+ resolvedAt: any;
23
+ };
24
+ export declare function setIssueStatus(request: Request, issueId: string, status: 'resolved' | 'ignored' | 'open'): Promise<Response>;
25
+ /** Load the audit entity + collection for an issue's linked document. */
26
+ export declare function loadIssueFixContext(issue: {
27
+ entityType?: string | null;
28
+ entityId?: string | null;
29
+ }): Promise<{
30
+ error: Response;
31
+ } | {
32
+ collection: string;
33
+ entity: import('../../../../seo/audit-engine.js').AuditEntityInput;
34
+ updatedAt: Date;
35
+ siteSeo: import('../../../../config/types.js').SiteSEOConfig | undefined;
36
+ }>;
37
+ //# sourceMappingURL=issue-helpers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"issue-helpers.d.ts","sourceRoot":"","sources":["../../../../../src/api/routes/seo/handlers/issue-helpers.ts"],"names":[],"mappings":"AAeA,wBAAgB,aAAa,CAAC,CAAC,EAAE,GAAG;;;;;;;;;;;;;;;;;;;;;;EAwBnC;AAED,wBAAsB,cAAc,CAClC,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,UAAU,GAAG,SAAS,GAAG,MAAM,GACtC,OAAO,CAAC,QAAQ,CAAC,CA0BnB;AAED,yEAAyE;AACzE,wBAAsB,mBAAmB,CAAC,KAAK,EAAE;IAC/C,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CACzB,GAAG,OAAO,CACP;IAAE,KAAK,EAAE,QAAQ,CAAA;CAAE,GACnB;IACE,UAAU,EAAE,MAAM,CAAA;IAClB,MAAM,EAAE,OAAO,iCAAiC,EAAE,gBAAgB,CAAA;IAClE,SAAS,EAAE,IAAI,CAAA;IACf,OAAO,EAAE,OAAO,6BAA6B,EAAE,aAAa,GAAG,SAAS,CAAA;CACzE,CACJ,CAKA"}
@@ -0,0 +1,72 @@
1
+ import { logEvent } from '../../../../security/audit.js';
2
+ import { json, errorResponse, hasModel, modelNotAvailable, requireAuth, WRITE_ROLES, requireRole, } from '../../../route-helpers.js';
3
+ import { db } from './shared.js';
4
+ // ---------------------------------------------------------------------------
5
+ // SEO Operations Center — audit engine, issues, overview, content records
6
+ // ---------------------------------------------------------------------------
7
+ export function seoIssueToApi(i) {
8
+ return {
9
+ id: i.id,
10
+ auditRunId: i.auditRunId ?? null,
11
+ entityType: i.entityType ?? null,
12
+ entityId: i.entityId ?? null,
13
+ entityTitle: i.entityTitle ?? null,
14
+ url: i.url ?? null,
15
+ severity: i.severity,
16
+ category: i.category,
17
+ type: i.type,
18
+ title: i.title,
19
+ description: i.description ?? null,
20
+ impact: i.impact ?? null,
21
+ recommendation: i.recommendation ?? null,
22
+ status: i.status,
23
+ fixable: i.fixable ?? false,
24
+ fixActionType: i.fixActionType ?? null,
25
+ relatedEntityIds: Array.isArray(i.relatedEntityIds) ? i.relatedEntityIds : [],
26
+ source: i.source ?? 'audit',
27
+ firstDetectedAt: i.firstDetectedAt ?? null,
28
+ lastDetectedAt: i.lastDetectedAt ?? null,
29
+ resolvedAt: i.resolvedAt ?? null,
30
+ };
31
+ }
32
+ export async function setIssueStatus(request, issueId, status) {
33
+ const auth = await requireAuth(request);
34
+ if (auth.error)
35
+ return auth.error;
36
+ const roleErr = requireRole(auth.session.role, WRITE_ROLES);
37
+ if (roleErr)
38
+ return roleErr;
39
+ if (!hasModel(db(), 'seoIssue'))
40
+ return modelNotAvailable('SeoIssue');
41
+ const existing = await db().seoIssue.findUnique({ where: { id: issueId } });
42
+ if (!existing)
43
+ return errorResponse('Issue not found', 404);
44
+ const issue = await db().seoIssue.update({
45
+ where: { id: issueId },
46
+ data: {
47
+ status,
48
+ resolvedAt: status === 'resolved' ? new Date() : null,
49
+ resolvedById: status === 'resolved' ? auth.session.userId : null,
50
+ },
51
+ });
52
+ try {
53
+ await logEvent({
54
+ event: 'settings_changed',
55
+ userId: auth.session.userId,
56
+ details: { action: 'seo_issue_status', issueId, status },
57
+ });
58
+ }
59
+ catch {
60
+ /* noop */
61
+ }
62
+ return json({ data: seoIssueToApi(issue) });
63
+ }
64
+ /** Load the audit entity + collection for an issue's linked document. */
65
+ export async function loadIssueFixContext(issue) {
66
+ const { loadIssueFixContext: load } = await import('../../../../seo/issue-fix-apply.js');
67
+ const loaded = await load(db(), issue);
68
+ if (!loaded.ok)
69
+ return { error: errorResponse(loaded.message, loaded.status) };
70
+ return loaded.ctx;
71
+ }
72
+ //# sourceMappingURL=issue-helpers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"issue-helpers.js","sourceRoot":"","sources":["../../../../../src/api/routes/seo/handlers/issue-helpers.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ export declare function postSeoIssuesBatchContentBriefs(request: Request): Promise<Response>;
2
+ export declare function getSeoIssueContentBrief(request: Request, params: Record<string, string>): Promise<Response>;
3
+ export declare function postSeoIssueContentBrief(request: Request, params: Record<string, string>): Promise<Response>;
4
+ export declare function getSeoIssueContentResearch(request: Request, params: Record<string, string>): Promise<Response>;
5
+ export declare function postSeoIssueContentResearch(request: Request, params: Record<string, string>): Promise<Response>;
6
+ export declare function postSeoIssueResearchAndBrief(request: Request, params: Record<string, string>): Promise<Response>;
7
+ //# sourceMappingURL=issues-briefs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"issues-briefs.d.ts","sourceRoot":"","sources":["../../../../../src/api/routes/seo/handlers/issues-briefs.ts"],"names":[],"mappings":"AAkBA,wBAAsB,+BAA+B,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,CA4GzF;AAED,wBAAsB,uBAAuB,CAC3C,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC7B,OAAO,CAAC,QAAQ,CAAC,CA0CnB;AAED,wBAAsB,wBAAwB,CAC5C,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC7B,OAAO,CAAC,QAAQ,CAAC,CAuDnB;AAED,wBAAsB,0BAA0B,CAC9C,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC7B,OAAO,CAAC,QAAQ,CAAC,CA0CnB;AAED,wBAAsB,2BAA2B,CAC/C,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC7B,OAAO,CAAC,QAAQ,CAAC,CAgEnB;AAED,wBAAsB,4BAA4B,CAChD,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC7B,OAAO,CAAC,QAAQ,CAAC,CAwFnB"}