@prenta/core 7.6.2 → 7.6.5

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 (46) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/dist/actions.d.ts +12 -0
  3. package/dist/actions.d.ts.map +1 -1
  4. package/dist/actions.js +33 -0
  5. package/dist/actions.js.map +1 -1
  6. package/dist/api/handler-factory.d.ts.map +1 -1
  7. package/dist/api/handler-factory.js +2 -1
  8. package/dist/api/handler-factory.js.map +1 -1
  9. package/dist/api/openapi.d.ts.map +1 -1
  10. package/dist/api/openapi.js +36 -0
  11. package/dist/api/openapi.js.map +1 -1
  12. package/dist/api/routes/auth.d.ts.map +1 -1
  13. package/dist/api/routes/auth.js +24 -33
  14. package/dist/api/routes/auth.js.map +1 -1
  15. package/dist/api/routes/documents.d.ts.map +1 -1
  16. package/dist/api/routes/documents.js +60 -4
  17. package/dist/api/routes/documents.js.map +1 -1
  18. package/dist/api/routes/media.d.ts.map +1 -1
  19. package/dist/api/routes/media.js +16 -16
  20. package/dist/api/routes/media.js.map +1 -1
  21. package/dist/api/routes/meta.d.ts +5 -0
  22. package/dist/api/routes/meta.d.ts.map +1 -1
  23. package/dist/api/routes/meta.js +29 -16
  24. package/dist/api/routes/meta.js.map +1 -1
  25. package/dist/api/routes/security-center.d.ts.map +1 -1
  26. package/dist/api/routes/security-center.js +54 -1
  27. package/dist/api/routes/security-center.js.map +1 -1
  28. package/dist/api/routes/seo.d.ts.map +1 -1
  29. package/dist/api/routes/seo.js +18 -28
  30. package/dist/api/routes/seo.js.map +1 -1
  31. package/dist/api/routes/users.d.ts.map +1 -1
  32. package/dist/api/routes/users.js +18 -17
  33. package/dist/api/routes/users.js.map +1 -1
  34. package/dist/api/security-headers.d.ts +7 -5
  35. package/dist/api/security-headers.d.ts.map +1 -1
  36. package/dist/api/security-headers.js +25 -7
  37. package/dist/api/security-headers.js.map +1 -1
  38. package/dist/api/validate-body.d.ts +240 -0
  39. package/dist/api/validate-body.d.ts.map +1 -0
  40. package/dist/api/validate-body.js +168 -0
  41. package/dist/api/validate-body.js.map +1 -0
  42. package/dist/security/audit-export.d.ts +42 -0
  43. package/dist/security/audit-export.d.ts.map +1 -0
  44. package/dist/security/audit-export.js +93 -0
  45. package/dist/security/audit-export.js.map +1 -0
  46. package/package.json +1 -1
