@prenta/admin 1.13.0 → 1.15.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 (100) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/dist/__tests__/lib/api.test.d.ts +2 -0
  3. package/dist/__tests__/lib/api.test.d.ts.map +1 -0
  4. package/dist/__tests__/lib/api.test.js +58 -0
  5. package/dist/__tests__/lib/api.test.js.map +1 -0
  6. package/dist/__tests__/lib/seo-service-autopilot.test.d.ts +2 -0
  7. package/dist/__tests__/lib/seo-service-autopilot.test.d.ts.map +1 -0
  8. package/dist/__tests__/lib/seo-service-autopilot.test.js +171 -0
  9. package/dist/__tests__/lib/seo-service-autopilot.test.js.map +1 -0
  10. package/dist/__tests__/lib/seo-service-proposals.test.d.ts +2 -0
  11. package/dist/__tests__/lib/seo-service-proposals.test.d.ts.map +1 -0
  12. package/dist/__tests__/lib/seo-service-proposals.test.js +99 -0
  13. package/dist/__tests__/lib/seo-service-proposals.test.js.map +1 -0
  14. package/dist/__tests__/router/seo-tab-for-path.test.js +1 -0
  15. package/dist/__tests__/router/seo-tab-for-path.test.js.map +1 -1
  16. package/dist/__tests__/views/redirects-pane.render.test.js +30 -12
  17. package/dist/__tests__/views/redirects-pane.render.test.js.map +1 -1
  18. package/dist/__tests__/views/seo-autopilot-applied.render.test.d.ts +2 -0
  19. package/dist/__tests__/views/seo-autopilot-applied.render.test.d.ts.map +1 -0
  20. package/dist/__tests__/views/seo-autopilot-applied.render.test.js +330 -0
  21. package/dist/__tests__/views/seo-autopilot-applied.render.test.js.map +1 -0
  22. package/dist/__tests__/views/seo-autopilot-card.render.test.d.ts +2 -0
  23. package/dist/__tests__/views/seo-autopilot-card.render.test.d.ts.map +1 -0
  24. package/dist/__tests__/views/seo-autopilot-card.render.test.js +512 -0
  25. package/dist/__tests__/views/seo-autopilot-card.render.test.js.map +1 -0
  26. package/dist/__tests__/views/seo-proposals-tab.render.test.d.ts +2 -0
  27. package/dist/__tests__/views/seo-proposals-tab.render.test.d.ts.map +1 -0
  28. package/dist/__tests__/views/seo-proposals-tab.render.test.js +431 -0
  29. package/dist/__tests__/views/seo-proposals-tab.render.test.js.map +1 -0
  30. package/dist/__tests__/views/seo-settings.render.test.js +41 -4
  31. package/dist/__tests__/views/seo-settings.render.test.js.map +1 -1
  32. package/dist/components/seo/ChangePreview.d.ts +6 -0
  33. package/dist/components/seo/ChangePreview.d.ts.map +1 -0
  34. package/dist/components/seo/ChangePreview.js +18 -0
  35. package/dist/components/seo/ChangePreview.js.map +1 -0
  36. package/dist/components/seo/SeoIssueFixPanel.d.ts.map +1 -1
  37. package/dist/components/seo/SeoIssueFixPanel.js +1 -14
  38. package/dist/components/seo/SeoIssueFixPanel.js.map +1 -1
  39. package/dist/lib/api.d.ts +13 -2
  40. package/dist/lib/api.d.ts.map +1 -1
  41. package/dist/lib/api.js +1 -2
  42. package/dist/lib/api.js.map +1 -1
  43. package/dist/lib/seo-service.d.ts +293 -2
  44. package/dist/lib/seo-service.d.ts.map +1 -1
  45. package/dist/lib/seo-service.js +170 -0
  46. package/dist/lib/seo-service.js.map +1 -1
  47. package/dist/prenta-admin.css +1 -1
  48. package/dist/views/SEO.d.ts +5 -1
  49. package/dist/views/SEO.d.ts.map +1 -1
  50. package/dist/views/SEO.js +28 -9
  51. package/dist/views/SEO.js.map +1 -1
  52. package/dist/views/seo/AutopilotAppliedSection.d.ts +10 -0
  53. package/dist/views/seo/AutopilotAppliedSection.d.ts.map +1 -0
  54. package/dist/views/seo/AutopilotAppliedSection.js +295 -0
  55. package/dist/views/seo/AutopilotAppliedSection.js.map +1 -0
  56. package/dist/views/seo/ProposalsTab.d.ts +7 -0
  57. package/dist/views/seo/ProposalsTab.d.ts.map +1 -0
  58. package/dist/views/seo/ProposalsTab.js +334 -0
  59. package/dist/views/seo/ProposalsTab.js.map +1 -0
  60. package/dist/views/seo/RedirectsTab.d.ts +3 -1
  61. package/dist/views/seo/RedirectsTab.d.ts.map +1 -1
  62. package/dist/views/seo/RedirectsTab.js +14 -19
  63. package/dist/views/seo/RedirectsTab.js.map +1 -1
  64. package/dist/views/seo/relative-age.d.ts +7 -0
  65. package/dist/views/seo/relative-age.d.ts.map +1 -0
  66. package/dist/views/seo/relative-age.js +20 -0
  67. package/dist/views/seo/relative-age.js.map +1 -0
  68. package/dist/views/settings/SeoAutopilotCard.d.ts +30 -0
  69. package/dist/views/settings/SeoAutopilotCard.d.ts.map +1 -0
  70. package/dist/views/settings/SeoAutopilotCard.js +375 -0
  71. package/dist/views/settings/SeoAutopilotCard.js.map +1 -0
  72. package/dist/views/settings/SeoSettingsTab.d.ts.map +1 -1
  73. package/dist/views/settings/SeoSettingsTab.js +2 -1
  74. package/dist/views/settings/SeoSettingsTab.js.map +1 -1
  75. package/dist/views/settings/components.d.ts +3 -1
  76. package/dist/views/settings/components.d.ts.map +1 -1
  77. package/dist/views/settings/components.js +2 -2
  78. package/dist/views/settings/components.js.map +1 -1
  79. package/package.json +3 -3
  80. package/src/__tests__/lib/api.test.ts +76 -0
  81. package/src/__tests__/lib/seo-service-autopilot.test.ts +196 -0
  82. package/src/__tests__/lib/seo-service-proposals.test.ts +108 -0
  83. package/src/__tests__/router/seo-tab-for-path.test.ts +1 -0
  84. package/src/__tests__/views/redirects-pane.render.test.tsx +36 -16
  85. package/src/__tests__/views/seo-autopilot-applied.render.test.tsx +382 -0
  86. package/src/__tests__/views/seo-autopilot-card.render.test.tsx +610 -0
  87. package/src/__tests__/views/seo-proposals-tab.render.test.tsx +531 -0
  88. package/src/__tests__/views/seo-settings.render.test.tsx +47 -7
  89. package/src/components/seo/ChangePreview.tsx +47 -0
  90. package/src/components/seo/SeoIssueFixPanel.tsx +1 -44
  91. package/src/lib/api.ts +19 -3
  92. package/src/lib/seo-service.ts +455 -2
  93. package/src/views/SEO.tsx +41 -8
  94. package/src/views/seo/AutopilotAppliedSection.tsx +597 -0
  95. package/src/views/seo/ProposalsTab.tsx +761 -0
  96. package/src/views/seo/RedirectsTab.tsx +39 -60
  97. package/src/views/seo/relative-age.ts +15 -0
  98. package/src/views/settings/SeoAutopilotCard.tsx +826 -0
  99. package/src/views/settings/SeoSettingsTab.tsx +2 -0
  100. package/src/views/settings/components.tsx +10 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,36 @@
