@actuate-media/cms-core 0.58.0 → 0.59.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=media-upload-storage.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"media-upload-storage.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/api/media-upload-storage.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,152 @@
1
+ import { afterEach, beforeEach, describe, expect, it } from 'vitest';
2
+ import { handleActuateAPI } from '../../api/index.js';
3
+ import { initDB } from '../../db.js';
4
+ import { generateApiKey } from '../../security/api-key-enhanced.js';
5
+ import { setStorageAdapter } from '../../storage/index.js';
6
+ /**
7
+ * Regression tests for the media upload storage contract (broken-image bug):
8
+ *
9
+ * The old `/media/upload` swallowed blob-storage failures and stored a
10
+ * `/api/cms/media/file/<key>` fallback URL — a path no route serves — so the
11
+ * API returned 201, a media record appeared in the library, but the bytes
12
+ * were never persisted and every thumbnail 404'd.
13
+ *
14
+ * The contract now is:
15
+ * - storage failure (adapter throw, or no adapter + blob unavailable)
16
+ * → 500, and NO media record is created;
17
+ * - storage success → 201 with `data.url` set to the real public URL
18
+ * (the admin uses it for immediate previews) and `storageKey` equal to
19
+ * that URL — never a dead fallback path.
20
+ */
21
+ const VALID_SECRET = 'a'.repeat(48);
22
+ // A 1×1 transparent PNG — valid magic bytes; uploaded with skipOptimize so the
23
+ // image pipeline (sharp) never runs.
24
+ const TINY_PNG = Buffer.from('iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAC0lEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==', 'base64');
25
+ function createMockDB(apiKey) {
26
+ const created = [];
27
+ const db = {
28
+ apiKey: {
29
+ findMany: async () => [apiKey],
30
+ findUnique: async ({ where }) => apiKey.keyHash === where.keyHash ? apiKey : null,
31
+ update: async () => apiKey,
32
+ },
33
+ media: {
34
+ create: async ({ data }) => {
35
+ const row = { id: `media-${created.length + 1}`, ...data };
36
+ created.push(row);
37
+ return row;
38
+ },
39
+ },
40
+ auditLog: {
41
+ create: async () => ({}),
42
+ },
43
+ user: {},
44
+ session: {},
45
+ };
46
+ return { db, created };
47
+ }
48
+ async function makeKey() {
49
+ const { key, keyHash, keyPrefix } = await generateApiKey({
50
+ prefix: 'act_sk',
51
+ scopes: { admin: true },
52
+ });
53
+ return {
54
+ key,
55
+ record: {
56
+ id: 'apikey-1',
57
+ keyHash,
58
+ keyPrefix,
59
+ userId: 'user-1',
60
+ scopes: { admin: true },
61
+ ipRestrictions: null,
62
+ expiresAt: null,
63
+ lastUsedAt: null,
64
+ revokedAt: null,
65
+ },
66
+ };
67
+ }
68
+ /**
69
+ * Build a multipart upload request with a buffered body and an explicit
70
+ * Content-Length (the route rejects length-less bodies up front), mirroring
71
+ * what a real HTTP server sees.
72
+ */
73
+ async function uploadRequest(key) {
74
+ const form = new FormData();
75
+ form.append('file', new File([TINY_PNG], 'logo.png', { type: 'image/png' }));
76
+ form.append('skipOptimize', 'true');
77
+ const draft = new Request('https://example.com/api/cms/media/upload', {
78
+ method: 'POST',
79
+ body: form,
80
+ });
81
+ const body = Buffer.from(await draft.arrayBuffer());
82
+ const headers = new Headers(draft.headers);
83
+ headers.set('content-length', String(body.byteLength));
84
+ headers.set('Authorization', `Bearer ${key}`);
85
+ return new Request(draft.url, { method: 'POST', headers, body });
86
+ }
87
+ describe('POST /media/upload — storage contract', () => {
88
+ beforeEach(() => {
89
+ delete globalThis.__actuateConfig;
90
+ process.env.CMS_SECRET = VALID_SECRET;
91
+ setStorageAdapter(null);
92
+ });
93
+ afterEach(() => {
94
+ setStorageAdapter(null);
95
+ });
96
+ it('returns 201 with a real url + storageKey when the storage adapter succeeds', async () => {
97
+ const { key, record } = await makeKey();
98
+ const { db, created } = createMockDB(record);
99
+ initDB(db);
100
+ const handler = handleActuateAPI({ prismaClient: db, config: { collections: {} } });
101
+ const stored = [];
102
+ setStorageAdapter({
103
+ upload: async (storageKey) => {
104
+ stored.push(storageKey);
105
+ return `https://cdn.example.com/${storageKey}`;
106
+ },
107
+ download: async () => Buffer.alloc(0),
108
+ delete: async () => { },
109
+ getSignedUrl: async (k) => `https://cdn.example.com/${k}`,
110
+ });
111
+ const res = await handler(await uploadRequest(key));
112
+ expect(res.status).toBe(201);
113
+ const body = (await res.json());
114
+ expect(stored).toHaveLength(1);
115
+ expect(body.data.url).toBe(`https://cdn.example.com/${stored[0]}`);
116
+ expect(body.data.storageKey).toBe(body.data.url);
117
+ expect(created).toHaveLength(1);
118
+ expect(created[0].storageKey).toBe(body.data.url);
119
+ });
120
+ it('returns 500 and creates NO media record when the storage adapter throws', async () => {
121
+ const { key, record } = await makeKey();
122
+ const { db, created } = createMockDB(record);
123
+ initDB(db);
124
+ const handler = handleActuateAPI({ prismaClient: db, config: { collections: {} } });
125
+ setStorageAdapter({
126
+ upload: async () => {
127
+ throw new Error('disk on fire');
128
+ },
129
+ download: async () => Buffer.alloc(0),
130
+ delete: async () => { },
131
+ getSignedUrl: async () => '',
132
+ });
133
+ const res = await handler(await uploadRequest(key));
134
+ expect(res.status).toBe(500);
135
+ expect(created).toHaveLength(0);
136
+ });
137
+ it('returns 500 and creates NO media record when no adapter is set and blob storage fails', async () => {
138
+ // No storage adapter → the route falls through to @vercel/blob, which has
139
+ // no BLOB_READ_WRITE_TOKEN in tests and must fail. The old code turned
140
+ // this exact situation into a 201 + dead `/api/cms/media/file/…` URL.
141
+ const { key, record } = await makeKey();
142
+ const { db, created } = createMockDB(record);
143
+ initDB(db);
144
+ const handler = handleActuateAPI({ prismaClient: db, config: { collections: {} } });
145
+ const res = await handler(await uploadRequest(key));
146
+ expect(res.status).toBe(500);
147
+ const body = (await res.json());
148
+ expect(String(body.error)).toContain('storage');
149
+ expect(created).toHaveLength(0);
150
+ });
151
+ });
152
+ //# sourceMappingURL=media-upload-storage.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"media-upload-storage.test.js","sourceRoot":"","sources":["../../../src/__tests__/api/media-upload-storage.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=route-contracts.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"route-contracts.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/api/route-contracts.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,430 @@
1
+ /**
2
+ * API-handler contract tests (M13).
3
+ *
4
+ * `ROUTE_CONTRACT` below is the checked-in contract for the entire REST
5
+ * surface: every registered route (in registration order, which is semantic —
6
+ * the router is first-match-wins) paired with the exact status an
7
+ * UNAUTHENTICATED request must receive.
8
+ *
9
+ * What this guards against:
10
+ * - silently dropped/renamed routes (e.g. during a route-module refactor)
11
+ * - a protected route accidentally becoming public (401 → 2xx is a security
12
+ * regression and fails loudly here)
13
+ * - handlers that 500 on anonymous traffic instead of failing cleanly
14
+ * - error responses that stop emitting the `{ error: string }` JSON envelope
15
+ *
16
+ * How to update on an INTENTIONAL change: add/remove/edit the table entry in
17
+ * the same PR that changes the route, so the diff documents the new contract.
18
+ * A new route that serves anonymous traffic (expected status 2xx/3xx) must
19
+ * also be added to `ANONYMOUS_SURFACE` with a one-line justification.
20
+ *
21
+ * Status legend:
22
+ * 401 protected — handler rejects before any work happens
23
+ * 400/404 reachable anonymously, but rejects the dummy input/params
24
+ * 2xx/204 deliberately public — must be listed in ANONYMOUS_SURFACE
25
+ */
26
+ import { beforeAll, describe, expect, it } from 'vitest';
27
+ import { createApiRouter } from '../../api/router.js';
28
+ import { registerCMSRoutes } from '../../api/handlers.js';
29
+ import { setActuateConfig } from '../../config/runtime.js';
30
+ import { initDB } from '../../db.js';
31
+ // ─── Harness ──────────────────────────────────────────────────────────
32
+ /**
33
+ * A Prisma-shaped mock where every model delegate exists and returns empty
34
+ * results. The sweep never authenticates, so protected handlers must reject
35
+ * before touching the DB; public handlers see an empty-but-healthy database.
36
+ */
37
+ function permissiveMockDb() {
38
+ const delegate = {
39
+ findUnique: async () => null,
40
+ findFirst: async () => null,
41
+ findMany: async () => [],
42
+ count: async () => 0,
43
+ aggregate: async () => ({}),
44
+ groupBy: async () => [],
45
+ create: async (a) => ({ id: 'x', ...a?.data }),
46
+ update: async (a) => ({ id: 'x', ...a?.data }),
47
+ updateMany: async () => ({ count: 0 }),
48
+ upsert: async () => ({ id: 'x' }),
49
+ delete: async () => ({ id: 'x' }),
50
+ deleteMany: async () => ({ count: 0 }),
51
+ };
52
+ const base = {
53
+ $queryRaw: async () => [{ ok: 1 }],
54
+ $executeRaw: async () => 0,
55
+ $transaction: async (fn) => typeof fn === 'function'
56
+ ? fn(permissiveMockDb())
57
+ : Promise.all(fn),
58
+ };
59
+ return new Proxy(base, {
60
+ get(target, prop) {
61
+ if (prop in target)
62
+ return target[prop];
63
+ if (typeof prop === 'string' && !prop.startsWith('$') && prop !== 'then')
64
+ return delegate;
65
+ return undefined;
66
+ },
67
+ });
68
+ }
69
+ const router = createApiRouter();
70
+ beforeAll(() => {
71
+ process.env.CMS_SECRET = 'contract-suite-secret-0123456789abcdef';
72
+ process.env.CRON_SECRET = 'cron-secret-for-contract-tests';
73
+ setActuateConfig({
74
+ collections: [
75
+ {
76
+ slug: 'pages',
77
+ labels: { singular: 'Page', plural: 'Pages' },
78
+ fields: [{ name: 'title', type: 'text' }],
79
+ },
80
+ ],
81
+ });
82
+ initDB(permissiveMockDb());
83
+ registerCMSRoutes(router);
84
+ });
85
+ /** Fire an anonymous request at a route, substituting dummy path params. */
86
+ async function anonymousRequest(method, pattern) {
87
+ const path = pattern.replace(/:([^/]+)/g, 'test-param');
88
+ const init = method === 'GET' || method === 'OPTIONS'
89
+ ? { method }
90
+ : {
91
+ method,
92
+ headers: { 'content-type': 'application/json' },
93
+ body: JSON.stringify({}),
94
+ };
95
+ // A handler that hangs on anonymous traffic (e.g. an SSE stream that does
96
+ // not reject unauthenticated clients) should fail this suite cleanly
97
+ // rather than stall the worker until the global test timeout.
98
+ return Promise.race([
99
+ router.handle(new Request(`https://example.com${path}`, init)),
100
+ new Promise((_, reject) => setTimeout(() => reject(new Error(`${method} ${pattern} did not respond within 5s`)), 5000)),
101
+ ]);
102
+ }
103
+ // ─── The contract ─────────────────────────────────────────────────────
104
+ const ROUTE_CONTRACT = [
105
+ ['GET /auth/csrf', 200],
106
+ ['GET /openapi.json', 200],
107
+ ['GET /collections', 200],
108
+ ['GET /docs', 200],
109
+ ['POST /auth/login', 400],
110
+ ['GET /dev/login', 404],
111
+ ['POST /dev/login', 404],
112
+ ['POST /auth/logout', 401],
113
+ ['POST /auth/forgot-password', 400],
114
+ ['POST /auth/reset-password', 400],
115
+ ['GET /auth/me', 401],
116
+ ['POST /auth/totp/setup', 401],
117
+ ['POST /auth/totp/verify', 401],
118
+ ['POST /auth/totp/disable', 401],
119
+ ['POST /auth/totp/login', 400],
120
+ ['GET /auth/oauth/:provider', 400],
121
+ ['GET /auth/oauth/:provider/callback', 400],
122
+ ['GET /collections/:slug', 401],
123
+ ['GET /collections/:slug/:id', 401],
124
+ ['POST /collections/:slug', 401],
125
+ ['PUT /collections/:slug/:id', 401],
126
+ ['DELETE /collections/:slug/:id', 401],
127
+ ['GET /page-sections/types', 401],
128
+ ['POST /page-sections/validate', 401],
129
+ ['GET /page-sections/:collection/:id', 401],
130
+ ['POST /page-sections/:collection/:id', 401],
131
+ ['POST /page-sections/:collection/:id/reorder', 401],
132
+ ['PATCH /page-sections/:collection/:id/:sectionId', 401],
133
+ ['DELETE /page-sections/:collection/:id/:sectionId', 401],
134
+ ['GET /post-templates/:type', 401],
135
+ ['PUT /post-templates/:type', 401],
136
+ ['GET /posts', 401],
137
+ ['GET /media', 401],
138
+ ['POST /media/presign', 401],
139
+ ['POST /media/upload', 401],
140
+ ['POST /media/:id/optimize', 401],
141
+ ['PUT /media/:id', 401],
142
+ ['DELETE /media/:id', 401],
143
+ ['GET /updates/check', 401],
144
+ ['GET /updates/config', 401],
145
+ ['PUT /updates/config', 401],
146
+ ['POST /updates/apply', 401],
147
+ ['GET /captcha/config', 200],
148
+ ['GET /setup/status', 200],
149
+ ['POST /setup/create-admin', 400],
150
+ ['GET /health', 200],
151
+ ['GET /stats', 401],
152
+ ['GET /stats/content-health', 401],
153
+ ['GET /stats/api-delivery', 401],
154
+ ['GET /search/global', 401],
155
+ ['GET /api-keys', 401],
156
+ ['POST /api-keys', 401],
157
+ ['DELETE /api-keys/:id', 401],
158
+ ['GET /users', 401],
159
+ ['GET /users/stats', 401],
160
+ ['GET /users/search', 401],
161
+ ['POST /users/invite', 401],
162
+ ['DELETE /users/:id', 401],
163
+ ['PATCH /users/:id/role', 401],
164
+ ['GET /users/:id', 401],
165
+ ['GET /users/:id/sessions', 401],
166
+ ['DELETE /users/:id/sessions/:sessionId', 401],
167
+ ['POST /users/:id/sessions/revoke-all', 401],
168
+ ['GET /users/:id/activity', 401],
169
+ ['GET /users/:id/permissions', 401],
170
+ ['POST /users/:id/password-reset', 401],
171
+ ['POST /users/:id/force-password-reset', 401],
172
+ ['POST /users/:id/mfa-reset', 401],
173
+ ['POST /users/:id/require-mfa', 401],
174
+ ['POST /users/:id/suspend', 401],
175
+ ['POST /users/:id/reactivate', 401],
176
+ ['POST /users/:id/lock', 401],
177
+ ['POST /users/:id/unlock', 401],
178
+ ['POST /users/:id/transfer-content', 401],
179
+ ['GET /invites', 401],
180
+ ['POST /invites/:id/resend', 401],
181
+ ['POST /invites/:id/cancel', 401],
182
+ ['PATCH /invites/:id', 401],
183
+ ['GET /access-review', 401],
184
+ ['POST /access-review/:id/dismiss', 401],
185
+ ['GET /forms', 401],
186
+ ['GET /forms/:id/submissions', 401],
187
+ ['OPTIONS /public/forms/:slug', 204],
188
+ ['GET /public/forms/:slug', 404],
189
+ ['OPTIONS /public/forms/:slug/submit', 204],
190
+ ['POST /public/forms/:slug/submit', 404],
191
+ ['POST /forms/:id/submit', 404],
192
+ ['GET /forms/stats', 401],
193
+ ['GET /forms/sidebar-counts', 401],
194
+ ['GET /forms/entries/counts', 401],
195
+ ['GET /forms/entries/export', 401],
196
+ ['GET /forms/entries/:entryId', 401],
197
+ ['PATCH /forms/entries/:entryId', 401],
198
+ ['DELETE /forms/entries/:entryId', 401],
199
+ ['POST /forms/entries/bulk', 401],
200
+ ['GET /forms/entries', 401],
201
+ ['POST /forms', 401],
202
+ ['GET /forms/:id', 401],
203
+ ['PATCH /forms/:id', 401],
204
+ ['DELETE /forms/:id', 401],
205
+ ['POST /forms/:id/duplicate', 401],
206
+ ['GET /forms/:id/schema', 401],
207
+ ['PUT /forms/:id/schema', 401],
208
+ ['GET /forms/:id/notifications', 401],
209
+ ['PUT /forms/:id/notifications', 401],
210
+ ['PUT /forms/:id/notify', 401],
211
+ ['GET /forms/:id/embed', 401],
212
+ ['PUT /forms/:id/embed', 401],
213
+ ['GET /forms/:id/webhooks', 401],
214
+ ['POST /forms/:id/webhooks', 401],
215
+ ['PATCH /forms/:id/webhooks/:webhookId', 401],
216
+ ['DELETE /forms/:id/webhooks/:webhookId', 401],
217
+ ['POST /forms/:id/webhooks/:webhookId/test', 401],
218
+ ['POST /forms/:id/notifications/test', 401],
219
+ ['GET /redirects', 401],
220
+ ['POST /redirects', 401],
221
+ ['DELETE /redirects/:id', 401],
222
+ ['GET /seo/redirects', 401],
223
+ ['GET /seo/redirects/overview', 401],
224
+ ['GET /seo/redirects/chains', 401],
225
+ ['POST /seo/redirects/flatten', 401],
226
+ ['GET /seo/redirects/suggestions', 401],
227
+ ['POST /seo/redirects/suggest', 401],
228
+ ['POST /seo/redirects/suggestions/:id/accept', 401],
229
+ ['POST /seo/redirects/suggestions/:id/dismiss', 401],
230
+ ['GET /seo/redirects/export', 401],
231
+ ['POST /seo/redirects/import', 401],
232
+ ['POST /seo/redirects', 401],
233
+ ['GET /seo/redirects/:id', 401],
234
+ ['PUT /seo/redirects/:id', 401],
235
+ ['DELETE /seo/redirects/:id', 401],
236
+ ['GET /redirects/resolve', 200],
237
+ ['GET /redirects/public', 200],
238
+ ['POST /redirects/record-hit', 200],
239
+ ['POST /redirects/record-404', 200],
240
+ ['GET /seo/pages', 401],
241
+ ['GET /seo/link-health', 401],
242
+ ['POST /seo/scan', 401],
243
+ ['POST /seo/audit', 401],
244
+ ['GET /seo/audits', 401],
245
+ ['GET /seo/audits/:id', 401],
246
+ ['GET /seo/issues', 401],
247
+ ['GET /seo/issues/:id', 401],
248
+ ['POST /seo/issues/:id/resolve', 401],
249
+ ['POST /seo/issues/:id/ignore', 401],
250
+ ['POST /seo/issues/:id/reopen', 401],
251
+ ['GET /seo/overview', 401],
252
+ ['GET /seo/search-performance', 401],
253
+ ['GET /seo/content', 401],
254
+ ['GET /seo/content/:entityType/:entityId', 401],
255
+ ['PUT /seo/content/:entityType/:entityId', 401],
256
+ ['GET /seo/analysis/:documentId', 401],
257
+ ['GET /seo/readability/:documentId', 401],
258
+ ['GET /seo/internal-links/:documentId', 401],
259
+ ['GET /llms.txt', 200],
260
+ ['GET /sitemap.xml', 200],
261
+ ['GET /sitemaps/:slug', 404],
262
+ ['GET /robots.txt', 200],
263
+ ['GET /og.png', 200],
264
+ ['GET /seo/schema/:documentId', 401],
265
+ ['GET /seo/meta/:documentId', 401],
266
+ ['GET /seo/summary', 401],
267
+ ['GET /seo/config', 401],
268
+ ['PUT /seo/config', 401],
269
+ ['GET /seo/index-status', 401],
270
+ ['GET /seo/sitemap/status', 401],
271
+ ['POST /seo/sitemap/regenerate', 401],
272
+ ['GET /seo/crawl-settings', 401],
273
+ ['PUT /seo/crawl-settings', 401],
274
+ ['GET /seo/robots', 401],
275
+ ['PUT /seo/robots', 401],
276
+ ['GET /resolve', 400],
277
+ ['GET /folders', 401],
278
+ ['POST /folders', 401],
279
+ ['PUT /folders/:id', 401],
280
+ ['DELETE /folders/:id', 401],
281
+ ['PUT /documents/:id/folder', 401],
282
+ ['PUT /media/:id/folder', 401],
283
+ ['POST /preview/token', 401],
284
+ ['GET /preview/:collection/:id', 401],
285
+ ['GET /preview/stream', 401],
286
+ ['POST /documents/:documentId/comments', 401],
287
+ ['GET /documents/:documentId/comments', 401],
288
+ ['PATCH /comments/:id', 401],
289
+ ['POST /comments/:id/resolve', 401],
290
+ ['POST /comments/:id/reopen', 401],
291
+ ['DELETE /comments/:id', 401],
292
+ ['GET /notifications', 401],
293
+ ['GET /notifications/unread-count', 401],
294
+ ['POST /notifications/:id/read', 401],
295
+ ['POST /notifications/read-all', 401],
296
+ ['GET /notifications/stream', 401],
297
+ ['POST /collections/:slug/:id/workflow', 401],
298
+ ['GET /collections/:slug/:id/workflow', 401],
299
+ ['GET /collections/:slug/:id/versions', 401],
300
+ ['POST /collections/:slug/:id/versions/:versionId/restore', 401],
301
+ ['POST /collections/:slug/:id/schedule', 401],
302
+ ['DELETE /collections/:slug/:id/schedule', 401],
303
+ ['POST /scheduling/run', 401],
304
+ ['GET /cron/publish', 401],
305
+ ['POST /cron/publish', 401],
306
+ ['GET /cron/cleanup', 401],
307
+ ['POST /cron/cleanup', 401],
308
+ ['GET /cron/seo-scan', 401],
309
+ ['POST /cron/seo-scan', 401],
310
+ ['GET /cron/content-health', 401],
311
+ ['POST /cron/content-health', 401],
312
+ ['GET /scheduling/calendar', 401],
313
+ ['GET /public/globals/:slug', 404],
314
+ ['GET /public/navigations/:slug', 404],
315
+ ['GET /public/brand', 200],
316
+ ['GET /appearance', 401],
317
+ ['GET /security', 401],
318
+ ['GET /ai/status', 401],
319
+ ['GET /ai/settings', 401],
320
+ ['PUT /ai/settings', 401],
321
+ ['POST /ai/providers', 401],
322
+ ['PUT /ai/providers/:id', 401],
323
+ ['DELETE /ai/providers/:id', 401],
324
+ ['POST /ai/providers/:id/test', 401],
325
+ ['POST /ai/providers/:id/sync-models', 401],
326
+ ['GET /ai/models', 401],
327
+ ['GET /ai/usage/summary', 401],
328
+ ['PUT /security', 401],
329
+ ['POST /security/sessions/revoke-all', 401],
330
+ ['GET /globals/:slug', 401],
331
+ ['PUT /globals/:slug', 401],
332
+ ['GET /webhooks', 401],
333
+ ['POST /webhooks', 401],
334
+ ['PUT /webhooks/:id', 401],
335
+ ['DELETE /webhooks/:id', 401],
336
+ ['GET /webhooks/:id/deliveries', 401],
337
+ ['POST /webhooks/retry', 401],
338
+ ['GET /script-tags/resolve', 200],
339
+ ['GET /script-tags', 401],
340
+ ['POST /script-tags', 401],
341
+ ['PUT /script-tags/:id', 401],
342
+ ['DELETE /script-tags/:id', 401],
343
+ ['GET /presence/:documentId', 401],
344
+ ['POST /presence/:documentId/heartbeat', 401],
345
+ ['GET /page-templates', 401],
346
+ ['GET /page-templates/:id', 401],
347
+ ['POST /page-templates', 401],
348
+ ['PUT /page-templates/:id', 401],
349
+ ['DELETE /page-templates/:id', 401],
350
+ ['POST /page-templates/seed', 401],
351
+ ['GET /saved-sections', 401],
352
+ ['GET /saved-sections/:id', 401],
353
+ ['POST /saved-sections', 401],
354
+ ['PUT /saved-sections/:id', 401],
355
+ ['DELETE /saved-sections/:id', 401],
356
+ ['POST /page-builder/generate', 401],
357
+ ['POST /page-builder/generate-block', 401],
358
+ ['POST /page-builder/create', 401],
359
+ ['POST /collections/:slug/ai-create', 401],
360
+ ['POST /page-builder/audit-a11y', 401],
361
+ ['POST /page-builder/fix-a11y', 401],
362
+ ['POST /ai/audit-document', 401],
363
+ ['POST /ai/coauthor', 401],
364
+ ['POST /ai/suggest-internal-links', 401],
365
+ ['POST /ai/media-metadata', 401],
366
+ ['POST /ai/seo/generate-field', 401],
367
+ ['POST /ai/seo/explain-issue', 401],
368
+ ['POST /ai/seo/generate-schema', 401],
369
+ ['POST /ai/seo/summarize', 401],
370
+ ];
371
+ /**
372
+ * Routes that deliberately answer anonymous requests with 2xx, and why.
373
+ * Everything else that is not 401 is anonymous-reachable but rejects the
374
+ * sweep's dummy input (400/404), which the table above already pins down.
375
+ */
376
+ const ANONYMOUS_SURFACE = [
377
+ ['GET /auth/csrf', 'issues the CSRF token cookie that login itself requires'],
378
+ ['GET /openapi.json', 'public API discovery — schema-shape metadata only'],
379
+ ['GET /collections', 'public discovery for agents/MCP, same data as OpenAPI'],
380
+ ['GET /docs', 'public HTML API docs'],
381
+ ['GET /captcha/config', 'public form embeds need the captcha site key'],
382
+ ['GET /setup/status', 'setup wizard probe; reveals only whether setup ran'],
383
+ ['GET /health', 'health probe for uptime monitors'],
384
+ ['OPTIONS /public/forms/:slug', 'CORS preflight for cross-origin form embeds'],
385
+ ['OPTIONS /public/forms/:slug/submit', 'CORS preflight for cross-origin form embeds'],
386
+ ['GET /redirects/resolve', 'public-site middleware resolves redirects per-request'],
387
+ ['GET /redirects/public', 'public-site middleware bulk-loads the redirect map'],
388
+ ['POST /redirects/record-hit', 'public-site middleware logs redirect hits'],
389
+ ['POST /redirects/record-404', 'public-site frontend logs broken links'],
390
+ ['GET /llms.txt', 'public SEO artifact'],
391
+ ['GET /sitemap.xml', 'public SEO artifact'],
392
+ ['GET /robots.txt', 'public SEO artifact'],
393
+ ['GET /og.png', 'public Open Graph image'],
394
+ ['GET /public/brand', 'public site brand settings (colors, logo)'],
395
+ ['GET /script-tags/resolve', 'public site resolves enabled script tags'],
396
+ ];
397
+ // ─── Tests ────────────────────────────────────────────────────────────
398
+ describe('route inventory contract', () => {
399
+ it('registers exactly the expected routes, in registration order', () => {
400
+ const actual = router.routes.map((r) => `${r.method} ${r.path}`);
401
+ expect(actual).toEqual(ROUTE_CONTRACT.map(([route]) => route));
402
+ });
403
+ it('the contract table has no duplicate routes', () => {
404
+ const routes = ROUTE_CONTRACT.map(([route]) => route);
405
+ expect(new Set(routes).size).toBe(routes.length);
406
+ });
407
+ it('every 2xx route is documented in ANONYMOUS_SURFACE (and vice versa)', () => {
408
+ const documented = ANONYMOUS_SURFACE.map(([route]) => route).sort();
409
+ const anonymous2xx = ROUTE_CONTRACT.filter(([, status]) => status >= 200 && status < 300)
410
+ .map(([route]) => route)
411
+ .sort();
412
+ expect(anonymous2xx).toEqual(documented);
413
+ });
414
+ });
415
+ describe('unauthenticated status contract', () => {
416
+ it.each(ROUTE_CONTRACT.map(([route, status]) => ({ route, status })))('$route -> $status', async ({ route, status }) => {
417
+ const [method, pattern] = route.split(' ');
418
+ const res = await anonymousRequest(method, pattern);
419
+ expect(res.status).toBe(status);
420
+ // 5xx on anonymous traffic is never acceptable, regardless of the table.
421
+ expect(res.status, `${route} returned a server error`).toBeLessThan(500);
422
+ // Error envelope contract: JSON error responses carry { error: string }.
423
+ const contentType = res.headers.get('content-type') ?? '';
424
+ if (res.status >= 400 && contentType.includes('application/json')) {
425
+ const body = (await res.json());
426
+ expect(typeof body.error, `${route} error body missing "error" key`).toBe('string');
427
+ }
428
+ });
429
+ });
430
+ //# sourceMappingURL=route-contracts.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"route-contracts.test.js","sourceRoot":"","sources":["../../../src/__tests__/api/route-contracts.test.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"media.d.ts","sourceRoot":"","sources":["../../../src/api/routes/media.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAA;AAuB7C,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAmiB3D"}
1
+ {"version":3,"file":"media.d.ts","sourceRoot":"","sources":["../../../src/api/routes/media.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAA;AAuB7C,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAyjB3D"}