@reverso/api 0.1.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 (74) hide show
  1. package/README.md +47 -0
  2. package/dist/index.d.ts +41 -0
  3. package/dist/index.d.ts.map +1 -0
  4. package/dist/index.js +56 -0
  5. package/dist/index.js.map +1 -0
  6. package/dist/plugins/auth.d.ts +72 -0
  7. package/dist/plugins/auth.d.ts.map +1 -0
  8. package/dist/plugins/auth.js +173 -0
  9. package/dist/plugins/auth.js.map +1 -0
  10. package/dist/plugins/database.d.ts +19 -0
  11. package/dist/plugins/database.d.ts.map +1 -0
  12. package/dist/plugins/database.js +23 -0
  13. package/dist/plugins/database.js.map +1 -0
  14. package/dist/plugins/index.d.ts +5 -0
  15. package/dist/plugins/index.d.ts.map +1 -0
  16. package/dist/plugins/index.js +5 -0
  17. package/dist/plugins/index.js.map +1 -0
  18. package/dist/routes/auth.d.ts +6 -0
  19. package/dist/routes/auth.d.ts.map +1 -0
  20. package/dist/routes/auth.js +258 -0
  21. package/dist/routes/auth.js.map +1 -0
  22. package/dist/routes/content.d.ts +8 -0
  23. package/dist/routes/content.d.ts.map +1 -0
  24. package/dist/routes/content.js +339 -0
  25. package/dist/routes/content.js.map +1 -0
  26. package/dist/routes/forms.d.ts +8 -0
  27. package/dist/routes/forms.d.ts.map +1 -0
  28. package/dist/routes/forms.js +953 -0
  29. package/dist/routes/forms.js.map +1 -0
  30. package/dist/routes/index.d.ts +19 -0
  31. package/dist/routes/index.d.ts.map +1 -0
  32. package/dist/routes/index.js +31 -0
  33. package/dist/routes/index.js.map +1 -0
  34. package/dist/routes/media.d.ts +8 -0
  35. package/dist/routes/media.d.ts.map +1 -0
  36. package/dist/routes/media.js +400 -0
  37. package/dist/routes/media.js.map +1 -0
  38. package/dist/routes/pages.d.ts +8 -0
  39. package/dist/routes/pages.d.ts.map +1 -0
  40. package/dist/routes/pages.js +220 -0
  41. package/dist/routes/pages.js.map +1 -0
  42. package/dist/routes/redirects.d.ts +8 -0
  43. package/dist/routes/redirects.d.ts.map +1 -0
  44. package/dist/routes/redirects.js +462 -0
  45. package/dist/routes/redirects.js.map +1 -0
  46. package/dist/routes/schema.d.ts +8 -0
  47. package/dist/routes/schema.d.ts.map +1 -0
  48. package/dist/routes/schema.js +151 -0
  49. package/dist/routes/schema.js.map +1 -0
  50. package/dist/routes/sitemap.d.ts +8 -0
  51. package/dist/routes/sitemap.d.ts.map +1 -0
  52. package/dist/routes/sitemap.js +144 -0
  53. package/dist/routes/sitemap.js.map +1 -0
  54. package/dist/server.d.ts +47 -0
  55. package/dist/server.d.ts.map +1 -0
  56. package/dist/server.js +218 -0
  57. package/dist/server.js.map +1 -0
  58. package/dist/types.d.ts +91 -0
  59. package/dist/types.d.ts.map +1 -0
  60. package/dist/types.js +5 -0
  61. package/dist/types.js.map +1 -0
  62. package/dist/utils/index.d.ts +5 -0
  63. package/dist/utils/index.d.ts.map +1 -0
  64. package/dist/utils/index.js +5 -0
  65. package/dist/utils/index.js.map +1 -0
  66. package/dist/utils/security.d.ts +32 -0
  67. package/dist/utils/security.d.ts.map +1 -0
  68. package/dist/utils/security.js +154 -0
  69. package/dist/utils/security.js.map +1 -0
  70. package/dist/validation.d.ts +402 -0
  71. package/dist/validation.d.ts.map +1 -0
  72. package/dist/validation.js +308 -0
  73. package/dist/validation.js.map +1 -0
  74. package/package.json +76 -0