1
1
  # @actuate-media/cms-admin
2
2
 
3
+ ## 1.15.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 2f0c3b3: SEO Autopilot (auto-apply policy engine, roadmap item 5).
8
+ - **core**: per-issue-type autopilot policy on `SeoModuleSettings.autopilot`; deterministic gate (brand alignment, banned terms word-bounded, validators, duplicate check, redirect confidence, AI-governance veto, caps, cooldown); new `SeoAutoApply` ledger table (`prenta_seo_auto_applies`, migration `0017_seo_auto_applies`) with field-level before/after and one-call revert; daily `/cron/seo-autopilot` tick (outcome watch → generate → gate → apply → verify → ledger); Search Console outcome watch auto-reverts regressions and pauses the type; routes `GET/PUT /seo/autopilot/settings`, `POST /seo/autopilot/run`, `GET /seo/autopilot/applied`, `POST /seo/autopilot/applied/:id/revert`; digest gains an "Autopilot this week" block. The 404-recovery auto-apply lever is folded into the engine: the stored `redirectRecoveryAutoApply*` fields are deprecated and only ever _read_ — the policy resolver falls back to them per key (`types.redirect`, `redirectMinConfidence`, and `enabled` / `enabledById` when the lever is on) only when the `autopilot` block lacks that key, so explicit autopilot values always win. `GET/PUT /seo/redirects/recovery-settings` keep their wire shape but now read from and write to the autopilot block (never the legacy fields), and `generateRecoverySuggestions` no longer applies redirects itself — `/seo/redirects/suggest` keeps returning `autoApplied: 0` and `governanceBlocked: null` for one release. Existing instances add the `0 6 * * *` `/api/cms/cron/seo-autopilot` cron entry and run `prisma migrate deploy` (un-migrated instances get a self-describing 501 from the autopilot routes).
9
+ - **admin**: Settings → SEO "SEO Autopilot" card; SEO → Proposals "Applied by autopilot" section with Revert (409 conflict → "Revert anyway"); Redirects tab auto-apply controls replaced by a managed-by link.
10
+ - **mcp-server**: `get_seo_autopilot_settings`, `update_seo_autopilot_settings`, `run_seo_autopilot`, `list_seo_autopilot_applied`, `revert_seo_autopilot_change`.
11
+ - **create-prenta**: scaffolded `vercel.json` gains the `0 6 * * *` `/api/cms/cron/seo-autopilot` cron when the SEO plugin is selected; bundled Prisma assets resynced.
12
+
13
+ ## 1.14.0
14
+
15
+ ### Minor Changes
16
+
17
+ - 8b6b25c: AI Proposals Inbox (SEO AI roadmap item 4).
18
+
19
+ **@prenta/core**
20
+ - New routes: `GET /seo/proposals` (unified list of cached issue fixes + open 404 redirect suggestions with staleness, brand-alignment, confidence, and per-feature `allowBulkApply` flags), `POST /seo/proposals/generate` (confirm-gated batch generation, 10 issues per call, 3 concurrent, 20 s budget, halts on `rate_limited`), `POST /seo/proposals/bulk-apply` (max 50; >1 items require `allowBulkApply` for every represented feature → 403 `governance_blocked`; same-document items are applied sequentially against a batch-start snapshot; unreached items return `pending`), `POST /seo/issues/:id/dismiss-fix` (sticky dismissal, audited as `seo_fix_dismissed`).
21
+ - `SeoIssue.metadata.pendingFix` now stores `brandAlignment` (minimum across text fields) and `generatedAt`; `dismissedFingerprint` / `generateSkippedFingerprint` markers keep batch generation from recreating rejected or non-cacheable proposals until the document changes.
22
+ - `SuggestIssueFixResult` gains optional `aiError` (code + message) when the AI path refused or failed.
23
+ - `applyIssueFix` (`seo/issue-fix-apply.ts`) and `acceptRedirectSuggestion` (`redirects/suggestion-accept.ts`) are extracted services; the existing routes keep identical HTTP behaviour.
24
+ - `GET /seo/overview` gains `pendingProposals: { issueFixes, redirects }`.
25
+ - New governance helper `assertBulkApplyAllowed`.
26
+
27
+ **@prenta/admin**
28
+ - New SEO → Proposals tab: multi-select, batch approve (disabled with a Settings link when governance forbids bulk apply), batch dismiss, capped "Generate proposals" loop with Stop, stale-row flagging, "Apply remaining" after a time-budget cut-off. `ChangePreview` is now a shared component.
29
+
30
+ **@prenta/mcp-server**
31
+ - New tools: `list_seo_proposals`, `generate_seo_proposals` (confirm-gated), `bulk_apply_seo_proposals` (confirm-gated), `dismiss_seo_proposal`.
32
+ - `PrentaClientError` now carries the server's machine-readable `code` (e.g. `plan_required`, `governance_blocked`) alongside `status`, and tool error responses append it to the error text as `(code: <code>)` so the calling agent can branch on it.
33
+
3
34
  ## 1.13.0