@@ -0,0 +1,168 @@
1
+ import { z } from 'zod';
2
+ import { json, readJsonBody } from './route-helpers.js';
3
+ /**
4
+ * Schema failure for a JSON object body. `error` stays a string so existing
5
+ * clients keep working; `details` is the field list.
6
+ * A single issue uses its message as `error` so routes that already returned
7
+ * one sentence (empty bulk-apply items, and so on) stay compatible.
8
+ */
9
+ function validationError(details) {
10
+ const first = details[0];
11
+ const error = details.length === 1 && first
12
+ ? first.message
13
+ : details
14
+ .map((detail) => (detail.path ? `${detail.path}: ${detail.message}` : detail.message))
15
+ .join('; ');
16
+ return json({ error: error || 'Invalid request body', details }, 400);
17
+ }
18
+ function zodDetails(error) {
19
+ return error.issues.map((issue) => ({
20
+ path: issue.path.map(String).join('.'),
21
+ message: issue.message,
22
+ }));
23
+ }
24
+ export function validateData(data, schema) {
25
+ const result = schema.safeParse(data);
26
+ if (!result.success) {
27
+ return { ok: false, error: validationError(zodDetails(result.error)) };
28
+ }
29
+ return { ok: true, data: result.data };
30
+ }
31
+ /** Invalid JSON or a non-object is 400, then `schema` is applied. */
32
+ export async function validateBody(request, schema) {
33
+ const parsed = await readJsonBody(request);
34
+ if (!parsed.ok)
35
+ return parsed;
36
+ return validateData(parsed.data, schema);
37
+ }
38
+ const requiredString = (message) => z.string({ required_error: message, invalid_type_error: message }).trim().min(1, message);
39
+ export const loginBodySchema = z.object({
40
+ email: requiredString('Email is required'),
41
+ password: z
42
+ .string({ required_error: 'Password is required', invalid_type_error: 'Password is required' })
43
+ .min(1, 'Password is required'),
44
+ captchaToken: z.string().optional(),
45
+ });
46
+ export const forgotPasswordBodySchema = z.object({
47
+ email: requiredString('Email is required'),
48
+ });
49
+ export const resetPasswordBodySchema = z.object({
50
+ token: requiredString('Token and new password are required'),
51
+ password: z
52
+ .string({
53
+ required_error: 'Token and new password are required',
54
+ invalid_type_error: 'Token and new password are required',
55
+ })
56
+ .min(8, 'Password must be at least 8 characters'),
57
+ });
58
+ export const totpVerifyBodySchema = z.object({
59
+ code: requiredString('Code is required'),
60
+ });
61
+ const mfaRequired = 'mfaPendingToken and code are required';
62
+ export const totpLoginBodySchema = z.object({
63
+ mfaPendingToken: requiredString(mfaRequired),
64
+ code: requiredString(mfaRequired),
65
+ });
66
+ export const inviteBodySchema = z.object({
67
+ email: requiredString('Email is required'),
68
+ role: z.string().optional(),
69
+ message: z.string().optional(),
70
+ expiresInDays: z.number().optional(),
71
+ });
72
+ export const rolePatchBodySchema = z.object({
73
+ role: z
74
+ .string({
75
+ required_error: 'Select a valid role.',
76
+ invalid_type_error: 'Select a valid role.',
77
+ })
78
+ .min(1, 'Select a valid role.'),
79
+ });
80
+ export const apiKeyCreateBodySchema = z.object({
81
+ name: z
82
+ .string({ required_error: 'name is required', invalid_type_error: 'name is required' })
83
+ .trim()
84
+ .min(1, 'name is required')
85
+ .max(100, 'name must be 100 characters or fewer'),
86
+ scopes: z.record(z.unknown()).nullish(),
87
+ ipRestrictions: z.array(z.string()).optional(),
88
+ expiresAt: z.string().nullable().optional(),
89
+ });
90
+ export const transferContentBodySchema = z.object({
91
+ toUserId: requiredString('A recipient (toUserId) is required.'),
92
+ });
93
+ /**
94
+ * Collection writes carry arbitrary field maps. Unknown keys must survive
95
+ * (passthrough) or a partial update would drop custom fields. `title` / `slug`
96
+ * are only type-checked when present. Validate after `flattenDocumentWriteBody`.
97
+ */
98
+ export const documentWriteBodySchema = z
99
+ .object({
100
+ title: z.string().nullable().optional(),
101
+ slug: z.string().nullable().optional(),
102
+ })
103
+ .passthrough();
104
+ export const mediaPresignBodySchema = z.object({
105
+ filename: requiredString('filename and contentType are required'),
106
+ contentType: requiredString('filename and contentType are required'),
107
+ });
108
+ export const mediaMetadataPatchSchema = z.object({
109
+ alt: z.string().optional(),
110
+ title: z.string().optional(),
111
+ filename: z.string().optional(),
112
+ caption: z.string().optional(),
113
+ description: z.string().optional(),
114
+ focusKeyword: z.string().optional(),
115
+ focalX: z.number().optional(),
116
+ focalY: z.number().optional(),
117
+ isDecorative: z.boolean().optional(),
118
+ });
119
+ export const mediaBulkUpdateBodySchema = z.object({
120
+ items: z
121
+ .array(z.unknown(), {
122
+ required_error: 'items must be a non-empty array',
123
+ invalid_type_error: 'items must be a non-empty array',
124
+ })
125
+ .min(1, 'items must be a non-empty array'),
126
+ });
127
+ const bulkDeleteConfirm = 'confirm: true is required for bulk media delete';
128
+ export const mediaBulkDeleteBodySchema = z.object({
129
+ ids: z
130
+ .array(z.unknown(), {
131
+ required_error: 'ids must be a non-empty array',
132
+ invalid_type_error: 'ids must be a non-empty array',
133
+ })
134
+ .min(1, 'ids must be a non-empty array'),
135
+ confirm: z
136
+ .boolean({
137
+ required_error: bulkDeleteConfirm,
138
+ invalid_type_error: bulkDeleteConfirm,
139
+ })
140
+ .refine((value) => value === true, { message: bulkDeleteConfirm }),
141
+ });
142
+ const linkApplyRequired = 'sourceEntityId, targetEntityId, anchorText, and fingerprint are required';
143
+ export const seoLinkApplyBodySchema = z.object({
144
+ sourceEntityId: requiredString(linkApplyRequired),
145
+ targetEntityId: requiredString(linkApplyRequired),
146
+ anchorText: requiredString(linkApplyRequired),
147
+ fingerprint: z
148
+ .string({ required_error: linkApplyRequired, invalid_type_error: linkApplyRequired })
149
+ .min(1, linkApplyRequired),
150
+ });
151
+ /** Shape only. FAQ length, uniqueness, and heading limits stay in the route. */
152
+ export const seoApplyFixBodySchema = z
153
+ .object({
154
+ fingerprint: z.string().optional(),
155
+ includeItems: z.array(z.number().int().nonnegative()).optional(),
156
+ headingOverride: z.string().optional(),
157
+ })
158
+ .passthrough();
159
+ export const seoBulkApplyBodySchema = z.object({
160
+ items: z
161
+ .array(z.object({
162
+ kind: z.enum(['issue-fix', 'redirect']),
163
+ id: z.string().min(1),
164
+ fingerprint: z.string().optional(),
165
+ }))
166
+ .min(1, 'items must be a non-empty array.'),
167
+ });
168
+ //# sourceMappingURL=validate-body.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate-body.js","sourceRoot":"","sources":["../../src/api/validate-body.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,42 @@
1
+ /** Hard cap so an export cannot load the whole audit table in one response. */
2
+ export declare const AUDIT_LOG_EXPORT_MAX = 10000;
3
+ export interface AuditLogExportRow {
4
+ id: string;
5
+ event: string;
6
+ userId: string | null;
7
+ ipAddress: string | null;
8
+ userAgent: string | null;
9
+ details: unknown;
10
+ timestamp: Date | string;
11
+ }
12
+ export interface AuditLogExportDb {
13
+ auditLog: {
14
+ findMany: (args: {
15
+ where?: Record<string, unknown>;
16
+ orderBy?: {
17
+ timestamp: 'desc';
18
+ };
19
+ take?: number;
20
+ }) => Promise<AuditLogExportRow[]>;
21
+ };
22
+ }
23
+ export type AuditLogRange = {
24
+ ok: true;
25
+ from?: Date;
26
+ to?: Date;
27
+ } | {
28
+ ok: false;
29
+ error: string;
30
+ };
31
+ /** `from` / `to` are optional ISO timestamps or `YYYY-MM-DD` (UTC, inclusive). */
32
+ export declare function parseAuditLogRange(fromRaw: string | null, toRaw: string | null): AuditLogRange;
33
+ export declare function loadAuditLogForExport(db: AuditLogExportDb, range: {
34
+ from?: Date;
35
+ to?: Date;
36
+ }, max?: number): Promise<{
37
+ rows: AuditLogExportRow[];
38
+ truncated: boolean;
39
+ }>;
40
+ export declare function auditLogToCsv(rows: AuditLogExportRow[]): string;
41
+ export declare function auditLogToJson(rows: AuditLogExportRow[], truncated: boolean): string;
42
+ //# sourceMappingURL=audit-export.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit-export.d.ts","sourceRoot":"","sources":["../../src/security/audit-export.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,eAAO,MAAM,oBAAoB,QAAS,CAAA;AAE1C,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;IACrB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,OAAO,EAAE,OAAO,CAAA;IAChB,SAAS,EAAE,IAAI,GAAG,MAAM,CAAA;CACzB;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE;QACR,QAAQ,EAAE,CAAC,IAAI,EAAE;YACf,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;YAC/B,OAAO,CAAC,EAAE;gBAAE,SAAS,EAAE,MAAM,CAAA;aAAE,CAAA;YAC/B,IAAI,CAAC,EAAE,MAAM,CAAA;SACd,KAAK,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAAA;KACnC,CAAA;CACF;AAED,MAAM,MAAM,aAAa,GAAG;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,IAAI,CAAC,EAAE,IAAI,CAAC;IAAC,EAAE,CAAC,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAA;AAgB/F,kFAAkF;AAClF,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,aAAa,CAiB9F;AASD,wBAAsB,qBAAqB,CACzC,EAAE,EAAE,gBAAgB,EACpB,KAAK,EAAE;IAAE,IAAI,CAAC,EAAE,IAAI,CAAC;IAAC,EAAE,CAAC,EAAE,IAAI,CAAA;CAAE,EACjC,GAAG,SAAuB,GACzB,OAAO,CAAC;IAAE,IAAI,EAAE,iBAAiB,EAAE,CAAC;IAAC,SAAS,EAAE,OAAO,CAAA;CAAE,CAAC,CAQ5D;AAcD,wBAAgB,aAAa,CAAC,IAAI,EAAE,iBAAiB,EAAE,GAAG,MAAM,CAe/D;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,iBAAiB,EAAE,EAAE,SAAS,EAAE,OAAO,GAAG,MAAM,CAcpF"}
@@ -0,0 +1,93 @@
1
+ /** Hard cap so an export cannot load the whole audit table in one response. */
2
+ export const AUDIT_LOG_EXPORT_MAX = 10_000;
3
+ const DATE_ONLY = /^\d{4}-\d{2}-\d{2}$/;
4
+ function parseBound(value, endOfDay) {
5
+ const trimmed = value.trim();
6
+ if (!trimmed)
7
+ return null;
8
+ if (DATE_ONLY.test(trimmed)) {
9
+ const iso = endOfDay ? `${trimmed}T23:59:59.999Z` : `${trimmed}T00:00:00.000Z`;
10
+ const date = new Date(iso);
11
+ return Number.isNaN(date.getTime()) ? null : date;
12
+ }
13
+ const date = new Date(trimmed);
14
+ return Number.isNaN(date.getTime()) ? null : date;
15
+ }
16
+ /** `from` / `to` are optional ISO timestamps or `YYYY-MM-DD` (UTC, inclusive). */
17
+ export function parseAuditLogRange(fromRaw, toRaw) {
18
+ let from;
19
+ let to;
20
+ if (fromRaw?.trim()) {
21
+ const parsed = parseBound(fromRaw, false);
22
+ if (!parsed)
23
+ return { ok: false, error: '"from" must be an ISO date or YYYY-MM-DD' };
24
+ from = parsed;
25
+ }
26
+ if (toRaw?.trim()) {
27
+ const parsed = parseBound(toRaw, DATE_ONLY.test(toRaw.trim()));
28
+ if (!parsed)
29
+ return { ok: false, error: '"to" must be an ISO date or YYYY-MM-DD' };
30
+ to = parsed;
31
+ }
32
+ if (from && to && from.getTime() > to.getTime()) {
33
+ return { ok: false, error: '"from" must be on or before "to"' };
34
+ }
35
+ return { ok: true, from, to };
36
+ }
37
+ function auditLogWhere(range) {
38
+ const timestamp = {};
39
+ if (range.from)
40
+ timestamp.gte = range.from;
41
+ if (range.to)
42
+ timestamp.lte = range.to;
43
+ return Object.keys(timestamp).length > 0 ? { timestamp } : {};
44
+ }
45
+ export async function loadAuditLogForExport(db, range, max = AUDIT_LOG_EXPORT_MAX) {
46
+ const rows = await db.auditLog.findMany({
47
+ where: auditLogWhere(range),
48
+ orderBy: { timestamp: 'desc' },
49
+ take: max + 1,
50
+ });
51
+ const truncated = rows.length > max;
52
+ return { rows: truncated ? rows.slice(0, max) : rows, truncated };
53
+ }
54
+ function isoTimestamp(value) {
55
+ const date = value instanceof Date ? value : new Date(value);
56
+ return Number.isNaN(date.getTime()) ? String(value) : date.toISOString();
57
+ }
58
+ function csvCell(value) {
59
+ const text = value == null ? '' : typeof value === 'string' ? value : (JSON.stringify(value) ?? '');
60
+ if (/[",\n\r]/.test(text))
61
+ return `"${text.replace(/"/g, '""')}"`;
62
+ return text;
63
+ }
64
+ export function auditLogToCsv(rows) {
65
+ const header = 'timestamp,event,userId,ipAddress,userAgent,details';
66
+ const lines = rows.map((row) => [
67
+ isoTimestamp(row.timestamp),
68
+ row.event,
69
+ row.userId,
70
+ row.ipAddress,
71
+ row.userAgent,
72
+ row.details ?? '',
73
+ ]
74
+ .map(csvCell)
75
+ .join(','));
76
+ return [header, ...lines].join('\n');
77
+ }
78
+ export function auditLogToJson(rows, truncated) {
79
+ return JSON.stringify({
80
+ count: rows.length,
81
+ truncated,
82
+ entries: rows.map((row) => ({
83
+ id: row.id,
84
+ timestamp: isoTimestamp(row.timestamp),
85
+ event: row.event,
86
+ userId: row.userId,
87
+ ipAddress: row.ipAddress,
88
+ userAgent: row.userAgent,
89
+ details: row.details ?? null,
90
+ })),
91
+ });
92
+ }
93
+ //# sourceMappingURL=audit-export.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit-export.js","sourceRoot":"","sources":["../../src/security/audit-export.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@prenta/core",
3
- "version": "7.6.2",
3
+ "version": "7.6.5",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",