@prenta/core 4.1.1 → 4.3.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 (60) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/actions.d.ts.map +1 -1
  3. package/dist/actions.js +4 -4
  4. package/dist/actions.js.map +1 -1
  5. package/dist/ai/brand-voice-analyze.d.ts.map +1 -1
  6. package/dist/ai/brand-voice-analyze.js +11 -11
  7. package/dist/ai/brand-voice-analyze.js.map +1 -1
  8. package/dist/api/routes/ai-authoring.d.ts.map +1 -1
  9. package/dist/api/routes/ai-authoring.js +24 -12
  10. package/dist/api/routes/ai-authoring.js.map +1 -1
  11. package/dist/api/routes/documents.d.ts.map +1 -1
  12. package/dist/api/routes/documents.js +2 -15
  13. package/dist/api/routes/documents.js.map +1 -1
  14. package/dist/api/routes/seo-public.d.ts +0 -8
  15. package/dist/api/routes/seo-public.d.ts.map +1 -1
  16. package/dist/api/routes/seo-public.js +67 -29
  17. package/dist/api/routes/seo-public.js.map +1 -1
  18. package/dist/api/routes/seo.d.ts.map +1 -1
  19. package/dist/api/routes/seo.js +383 -121
  20. package/dist/api/routes/seo.js.map +1 -1
  21. package/dist/media/usage-sync.d.ts.map +1 -1
  22. package/dist/media/usage-sync.js +15 -11
  23. package/dist/media/usage-sync.js.map +1 -1
  24. package/dist/redirects/recovery.d.ts +8 -2
  25. package/dist/redirects/recovery.d.ts.map +1 -1
  26. package/dist/redirects/recovery.js +43 -24
  27. package/dist/redirects/recovery.js.map +1 -1
  28. package/dist/seo/audit-engine.d.ts +12 -0
  29. package/dist/seo/audit-engine.d.ts.map +1 -1
  30. package/dist/seo/audit-engine.js +24 -0
  31. package/dist/seo/audit-engine.js.map +1 -1
  32. package/dist/seo/audit-runner.d.ts +12 -0
  33. package/dist/seo/audit-runner.d.ts.map +1 -1
  34. package/dist/seo/audit-runner.js +45 -10
  35. package/dist/seo/audit-runner.js.map +1 -1
  36. package/dist/seo/index.d.ts +8 -1
  37. package/dist/seo/index.d.ts.map +1 -1
  38. package/dist/seo/index.js +5 -1
  39. package/dist/seo/index.js.map +1 -1
  40. package/dist/seo/issue-fix-link-insert.d.ts +105 -0
  41. package/dist/seo/issue-fix-link-insert.d.ts.map +1 -0
  42. package/dist/seo/issue-fix-link-insert.js +461 -0
  43. package/dist/seo/issue-fix-link-insert.js.map +1 -0
  44. package/dist/seo/issue-fix-verify.d.ts +31 -0
  45. package/dist/seo/issue-fix-verify.d.ts.map +1 -0
  46. package/dist/seo/issue-fix-verify.js +76 -0
  47. package/dist/seo/issue-fix-verify.js.map +1 -0
  48. package/dist/seo/issue-fix.d.ts +2 -2
  49. package/dist/seo/issue-fix.d.ts.map +1 -1
  50. package/dist/seo/issue-fix.js +9 -0
  51. package/dist/seo/issue-fix.js.map +1 -1
  52. package/dist/seo/link-suggest.d.ts +49 -0
  53. package/dist/seo/link-suggest.d.ts.map +1 -0
  54. package/dist/seo/link-suggest.js +149 -0
  55. package/dist/seo/link-suggest.js.map +1 -0
  56. package/dist/seo/nav-link-targets.d.ts +9 -0
  57. package/dist/seo/nav-link-targets.d.ts.map +1 -0
  58. package/dist/seo/nav-link-targets.js +47 -0
  59. package/dist/seo/nav-link-targets.js.map +1 -0
  60. package/package.json +4 -5
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/seo/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/seo/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,cAAc,EACd,oBAAoB,EACpB,aAAa,EACb,cAAc,EACd,kBAAkB,EAClB,cAAc,EACd,eAAe,GAChB,MAAM,eAAe,CAAA;AAUtB,OAAO,EACL,gBAAgB,EAChB,kBAAkB,EAClB,oBAAoB,EACpB,4BAA4B,EAC5B,0BAA0B,EAC1B,qBAAqB,GACtB,MAAM,gBAAgB,CAAA;AAIvB,OAAO,EAAE,uBAAuB,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAA;AAI5E,OAAO,EACL,YAAY,EACZ,gBAAgB,EAChB,qBAAqB,EACrB,sBAAsB,EACtB,wBAAwB,EACxB,6BAA6B,EAC7B,4BAA4B,EAC5B,iBAAiB,EACjB,2BAA2B,GAC5B,MAAM,sBAAsB,CAAA;AAS7B,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAA;AACjE,OAAO,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AAE1E,OAAO,EACL,6BAA6B,EAC7B,yBAAyB,EACzB,mBAAmB,GACpB,MAAM,uBAAuB,CAAA;AAE9B,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAA;AAC7F,OAAO,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAA;AAKzD,OAAO,EACL,eAAe,EACf,gBAAgB,EAChB,kBAAkB,EAClB,mBAAmB,EACnB,kBAAkB,EAClB,4BAA4B,EAC5B,oBAAoB,GACrB,MAAM,gBAAgB,CAAA;AAEvB,OAAO,EACL,4BAA4B,EAC5B,uBAAuB,EACvB,0BAA0B,EAC1B,2BAA2B,GAC5B,MAAM,oBAAoB,CAAA;AAG3B,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAA;AAEhE,OAAO,EACL,mBAAmB,EACnB,iBAAiB,EACjB,kBAAkB,EAClB,sBAAsB,EACtB,qBAAqB,GACtB,MAAM,oBAAoB,CAAA;AAG3B,OAAO,EACL,kBAAkB,EAClB,eAAe,EACf,YAAY,EACZ,6BAA6B,EAC7B,6BAA6B,GAC9B,MAAM,qBAAqB,CAAA;AAK5B,OAAO,EACL,+BAA+B,EAC/B,+BAA+B,EAC/B,yBAAyB,EACzB,4BAA4B,EAC5B,0BAA0B,EAC1B,oBAAoB,GACrB,MAAM,kBAAkB,CAAA;AAMzB,OAAO,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAA;AAI3F,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAIxD,OAAO,EACL,qBAAqB,EACrB,WAAW,EACX,gBAAgB,EAChB,iBAAiB,GAClB,MAAM,cAAc,CAAA;AAIrB,OAAO,EAAE,kBAAkB,EAAE,0BAA0B,EAAE,MAAM,qBAAqB,CAAA;AAIpF,OAAO,EACL,qBAAqB,EACrB,eAAe,EACf,eAAe,EACf,iBAAiB,EACjB,kBAAkB,EAClB,wBAAwB,EACxB,2BAA2B,EAC3B,wBAAwB,GACzB,MAAM,mBAAmB,CAAA;AAI1B,OAAO,EACL,sBAAsB,EACtB,eAAe,EACf,sBAAsB,EACtB,uBAAuB,EACvB,iBAAiB,EACjB,2BAA2B,GAC5B,MAAM,qBAAqB,CAAA;AAS5B,OAAO,EACL,qBAAqB,EACrB,qBAAqB,EACrB,gBAAgB,EAChB,OAAO,EACP,gBAAgB,EAChB,gBAAgB,GACjB,MAAM,YAAY,CAAA;AAanB,OAAO,EAAE,mBAAmB,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAWpF,OAAO,EACL,kBAAkB,EAClB,mBAAmB,EACnB,kBAAkB,EAClB,qBAAqB,EACrB,8BAA8B,EAC9B,oBAAoB,EACpB,kBAAkB,GACnB,MAAM,mBAAmB,CAAA;AAC1B,OAAO,EAAE,2BAA2B,EAAE,MAAM,qBAAqB,CAAA;AAEjE,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AAErD,OAAO,EACL,kBAAkB,EAClB,qBAAqB,EACrB,yBAAyB,GAC1B,MAAM,oBAAoB,CAAA;AAC3B,OAAO,EACL,0BAA0B,EAC1B,gCAAgC,EAChC,mBAAmB,GACpB,MAAM,2BAA2B,CAAA;AAIlC,OAAO,EACL,sBAAsB,EACtB,kBAAkB,EAClB,yBAAyB,GAC1B,MAAM,mBAAmB,CAAA;AAY1B,OAAO,EACL,uBAAuB,EACvB,eAAe,EACf,sBAAsB,EACtB,yBAAyB,EACzB,mBAAmB,EACnB,uBAAuB,EACvB,cAAc,EACd,cAAc,EACd,aAAa,EACb,aAAa,GACd,MAAM,gBAAgB,CAAA;AAUvB,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,sBAAsB,EACtB,oBAAoB,GACrB,MAAM,mBAAmB,CAAA;AAG1B,OAAO,EACL,uBAAuB,EACvB,oBAAoB,EACpB,wBAAwB,GACzB,MAAM,4BAA4B,CAAA;AASnC,OAAO,EAAE,2BAA2B,EAAE,MAAM,uBAAuB,CAAA;AACnE,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAA;AAOvD,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAA;AAGzD,OAAO,EACL,wBAAwB,EACxB,oBAAoB,EACpB,gBAAgB,EAChB,oBAAoB,EACpB,iBAAiB,EACjB,sBAAsB,GACvB,MAAM,uBAAuB,CAAA;AAG9B,OAAO,EACL,oBAAoB,EACpB,oBAAoB,EACpB,wBAAwB,EACxB,sBAAsB,EACtB,0BAA0B,EAC1B,yBAAyB,GAC1B,MAAM,0BAA0B,CAAA;AASjC,OAAO,EACL,uBAAuB,EACvB,uBAAuB,EACvB,2BAA2B,EAC3B,yBAAyB,EACzB,6BAA6B,EAC7B,oBAAoB,EACpB,mBAAmB,GACpB,MAAM,6BAA6B,CAAA;AASpC,OAAO,EACL,sBAAsB,EACtB,mCAAmC,EACnC,uBAAuB,EACvB,iBAAiB,EACjB,iBAAiB,EACjB,yBAAyB,EACzB,sBAAsB,EACtB,kBAAkB,EAClB,iBAAiB,GAClB,MAAM,iBAAiB,CAAA;AAExB,OAAO,EACL,wBAAwB,EACxB,oBAAoB,EACpB,4BAA4B,EAC5B,0BAA0B,GAC3B,MAAM,+BAA+B,CAAA;AAEtC,OAAO,EACL,0BAA0B,EAC1B,sBAAsB,EACtB,uBAAuB,GACxB,MAAM,yBAAyB,CAAA"}
@@ -0,0 +1,105 @@
1
+ /**
2
+ * Wrap/fingerprint helpers plus suggest, apply, and verify for approved
3
+ * internal-link inserts. Walks document JSON the same way `replaceHrefInValue`
4
+ * does and wraps one existing phrase. Apply recomputes the wrap on live
5
+ * `document.data` and never writes `status`.
6
+ */
7
+ import { updateDocument, type ActionContext } from '../actions.js';
8
+ import type { PrentaDB } from '../db/client-types.js';
9
+ import type { AuditEntityInput } from './audit-engine.js';
10
+ import { type SeoIssueFixContext, type SeoIssueFixInput, type SeoIssueFixSuggestion } from './issue-fix.js';
11
+ import type { InboundLinkSuggestion, SuggestInboundLinksInput } from './link-suggest.js';
12
+ export declare const INSERT_LINK_MIN_CONFIDENCE = 40;
13
+ export declare const INSERT_LINK_FIX_TYPES: Set<string>;
14
+ export declare const ANCHOR_MIN = 3;
15
+ export declare const ANCHOR_MAX = 80;
16
+ export interface InternalLinkInsert {
17
+ sourceEntityId: string;
18
+ sourceCollection: string;
19
+ targetEntityId: string;
20
+ targetPath: string;
21
+ anchorText: string;
22
+ excerpt: string;
23
+ confidence: number;
24
+ }
25
+ export type LinkInsertMissReason = 'not-found' | 'inside-link' | 'unsupported-field-shape' | 'anchor-length';
26
+ export type WrappableAnchorResult = {
27
+ path: string[];
28
+ match: string;
29
+ reason?: undefined;
30
+ } | {
31
+ path: null;
32
+ match: null;
33
+ reason: LinkInsertMissReason;
34
+ };
35
+ export declare function confidenceToPercent(score: number): number;
36
+ export declare function normalizeAnchor(anchor: string): string;
37
+ export declare function buildInsertLinkFingerprint(sourceEntityId: string, targetEntityId: string, anchorText: string, sourceUpdatedAt: string | Date): string;
38
+ export declare function sourceAlreadyLinksTo(data: Record<string, unknown>, targetPath: string, siteUrl?: string): boolean;
39
+ export declare function findWrappableAnchor(data: Record<string, unknown>, anchorText: string): WrappableAnchorResult;
40
+ export declare function buildLinkInsertPatch(data: Record<string, unknown>, anchorText: string, targetPath: string): {
41
+ patch: Record<string, unknown>;
42
+ changed: boolean;
43
+ reason?: string;
44
+ };
45
+ export interface SuggestOrphanLinkFixDeps {
46
+ suggestInboundLinks: (input: SuggestInboundLinksInput) => Promise<InboundLinkSuggestion[] | {
47
+ suggestions: InboundLinkSuggestion[];
48
+ }>;
49
+ db?: PrentaDB;
50
+ }
51
+ /**
52
+ * Pick the highest-confidence wrappable inbound suggestion for an orphan-page
53
+ * issue. `suggestInboundLinks` is injected so tests do not boot the AI plugin.
54
+ */
55
+ export declare function suggestOrphanLinkFix(issue: SeoIssueFixInput, ctx: SeoIssueFixContext, deps: SuggestOrphanLinkFixDeps): Promise<SeoIssueFixSuggestion>;
56
+ export interface ApplyInternalLinkInsertInput {
57
+ db: PrentaDB;
58
+ ctx: ActionContext;
59
+ sourceEntityId: string;
60
+ targetEntityId: string;
61
+ anchorText: string;
62
+ targetPath: string;
63
+ }
64
+ export interface ApplyInternalLinkInsertResult {
65
+ sourceCollection: string;
66
+ sourceStatus: string;
67
+ patch: Record<string, unknown>;
68
+ }
69
+ export interface VerifyInternalLinkInsertInput {
70
+ db: PrentaDB;
71
+ sourceEntityId: string;
72
+ targetEntityId: string;
73
+ targetPath: string;
74
+ siteUrl: string;
75
+ navLinks: string[];
76
+ /** Test seam — production loads the two documents into a two-node snapshot. */
77
+ entities?: AuditEntityInput[];
78
+ }
79
+ export interface LinkInsertDeps {
80
+ updateDocument: typeof updateDocument;
81
+ }
82
+ /**
83
+ * Apply a wrap on the live source, then verify inbound by reloading from DB
84
+ * (never pass stale pre-write `data`). Callers keep auth / fingerprint / resolve.
85
+ */
86
+ export declare function applyAndVerifyInternalLinkInsert(input: ApplyInternalLinkInsertInput & {
87
+ siteUrl: string;
88
+ navLinks: string[];
89
+ }, deps?: LinkInsertDeps): Promise<{
90
+ apply: ApplyInternalLinkInsertResult;
91
+ verify: {
92
+ ok: true;
93
+ } | {
94
+ ok: false;
95
+ reason: string;
96
+ };
97
+ }>;
98
+ export declare function applyInternalLinkInsert(input: ApplyInternalLinkInsertInput, deps?: LinkInsertDeps): Promise<ApplyInternalLinkInsertResult>;
99
+ export declare function verifyInternalLinkInsert(input: VerifyInternalLinkInsertInput): Promise<{
100
+ ok: true;
101
+ } | {
102
+ ok: false;
103
+ reason: string;
104
+ }>;
105
+ //# sourceMappingURL=issue-fix-link-insert.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"issue-fix-link-insert.d.ts","sourceRoot":"","sources":["../../src/seo/issue-fix-link-insert.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,461 @@
1
+ /**
2
+ * Wrap/fingerprint helpers plus suggest, apply, and verify for approved
3
+ * internal-link inserts. Walks document JSON the same way `replaceHrefInValue`
4
+ * does and wraps one existing phrase. Apply recomputes the wrap on live
5
+ * `document.data` and never writes `status`.
6
+ */
7
+ import { updateDocument } from '../actions.js';
8
+ import { getPrentaConfig } from '../config/runtime.js';
9
+ import { normalizeRedirectPath } from '../redirects/graph.js';
10
+ import { documentContentForSeoAnalysis } from './document-content.js';
11
+ import { documentPublicPath } from './document-path.js';
12
+ import { buildFixFingerprint, } from './issue-fix.js';
13
+ export const INSERT_LINK_MIN_CONFIDENCE = 40;
14
+ export const INSERT_LINK_FIX_TYPES = new Set(['orphan-page']);
15
+ export const ANCHOR_MIN = 3;
16
+ export const ANCHOR_MAX = 80;
17
+ export function confidenceToPercent(score) {
18
+ if (Number.isFinite(score) && score <= 1)
19
+ return Math.round(score * 100);
20
+ return Math.round(score);
21
+ }
22
+ export function normalizeAnchor(anchor) {
23
+ return anchor.trim().replace(/\s+/g, ' ').toLowerCase();
24
+ }
25
+ export function buildInsertLinkFingerprint(sourceEntityId, targetEntityId, anchorText, sourceUpdatedAt) {
26
+ return `${sourceEntityId}:${targetEntityId}:${normalizeAnchor(anchorText)}:${new Date(sourceUpdatedAt).getTime()}`;
27
+ }
28
+ export function sourceAlreadyLinksTo(data, targetPath, siteUrl) {
29
+ const hrefs = targetHrefCandidates(targetPath, siteUrl);
30
+ return walkStrings(data, (text) => stringLinksToTarget(text, hrefs));
31
+ }
32
+ export function findWrappableAnchor(data, anchorText) {
33
+ const trimmed = anchorText.trim();
34
+ if (trimmed.length < ANCHOR_MIN || trimmed.length > ANCHOR_MAX) {
35
+ return { path: null, match: null, reason: 'anchor-length' };
36
+ }
37
+ let sawInsideLink = false;
38
+ let sawUnsupported = false;
39
+ const found = walkForAnchor(data, [], null, null, trimmed, (hit) => {
40
+ if (hit.kind === 'unsupported') {
41
+ sawUnsupported = true;
42
+ return null;
43
+ }
44
+ if (hit.kind === 'inside-link') {
45
+ sawInsideLink = true;
46
+ return null;
47
+ }
48
+ return { path: hit.path, match: hit.match };
49
+ });
50
+ if (found)
51
+ return found;
52
+ if (sawInsideLink)
53
+ return { path: null, match: null, reason: 'inside-link' };
54
+ if (sawUnsupported)
55
+ return { path: null, match: null, reason: 'unsupported-field-shape' };
56
+ return { path: null, match: null, reason: 'not-found' };
57
+ }
58
+ export function buildLinkInsertPatch(data, anchorText, targetPath) {
59
+ const found = findWrappableAnchor(data, anchorText);
60
+ if (!found.path) {
61
+ return { patch: {}, changed: false, reason: found.reason };
62
+ }
63
+ const topKey = found.path[0];
64
+ const next = wrapAtPath(data[topKey], found.path.slice(1), anchorText, targetPath);
65
+ return { patch: { [topKey]: next }, changed: true };
66
+ }
67
+ function inboundRows(result) {
68
+ return Array.isArray(result) ? result : result.suggestions;
69
+ }
70
+ function missJustification(reason) {
71
+ switch (reason) {
72
+ case 'already-linked':
73
+ return 'The best inbound source is already linked to this page.';
74
+ case 'low-confidence':
75
+ return 'The best inbound suggestion is below the wrappable confidence floor (low confidence).';
76
+ case 'no-phrase':
77
+ return 'No wrappable phrase in source matches this page title.';
78
+ default:
79
+ return 'No wrappable inbound link suggestion was found.';
80
+ }
81
+ }
82
+ function inferMissReason(row) {
83
+ if (row.notWrappableReason)
84
+ return row.notWrappableReason;
85
+ if (confidenceToPercent(row.confidence) < INSERT_LINK_MIN_CONFIDENCE)
86
+ return 'low-confidence';
87
+ return 'no-phrase';
88
+ }
89
+ function insertLinkChanges(row, targetPath) {
90
+ const wrapHint = row.excerpt.includes(row.anchorText)
91
+ ? row.excerpt.replace(row.anchorText, `<a href="${targetPath}">${row.anchorText}</a>`)
92
+ : `${row.excerpt} → ${targetPath}`;
93
+ return [
94
+ {
95
+ field: 'source',
96
+ label: 'Source page',
97
+ before: null,
98
+ after: `${row.sourceTitle} (${row.sourceUrl})`,
99
+ },
100
+ {
101
+ field: 'anchor',
102
+ label: 'Anchor text',
103
+ before: row.anchorText,
104
+ after: `${row.anchorText} → ${targetPath}`,
105
+ },
106
+ {
107
+ field: 'excerpt',
108
+ label: 'Excerpt',
109
+ before: row.excerpt,
110
+ after: wrapHint,
111
+ },
112
+ ];
113
+ }
114
+ /**
115
+ * Pick the highest-confidence wrappable inbound suggestion for an orphan-page
116
+ * issue. `suggestInboundLinks` is injected so tests do not boot the AI plugin.
117
+ */
118
+ export async function suggestOrphanLinkFix(issue, ctx, deps) {
119
+ const targetEntityId = issue.entityId ?? ctx.entity.entityId;
120
+ const targetPath = ctx.entity.url;
121
+ const targetEntityType = issue.entityType === 'post' ? 'post' : 'page';
122
+ let rows = [];
123
+ try {
124
+ rows = inboundRows(await deps.suggestInboundLinks({
125
+ db: deps.db,
126
+ targetEntityId,
127
+ targetEntityType,
128
+ }));
129
+ }
130
+ catch {
131
+ return {
132
+ autoFixable: false,
133
+ fingerprint: buildFixFingerprint(targetEntityId, issue.type, ctx.updatedAt),
134
+ patch: {},
135
+ changes: [],
136
+ justification: 'No wrappable inbound link suggestion was found.',
137
+ };
138
+ }
139
+ const wrappable = rows
140
+ .filter((row) => row.wrappable && confidenceToPercent(row.confidence) >= INSERT_LINK_MIN_CONFIDENCE)
141
+ .sort((a, b) => b.confidence - a.confidence);
142
+ const bestWrappable = wrappable[0];
143
+ if (bestWrappable) {
144
+ return {
145
+ autoFixable: true,
146
+ source: bestWrappable.matchKind === 'semantic' ? 'ai' : 'deterministic',
147
+ fixStrategy: 'insert-link',
148
+ fingerprint: bestWrappable.fingerprint,
149
+ patch: {
150
+ sourceEntityId: bestWrappable.sourceEntityId,
151
+ targetEntityId,
152
+ targetPath,
153
+ anchorText: bestWrappable.anchorText,
154
+ },
155
+ changes: insertLinkChanges(bestWrappable, targetPath),
156
+ justification: `Insert a link from “${bestWrappable.sourceTitle}” using the existing phrase “${bestWrappable.anchorText}”.`,
157
+ };
158
+ }
159
+ const best = [...rows].sort((a, b) => b.confidence - a.confidence)[0];
160
+ return {
161
+ autoFixable: false,
162
+ fingerprint: best?.fingerprint ?? buildFixFingerprint(targetEntityId, issue.type, ctx.updatedAt),
163
+ patch: {},
164
+ changes: [],
165
+ justification: missJustification(best ? inferMissReason(best) : undefined),
166
+ };
167
+ }
168
+ function asRecord(value) {
169
+ return value && typeof value === 'object' && !Array.isArray(value)
170
+ ? value
171
+ : {};
172
+ }
173
+ function nonemptyString(value) {
174
+ return typeof value === 'string' && value.length > 0 ? value : null;
175
+ }
176
+ /** Same public path `documentToAuditEntity` resolves (via `resolveDocumentUrl` with empty siteUrl). */
177
+ function liveDocumentPublicPath(doc) {
178
+ const data = asRecord(doc.data);
179
+ const slug = nonemptyString(data.slug) ?? nonemptyString(doc.slug) ?? doc.id;
180
+ const collectionDef = getPrentaConfig()?.collections?.[doc.collection];
181
+ return documentPublicPath({
182
+ urlPrefix: collectionDef?.urlPrefix,
183
+ slug,
184
+ data,
185
+ });
186
+ }
187
+ async function loadLiveDocument(db, id) {
188
+ return db.document.findFirst({
189
+ where: { id, deletedAt: null },
190
+ select: { id: true, collection: true, status: true, data: true, slug: true },
191
+ });
192
+ }
193
+ function documentToGraphEntity(doc) {
194
+ const data = asRecord(doc.data);
195
+ return {
196
+ entityType: 'page',
197
+ entityId: doc.id,
198
+ title: nonemptyString(data.title) ?? 'Untitled',
199
+ url: liveDocumentPublicPath(doc),
200
+ // Same flattened prose the audit uses — never JSON.stringify(sections).
201
+ content: documentContentForSeoAnalysis({ data }),
202
+ };
203
+ }
204
+ /**
205
+ * Apply a wrap on the live source, then verify inbound by reloading from DB
206
+ * (never pass stale pre-write `data`). Callers keep auth / fingerprint / resolve.
207
+ */
208
+ export async function applyAndVerifyInternalLinkInsert(input, deps) {
209
+ const apply = await applyInternalLinkInsert(input, deps);
210
+ const verify = await verifyInternalLinkInsert({
211
+ db: input.db,
212
+ sourceEntityId: input.sourceEntityId,
213
+ targetEntityId: input.targetEntityId,
214
+ targetPath: input.targetPath,
215
+ siteUrl: input.siteUrl,
216
+ navLinks: input.navLinks,
217
+ });
218
+ return { apply, verify };
219
+ }
220
+ export async function applyInternalLinkInsert(input, deps) {
221
+ const write = deps?.updateDocument ?? updateDocument;
222
+ const source = await loadLiveDocument(input.db, input.sourceEntityId);
223
+ if (!source)
224
+ throw new Error('SOURCE_NOT_FOUND');
225
+ const target = await loadLiveDocument(input.db, input.targetEntityId);
226
+ if (!target)
227
+ throw new Error('TARGET_NOT_FOUND');
228
+ const livePath = liveDocumentPublicPath(target);
229
+ if (normalizeRedirectPath(input.targetPath) !== normalizeRedirectPath(livePath)) {
230
+ throw new Error('TARGET_PATH_MISMATCH');
231
+ }
232
+ const data = asRecord(source.data);
233
+ const siteUrl = getPrentaConfig()?.seo?.siteUrl;
234
+ if (sourceAlreadyLinksTo(data, livePath, siteUrl)) {
235
+ throw new Error('ALREADY_LINKED');
236
+ }
237
+ const { patch, changed } = buildLinkInsertPatch(data, input.anchorText, livePath);
238
+ if (!changed)
239
+ throw new Error('NOT_WRAPPABLE');
240
+ await write(source.collection, input.sourceEntityId, patch, input.ctx);
241
+ return {
242
+ sourceCollection: source.collection,
243
+ sourceStatus: String(source.status),
244
+ patch,
245
+ };
246
+ }
247
+ export async function verifyInternalLinkInsert(input) {
248
+ const source = await loadLiveDocument(input.db, input.sourceEntityId);
249
+ if (!source)
250
+ return { ok: false, reason: 'href-missing' };
251
+ const data = asRecord(source.data);
252
+ if (!sourceAlreadyLinksTo(data, input.targetPath, input.siteUrl)) {
253
+ return { ok: false, reason: 'href-missing' };
254
+ }
255
+ let entities = input.entities;
256
+ if (!entities) {
257
+ const target = await loadLiveDocument(input.db, input.targetEntityId);
258
+ if (!target)
259
+ return { ok: false, reason: 'still-orphan' };
260
+ entities = [documentToGraphEntity(source), documentToGraphEntity(target)];
261
+ }
262
+ if (!entities.some((entity) => entity.entityId === input.targetEntityId) ||
263
+ inboundCountToTarget(entities, input) < 1) {
264
+ return { ok: false, reason: 'still-orphan' };
265
+ }
266
+ return { ok: true };
267
+ }
268
+ /** Content + nav inbound to the target path. Home is never in `orphaned`, so do not use that list. */
269
+ function inboundCountToTarget(entities, input) {
270
+ const hrefs = targetHrefCandidates(input.targetPath, input.siteUrl);
271
+ let count = 0;
272
+ for (const entity of entities) {
273
+ if (entity.entityId === input.targetEntityId)
274
+ continue;
275
+ if (stringLinksToTarget(entity.content ?? '', hrefs))
276
+ count++;
277
+ }
278
+ const navTargets = new Set(hrefs.map((href) => normalizeRedirectPath(href)));
279
+ navTargets.add(normalizeRedirectPath(input.targetPath));
280
+ if (input.navLinks.some((href) => navTargets.has(normalizeRedirectPath(href)))) {
281
+ count++;
282
+ }
283
+ return count;
284
+ }
285
+ function escapeRegExp(value) {
286
+ return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
287
+ }
288
+ function trimTrailingSlashes(value) {
289
+ return value.replace(/\/+$/, '');
290
+ }
291
+ function targetHrefCandidates(targetPath, siteUrl) {
292
+ const path = trimTrailingSlashes(targetPath);
293
+ const hrefs = new Set();
294
+ if (targetPath)
295
+ hrefs.add(targetPath);
296
+ if (path)
297
+ hrefs.add(path);
298
+ if (siteUrl) {
299
+ const origin = trimTrailingSlashes(siteUrl);
300
+ const absPath = path.startsWith('/') ? path : `/${path}`;
301
+ hrefs.add(`${origin}${absPath}`);
302
+ }
303
+ return [...hrefs];
304
+ }
305
+ /** Same href= extraction as `buildLinkGraphSnapshot` / `extractHrefTargets` — no markdown `](path)`. */
306
+ function stringLinksToTarget(text, hrefs) {
307
+ for (const href of hrefs) {
308
+ if (text.includes(`href="${href}"`) || text.includes(`href='${href}'`)) {
309
+ return true;
310
+ }
311
+ }
312
+ return false;
313
+ }
314
+ function walkStrings(value, visit) {
315
+ if (typeof value === 'string')
316
+ return visit(value);
317
+ if (Array.isArray(value)) {
318
+ for (const item of value) {
319
+ if (walkStrings(item, visit))
320
+ return true;
321
+ }
322
+ return false;
323
+ }
324
+ if (value && typeof value === 'object') {
325
+ for (const child of Object.values(value)) {
326
+ if (walkStrings(child, visit))
327
+ return true;
328
+ }
329
+ }
330
+ return false;
331
+ }
332
+ function isStructuredTextField(parent, key) {
333
+ // ProseMirror/TipTap text leaves only — not CMS fields named `text`
334
+ // on a typed section (e.g. quote `{ type: 'quote', text: '…' }`).
335
+ return key === 'text' && parent?.type === 'text';
336
+ }
337
+ function findAnchorMatches(text, anchor) {
338
+ const escaped = escapeRegExp(anchor);
339
+ const re = new RegExp(`(^|\\W)(${escaped})(\\W|$)`, 'gi');
340
+ const matches = [];
341
+ let m;
342
+ while ((m = re.exec(text)) !== null) {
343
+ const prefix = m[1] ?? '';
344
+ const matched = m[2] ?? '';
345
+ const index = m.index + prefix.length;
346
+ matches.push({ index, match: matched });
347
+ re.lastIndex = index + matched.length;
348
+ }
349
+ return matches;
350
+ }
351
+ function isAnchorOpenAt(lower, index) {
352
+ if (lower.slice(index, index + 2) !== '<a')
353
+ return false;
354
+ const next = lower[index + 2];
355
+ return next === undefined || next === '>' || next === '/' || /\s/.test(next);
356
+ }
357
+ function isInsideHtmlAnchor(text, index) {
358
+ const before = text.slice(0, index).toLowerCase();
359
+ let lastOpen = -1;
360
+ for (let i = 0; i < before.length; i++) {
361
+ if (isAnchorOpenAt(before, i))
362
+ lastOpen = i;
363
+ }
364
+ if (lastOpen === -1)
365
+ return false;
366
+ return lastOpen > before.lastIndexOf('</a>');
367
+ }
368
+ function isInsideMarkdownLink(text, index) {
369
+ const re = /\[([^\]]*)\]\(([^)]*)\)/g;
370
+ let m;
371
+ while ((m = re.exec(text)) !== null) {
372
+ const start = m.index;
373
+ const end = start + m[0].length;
374
+ if (index >= start && index < end)
375
+ return true;
376
+ }
377
+ return false;
378
+ }
379
+ function isInsideHtmlTag(text, index) {
380
+ const before = text.slice(0, index);
381
+ const lastOpen = before.lastIndexOf('<');
382
+ if (lastOpen === -1)
383
+ return false;
384
+ return !before.slice(lastOpen).includes('>');
385
+ }
386
+ /** Always HTML — link graph / verify only count `href=` (plan Task 1). */
387
+ function wrapMatch(text, index, match, targetPath) {
388
+ const wrapped = `<a href="${targetPath}">${match}</a>`;
389
+ return text.slice(0, index) + wrapped + text.slice(index + match.length);
390
+ }
391
+ function firstWrappableInString(text, anchor) {
392
+ const matches = findAnchorMatches(text, anchor);
393
+ if (matches.length === 0)
394
+ return null;
395
+ let insideLink = false;
396
+ for (const hit of matches) {
397
+ if (isInsideHtmlTag(text, hit.index)) {
398
+ continue;
399
+ }
400
+ if (isInsideHtmlAnchor(text, hit.index) || isInsideMarkdownLink(text, hit.index)) {
401
+ insideLink = true;
402
+ continue;
403
+ }
404
+ return hit;
405
+ }
406
+ return insideLink ? { insideLink: true } : null;
407
+ }
408
+ function walkForAnchor(value, path, parent, key, anchor, onHit) {
409
+ if (typeof value === 'string') {
410
+ const result = firstWrappableInString(value, anchor);
411
+ if (!result)
412
+ return null;
413
+ if (isStructuredTextField(parent, key)) {
414
+ return onHit({ kind: 'unsupported' });
415
+ }
416
+ if ('insideLink' in result) {
417
+ return onHit({ kind: 'inside-link' });
418
+ }
419
+ return onHit({ kind: 'wrappable', path, match: result.match });
420
+ }
421
+ if (Array.isArray(value)) {
422
+ for (let i = 0; i < value.length; i++) {
423
+ const found = walkForAnchor(value[i], [...path, String(i)], null, null, anchor, onHit);
424
+ if (found)
425
+ return found;
426
+ }
427
+ return null;
428
+ }
429
+ if (value && typeof value === 'object') {
430
+ const obj = value;
431
+ for (const [childKey, child] of Object.entries(obj)) {
432
+ const found = walkForAnchor(child, [...path, childKey], obj, childKey, anchor, onHit);
433
+ if (found)
434
+ return found;
435
+ }
436
+ }
437
+ return null;
438
+ }
439
+ function wrapAtPath(value, path, anchorText, targetPath) {
440
+ if (path.length === 0) {
441
+ if (typeof value !== 'string')
442
+ return value;
443
+ const hit = firstWrappableInString(value, anchorText.trim());
444
+ if (!hit || 'insideLink' in hit)
445
+ return value;
446
+ return wrapMatch(value, hit.index, hit.match, targetPath);
447
+ }
448
+ const [head, ...rest] = path;
449
+ if (head === undefined)
450
+ return value;
451
+ if (Array.isArray(value)) {
452
+ const index = Number(head);
453
+ return value.map((item, i) => i === index ? wrapAtPath(item, rest, anchorText, targetPath) : item);
454
+ }
455
+ if (value && typeof value === 'object') {
456
+ const obj = value;
457
+ return { ...obj, [head]: wrapAtPath(obj[head], rest, anchorText, targetPath) };
458
+ }
459
+ return value;
460
+ }
461
+ //# sourceMappingURL=issue-fix-link-insert.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"issue-fix-link-insert.js","sourceRoot":"","sources":["../../src/seo/issue-fix-link-insert.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,cAAc,EAAsB,MAAM,eAAe,CAAA;AAElE,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA;AACtD,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAA;AAE7D,OAAO,EAAE,6BAA6B,EAAE,MAAM,uBAAuB,CAAA;AACrE,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAA;AACvD,OAAO,EACL,mBAAmB,GAKpB,MAAM,gBAAgB,CAAA;AAOvB,MAAM,CAAC,MAAM,0BAA0B,GAAG,EAAE,CAAA;AAC5C,MAAM,CAAC,MAAM,qBAAqB,GAAG,IAAI,GAAG,CAAC,CAAC,aAAa,CAAC,CAAC,CAAA;AAC7D,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,CAAA;AAC3B,MAAM,CAAC,MAAM,UAAU,GAAG,EAAE,CAAA;AAsB5B,MAAM,UAAU,mBAAmB,CAAC,KAAa;IAC/C,IAAI,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,GAAG,CAAC,CAAA;IACxE,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;AAC1B,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,MAAc;IAC5C,OAAO,MAAM,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,WAAW,EAAE,CAAA;AACzD,CAAC;AAED,MAAM,UAAU,0BAA0B,CACxC,cAAsB,EACtB,cAAsB,EACtB,UAAkB,EAClB,eAA8B;IAE9B,OAAO,GAAG,cAAc,IAAI,cAAc,IAAI,eAAe,CAAC,UAAU,CAAC,IAAI,IAAI,IAAI,CAAC,eAAe,CAAC,CAAC,OAAO,EAAE,EAAE,CAAA;AACpH,CAAC;AAED,MAAM,UAAU,oBAAoB,CAClC,IAA6B,EAC7B,UAAkB,EAClB,OAAgB;IAEhB,MAAM,KAAK,GAAG,oBAAoB,CAAC,UAAU,EAAE,OAAO,CAAC,CAAA;IACvD,OAAO,WAAW,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,mBAAmB,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAA;AACtE,CAAC;AAED,MAAM,UAAU,mBAAmB,CACjC,IAA6B,EAC7B,UAAkB;IAElB,MAAM,OAAO,GAAG,UAAU,CAAC,IAAI,EAAE,CAAA;IACjC,IAAI,OAAO,CAAC,MAAM,GAAG,UAAU,IAAI,OAAO,CAAC,MAAM,GAAG,UAAU,EAAE,CAAC;QAC/D,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,eAAe,EAAE,CAAA;IAC7D,CAAC;IAED,IAAI,aAAa,GAAG,KAAK,CAAA;IACzB,IAAI,cAAc,GAAG,KAAK,CAAA;IAE1B,MAAM,KAAK,GAAG,aAAa,CAAC,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;QACjE,IAAI,GAAG,CAAC,IAAI,KAAK,aAAa,EAAE,CAAC;YAC/B,cAAc,GAAG,IAAI,CAAA;YACrB,OAAO,IAAI,CAAA;QACb,CAAC;QACD,IAAI,GAAG,CAAC,IAAI,KAAK,aAAa,EAAE,CAAC;YAC/B,aAAa,GAAG,IAAI,CAAA;YACpB,OAAO,IAAI,CAAA;QACb,CAAC;QACD,OAAO,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,KAAK,EAAE,GAAG,CAAC,KAAK,EAAE,CAAA;IAC7C,CAAC,CAAC,CAAA;IAEF,IAAI,KAAK;QAAE,OAAO,KAAK,CAAA;IACvB,IAAI,aAAa;QAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,aAAa,EAAE,CAAA;IAC5E,IAAI,cAAc;QAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,yBAAyB,EAAE,CAAA;IACzF,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,CAAA;AACzD,CAAC;AAED,MAAM,UAAU,oBAAoB,CAClC,IAA6B,EAC7B,UAAkB,EAClB,UAAkB;IAElB,MAAM,KAAK,GAAG,mBAAmB,CAAC,IAAI,EAAE,UAAU,CAAC,CAAA;IACnD,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;QAChB,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,CAAA;IAC5D,CAAC;IACD,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAE,CAAA;IAC7B,MAAM,IAAI,GAAG,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,UAAU,CAAC,CAAA;IAClF,OAAO,EAAE,KAAK,EAAE,EAAE,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAA;AACrD,CAAC;AASD,SAAS,WAAW,CAClB,MAA0E;IAE1E,OAAO,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,WAAW,CAAA;AAC5D,CAAC;AAED,SAAS,iBAAiB,CAAC,MAA6C;IACtE,QAAQ,MAAM,EAAE,CAAC;QACf,KAAK,gBAAgB;YACnB,OAAO,yDAAyD,CAAA;QAClE,KAAK,gBAAgB;YACnB,OAAO,uFAAuF,CAAA;QAChG,KAAK,WAAW;YACd,OAAO,wDAAwD,CAAA;QACjE;YACE,OAAO,iDAAiD,CAAA;IAC5D,CAAC;AACH,CAAC;AAED,SAAS,eAAe,CAAC,GAA0B;IACjD,IAAI,GAAG,CAAC,kBAAkB;QAAE,OAAO,GAAG,CAAC,kBAAkB,CAAA;IACzD,IAAI,mBAAmB,CAAC,GAAG,CAAC,UAAU,CAAC,GAAG,0BAA0B;QAAE,OAAO,gBAAgB,CAAA;IAC7F,OAAO,WAAW,CAAA;AACpB,CAAC;AAED,SAAS,iBAAiB,CAAC,GAA0B,EAAE,UAAkB;IACvE,MAAM,QAAQ,GAAG,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,UAAU,CAAC;QACnD,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,EAAE,YAAY,UAAU,KAAK,GAAG,CAAC,UAAU,MAAM,CAAC;QACtF,CAAC,CAAC,GAAG,GAAG,CAAC,OAAO,MAAM,UAAU,EAAE,CAAA;IACpC,OAAO;QACL;YACE,KAAK,EAAE,QAAQ;YACf,KAAK,EAAE,aAAa;YACpB,MAAM,EAAE,IAAI;YACZ,KAAK,EAAE,GAAG,GAAG,CAAC,WAAW,KAAK,GAAG,CAAC,SAAS,GAAG;SAC/C;QACD;YACE,KAAK,EAAE,QAAQ;YACf,KAAK,EAAE,aAAa;YACpB,MAAM,EAAE,GAAG,CAAC,UAAU;YACtB,KAAK,EAAE,GAAG,GAAG,CAAC,UAAU,MAAM,UAAU,EAAE;SAC3C;QACD;YACE,KAAK,EAAE,SAAS;YAChB,KAAK,EAAE,SAAS;YAChB,MAAM,EAAE,GAAG,CAAC,OAAO;YACnB,KAAK,EAAE,QAAQ;SAChB;KACF,CAAA;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,KAAuB,EACvB,GAAuB,EACvB,IAA8B;IAE9B,MAAM,cAAc,GAAG,KAAK,CAAC,QAAQ,IAAI,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAA;IAC5D,MAAM,UAAU,GAAG,GAAG,CAAC,MAAM,CAAC,GAAG,CAAA;IACjC,MAAM,gBAAgB,GAAG,KAAK,CAAC,UAAU,KAAK,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAA;IACtE,IAAI,IAAI,GAA4B,EAAE,CAAA;IACtC,IAAI,CAAC;QACH,IAAI,GAAG,WAAW,CAChB,MAAM,IAAI,CAAC,mBAAmB,CAAC;YAC7B,EAAE,EAAE,IAAI,CAAC,EAAoC;YAC7C,cAAc;YACd,gBAAgB;SACjB,CAAC,CACH,CAAA;IACH,CAAC;IAAC,MAAM,CAAC;QACP,OAAO;YACL,WAAW,EAAE,KAAK;YAClB,WAAW,EAAE,mBAAmB,CAAC,cAAc,EAAE,KAAK,CAAC,IAAI,EAAE,GAAG,CAAC,SAAS,CAAC;YAC3E,KAAK,EAAE,EAAE;YACT,OAAO,EAAE,EAAE;YACX,aAAa,EAAE,iDAAiD;SACjE,CAAA;IACH,CAAC;IAED,MAAM,SAAS,GAAG,IAAI;SACnB,MAAM,CACL,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,SAAS,IAAI,mBAAmB,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,0BAA0B,CAC5F;SACA,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,GAAG,CAAC,CAAC,UAAU,CAAC,CAAA;IAC9C,MAAM,aAAa,GAAG,SAAS,CAAC,CAAC,CAAC,CAAA;IAClC,IAAI,aAAa,EAAE,CAAC;QAClB,OAAO;YACL,WAAW,EAAE,IAAI;YACjB,MAAM,EAAE,aAAa,CAAC,SAAS,KAAK,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,eAAe;YACvE,WAAW,EAAE,aAAa;YAC1B,WAAW,EAAE,aAAa,CAAC,WAAW;YACtC,KAAK,EAAE;gBACL,cAAc,EAAE,aAAa,CAAC,cAAc;gBAC5C,cAAc;gBACd,UAAU;gBACV,UAAU,EAAE,aAAa,CAAC,UAAU;aACrC;YACD,OAAO,EAAE,iBAAiB,CAAC,aAAa,EAAE,UAAU,CAAC;YACrD,aAAa,EAAE,uBAAuB,aAAa,CAAC,WAAW,gCAAgC,aAAa,CAAC,UAAU,IAAI;SAC5H,CAAA;IACH,CAAC;IAED,MAAM,IAAI,GAAG,CAAC,GAAG,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,GAAG,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAA;IACrE,OAAO;QACL,WAAW,EAAE,KAAK;QAClB,WAAW,EACT,IAAI,EAAE,WAAW,IAAI,mBAAmB,CAAC,cAAc,EAAE,KAAK,CAAC,IAAI,EAAE,GAAG,CAAC,SAAS,CAAC;QACrF,KAAK,EAAE,EAAE;QACT,OAAO,EAAE,EAAE;QACX,aAAa,EAAE,iBAAiB,CAAC,IAAI,CAAC,CAAC,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;KAC3E,CAAA;AACH,CAAC;AAwCD,SAAS,QAAQ,CAAC,KAAc;IAC9B,OAAO,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAChE,CAAC,CAAE,KAAiC;QACpC,CAAC,CAAC,EAAE,CAAA;AACR,CAAC;AAED,SAAS,cAAc,CAAC,KAAc;IACpC,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAA;AACrE,CAAC;AAED,uGAAuG;AACvG,SAAS,sBAAsB,CAAC,GAAY;IAC1C,MAAM,IAAI,GAAG,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;IAC/B,MAAM,IAAI,GAAG,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,cAAc,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,EAAE,CAAA;IAC5E,MAAM,aAAa,GAAG,eAAe,EAAE,EAAE,WAAW,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC,CAAA;IACtE,OAAO,kBAAkB,CAAC;QACxB,SAAS,EAAE,aAAa,EAAE,SAAS;QACnC,IAAI;QACJ,IAAI;KACL,CAAC,CAAA;AACJ,CAAC;AAED,KAAK,UAAU,gBAAgB,CAAC,EAAY,EAAE,EAAU;IACtD,OAAO,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC;QAC3B,KAAK,EAAE,EAAE,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE;QAC9B,MAAM,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE;KAC7E,CAAC,CAAA;AACJ,CAAC;AAED,SAAS,qBAAqB,CAAC,GAAY;IACzC,MAAM,IAAI,GAAG,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;IAC/B,OAAO;QACL,UAAU,EAAE,MAAM;QAClB,QAAQ,EAAE,GAAG,CAAC,EAAE;QAChB,KAAK,EAAE,cAAc,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,UAAU;QAC/C,GAAG,EAAE,sBAAsB,CAAC,GAAG,CAAC;QAChC,wEAAwE;QACxE,OAAO,EAAE,6BAA6B,CAAC,EAAE,IAAI,EAAE,CAAC;KACjD,CAAA;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,gCAAgC,CACpD,KAGC,EACD,IAAqB;IAKrB,MAAM,KAAK,GAAG,MAAM,uBAAuB,CAAC,KAAK,EAAE,IAAI,CAAC,CAAA;IACxD,MAAM,MAAM,GAAG,MAAM,wBAAwB,CAAC;QAC5C,EAAE,EAAE,KAAK,CAAC,EAAE;QACZ,cAAc,EAAE,KAAK,CAAC,cAAc;QACpC,cAAc,EAAE,KAAK,CAAC,cAAc;QACpC,UAAU,EAAE,KAAK,CAAC,UAAU;QAC5B,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB,QAAQ,EAAE,KAAK,CAAC,QAAQ;KACzB,CAAC,CAAA;IACF,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,CAAA;AAC1B,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAC3C,KAAmC,EACnC,IAAqB;IAErB,MAAM,KAAK,GAAG,IAAI,EAAE,cAAc,IAAI,cAAc,CAAA;IAEpD,MAAM,MAAM,GAAG,MAAM,gBAAgB,CAAC,KAAK,CAAC,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,CAAA;IACrE,IAAI,CAAC,MAAM;QAAE,MAAM,IAAI,KAAK,CAAC,kBAAkB,CAAC,CAAA;IAEhD,MAAM,MAAM,GAAG,MAAM,gBAAgB,CAAC,KAAK,CAAC,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,CAAA;IACrE,IAAI,CAAC,MAAM;QAAE,MAAM,IAAI,KAAK,CAAC,kBAAkB,CAAC,CAAA;IAEhD,MAAM,QAAQ,GAAG,sBAAsB,CAAC,MAAM,CAAC,CAAA;IAC/C,IAAI,qBAAqB,CAAC,KAAK,CAAC,UAAU,CAAC,KAAK,qBAAqB,CAAC,QAAQ,CAAC,EAAE,CAAC;QAChF,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAA;IACzC,CAAC;IAED,MAAM,IAAI,GAAG,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;IAClC,MAAM,OAAO,GAAG,eAAe,EAAE,EAAE,GAAG,EAAE,OAAO,CAAA;IAC/C,IAAI,oBAAoB,CAAC,IAAI,EAAE,QAAQ,EAAE,OAAO,CAAC,EAAE,CAAC;QAClD,MAAM,IAAI,KAAK,CAAC,gBAAgB,CAAC,CAAA;IACnC,CAAC;IAED,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,oBAAoB,CAAC,IAAI,EAAE,KAAK,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAA;IACjF,IAAI,CAAC,OAAO;QAAE,MAAM,IAAI,KAAK,CAAC,eAAe,CAAC,CAAA;IAE9C,MAAM,KAAK,CAAC,MAAM,CAAC,UAAU,EAAE,KAAK,CAAC,cAAc,EAAE,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,CAAA;IAEtE,OAAO;QACL,gBAAgB,EAAE,MAAM,CAAC,UAAU;QACnC,YAAY,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC;QACnC,KAAK;KACN,CAAA;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAC5C,KAAoC;IAEpC,MAAM,MAAM,GAAG,MAAM,gBAAgB,CAAC,KAAK,CAAC,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,CAAA;IACrE,IAAI,CAAC,MAAM;QAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,cAAc,EAAE,CAAA;IAEzD,MAAM,IAAI,GAAG,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;IAClC,IAAI,CAAC,oBAAoB,CAAC,IAAI,EAAE,KAAK,CAAC,UAAU,EAAE,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC;QACjE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,cAAc,EAAE,CAAA;IAC9C,CAAC;IAED,IAAI,QAAQ,GAAG,KAAK,CAAC,QAAQ,CAAA;IAC7B,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,MAAM,MAAM,GAAG,MAAM,gBAAgB,CAAC,KAAK,CAAC,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,CAAA;QACrE,IAAI,CAAC,MAAM;YAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,cAAc,EAAE,CAAA;QACzD,QAAQ,GAAG,CAAC,qBAAqB,CAAC,MAAM,CAAC,EAAE,qBAAqB,CAAC,MAAM,CAAC,CAAC,CAAA;IAC3E,CAAC;IAED,IACE,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,QAAQ,KAAK,KAAK,CAAC,cAAc,CAAC;QACpE,oBAAoB,CAAC,QAAQ,EAAE,KAAK,CAAC,GAAG,CAAC,EACzC,CAAC;QACD,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,cAAc,EAAE,CAAA;IAC9C,CAAC;IAED,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAA;AACrB,CAAC;AAED,sGAAsG;AACtG,SAAS,oBAAoB,CAC3B,QAA4B,EAC5B,KAAoC;IAEpC,MAAM,KAAK,GAAG,oBAAoB,CAAC,KAAK,CAAC,UAAU,EAAE,KAAK,CAAC,OAAO,CAAC,CAAA;IACnE,IAAI,KAAK,GAAG,CAAC,CAAA;IACb,KAAK,MAAM,MAAM,IAAI,QAAQ,EAAE,CAAC;QAC9B,IAAI,MAAM,CAAC,QAAQ,KAAK,KAAK,CAAC,cAAc;YAAE,SAAQ;QACtD,IAAI,mBAAmB,CAAC,MAAM,CAAC,OAAO,IAAI,EAAE,EAAE,KAAK,CAAC;YAAE,KAAK,EAAE,CAAA;IAC/D,CAAC;IACD,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,qBAAqB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IAC5E,UAAU,CAAC,GAAG,CAAC,qBAAqB,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAA;IACvD,IAAI,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,qBAAqB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;QAC/E,KAAK,EAAE,CAAA;IACT,CAAC;IACD,OAAO,KAAK,CAAA;AACd,CAAC;AAED,SAAS,YAAY,CAAC,KAAa;IACjC,OAAO,KAAK,CAAC,OAAO,CAAC,qBAAqB,EAAE,MAAM,CAAC,CAAA;AACrD,CAAC;AAED,SAAS,mBAAmB,CAAC,KAAa;IACxC,OAAO,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAA;AAClC,CAAC;AAED,SAAS,oBAAoB,CAAC,UAAkB,EAAE,OAAgB;IAChE,MAAM,IAAI,GAAG,mBAAmB,CAAC,UAAU,CAAC,CAAA;IAC5C,MAAM,KAAK,GAAG,IAAI,GAAG,EAAU,CAAA;IAC/B,IAAI,UAAU;QAAE,KAAK,CAAC,GAAG,CAAC,UAAU,CAAC,CAAA;IACrC,IAAI,IAAI;QAAE,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;IACzB,IAAI,OAAO,EAAE,CAAC;QACZ,MAAM,MAAM,GAAG,mBAAmB,CAAC,OAAO,CAAC,CAAA;QAC3C,MAAM,OAAO,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAA;QACxD,KAAK,CAAC,GAAG,CAAC,GAAG,MAAM,GAAG,OAAO,EAAE,CAAC,CAAA;IAClC,CAAC;IACD,OAAO,CAAC,GAAG,KAAK,CAAC,CAAA;AACnB,CAAC;AAED,wGAAwG;AACxG,SAAS,mBAAmB,CAAC,IAAY,EAAE,KAAe;IACxD,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,IAAI,CAAC,QAAQ,CAAC,SAAS,IAAI,GAAG,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,SAAS,IAAI,GAAG,CAAC,EAAE,CAAC;YACvE,OAAO,IAAI,CAAA;QACb,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAA;AACd,CAAC;AAED,SAAS,WAAW,CAAC,KAAc,EAAE,KAAgC;IACnE,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC,KAAK,CAAC,CAAA;IAClD,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACzB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,IAAI,WAAW,CAAC,IAAI,EAAE,KAAK,CAAC;gBAAE,OAAO,IAAI,CAAA;QAC3C,CAAC;QACD,OAAO,KAAK,CAAA;IACd,CAAC;IACD,IAAI,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QACvC,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,MAAM,CAAC,KAAgC,CAAC,EAAE,CAAC;YACpE,IAAI,WAAW,CAAC,KAAK,EAAE,KAAK,CAAC;gBAAE,OAAO,IAAI,CAAA;QAC5C,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAA;AACd,CAAC;AAOD,SAAS,qBAAqB,CAC5B,MAAsC,EACtC,GAAkB;IAElB,oEAAoE;IACpE,kEAAkE;IAClE,OAAO,GAAG,KAAK,MAAM,IAAI,MAAM,EAAE,IAAI,KAAK,MAAM,CAAA;AAClD,CAAC;AAED,SAAS,iBAAiB,CAAC,IAAY,EAAE,MAAc;IACrD,MAAM,OAAO,GAAG,YAAY,CAAC,MAAM,CAAC,CAAA;IACpC,MAAM,EAAE,GAAG,IAAI,MAAM,CAAC,WAAW,OAAO,UAAU,EAAE,IAAI,CAAC,CAAA;IACzD,MAAM,OAAO,GAA4C,EAAE,CAAA;IAC3D,IAAI,CAAyB,CAAA;IAC7B,OAAO,CAAC,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;QACpC,MAAM,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAA;QACzB,MAAM,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAA;QAC1B,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,GAAG,MAAM,CAAC,MAAM,CAAA;QACrC,OAAO,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAA;QACvC,EAAE,CAAC,SAAS,GAAG,KAAK,GAAG,OAAO,CAAC,MAAM,CAAA;IACvC,CAAC;IACD,OAAO,OAAO,CAAA;AAChB,CAAC;AAED,SAAS,cAAc,CAAC,KAAa,EAAE,KAAa;IAClD,IAAI,KAAK,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,GAAG,CAAC,CAAC,KAAK,IAAI;QAAE,OAAO,KAAK,CAAA;IACxD,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,CAAA;IAC7B,OAAO,IAAI,KAAK,SAAS,IAAI,IAAI,KAAK,GAAG,IAAI,IAAI,KAAK,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AAC9E,CAAC;AAED,SAAS,kBAAkB,CAAC,IAAY,EAAE,KAAa;IACrD,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,WAAW,EAAE,CAAA;IACjD,IAAI,QAAQ,GAAG,CAAC,CAAC,CAAA;IACjB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACvC,IAAI,cAAc,CAAC,MAAM,EAAE,CAAC,CAAC;YAAE,QAAQ,GAAG,CAAC,CAAA;IAC7C,CAAC;IACD,IAAI,QAAQ,KAAK,CAAC,CAAC;QAAE,OAAO,KAAK,CAAA;IACjC,OAAO,QAAQ,GAAG,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,CAAA;AAC9C,CAAC;AAED,SAAS,oBAAoB,CAAC,IAAY,EAAE,KAAa;IACvD,MAAM,EAAE,GAAG,0BAA0B,CAAA;IACrC,IAAI,CAAyB,CAAA;IAC7B,OAAO,CAAC,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;QACpC,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,CAAA;QACrB,MAAM,GAAG,GAAG,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAA;QAC/B,IAAI,KAAK,IAAI,KAAK,IAAI,KAAK,GAAG,GAAG;YAAE,OAAO,IAAI,CAAA;IAChD,CAAC;IACD,OAAO,KAAK,CAAA;AACd,CAAC;AAED,SAAS,eAAe,CAAC,IAAY,EAAE,KAAa;IAClD,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAA;IACnC,MAAM,QAAQ,GAAG,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,CAAA;IACxC,IAAI,QAAQ,KAAK,CAAC,CAAC;QAAE,OAAO,KAAK,CAAA;IACjC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAA;AAC9C,CAAC;AAED,0EAA0E;AAC1E,SAAS,SAAS,CAAC,IAAY,EAAE,KAAa,EAAE,KAAa,EAAE,UAAkB;IAC/E,MAAM,OAAO,GAAG,YAAY,UAAU,KAAK,KAAK,MAAM,CAAA;IACtD,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,GAAG,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC,CAAA;AAC1E,CAAC;AAED,SAAS,sBAAsB,CAC7B,IAAY,EACZ,MAAc;IAEd,MAAM,OAAO,GAAG,iBAAiB,CAAC,IAAI,EAAE,MAAM,CAAC,CAAA;IAC/C,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAA;IACrC,IAAI,UAAU,GAAG,KAAK,CAAA;IACtB,KAAK,MAAM,GAAG,IAAI,OAAO,EAAE,CAAC;QAC1B,IAAI,eAAe,CAAC,IAAI,EAAE,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;YACrC,SAAQ;QACV,CAAC;QACD,IAAI,kBAAkB,CAAC,IAAI,EAAE,GAAG,CAAC,KAAK,CAAC,IAAI,oBAAoB,CAAC,IAAI,EAAE,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;YACjF,UAAU,GAAG,IAAI,CAAA;YACjB,SAAQ;QACV,CAAC;QACD,OAAO,GAAG,CAAA;IACZ,CAAC;IACD,OAAO,UAAU,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAA;AACjD,CAAC;AAED,SAAS,aAAa,CACpB,KAAc,EACd,IAAc,EACd,MAAsC,EACtC,GAAkB,EAClB,MAAc,EACd,KAAmE;IAEnE,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,MAAM,MAAM,GAAG,sBAAsB,CAAC,KAAK,EAAE,MAAM,CAAC,CAAA;QACpD,IAAI,CAAC,MAAM;YAAE,OAAO,IAAI,CAAA;QACxB,IAAI,qBAAqB,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,CAAC;YACvC,OAAO,KAAK,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,CAAC,CAAA;QACvC,CAAC;QACD,IAAI,YAAY,IAAI,MAAM,EAAE,CAAC;YAC3B,OAAO,KAAK,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,CAAC,CAAA;QACvC,CAAC;QACD,OAAO,KAAK,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC,CAAA;IAChE,CAAC;IACD,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACzB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACtC,MAAM,KAAK,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,CAAA;YACtF,IAAI,KAAK;gBAAE,OAAO,KAAK,CAAA;QACzB,CAAC;QACD,OAAO,IAAI,CAAA;IACb,CAAC;IACD,IAAI,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QACvC,MAAM,GAAG,GAAG,KAAgC,CAAA;QAC5C,KAAK,MAAM,CAAC,QAAQ,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;YACpD,MAAM,KAAK,GAAG,aAAa,CAAC,KAAK,EAAE,CAAC,GAAG,IAAI,EAAE,QAAQ,CAAC,EAAE,GAAG,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,CAAC,CAAA;YACrF,IAAI,KAAK;gBAAE,OAAO,KAAK,CAAA;QACzB,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAA;AACb,CAAC;AAED,SAAS,UAAU,CACjB,KAAc,EACd,IAAc,EACd,UAAkB,EAClB,UAAkB;IAElB,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACtB,IAAI,OAAO,KAAK,KAAK,QAAQ;YAAE,OAAO,KAAK,CAAA;QAC3C,MAAM,GAAG,GAAG,sBAAsB,CAAC,KAAK,EAAE,UAAU,CAAC,IAAI,EAAE,CAAC,CAAA;QAC5D,IAAI,CAAC,GAAG,IAAI,YAAY,IAAI,GAAG;YAAE,OAAO,KAAK,CAAA;QAC7C,OAAO,SAAS,CAAC,KAAK,EAAE,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,KAAK,EAAE,UAAU,CAAC,CAAA;IAC3D,CAAC;IACD,MAAM,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,GAAG,IAAI,CAAA;IAC5B,IAAI,IAAI,KAAK,SAAS;QAAE,OAAO,KAAK,CAAA;IACpC,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACzB,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,CAAA;QAC1B,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE,CAC3B,CAAC,KAAK,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,EAAE,IAAI,EAAE,UAAU,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC,IAAI,CACpE,CAAA;IACH,CAAC;IACD,IAAI,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QACvC,MAAM,GAAG,GAAG,KAAgC,CAAA;QAC5C,OAAO,EAAE,GAAG,GAAG,EAAE,CAAC,IAAI,CAAC,EAAE,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,UAAU,CAAC,EAAE,CAAA;IAChF,CAAC;IACD,OAAO,KAAK,CAAA;AACd,CAAC"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Post-apply checks for SEO issue fixes. Apply-fix calls this before resolving.
3
+ * Does not run a full site audit.
4
+ */
5
+ import type { PrentaDB } from '../db/client-types.js';
6
+ import type { SeoIssueFixSuggestion } from './issue-fix.js';
7
+ export interface VerifySeoIssueFixInput {
8
+ issueType: string;
9
+ suggestion: SeoIssueFixSuggestion;
10
+ entityId: string | null;
11
+ /** Live document data + SEO fields after the write. */
12
+ live: {
13
+ data: Record<string, unknown>;
14
+ metaTitle?: string | null;
15
+ metaDescription?: string | null;
16
+ canonical?: string | null;
17
+ noindex?: boolean | null;
18
+ structuredDataType?: string | null;
19
+ status?: string;
20
+ };
21
+ db: PrentaDB;
22
+ siteUrl: string;
23
+ navLinks: string[];
24
+ }
25
+ export declare function verifySeoIssueFix(input: VerifySeoIssueFixInput): Promise<{
26
+ ok: true;
27
+ } | {
28
+ ok: false;
29
+ reason: string;
30
+ }>;
31
+ //# sourceMappingURL=issue-fix-verify.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"issue-fix-verify.d.ts","sourceRoot":"","sources":["../../src/seo/issue-fix-verify.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAA;AACrD,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAA;AAG3D,MAAM,WAAW,sBAAsB;IACrC,SAAS,EAAE,MAAM,CAAA;IACjB,UAAU,EAAE,qBAAqB,CAAA;IACjC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;IACvB,uDAAuD;IACvD,IAAI,EAAE;QACJ,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;QAC7B,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;QACzB,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;QAC/B,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;QACzB,OAAO,CAAC,EAAE,OAAO,GAAG,IAAI,CAAA;QACxB,kBAAkB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;QAClC,MAAM,CAAC,EAAE,MAAM,CAAA;KAChB,CAAA;IACD,EAAE,EAAE,QAAQ,CAAA;IACZ,OAAO,EAAE,MAAM,CAAA;IACf,QAAQ,EAAE,MAAM,EAAE,CAAA;CACnB;AA+BD,wBAAsB,iBAAiB,CACrC,KAAK,EAAE,sBAAsB,GAC5B,OAAO,CAAC;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAmDvD"}