4
35
 
5
36
  ### Minor Changes
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=api.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/lib/api.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,58 @@
1
+ // @vitest-environment node
2
+ import { afterEach, describe, expect, it, vi } from 'vitest';
3
+ import { cmsApi, getApiBase, setApiBase } from '../../lib/api.js';
4
+ function jsonResponse(status, body) {
5
+ return new Response(JSON.stringify(body), {
6
+ status,
7
+ headers: { 'Content-Type': 'application/json' },
8
+ });
9
+ }
10
+ const originalBase = getApiBase();
11
+ afterEach(() => {
12
+ vi.unstubAllGlobals();
13
+ setApiBase(originalBase);
14
+ });
15
+ describe('cmsApi', () => {
16
+ it('unwraps a 2xx { data } envelope once and reports the status', async () => {
17
+ const fetchMock = vi.fn(async () => jsonResponse(200, { data: { docs: [], total: 0 } }));
18
+ vi.stubGlobal('fetch', fetchMock);
19
+ await expect(cmsApi('/seo/autopilot/applied?page=1')).resolves.toEqual({
20
+ data: { docs: [], total: 0 },
21
+ status: 200,
22
+ });
23
+ expect(fetchMock).toHaveBeenCalledTimes(1);
24
+ const [url, init] = fetchMock.mock.calls[0];
25
+ expect(url).toBe('/api/cms/seo/autopilot/applied?page=1');
26
+ expect(init.credentials).toBe('include');
27
+ });
28
+ it('surfaces a non-2xx JSON body as error, code, errorBody, and status', async () => {
29
+ const body = {
30
+ error: 'metaTitle was edited since autopilot changed it',
31
+ code: 'conflict',
32
+ fields: ['metaTitle'],
33
+ };
34
+ vi.stubGlobal('fetch', vi.fn(async () => jsonResponse(409, body)));
35
+ await expect(cmsApi('/seo/autopilot/applied/la-1/revert', { method: 'POST' })).resolves.toEqual({
36
+ error: 'metaTitle was edited since autopilot changed it',
37
+ code: 'conflict',
38
+ errorBody: body,
39
+ status: 409,
40
+ });
41
+ });
42
+ it('falls back to a generic message and drops a non-string code on a bare non-2xx', async () => {
43
+ vi.stubGlobal('fetch', vi.fn(async () => new Response('not json', { status: 502 })));
44
+ await expect(cmsApi('/anything')).resolves.toEqual({
45
+ error: 'Request failed (502)',
46
+ code: undefined,
47
+ errorBody: {},
48
+ status: 502,
49
+ });
50
+ });
51
+ it('reports a network failure as status 0 without an errorBody', async () => {
52
+ vi.stubGlobal('fetch', vi.fn(async () => {
53
+ throw new Error('offline');
54
+ }));
55
+ await expect(cmsApi('/anything')).resolves.toEqual({ error: 'offline', status: 0 });
56
+ });
57
+ });
58
+ //# sourceMappingURL=api.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.test.js","sourceRoot":"","sources":["../../../src/__tests__/lib/api.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=seo-service-autopilot.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"seo-service-autopilot.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/lib/seo-service-autopilot.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,171 @@
1
+ import { beforeEach, describe, expect, it, vi } from 'vitest';
2
+ /**
3
+ * Wire-level tests for the SEO Autopilot service wrappers. The render tests
4
+ * replace this module wholesale (`vi.mock('../../lib/seo-service.js')`), so
5
+ * URL construction, envelope unwrapping, and the 409 → `conflictFields`
6
+ * mapping are pinned here against a mocked `cmsApi`.
7
+ */
8
+ const cmsApi = vi.fn();
9
+ vi.mock('../../lib/api.js', () => ({ cmsApi: (...args) => cmsApi(...args) }));
10
+ const svc = await import('../../lib/seo-service.js');
11
+ const SETTINGS = {
12
+ enabled: true,
13
+ enabledById: 'u1',
14
+ pausedAt: null,
15
+ pausedReason: null,
16
+ types: { 'missing-meta-title': true },
17
+ pausedTypes: {},
18
+ minBrandAlignment: 85,
19
+ redirectMinConfidence: 85,
20
+ maxPerRun: 5,
21
+ maxPerDay: 20,
22
+ verifyFailuresPerRun: 2,
23
+ outcomeWatch: { enabled: true, days: 14, dropRatio: 0.4, minPriorClicks: 50 },
24
+ lastRunAt: null,
25
+ lastRun: null,
26
+ governance: { issueFixApprovalRequired: false, redirectApprovalRequired: false },
27
+ };
28
+ beforeEach(() => {
29
+ // Block body on purpose: `mockReset()` returns the mock, and vitest would
30
+ // run a returned function as after-test cleanup.
31
+ cmsApi.mockReset();
32
+ });
33
+ describe('autopilot settings wrappers', () => {
34
+ it('fetchAutopilotSettings GETs /seo/autopilot/settings and returns the body', async () => {
35
+ cmsApi.mockResolvedValueOnce({ status: 200, data: SETTINGS });
36
+ await expect(svc.fetchAutopilotSettings()).resolves.toEqual({ settings: SETTINGS });
37
+ expect(cmsApi).toHaveBeenLastCalledWith('/seo/autopilot/settings');
38
+ });
39
+ it('fetchAutopilotSettings surfaces a transport error and rejects a malformed body', async () => {
40
+ cmsApi.mockResolvedValueOnce({ status: 500, error: 'boom' });
41
+ await expect(svc.fetchAutopilotSettings()).resolves.toEqual({ settings: null, error: 'boom' });
42
+ cmsApi.mockResolvedValueOnce({ status: 200, data: { enabled: 'yes' } });
43
+ await expect(svc.fetchAutopilotSettings()).resolves.toEqual({
44
+ settings: null,
45
+ error: 'Unexpected autopilot settings response',
46
+ });
47
+ });
48
+ it('updateAutopilotSettings PUTs the sparse patch verbatim and adopts the echoed policy', async () => {
49
+ cmsApi.mockResolvedValueOnce({ status: 200, data: { ...SETTINGS, maxPerRun: 9 } });
50
+ await expect(svc.updateAutopilotSettings({ maxPerRun: 9, outcomeWatch: { days: 7 } })).resolves.toEqual({ ok: true, settings: { ...SETTINGS, maxPerRun: 9 } });
51
+ expect(cmsApi).toHaveBeenLastCalledWith('/seo/autopilot/settings', {
52
+ method: 'PUT',
53
+ body: JSON.stringify({ maxPerRun: 9, outcomeWatch: { days: 7 } }),
54
+ });
55
+ cmsApi.mockResolvedValueOnce({ status: 400, error: 'maxPerRun must be an integer' });
56
+ await expect(svc.updateAutopilotSettings({ maxPerRun: 99 })).resolves.toEqual({
57
+ ok: false,
58
+ error: 'maxPerRun must be an integer',
59
+ });
60
+ });
61
+ it('runAutopilotNow POSTs an empty object and returns the run summary', async () => {
62
+ const summary = {
63
+ startedAt: '2026-09-07T04:00:00Z',
64
+ durationMs: 10,
65
+ applied: 1,
66
+ verifyFailed: 0,
67
+ reverted: 0,
68
+ gated: {},
69
+ applyOutcomes: {},
70
+ generated: { generated: 1, skipped: 0, failed: 0, haltedReason: null },
71
+ halted: false,
72
+ haltedReason: null,
73
+ };
74
+ cmsApi.mockResolvedValueOnce({ status: 200, data: summary });
75
+ await expect(svc.runAutopilotNow()).resolves.toEqual({ ok: true, summary });
76
+ expect(cmsApi).toHaveBeenLastCalledWith('/seo/autopilot/run', { method: 'POST', body: '{}' });
77
+ cmsApi.mockResolvedValueOnce({ status: 403, error: 'Admin only' });
78
+ await expect(svc.runAutopilotNow()).resolves.toEqual({ ok: false, error: 'Admin only' });
79
+ });
80
+ });
81
+ describe('fetchAutopilotApplied', () => {
82
+ const list = { docs: [], total: 0, page: 2, pageSize: 20, canRevert: true };
83
+ it('encodes page, pageSize, and the optional filters in that order', async () => {
84
+ cmsApi.mockResolvedValueOnce({ status: 200, data: list });
85
+ await expect(svc.fetchAutopilotApplied({ page: 2, pageSize: 20, status: 'applied' })).resolves.toEqual(list);
86
+ expect(cmsApi).toHaveBeenLastCalledWith('/seo/autopilot/applied?page=2&pageSize=20&status=applied');
87
+ cmsApi.mockResolvedValueOnce({ status: 200, data: list });
88
+ await svc.fetchAutopilotApplied({ page: 1, pageSize: 20, outcome: 'regressed' });
89
+ expect(cmsApi).toHaveBeenLastCalledWith('/seo/autopilot/applied?page=1&pageSize=20&outcome=regressed');
90
+ });
91
+ it('always sends page and pageSize even when no filter is set', async () => {
92
+ cmsApi.mockResolvedValueOnce({ status: 200, data: list });
93
+ await svc.fetchAutopilotApplied({ page: 1, pageSize: 20 });
94
+ expect(cmsApi).toHaveBeenLastCalledWith('/seo/autopilot/applied?page=1&pageSize=20');
95
+ });
96
+ it('throws on a transport error and falls back to an empty page on a missing body', async () => {
97
+ cmsApi.mockResolvedValueOnce({ status: 501, error: 'Run prisma migrate deploy' });
98
+ await expect(svc.fetchAutopilotApplied({ page: 1, pageSize: 20 })).rejects.toThrow('Run prisma migrate deploy');
99
+ cmsApi.mockResolvedValueOnce({ status: 200 });
100
+ await expect(svc.fetchAutopilotApplied({ page: 3, pageSize: 10 })).resolves.toEqual({
101
+ docs: [],
102
+ total: 0,
103
+ page: 3,
104
+ pageSize: 10,
105
+ canRevert: false,
106
+ });
107
+ });
108
+ });
109
+ describe('revertAutopilotChange', () => {
110
+ it('POSTs { force } to the encoded revert path and resolves ok', async () => {
111
+ cmsApi.mockResolvedValueOnce({ status: 200, data: { reverted: true } });
112
+ await expect(svc.revertAutopilotChange('la/1')).resolves.toEqual({ ok: true });
113
+ expect(cmsApi).toHaveBeenLastCalledWith('/seo/autopilot/applied/la%2F1/revert', {
114
+ method: 'POST',
115
+ body: JSON.stringify({ force: false }),
116
+ });
117
+ cmsApi.mockResolvedValueOnce({ status: 200, data: { reverted: true } });
118
+ await svc.revertAutopilotChange('la-1', true);
119
+ expect(cmsApi).toHaveBeenLastCalledWith('/seo/autopilot/applied/la-1/revert', {
120
+ method: 'POST',
121
+ body: JSON.stringify({ force: true }),
122
+ });
123
+ });
124
+ it('maps a 409 conflict body to conflictFields', async () => {
125
+ const error = 'metaTitle was edited since autopilot changed it';
126
+ cmsApi.mockResolvedValueOnce({
127
+ ok: false,
128
+ error,
129
+ code: 'conflict',
130
+ status: 409,
131
+ errorBody: { error, code: 'conflict', fields: ['metaTitle'] },
132
+ });
133
+ await expect(svc.revertAutopilotChange('la-1')).resolves.toEqual({
134
+ ok: false,
135
+ error,
136
+ conflictFields: ['metaTitle'],
137
+ });
138
+ });
139
+ it('does not report conflictFields when the error is not a conflict', async () => {
140
+ cmsApi.mockResolvedValueOnce({
141
+ ok: false,
142
+ error: 'Not found',
143
+ code: undefined,
144
+ status: 404,
145
+ errorBody: { error: 'Not found', fields: ['metaTitle'] },
146
+ });
147
+ const res = await svc.revertAutopilotChange('la-1');
148
+ expect(res).toEqual({ ok: false, error: 'Not found' });
149
+ expect(res).not.toHaveProperty('conflictFields');
150
+ });
151
+ it('filters non-string entries out of a conflict field list and tolerates a missing list', async () => {
152
+ cmsApi.mockResolvedValueOnce({
153
+ error: 'conflict',
154
+ code: 'conflict',
155
+ status: 409,
156
+ errorBody: { fields: ['metaTitle', 42, null, { name: 'x' }, 'metaDescription'] },
157
+ });
158
+ await expect(svc.revertAutopilotChange('la-1')).resolves.toEqual({
159
+ ok: false,
160
+ error: 'conflict',
161
+ conflictFields: ['metaTitle', 'metaDescription'],
162
+ });
163
+ cmsApi.mockResolvedValueOnce({ error: 'conflict', code: 'conflict', status: 409 });
164
+ await expect(svc.revertAutopilotChange('la-1')).resolves.toEqual({
165
+ ok: false,
166
+ error: 'conflict',
167
+ conflictFields: [],
168
+ });
169
+ });
170
+ });
171
+ //# sourceMappingURL=seo-service-autopilot.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"seo-service-autopilot.test.js","sourceRoot":"","sources":["../../../src/__tests__/lib/seo-service-autopilot.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=seo-service-proposals.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"seo-service-proposals.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/lib/seo-service-proposals.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,99 @@
1
+ import { beforeEach, describe, expect, it, vi } from 'vitest';
2
+ const cmsApi = vi.fn();
3
+ vi.mock('../../lib/api.js', () => ({ cmsApi: (...args) => cmsApi(...args) }));
4
+ const svc = await import('../../lib/seo-service.js');
5
+ beforeEach(() => {
6
+ // Block body on purpose: `mockReset()` returns the mock, and vitest would
7
+ // run a returned function as after-test cleanup.
8
+ cmsApi.mockReset();
9
+ });
10
+ describe('proposal service helpers', () => {
11
+ it('fetchSeoProposals GETs /seo/proposals and throws on error', async () => {
12
+ cmsApi.mockResolvedValueOnce({ status: 500, error: 'boom' });
13
+ await expect(svc.fetchSeoProposals()).rejects.toThrow('boom');
14
+ cmsApi.mockResolvedValueOnce({
15
+ status: 200,
16
+ data: {
17
+ proposals: [],
18
+ counts: { issueFixes: 0, redirects: 0, stale: 0, eligibleForGeneration: 0 },
19
+ governance: { issueFixBulk: false, redirectBulk: false },
20
+ },
21
+ });
22
+ await expect(svc.fetchSeoProposals()).resolves.toMatchObject({ proposals: [] });
23
+ expect(cmsApi).toHaveBeenLastCalledWith('/seo/proposals');
24
+ });
25
+ it('fetchSeoProposals fills in autopilot when an older core omits it', async () => {
26
+ cmsApi.mockResolvedValueOnce({
27
+ status: 200,
28
+ data: {
29
+ proposals: [],
30
+ counts: { issueFixes: 0, redirects: 0, stale: 0, eligibleForGeneration: 0 },
31
+ governance: { issueFixBulk: true, redirectBulk: false },
32
+ },
33
+ });
34
+ await expect(svc.fetchSeoProposals()).resolves.toEqual({
35
+ proposals: [],
36
+ counts: { issueFixes: 0, redirects: 0, stale: 0, eligibleForGeneration: 0 },
37
+ governance: { issueFixBulk: true, redirectBulk: false },
38
+ autopilot: { enabled: false, pausedReason: null, lastRunAt: null, appliedLast7d: 0 },
39
+ });
40
+ // A server that does send it wins over the fallback.
41
+ const autopilot = { enabled: true, pausedReason: null, lastRunAt: null, appliedLast7d: 3 };
42
+ cmsApi.mockResolvedValueOnce({
43
+ status: 200,
44
+ data: {
45
+ proposals: [],
46
+ counts: { issueFixes: 0, redirects: 0, stale: 0, eligibleForGeneration: 0 },
47
+ governance: { issueFixBulk: true, redirectBulk: false },
48
+ autopilot,
49
+ },
50
+ });
51
+ await expect(svc.fetchSeoProposals()).resolves.toMatchObject({ autopilot });
52
+ });
53
+ it('generateSeoProposals POSTs confirm: true and returns the result or error', async () => {
54
+ cmsApi.mockResolvedValueOnce({
55
+ status: 200,
56
+ data: { generated: 3, skipped: 1, failed: 0, remaining: 2, haltedReason: null },
57
+ });
58
+ await expect(svc.generateSeoProposals()).resolves.toEqual({
59
+ result: { generated: 3, skipped: 1, failed: 0, remaining: 2, haltedReason: null },
60
+ });
61
+ expect(cmsApi).toHaveBeenCalledWith('/seo/proposals/generate', {
62
+ method: 'POST',
63
+ body: JSON.stringify({ confirm: true }),
64
+ });
65
+ cmsApi.mockResolvedValueOnce({ status: 429, error: 'AI rate limit reached.' });
66
+ await expect(svc.generateSeoProposals()).resolves.toEqual({ error: 'AI rate limit reached.' });
67
+ });
68
+ it('bulkApplySeoProposals flags governance_blocked distinctly', async () => {
69
+ cmsApi.mockResolvedValueOnce({
70
+ status: 403,
71
+ error: 'Enable "Allow bulk apply"',
72
+ code: 'governance_blocked',
73
+ });
74
+ await expect(svc.bulkApplySeoProposals([{ kind: 'issue-fix', id: 'i1', fingerprint: 'f' }])).resolves.toEqual({ error: 'Enable "Allow bulk apply"', governanceBlocked: true });
75
+ cmsApi.mockResolvedValueOnce({
76
+ status: 200,
77
+ data: {
78
+ results: [{ kind: 'issue-fix', id: 'i1', status: 'applied' }],
79
+ applied: 1,
80
+ failed: 0,
81
+ pending: 0,
82
+ },
83
+ });
84
+ await expect(svc.bulkApplySeoProposals([{ kind: 'issue-fix', id: 'i1' }])).resolves.toEqual({
85
+ result: {
86
+ results: [{ kind: 'issue-fix', id: 'i1', status: 'applied' }],
87
+ applied: 1,
88
+ failed: 0,
89
+ pending: 0,
90
+ },
91
+ });
92
+ });
93
+ it('dismissSeoIssueFix POSTs to the encoded issue path', async () => {
94
+ cmsApi.mockResolvedValueOnce({ status: 200, data: { dismissed: true } });
95
+ await expect(svc.dismissSeoIssueFix('a/b')).resolves.toEqual({});
96
+ expect(cmsApi).toHaveBeenCalledWith('/seo/issues/a%2Fb/dismiss-fix', { method: 'POST' });
97
+ });
98
+ });
99
+ //# sourceMappingURL=seo-service-proposals.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"seo-service-proposals.test.js","sourceRoot":"","sources":["../../../src/__tests__/lib/seo-service-proposals.test.ts"],"names":[],"mappings":"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"}
@@ -15,6 +15,7 @@ describe('seoTabForPath', () => {
15
15
  expect(seoTabForPath('/seo/links')).toBe('technical');
16
16
  expect(seoTabForPath('/seo/redirects')).toBe('redirects');
17
17
  expect(seoTabForPath('/seo/audit')).toBe('audit');
18
+ expect(seoTabForPath('/seo/proposals')).toBe('proposals');
18
19
  });