@@ -0,0 +1,462 @@
1
+ /**
2
+ * Redirects routes.
3
+ * Handles redirect CRUD operations for SEO.
4
+ */
5
+ import { bulkCreateRedirects, createRedirect, deleteRedirect, disableRedirect, enableRedirect, getEnabledRedirects, getRedirectByFromPath, getRedirectById, getRedirectStats, getRedirects, recordRedirectHit, updateRedirect, } from '@reverso/db';
6
+ import { idParamSchema, paginationSchema, redirectCreateSchema, redirectUpdateSchema } from '../validation.js';
7
+ const redirectsRoutes = async (fastify) => {
8
+ /**
9
+ * GET /redirects
10
+ * List all redirects.
11
+ */
12
+ fastify.get('/redirects', async (request, reply) => {
13
+ try {
14
+ const queryResult = paginationSchema.safeParse(request.query);
15
+ const { limit, offset } = queryResult.success ? queryResult.data : {};
16
+ const isEnabled = request.query.enabled === 'true' ? true : request.query.enabled === 'false' ? false : undefined;
17
+ const db = request.db;
18
+ const redirects = await getRedirects(db, { isEnabled, limit, offset });
19
+ const stats = await getRedirectStats(db);
20
+ return {
21
+ success: true,
22
+ data: redirects.map((r) => ({
23
+ id: r.id,
24
+ fromPath: r.fromPath,
25
+ toPath: r.toPath,
26
+ statusCode: r.statusCode,
27
+ isEnabled: r.isEnabled,
28
+ hitCount: r.hitCount,
29
+ lastHitAt: r.lastHitAt,
30
+ createdAt: r.createdAt,
31
+ updatedAt: r.updatedAt,
32
+ })),
33
+ meta: {
34
+ total: stats.total,
35
+ enabled: stats.enabled,
36
+ disabled: stats.disabled,
37
+ totalHits: stats.totalHits,
38
+ },
39
+ };
40
+ }
41
+ catch (error) {
42
+ fastify.log.error(error, 'Failed to list redirects');
43
+ return reply.status(500).send({
44
+ success: false,
45
+ error: 'Internal error',
46
+ message: 'Failed to list redirects',
47
+ });
48
+ }
49
+ });
50
+ /**
51
+ * POST /redirects
52
+ * Create a new redirect.
53
+ */
54
+ fastify.post('/redirects', async (request, reply) => {
55
+ try {
56
+ const bodyResult = redirectCreateSchema.safeParse(request.body);
57
+ if (!bodyResult.success) {
58
+ return reply.status(400).send({
59
+ success: false,
60
+ error: 'Validation error',
61
+ message: bodyResult.error.issues[0]?.message ?? 'Invalid request body',
62
+ });
63
+ }
64
+ const db = request.db;
65
+ const input = bodyResult.data;
66
+ // Check if fromPath already exists
67
+ const existing = await getRedirectByFromPath(db, input.fromPath);
68
+ if (existing) {
69
+ return reply.status(400).send({
70
+ success: false,
71
+ error: 'Validation error',
72
+ message: `Redirect from "${input.fromPath}" already exists`,
73
+ });
74
+ }
75
+ const redirect = await createRedirect(db, input);
76
+ return {
77
+ success: true,
78
+ data: {
79
+ id: redirect.id,
80
+ fromPath: redirect.fromPath,
81
+ toPath: redirect.toPath,
82
+ statusCode: redirect.statusCode,
83
+ isEnabled: redirect.isEnabled,
84
+ createdAt: redirect.createdAt,
85
+ },
86
+ };
87
+ }
88
+ catch (error) {
89
+ fastify.log.error(error, 'Failed to create redirect');
90
+ return reply.status(500).send({
91
+ success: false,
92
+ error: 'Internal error',
93
+ message: 'Failed to create redirect',
94
+ });
95
+ }
96
+ });
97
+ /**
98
+ * GET /redirects/:id
99
+ * Get a redirect by ID.
100
+ */
101
+ fastify.get('/redirects/:id', async (request, reply) => {
102
+ try {
103
+ const paramResult = idParamSchema.safeParse(request.params);
104
+ if (!paramResult.success) {
105
+ return reply.status(400).send({
106
+ success: false,
107
+ error: 'Validation error',
108
+ message: 'Invalid ID format',
109
+ });
110
+ }
111
+ const db = request.db;
112
+ const { id } = paramResult.data;
113
+ const redirect = await getRedirectById(db, id);
114
+ if (!redirect) {
115
+ return reply.status(404).send({
116
+ success: false,
117
+ error: 'Not found',
118
+ message: `Redirect with ID "${id}" not found`,
119
+ });
120
+ }
121
+ return {
122
+ success: true,
123
+ data: {
124
+ id: redirect.id,
125
+ fromPath: redirect.fromPath,
126
+ toPath: redirect.toPath,
127
+ statusCode: redirect.statusCode,
128
+ isEnabled: redirect.isEnabled,
129
+ hitCount: redirect.hitCount,
130
+ lastHitAt: redirect.lastHitAt,
131
+ createdAt: redirect.createdAt,
132
+ updatedAt: redirect.updatedAt,
133
+ },
134
+ };
135
+ }
136
+ catch (error) {
137
+ fastify.log.error(error, 'Failed to get redirect');
138
+ return reply.status(500).send({
139
+ success: false,
140
+ error: 'Internal error',
141
+ message: 'Failed to get redirect',
142
+ });
143
+ }
144
+ });
145
+ /**
146
+ * PUT /redirects/:id
147
+ * Update a redirect.
148
+ */
149
+ fastify.put('/redirects/:id', async (request, reply) => {
150
+ try {
151
+ const paramResult = idParamSchema.safeParse(request.params);
152
+ if (!paramResult.success) {
153
+ return reply.status(400).send({
154
+ success: false,
155
+ error: 'Validation error',
156
+ message: 'Invalid ID format',
157
+ });
158
+ }
159
+ const bodyResult = redirectUpdateSchema.safeParse(request.body);
160
+ if (!bodyResult.success) {
161
+ return reply.status(400).send({
162
+ success: false,
163
+ error: 'Validation error',
164
+ message: bodyResult.error.issues[0]?.message ?? 'Invalid request body',
165
+ });
166
+ }
167
+ const db = request.db;
168
+ const { id } = paramResult.data;
169
+ // If fromPath is being changed, check for duplicates
170
+ if (bodyResult.data.fromPath) {
171
+ const existing = await getRedirectByFromPath(db, bodyResult.data.fromPath);
172
+ if (existing && existing.id !== id) {
173
+ return reply.status(400).send({
174
+ success: false,
175
+ error: 'Validation error',
176
+ message: `Redirect from "${bodyResult.data.fromPath}" already exists`,
177
+ });
178
+ }
179
+ }
180
+ const redirect = await updateRedirect(db, id, bodyResult.data);
181
+ if (!redirect) {
182
+ return reply.status(404).send({
183
+ success: false,
184
+ error: 'Not found',
185
+ message: `Redirect with ID "${id}" not found`,
186
+ });
187
+ }
188
+ return {
189
+ success: true,
190
+ data: {
191
+ id: redirect.id,
192
+ fromPath: redirect.fromPath,
193
+ toPath: redirect.toPath,
194
+ statusCode: redirect.statusCode,
195
+ isEnabled: redirect.isEnabled,
196
+ updatedAt: redirect.updatedAt,
197
+ },
198
+ };
199
+ }
200
+ catch (error) {
201
+ fastify.log.error(error, 'Failed to update redirect');
202
+ return reply.status(500).send({
203
+ success: false,
204
+ error: 'Internal error',
205
+ message: 'Failed to update redirect',
206
+ });
207
+ }
208
+ });
209
+ /**
210
+ * DELETE /redirects/:id
211
+ * Delete a redirect.
212
+ */
213
+ fastify.delete('/redirects/:id', async (request, reply) => {
214
+ try {
215
+ const paramResult = idParamSchema.safeParse(request.params);
216
+ if (!paramResult.success) {
217
+ return reply.status(400).send({
218
+ success: false,
219
+ error: 'Validation error',
220
+ message: 'Invalid ID format',
221
+ });
222
+ }
223
+ const db = request.db;
224
+ const { id } = paramResult.data;
225
+ const redirect = await deleteRedirect(db, id);
226
+ if (!redirect) {
227
+ return reply.status(404).send({
228
+ success: false,
229
+ error: 'Not found',
230
+ message: `Redirect with ID "${id}" not found`,
231
+ });
232
+ }
233
+ return {
234
+ success: true,
235
+ data: { id: redirect.id, deleted: true },
236
+ };
237
+ }
238
+ catch (error) {
239
+ fastify.log.error(error, 'Failed to delete redirect');
240
+ return reply.status(500).send({
241
+ success: false,
242
+ error: 'Internal error',
243
+ message: 'Failed to delete redirect',
244
+ });
245
+ }
246
+ });
247
+ /**
248
+ * PUT /redirects/:id/enable
249
+ * Enable a redirect.
250
+ */
251
+ fastify.put('/redirects/:id/enable', async (request, reply) => {
252
+ try {
253
+ const paramResult = idParamSchema.safeParse(request.params);
254
+ if (!paramResult.success) {
255
+ return reply.status(400).send({
256
+ success: false,
257
+ error: 'Validation error',
258
+ message: 'Invalid ID format',
259
+ });
260
+ }
261
+ const db = request.db;
262
+ const { id } = paramResult.data;
263
+ const redirect = await enableRedirect(db, id);
264
+ if (!redirect) {
265
+ return reply.status(404).send({
266
+ success: false,
267
+ error: 'Not found',
268
+ message: `Redirect with ID "${id}" not found`,
269
+ });
270
+ }
271
+ return {
272
+ success: true,
273
+ data: {
274
+ id: redirect.id,
275
+ isEnabled: redirect.isEnabled,
276
+ },
277
+ };
278
+ }
279
+ catch (error) {
280
+ fastify.log.error(error, 'Failed to enable redirect');
281
+ return reply.status(500).send({
282
+ success: false,
283
+ error: 'Internal error',
284
+ message: 'Failed to enable redirect',
285
+ });
286
+ }
287
+ });
288
+ /**
289
+ * PUT /redirects/:id/disable
290
+ * Disable a redirect.
291
+ */
292
+ fastify.put('/redirects/:id/disable', async (request, reply) => {
293
+ try {
294
+ const paramResult = idParamSchema.safeParse(request.params);
295
+ if (!paramResult.success) {
296
+ return reply.status(400).send({
297
+ success: false,
298
+ error: 'Validation error',
299
+ message: 'Invalid ID format',
300
+ });
301
+ }
302
+ const db = request.db;
303
+ const { id } = paramResult.data;
304
+ const redirect = await disableRedirect(db, id);
305
+ if (!redirect) {
306
+ return reply.status(404).send({
307
+ success: false,
308
+ error: 'Not found',
309
+ message: `Redirect with ID "${id}" not found`,
310
+ });
311
+ }
312
+ return {
313
+ success: true,
314
+ data: {
315
+ id: redirect.id,
316
+ isEnabled: redirect.isEnabled,
317
+ },
318
+ };
319
+ }
320
+ catch (error) {
321
+ fastify.log.error(error, 'Failed to disable redirect');
322
+ return reply.status(500).send({
323
+ success: false,
324
+ error: 'Internal error',
325
+ message: 'Failed to disable redirect',
326
+ });
327
+ }
328
+ });
329
+ /**
330
+ * POST /redirects/bulk-import
331
+ * Bulk import redirects from CSV.
332
+ */
333
+ fastify.post('/redirects/bulk-import', async (request, reply) => {
334
+ try {
335
+ const { redirects: inputs } = request.body;
336
+ if (!Array.isArray(inputs) || inputs.length === 0) {
337
+ return reply.status(400).send({
338
+ success: false,
339
+ error: 'Validation error',
340
+ message: 'redirects must be a non-empty array',
341
+ });
342
+ }
343
+ // Validate each redirect
344
+ const validInputs = [];
345
+ for (const input of inputs) {
346
+ if (!input.fromPath || !input.toPath)
347
+ continue;
348
+ if (input.statusCode && ![301, 302, 307, 308].includes(input.statusCode))
349
+ continue;
350
+ validInputs.push({
351
+ fromPath: input.fromPath,
352
+ toPath: input.toPath,
353
+ statusCode: input.statusCode,
354
+ });
355
+ }
356
+ const db = request.db;
357
+ const result = await bulkCreateRedirects(db, validInputs);
358
+ return {
359
+ success: true,
360
+ data: {
361
+ created: result.created,
362
+ skipped: result.skipped,
363
+ errors: result.errors,
364
+ },
365
+ };
366
+ }
367
+ catch (error) {
368
+ fastify.log.error(error, 'Failed to bulk import redirects');
369
+ return reply.status(500).send({
370
+ success: false,
371
+ error: 'Internal error',
372
+ message: 'Failed to bulk import redirects',
373
+ });
374
+ }
375
+ });
376
+ /**
377
+ * GET /redirects/export
378
+ * Export redirects as CSV.
379
+ */
380
+ fastify.get('/redirects/export', async (request, reply) => {
381
+ try {
382
+ const db = request.db;
383
+ const redirects = await getRedirects(db, { limit: 10000 });
384
+ // Build CSV
385
+ const headers = ['From Path', 'To Path', 'Status Code', 'Enabled', 'Hit Count', 'Last Hit', 'Created At'];
386
+ const rows = redirects.map((r) => [
387
+ r.fromPath,
388
+ r.toPath,
389
+ String(r.statusCode),
390
+ r.isEnabled ? 'true' : 'false',
391
+ String(r.hitCount ?? 0),
392
+ r.lastHitAt?.toISOString() ?? '',
393
+ r.createdAt?.toISOString() ?? '',
394
+ ]);
395
+ const csv = [headers, ...rows].map((row) => row.map(escapeCSV).join(',')).join('\n');
396
+ reply.header('Content-Type', 'text/csv');
397
+ reply.header('Content-Disposition', 'attachment; filename="redirects.csv"');
398
+ return csv;
399
+ }
400
+ catch (error) {
401
+ fastify.log.error(error, 'Failed to export redirects');
402
+ return reply.status(500).send({
403
+ success: false,
404
+ error: 'Internal error',
405
+ message: 'Failed to export redirects',
406
+ });
407
+ }
408
+ });
409
+ /**
410
+ * GET /redirect
411
+ * Resolve a redirect (for middleware use).
412
+ */
413
+ fastify.get('/redirect', async (request, reply) => {
414
+ try {
415
+ const { path } = request.query;
416
+ if (!path) {
417
+ return reply.status(400).send({
418
+ success: false,
419
+ error: 'Validation error',
420
+ message: 'path query parameter is required',
421
+ });
422
+ }
423
+ const db = request.db;
424
+ const redirect = await getRedirectByFromPath(db, path);
425
+ if (!redirect || !redirect.isEnabled) {
426
+ return reply.status(404).send({
427
+ success: false,
428
+ error: 'Not found',
429
+ message: 'No redirect found for this path',
430
+ });
431
+ }
432
+ // Record the hit
433
+ await recordRedirectHit(db, redirect.id);
434
+ return {
435
+ success: true,
436
+ data: {
437
+ toPath: redirect.toPath,
438
+ statusCode: redirect.statusCode,
439
+ },
440
+ };
441
+ }
442
+ catch (error) {
443
+ fastify.log.error(error, 'Failed to resolve redirect');
444
+ return reply.status(500).send({
445
+ success: false,
446
+ error: 'Internal error',
447
+ message: 'Failed to resolve redirect',
448
+ });
449
+ }
450
+ });
451
+ };
452
+ /**
453
+ * Escape a value for CSV.
454
+ */
455
+ function escapeCSV(value) {
456
+ if (value.includes(',') || value.includes('"') || value.includes('\n')) {
457
+ return `"${value.replace(/"/g, '""')}"`;
458
+ }
459
+ return value;
460
+ }
461
+ export default redirectsRoutes;
462
+ //# sourceMappingURL=redirects.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"redirects.js","sourceRoot":"","sources":["../../src/routes/redirects.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Schema routes.
3
+ * Handles schema retrieval and sync from scanner.
4
+ */
5
+ import type { FastifyPluginAsync } from 'fastify';
6
+ declare const schemaRoutes: FastifyPluginAsync;
7
+ export default schemaRoutes;
8
+ //# sourceMappingURL=schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/routes/schema.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAYH,OAAO,KAAK,EAAmB,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAInE,QAAA,MAAM,YAAY,EAAE,kBA2JnB,CAAC;AAEF,eAAe,YAAY,CAAC"}
@@ -0,0 +1,151 @@
1
+ /**
2
+ * Schema routes.
3
+ * Handles schema retrieval and sync from scanner.
4
+ */
5
+ import { getFieldsBySectionId, getPages, getSectionsByPageId, parseFieldConfig, parseRepeaterConfig, parseSourceFiles, syncSchema, } from '@reverso/db';
6
+ import { schemaSyncSchema } from '../validation.js';
7
+ const schemaRoutes = async (fastify) => {
8
+ /**
9
+ * GET /schema
10
+ * Get the current schema from the database.
11
+ */
12
+ fastify.get('/schema', async (request, reply) => {
13
+ try {
14
+ const db = request.db;
15
+ const pages = await getPages(db);
16
+ const schemaPages = [];
17
+ for (const page of pages) {
18
+ const sections = await getSectionsByPageId(db, page.id);
19
+ const schemaSections = [];
20
+ for (const section of sections) {
21
+ const fields = await getFieldsBySectionId(db, section.id);
22
+ const schemaFields = fields.map((field) => ({
23
+ path: field.path,
24
+ type: field.type,
25
+ label: field.label ?? undefined,
26
+ placeholder: field.placeholder ?? undefined,
27
+ required: field.required ?? undefined,
28
+ validation: field.validation ?? undefined,
29
+ options: field.options ?? undefined,
30
+ condition: field.condition ?? undefined,
31
+ file: field.sourceFile ?? '',
32
+ line: field.sourceLine ?? 0,
33
+ column: field.sourceColumn ?? 0,
34
+ defaultContent: field.defaultValue ?? undefined,
35
+ help: field.help ?? undefined,
36
+ ...parseFieldConfig(field),
37
+ }));
38
+ schemaSections.push({
39
+ slug: section.slug,
40
+ name: section.name,
41
+ fields: schemaFields,
42
+ isRepeater: section.isRepeater ?? false,
43
+ repeaterConfig: parseRepeaterConfig(section),
44
+ order: section.sortOrder ?? 0,
45
+ });
46
+ }
47
+ schemaPages.push({
48
+ slug: page.slug,
49
+ name: page.name,
50
+ sections: schemaSections,
51
+ fieldCount: page.fieldCount ?? 0,
52
+ sourceFiles: parseSourceFiles(page),
53
+ });
54
+ }
55
+ const schema = {
56
+ version: '1.0.0',
57
+ generatedAt: new Date().toISOString(),
58
+ pages: schemaPages,
59
+ pageCount: schemaPages.length,
60
+ totalFields: schemaPages.reduce((sum, p) => sum + p.fieldCount, 0),
61
+ meta: {
62
+ srcDir: 'src',
63
+ filesScanned: 0,
64
+ filesWithMarkers: 0,
65
+ scanDuration: 0,
66
+ },
67
+ };
68
+ return { success: true, data: schema };
69
+ }
70
+ catch (error) {
71
+ fastify.log.error(error, 'Failed to get schema');
72
+ return reply.status(500).send({
73
+ success: false,
74
+ error: 'Internal error',
75
+ message: 'Failed to get schema',
76
+ });
77
+ }
78
+ });
79
+ /**
80
+ * POST /schema/sync
81
+ * Sync schema from scanner output to database.
82
+ */
83
+ fastify.post('/schema/sync', async (request, reply) => {
84
+ try {
85
+ const bodyResult = schemaSyncSchema.safeParse(request.body);
86
+ if (!bodyResult.success) {
87
+ return reply.status(400).send({
88
+ success: false,
89
+ error: 'Validation error',
90
+ message: bodyResult.error.issues[0]?.message ?? 'Invalid schema format',
91
+ });
92
+ }
93
+ const { schema, deleteRemoved } = bodyResult.data;
94
+ const result = await syncSchema(request.db, schema, {
95
+ deleteRemoved,
96
+ verbose: false,
97
+ });
98
+ return {
99
+ success: true,
100
+ data: result,
101
+ message: `Synced ${schema.pages.length} pages in ${result.duration}ms`,
102
+ };
103
+ }
104
+ catch (error) {
105
+ fastify.log.error(error, 'Failed to sync schema');
106
+ return reply.status(500).send({
107
+ success: false,
108
+ error: 'Internal error',
109
+ message: 'Failed to sync schema',
110
+ });
111
+ }
112
+ });
113
+ /**
114
+ * GET /schema/stats
115
+ * Get schema statistics.
116
+ */
117
+ fastify.get('/schema/stats', async (request, reply) => {
118
+ try {
119
+ const db = request.db;
120
+ const pages = await getPages(db);
121
+ let totalSections = 0;
122
+ let totalFields = 0;
123
+ for (const page of pages) {
124
+ const sections = await getSectionsByPageId(db, page.id);
125
+ totalSections += sections.length;
126
+ for (const section of sections) {
127
+ const fields = await getFieldsBySectionId(db, section.id);
128
+ totalFields += fields.length;
129
+ }
130
+ }
131
+ return {
132
+ success: true,
133
+ data: {
134
+ pages: pages.length,
135
+ sections: totalSections,
136
+ fields: totalFields,
137
+ },
138
+ };
139
+ }
140
+ catch (error) {
141
+ fastify.log.error(error, 'Failed to get schema stats');
142
+ return reply.status(500).send({
143
+ success: false,
144
+ error: 'Internal error',
145
+ message: 'Failed to get schema stats',
146
+ });
147
+ }
148
+ });
149
+ };
150
+ export default schemaRoutes;
151
+ //# sourceMappingURL=schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/routes/schema.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Sitemap route.
3
+ * Generates dynamic XML sitemap for SEO.
4
+ */
5
+ import type { FastifyPluginAsync } from 'fastify';
6
+ declare const sitemapRoutes: FastifyPluginAsync;
7
+ export default sitemapRoutes;
8
+ //# sourceMappingURL=sitemap.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sitemap.d.ts","sourceRoot":"","sources":["../../src/routes/sitemap.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAmB,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAiEnE,QAAA,MAAM,aAAa,EAAE,kBAkGpB,CAAC;AAEF,eAAe,aAAa,CAAC"}