19
20
  it('returns null for non-SEO paths so they fall through', () => {
20
21
  expect(seoTabForPath('/dashboard')).toBeNull();
@@ -1 +1 @@
1
- {"version":3,"file":"seo-tab-for-path.test.js","sourceRoot":"","sources":["../../../src/__tests__/router/seo-tab-for-path.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAA;AAE7C,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAElE,QAAQ,CAAC,eAAe,EAAE,GAAG,EAAE;IAC7B,EAAE,CAAC,kDAAkD,EAAE,GAAG,EAAE;QAC1D,uEAAuE;QACvE,yEAAyE;QACzE,MAAM,CAAC,aAAa,CAAC,kBAAkB,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;QACvD,MAAM,CAAC,aAAa,CAAC,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAA;IACzD,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,4CAA4C,EAAE,GAAG,EAAE;QACpD,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAA;QAC9C,MAAM,CAAC,aAAa,CAAC,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;QACrD,MAAM,CAAC,aAAa,CAAC,iBAAiB,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;QACxD,MAAM,CAAC,aAAa,CAAC,gBAAgB,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAA;QACzD,MAAM,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAA;QACrD,MAAM,CAAC,aAAa,CAAC,gBAAgB,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAA;QACzD,MAAM,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;IACnD,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,qDAAqD,EAAE,GAAG,EAAE;QAC7D,MAAM,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAA;QAC9C,MAAM,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAA;QAC1C,MAAM,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAA;QAC3C,MAAM,CAAC,aAAa,CAAC,WAAW,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAA;IAC/C,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,qEAAqE,EAAE,GAAG,EAAE;QAC7E,KAAK,MAAM,IAAI,IAAI,cAAc,EAAE,CAAC;YAClC,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAA;QAC5C,CAAC;IACH,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,wDAAwD,EAAE,GAAG,EAAE;QAChE,2EAA2E;QAC3E,wEAAwE;QACxE,KAAK,MAAM,IAAI,IAAI,CAAC,MAAM,EAAE,cAAc,EAAE,kBAAkB,CAAC,EAAE,CAAC;YAChE,MAAM,CAAC,cAAc,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,CAAA;YACtC,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAA;QAC5C,CAAC;IACH,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
1
+ {"version":3,"file":"seo-tab-for-path.test.js","sourceRoot":"","sources":["../../../src/__tests__/router/seo-tab-for-path.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAA;AAE7C,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAElE,QAAQ,CAAC,eAAe,EAAE,GAAG,EAAE;IAC7B,EAAE,CAAC,kDAAkD,EAAE,GAAG,EAAE;QAC1D,uEAAuE;QACvE,yEAAyE;QACzE,MAAM,CAAC,aAAa,CAAC,kBAAkB,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;QACvD,MAAM,CAAC,aAAa,CAAC,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAA;IACzD,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,4CAA4C,EAAE,GAAG,EAAE;QACpD,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAA;QAC9C,MAAM,CAAC,aAAa,CAAC,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;QACrD,MAAM,CAAC,aAAa,CAAC,iBAAiB,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;QACxD,MAAM,CAAC,aAAa,CAAC,gBAAgB,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAA;QACzD,MAAM,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAA;QACrD,MAAM,CAAC,aAAa,CAAC,gBAAgB,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAA;QACzD,MAAM,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;QACjD,MAAM,CAAC,aAAa,CAAC,gBAAgB,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAA;IAC3D,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,qDAAqD,EAAE,GAAG,EAAE;QAC7D,MAAM,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAA;QAC9C,MAAM,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAA;QAC1C,MAAM,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAA;QAC3C,MAAM,CAAC,aAAa,CAAC,WAAW,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAA;IAC/C,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,qEAAqE,EAAE,GAAG,EAAE;QAC7E,KAAK,MAAM,IAAI,IAAI,cAAc,EAAE,CAAC;YAClC,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAA;QAC5C,CAAC;IACH,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,wDAAwD,EAAE,GAAG,EAAE;QAChE,2EAA2E;QAC3E,wEAAwE;QACxE,KAAK,MAAM,IAAI,IAAI,CAAC,MAAM,EAAE,cAAc,EAAE,kBAAkB,CAAC,EAAE,CAAC;YAChE,MAAM,CAAC,cAAc,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,CAAA;YACtC,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAA;QAC5C,CAAC;IACH,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
@@ -34,6 +34,7 @@ const createRedirectRule = vi.fn(async (_p) => ({}));
34
34
  const updateRedirectRule = vi.fn(async (_id, _p) => ({}));
35
35
  const deleteRedirectRule = vi.fn(async (_id) => ({}));
36
36
  const generate404RecoverySuggestions = vi.fn(async () => ({}));
37
+ const saveRedirectRecoverySettings = vi.fn(async (_p) => ({}));
37
38
  vi.mock('../../lib/seo-service.js', () => ({
38
39
  fetchRedirectOverview: vi.fn(async () => ({
39
40
  activeRedirects: 2,
@@ -57,9 +58,9 @@ vi.mock('../../lib/seo-service.js', () => ({
57
58
  fetchRedirectRecoverySettings: vi.fn(async () => ({
58
59
  aiRerank: false,
59
60
  autoApply: false,
60
- autoApplyMinConfidence: 0.85,
61
+ autoApplyMinConfidence: 85,
61
62
  })),
62
- saveRedirectRecoverySettings: vi.fn(async () => ({})),
63
+ saveRedirectRecoverySettings: (p) => saveRedirectRecoverySettings(p),
63
64
  }));
64
65
  vi.mock('sonner', () => ({
65
66
  toast: { success: vi.fn(), error: vi.fn(), info: vi.fn(), loading: vi.fn() },
@@ -70,6 +71,8 @@ beforeEach(() => {
70
71
  createRedirectRule.mockClear();
71
72
  updateRedirectRule.mockClear();
72
73
  deleteRedirectRule.mockClear();
74
+ generate404RecoverySuggestions.mockClear();
75
+ saveRedirectRecoverySettings.mockClear();
73
76
  });
74
77
  describe('Redirects inline editor pane', () => {
75
78
  it('opens the pane on row click with the rule loaded', async () => {
@@ -129,19 +132,34 @@ describe('Redirects inline editor pane', () => {
129
132
  expect(createRedirectRule).not.toHaveBeenCalled();
130
133
  });
131
134
  });
132
- describe('AI 404 recovery governance feedback', () => {
133
- it('explains why auto-apply was skipped when governance blocked it', async () => {
134
- generate404RecoverySuggestions.mockResolvedValueOnce({
135
- autoApplied: 0,
136
- governanceBlocked: 'The "404 Recovery suggestions" feature requires human approval before AI results are applied.',
137
- });
135
+ describe('404 recovery settings', () => {
136
+ it('points auto-apply at SEO Autopilot instead of exposing its own controls', async () => {
137
+ const onNavigate = vi.fn();
138
+ render(_jsx(RedirectsTab, { onNavigate: onNavigate }));
139
+ await screen.findByRole('button', { name: '/old-path' });
140
+ // Task 8 moved the auto-apply policy into the autopilot; the card keeps
141
+ // AI re-ranking only and links to the Autopilot settings card.
142
+ expect(screen.getByLabelText('AI re-ranking')).toBeTruthy();
143
+ expect(screen.queryByLabelText(/Auto-apply high-confidence redirects/)).toBeNull();
144
+ expect(screen.queryByLabelText(/Auto-apply minimum confidence/)).toBeNull();
145
+ fireEvent.click(screen.getByRole('button', { name: 'SEO Autopilot' }));
146
+ expect(onNavigate).toHaveBeenCalledWith('/settings?tab=seo');
147
+ expect(screen.queryByRole('link')).toBeNull();
148
+ });
149
+ it('saves only the AI re-ranking flag', async () => {
150
+ render(_jsx(RedirectsTab, {}));
151
+ await screen.findByRole('button', { name: '/old-path' });
152
+ fireEvent.click(screen.getByLabelText('AI re-ranking'));
153
+ fireEvent.click(screen.getByRole('button', { name: 'Save settings' }));
154
+ await waitFor(() => expect(saveRedirectRecoverySettings).toHaveBeenCalledWith({ aiRerank: true }));
155
+ });
156
+ it('reports generation success without the retired auto-apply / governance messages', async () => {
157
+ generate404RecoverySuggestions.mockResolvedValueOnce({});
138
158
  const { toast } = await import('sonner');
139
159
  render(_jsx(RedirectsTab, {}));
140
160
  fireEvent.click(await screen.findByRole('button', { name: /Generate suggestions/ }));
141
- // Generation succeeded suggestions exist — but the operator is told the
142
- // governance reason instead of silently seeing nothing auto-applied.
143
- await waitFor(() => expect(toast.info).toHaveBeenCalledWith(expect.stringContaining('requires human approval')));
144
- expect(toast.success).toHaveBeenCalledWith('Generated 404 recovery suggestions.');
161
+ await waitFor(() => expect(toast.success).toHaveBeenCalledWith('Generated 404 recovery suggestions.'));
162
+ expect(toast.info).not.toHaveBeenCalled();
145
163
  });
146
164
  });
147
165
  //# sourceMappingURL=redirects-pane.render.test.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"redirects-pane.render.test.js","sourceRoot":"","sources":["../../../src/__tests__/views/redirects-pane.render.test.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"redirects-pane.render.test.js","sourceRoot":"","sources":["../../../src/__tests__/views/redirects-pane.render.test.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=seo-autopilot-applied.render.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"seo-autopilot-applied.render.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/views/seo-autopilot-applied.render.test.tsx"],"names":[],"mappings":""}