@prenta/core 7.7.1 → 7.8.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 (56) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/api/handler-factory.d.ts.map +1 -1
  3. package/dist/api/handler-factory.js +40 -14
  4. package/dist/api/handler-factory.js.map +1 -1
  5. package/dist/api/openapi.d.ts.map +1 -1
  6. package/dist/api/openapi.js +8 -2
  7. package/dist/api/openapi.js.map +1 -1
  8. package/dist/api/route-helpers/auth.d.ts +131 -0
  9. package/dist/api/route-helpers/auth.d.ts.map +1 -0
  10. package/dist/api/route-helpers/auth.js +505 -0
  11. package/dist/api/route-helpers/auth.js.map +1 -0
  12. package/dist/api/route-helpers/authoring.d.ts +32 -0
  13. package/dist/api/route-helpers/authoring.d.ts.map +1 -0
  14. package/dist/api/route-helpers/authoring.js +99 -0
  15. package/dist/api/route-helpers/authoring.js.map +1 -0
  16. package/dist/api/route-helpers/forms.d.ts +46 -0
  17. package/dist/api/route-helpers/forms.d.ts.map +1 -0
  18. package/dist/api/route-helpers/forms.js +435 -0
  19. package/dist/api/route-helpers/forms.js.map +1 -0
  20. package/dist/api/route-helpers/http.d.ts +87 -0
  21. package/dist/api/route-helpers/http.d.ts.map +1 -0
  22. package/dist/api/route-helpers/http.js +286 -0
  23. package/dist/api/route-helpers/http.js.map +1 -0
  24. package/dist/api/route-helpers/media.d.ts +37 -0
  25. package/dist/api/route-helpers/media.d.ts.map +1 -0
  26. package/dist/api/route-helpers/media.js +189 -0
  27. package/dist/api/route-helpers/media.js.map +1 -0
  28. package/dist/api/route-helpers/page-shape.d.ts +31 -0
  29. package/dist/api/route-helpers/page-shape.d.ts.map +1 -0
  30. package/dist/api/route-helpers/page-shape.js +98 -0
  31. package/dist/api/route-helpers/page-shape.js.map +1 -0
  32. package/dist/api/route-helpers.d.ts +8 -358
  33. package/dist/api/route-helpers.d.ts.map +1 -1
  34. package/dist/api/route-helpers.js +7 -1592
  35. package/dist/api/route-helpers.js.map +1 -1
  36. package/dist/api/routes/users/handlers/api-keys.d.ts +4 -0
  37. package/dist/api/routes/users/handlers/api-keys.d.ts.map +1 -0
  38. package/dist/api/routes/users/handlers/api-keys.js +164 -0
  39. package/dist/api/routes/users/handlers/api-keys.js.map +1 -0
  40. package/dist/api/routes/users/handlers/invites.d.ts +7 -0
  41. package/dist/api/routes/users/handlers/invites.d.ts.map +1 -0
  42. package/dist/api/routes/users/handlers/invites.js +201 -0
  43. package/dist/api/routes/users/handlers/invites.js.map +1 -0
  44. package/dist/api/routes/users/handlers/users-admin.d.ts +7 -0
  45. package/dist/api/routes/users/handlers/users-admin.d.ts.map +1 -0
  46. package/dist/api/routes/users/handlers/users-admin.js +310 -0
  47. package/dist/api/routes/users/handlers/users-admin.js.map +1 -0
  48. package/dist/api/routes/users/handlers/users-detail.d.ts +16 -0
  49. package/dist/api/routes/users/handlers/users-detail.d.ts.map +1 -0
  50. package/dist/api/routes/users/handlers/users-detail.js +525 -0
  51. package/dist/api/routes/users/handlers/users-detail.js.map +1 -0
  52. package/dist/api/routes/users.d.ts +4 -0
  53. package/dist/api/routes/users.d.ts.map +1 -1
  54. package/dist/api/routes/users.js +38 -1177
  55. package/dist/api/routes/users.js.map +1 -1
  56. package/package.json +1 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"authoring.js","sourceRoot":"","sources":["../../../src/api/route-helpers/authoring.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,46 @@
1
+ import type { FetchFormEntriesParams, FetchFormsParams, FormDefinition } from '../../forms/types.js';
2
+ import { type IncomingFile } from '../../forms/files.js';
3
+ export declare function normalizeSubmission(submission: any): any;
4
+ /**
5
+ * Map a forms-service domain error to an HTTP response. Returns `null` for
6
+ * unrecognised errors so the caller can fall through to `internalError`.
7
+ */
8
+ export declare function mapFormError(err: unknown): Response | null;
9
+ export declare function parseFormsQuery(url: URL): FetchFormsParams;
10
+ export declare function parseEntriesQuery(url: URL): FetchFormEntriesParams;
11
+ /**
12
+ * Build CORS headers for the public form endpoints. When the form has no
13
+ * embed allowlist we reflect the requesting origin (open embedding). When an
14
+ * allowlist is set we only echo the origin if it matches, so a disallowed site
15
+ * cannot read the response. Browser-level CORS is complemented by a hard
16
+ * server-side origin check in the submit handler.
17
+ */
18
+ export declare function formCorsHeaders(request: Request, allowedDomains?: string[]): Record<string, string>;
19
+ export declare function jsonWithHeaders(data: unknown, status: number, extra: Record<string, string>): Response;
20
+ /**
21
+ * Parse a public submission request into field values, files, and metadata.
22
+ * Supports both `application/json` (no files) and `multipart/form-data`
23
+ * (files + fields). Unknown/oversized bodies are rejected by the caller's
24
+ * Content-Length gate before this runs.
25
+ */
26
+ export declare function parseSubmissionRequest(request: Request): Promise<{
27
+ values: Record<string, unknown>;
28
+ files: IncomingFile[];
29
+ meta: {
30
+ attribution: Record<string, unknown> | null;
31
+ elapsedMs: number | null;
32
+ pageUrl: string | null;
33
+ captchaToken: string;
34
+ };
35
+ } | null>;
36
+ /**
37
+ * Shared public-submission handler used by both the slug-based public route and
38
+ * the legacy by-id route. Enforces per-IP+form rate limiting, embed-origin
39
+ * allowlisting, optional CAPTCHA, file validation, then runs the core
40
+ * submission pipeline. Always responds with CORS headers so embedded forms can
41
+ * read the result.
42
+ */
43
+ export declare function submitToForm(request: Request, form: FormDefinition): Promise<Response>;
44
+ /** Native HTML form posts typically prefer HTML; fetch/XHR clients send Accept: application/json. */
45
+ export declare function requestPrefersHtmlResponse(request: Request): boolean;
46
+ //# sourceMappingURL=forms.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"forms.d.ts","sourceRoot":"","sources":["../../../src/api/route-helpers/forms.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EACV,sBAAsB,EACtB,gBAAgB,EAChB,cAAc,EAEf,MAAM,sBAAsB,CAAA;AAO7B,OAAO,EAIL,KAAK,YAAY,EAClB,MAAM,sBAAsB,CAAA;AAS7B,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,GAAG,OAuBlD;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,OAAO,GAAG,QAAQ,GAAG,IAAI,CAc1D;AAED,wBAAgB,eAAe,CAAC,GAAG,EAAE,GAAG,GAAG,gBAAgB,CAkB1D;AAED,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,GAAG,GAAG,sBAAsB,CAyBlE;AAGD;;;;;;GAMG;AACH,wBAAgB,eAAe,CAC7B,OAAO,EAAE,OAAO,EAChB,cAAc,CAAC,EAAE,MAAM,EAAE,GACxB,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAcxB;AAuBD,wBAAgB,eAAe,CAC7B,IAAI,EAAE,OAAO,EACb,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC5B,QAAQ,CAKV;AAED;;;;;GAKG;AACH,wBAAsB,sBAAsB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC;IACtE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC/B,KAAK,EAAE,YAAY,EAAE,CAAA;IACrB,IAAI,EAAE;QACJ,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAA;QAC3C,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;QACxB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;QACtB,YAAY,EAAE,MAAM,CAAA;KACrB,CAAA;CACF,GAAG,IAAI,CAAC,CAkCR;AA4FD;;;;;;GAMG;AACH,wBAAsB,YAAY,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,QAAQ,CAAC,CAmJ5F;AAED,qGAAqG;AACrG,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAWpE"}
@@ -0,0 +1,435 @@
1
+ import { verifyCaptcha, getCaptchaConfig, isCaptchaProviderError } from '../../security/captcha.js';
2
+ import { logEvent } from '../../security/audit.js';
3
+ import { FormNotFoundError, FormValidationError, FormConflictError, FormHasSubmissionsError, } from '../../forms/service.js';
4
+ import { processSubmission, SubmissionValidationError, resolveSubmissionFields, } from '../../forms/submission.js';
5
+ import { validateSubmissionFiles, FORM_UPLOAD_ALLOWED_MIME_TYPES, DEFAULT_MAX_FILE_BYTES, } from '../../forms/files.js';
6
+ import { FormWebhookError } from '../../forms/webhooks.js';
7
+ import { createRateLimiter } from '../../security/rate-limit.js';
8
+ import { getClientIp, isResolvedIp } from '../../security/client-ip.js';
9
+ import { getPrentaConfig } from '../../config/runtime.js';
10
+ import { SECURITY_HEADERS } from '../security-headers.js';
11
+ import { json, errorResponse, internalError, clampPageSize, clampPage, asRecord } from './http.js';
12
+ import { checkRateLimitAsync } from './auth.js';
13
+ export function normalizeSubmission(submission) {
14
+ const data = asRecord(submission.data);
15
+ const attribution = asRecord(submission.attribution);
16
+ return {
17
+ ...submission,
18
+ name: String(data.name ?? submission.name ?? ''),
19
+ email: String(data.email ?? submission.email ?? ''),
20
+ phone: data.phone ?? submission.phone,
21
+ message: String(data.message ?? submission.message ?? ''),
22
+ status: submission.status ?? 'new',
23
+ attribution: {
24
+ source: String(attribution.source ?? '(direct)'),
25
+ medium: String(attribution.medium ?? '(none)'),
26
+ campaign: String(attribution.campaign ?? ''),
27
+ term: String(attribution.term ?? ''),
28
+ content: String(attribution.content ?? ''),
29
+ landingPage: String(attribution.landingPage ?? ''),
30
+ referrer: String(attribution.referrer ?? ''),
31
+ deviceType: attribution.deviceType ?? 'Desktop',
32
+ clickIds: asRecord(attribution.clickIds),
33
+ capturedAt: attribution.capturedAt ?? submission.submittedAt ?? submission.createdAt ?? null,
34
+ },
35
+ };
36
+ }
37
+ /**
38
+ * Map a forms-service domain error to an HTTP response. Returns `null` for
39
+ * unrecognised errors so the caller can fall through to `internalError`.
40
+ */
41
+ export function mapFormError(err) {
42
+ if (err instanceof FormNotFoundError)
43
+ return errorResponse(err.message, 404);
44
+ if (err instanceof FormValidationError) {
45
+ return json({ error: err.message, code: 'INVALID_SCHEMA', details: err.errors }, 400);
46
+ }
47
+ if (err instanceof FormConflictError)
48
+ return errorResponse(err.message, 409);
49
+ if (err instanceof FormHasSubmissionsError) {
50
+ return json({ error: err.message, code: 'FORM_HAS_SUBMISSIONS', submissionCount: err.submissionCount }, 409);
51
+ }
52
+ if (err instanceof FormWebhookError)
53
+ return errorResponse(err.message, err.status);
54
+ return null;
55
+ }
56
+ export function parseFormsQuery(url) {
57
+ const sp = url.searchParams;
58
+ const status = sp.get('status');
59
+ const notify = sp.get('notifyEnabled');
60
+ return {
61
+ search: sp.get('search') ?? undefined,
62
+ status: status === 'active' || status === 'draft' || status === 'archived' ? status : undefined,
63
+ notifyEnabled: notify == null ? undefined : notify === 'true',
64
+ sortBy: sp.get('sortBy') ?? undefined,
65
+ sortDirection: sp.get('sortDirection') === 'asc'
66
+ ? 'asc'
67
+ : sp.get('sortDirection') === 'desc'
68
+ ? 'desc'
69
+ : undefined,
70
+ page: sp.get('page') ? clampPage(sp.get('page')) : undefined,
71
+ pageSize: sp.get('pageSize') ? clampPageSize(sp.get('pageSize')) : undefined,
72
+ };
73
+ }
74
+ export function parseEntriesQuery(url) {
75
+ const sp = url.searchParams;
76
+ const spam = sp.get('spamStatus');
77
+ const boolParam = (key) => {
78
+ const v = sp.get(key);
79
+ return v == null ? undefined : v === 'true';
80
+ };
81
+ return {
82
+ search: sp.get('search') ?? undefined,
83
+ formId: sp.get('formId') ?? sp.get('form') ?? undefined,
84
+ unread: boolParam('unread'),
85
+ starred: boolParam('starred'),
86
+ archived: boolParam('archived'),
87
+ spamStatus: spam === 'clean' || spam === 'suspected' || spam === 'spam'
88
+ ? spam
89
+ : undefined,
90
+ dateFrom: sp.get('dateFrom') ?? undefined,
91
+ dateTo: sp.get('dateTo') ?? undefined,
92
+ thisWeek: boolParam('thisWeek'),
93
+ sortBy: sp.get('sortBy') ?? undefined,
94
+ sortDirection: sp.get('sortDirection') === 'asc' ? 'asc' : undefined,
95
+ page: sp.get('page') ? clampPage(sp.get('page')) : undefined,
96
+ pageSize: sp.get('pageSize') ? clampPageSize(sp.get('pageSize')) : undefined,
97
+ };
98
+ }
99
+ // ─── Public form submission helpers ─────────────────────────────────────────
100
+ /**
101
+ * Build CORS headers for the public form endpoints. When the form has no
102
+ * embed allowlist we reflect the requesting origin (open embedding). When an
103
+ * allowlist is set we only echo the origin if it matches, so a disallowed site
104
+ * cannot read the response. Browser-level CORS is complemented by a hard
105
+ * server-side origin check in the submit handler.
106
+ */
107
+ export function formCorsHeaders(request, allowedDomains) {
108
+ const origin = request.headers.get('origin');
109
+ const headers = {
110
+ 'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
111
+ 'Access-Control-Allow-Headers': 'Content-Type, X-Requested-With',
112
+ 'Access-Control-Max-Age': '600',
113
+ Vary: 'Origin',
114
+ };
115
+ if (!allowedDomains || allowedDomains.length === 0) {
116
+ headers['Access-Control-Allow-Origin'] = origin || '*';
117
+ }
118
+ else if (origin && isOriginAllowed(origin, allowedDomains)) {
119
+ headers['Access-Control-Allow-Origin'] = origin;
120
+ }
121
+ return headers;
122
+ }
123
+ function normalizeAllowedHost(domain) {
124
+ return domain
125
+ .trim()
126
+ .toLowerCase()
127
+ .replace(/^https?:\/\//, '')
128
+ .replace(/\/.*$/, '')
129
+ .replace(/^\*\./, '');
130
+ }
131
+ function isOriginAllowed(origin, allowedDomains) {
132
+ let host;
133
+ try {
134
+ host = new URL(origin).hostname.toLowerCase();
135
+ }
136
+ catch {
137
+ return false;
138
+ }
139
+ return allowedDomains
140
+ .map(normalizeAllowedHost)
141
+ .some((a) => a !== '' && (host === a || host.endsWith(`.${a}`)));
142
+ }
143
+ export function jsonWithHeaders(data, status, extra) {
144
+ return new Response(JSON.stringify(data), {
145
+ status,
146
+ headers: { ...SECURITY_HEADERS, ...extra },
147
+ });
148
+ }
149
+ /**
150
+ * Parse a public submission request into field values, files, and metadata.
151
+ * Supports both `application/json` (no files) and `multipart/form-data`
152
+ * (files + fields). Unknown/oversized bodies are rejected by the caller's
153
+ * Content-Length gate before this runs.
154
+ */
155
+ export async function parseSubmissionRequest(request) {
156
+ const contentType = request.headers.get('content-type') ?? '';
157
+ if (contentType.includes('multipart/form-data')) {
158
+ const form = await request.formData();
159
+ return parseFlatSubmissionEntries(form.entries());
160
+ }
161
+ if (contentType.includes('application/x-www-form-urlencoded')) {
162
+ const text = await request.text();
163
+ return parseFlatSubmissionEntries(new URLSearchParams(text).entries());
164
+ }
165
+ // JSON body.
166
+ const body = (await request.json().catch(() => null));
167
+ if (!body)
168
+ return null;
169
+ const values = body.fields && typeof body.fields === 'object' && !Array.isArray(body.fields)
170
+ ? body.fields
171
+ : null;
172
+ if (!values)
173
+ return null;
174
+ return {
175
+ values,
176
+ files: [],
177
+ meta: {
178
+ attribution: safeJsonObject(body.attribution),
179
+ elapsedMs: typeof body.elapsedMs === 'number' && Number.isFinite(body.elapsedMs)
180
+ ? body.elapsedMs
181
+ : null,
182
+ pageUrl: typeof body.pageUrl === 'string' ? body.pageUrl : null,
183
+ captchaToken: typeof body.captchaToken === 'string' ? body.captchaToken : '',
184
+ },
185
+ };
186
+ }
187
+ async function readSubmissionFile(value) {
188
+ if (typeof value !== 'object' || value === null || !('arrayBuffer' in value))
189
+ return null;
190
+ const file = value;
191
+ if (file.size === 0 && !file.name)
192
+ return null;
193
+ const buffer = Buffer.from(await file.arrayBuffer());
194
+ return {
195
+ fieldKey: '',
196
+ fileName: file.name || 'file',
197
+ mimeType: file.type || 'application/octet-stream',
198
+ size: buffer.byteLength,
199
+ buffer,
200
+ };
201
+ }
202
+ function parseFlatSubmissionEntries(entries) {
203
+ return (async () => {
204
+ const values = {};
205
+ const files = [];
206
+ let attribution = null;
207
+ let elapsedMs = null;
208
+ let pageUrl = null;
209
+ let captchaToken = '';
210
+ let renderStartedAt = null;
211
+ for (const [key, rawValue] of entries) {
212
+ if (typeof rawValue === 'object' && rawValue !== null && 'arrayBuffer' in rawValue) {
213
+ const file = await readSubmissionFile(rawValue);
214
+ if (file) {
215
+ file.fieldKey = key;
216
+ files.push(file);
217
+ }
218
+ continue;
219
+ }
220
+ const str = String(rawValue);
221
+ if (key === '__attribution') {
222
+ attribution = safeJsonObject(str);
223
+ }
224
+ else if (key === '__elapsedMs') {
225
+ const n = Number(str);
226
+ elapsedMs = Number.isFinite(n) ? n : null;
227
+ }
228
+ else if (key === '__renderStartedAt') {
229
+ const n = Number(str);
230
+ renderStartedAt = Number.isFinite(n) ? n : null;
231
+ }
232
+ else if (key === '__pageUrl') {
233
+ pageUrl = str || null;
234
+ }
235
+ else if (key === '__captchaToken' || key === 'captchaToken') {
236
+ captchaToken = str;
237
+ }
238
+ else if (Object.prototype.hasOwnProperty.call(values, key)) {
239
+ const existing = values[key];
240
+ values[key] = Array.isArray(existing) ? [...existing, str] : [existing, str];
241
+ }
242
+ else {
243
+ values[key] = str;
244
+ }
245
+ }
246
+ if (elapsedMs === null && renderStartedAt !== null) {
247
+ elapsedMs = Math.max(0, Date.now() - renderStartedAt);
248
+ }
249
+ return { values, files, meta: { attribution, elapsedMs, pageUrl, captchaToken } };
250
+ })();
251
+ }
252
+ function safeJsonObject(value) {
253
+ if (value && typeof value === 'object' && !Array.isArray(value)) {
254
+ return value;
255
+ }
256
+ if (typeof value === 'string' && value.trim()) {
257
+ try {
258
+ const parsed = JSON.parse(value);
259
+ if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {
260
+ return parsed;
261
+ }
262
+ }
263
+ catch {
264
+ /* ignore malformed attribution blob */
265
+ }
266
+ }
267
+ return null;
268
+ }
269
+ /**
270
+ * Shared public-submission handler used by both the slug-based public route and
271
+ * the legacy by-id route. Enforces per-IP+form rate limiting, embed-origin
272
+ * allowlisting, optional CAPTCHA, file validation, then runs the core
273
+ * submission pipeline. Always responds with CORS headers so embedded forms can
274
+ * read the result.
275
+ */
276
+ export async function submitToForm(request, form) {
277
+ const allowedDomains = form.embedSettings?.allowedDomains;
278
+ const cors = formCorsHeaders(request, allowedDomains);
279
+ const ip = getClientIp(request);
280
+ const rlKey = isResolvedIp(ip) ? `formsubmit:${ip}:${form.id}` : `formsubmit:_unknown:${form.id}`;
281
+ if (!(await checkRateLimitAsync(formLimiterGlobal, rlKey))) {
282
+ return jsonWithHeaders({ error: 'Too many submissions. Please try again later.' }, 429, cors);
283
+ }
284
+ // Hard server-side origin check when an embed allowlist is configured —
285
+ // browser CORS alone does not prevent a non-browser client from posting.
286
+ if (allowedDomains && allowedDomains.length > 0) {
287
+ const origin = request.headers.get('origin');
288
+ if (origin && !isOriginAllowed(origin, allowedDomains)) {
289
+ return jsonWithHeaders({ error: 'This form cannot be submitted from this origin.' }, 403, cors);
290
+ }
291
+ }
292
+ const parsed = await parseSubmissionRequest(request);
293
+ if (!parsed) {
294
+ return jsonWithHeaders({ error: 'Invalid or missing submission body.' }, 400, cors);
295
+ }
296
+ const captchaConfig = getCaptchaConfig();
297
+ if (captchaConfig.provider !== 'none' && captchaConfig.enforce) {
298
+ const result = await verifyCaptcha(parsed.meta.captchaToken, captchaConfig, isResolvedIp(ip) ? ip : undefined);
299
+ if (!result.success) {
300
+ const providerError = isCaptchaProviderError(result);
301
+ if (providerError && captchaConfig.onProviderError === 'fail-open') {
302
+ void logEvent({
303
+ event: 'captcha.provider_error',
304
+ details: {
305
+ formId: form.id,
306
+ formSlug: form.slug,
307
+ provider: captchaConfig.provider,
308
+ policy: 'fail-open',
309
+ errorCodes: result.errorCodes ?? [],
310
+ },
311
+ }).catch(() => { });
312
+ }
313
+ else {
314
+ void logEvent({
315
+ event: providerError ? 'captcha.provider_error' : 'captcha.verify_failed',
316
+ details: {
317
+ formId: form.id,
318
+ formSlug: form.slug,
319
+ provider: captchaConfig.provider,
320
+ policy: providerError ? captchaConfig.onProviderError : 'reject',
321
+ errorCodes: result.errorCodes ?? [],
322
+ score: result.score ?? null,
323
+ },
324
+ }).catch(() => { });
325
+ return jsonWithHeaders({
326
+ error: providerError
327
+ ? 'CAPTCHA provider unavailable. Please try again shortly.'
328
+ : 'CAPTCHA verification failed. Please try again.',
329
+ code: providerError ? 'CAPTCHA_PROVIDER_ERROR' : 'CAPTCHA_FAILED',
330
+ }, 403, cors);
331
+ }
332
+ }
333
+ }
334
+ if (parsed.files.length > 0) {
335
+ const fileCfg = getPrentaConfig()?.forms?.fileUpload;
336
+ if (fileCfg?.enabled === false) {
337
+ return jsonWithHeaders({ error: 'File uploads are not enabled for this site.' }, 400, cors);
338
+ }
339
+ const { fields } = await resolveSubmissionFields(form);
340
+ const fileCheck = validateSubmissionFiles(fields, parsed.files, {
341
+ maxSizeBytes: fileCfg?.maxSizeMB ? fileCfg.maxSizeMB * 1024 * 1024 : DEFAULT_MAX_FILE_BYTES,
342
+ allowedMimeTypes: fileCfg?.allowedMimeTypes ?? FORM_UPLOAD_ALLOWED_MIME_TYPES,
343
+ });
344
+ if (!fileCheck.ok) {
345
+ return jsonWithHeaders({ error: 'File validation failed.', code: 'INVALID_FILES', details: fileCheck.errors }, 422, cors);
346
+ }
347
+ }
348
+ const ctx = {
349
+ values: parsed.values,
350
+ files: parsed.files,
351
+ ip,
352
+ userAgent: request.headers.get('user-agent'),
353
+ referrer: request.headers.get('referer'),
354
+ origin: request.headers.get('origin'),
355
+ pageUrl: parsed.meta.pageUrl,
356
+ attribution: parsed.meta.attribution,
357
+ elapsedMs: parsed.meta.elapsedMs,
358
+ };
359
+ try {
360
+ const result = await processSubmission(form, ctx);
361
+ const confirmation = result.confirmation;
362
+ if (requestPrefersHtmlResponse(request)) {
363
+ if (confirmation.type === 'redirect' && confirmation.redirectUrl) {
364
+ return Response.redirect(confirmation.redirectUrl, 303);
365
+ }
366
+ const message = confirmation.message ??
367
+ form.successMessage ??
368
+ 'Thank you! Your submission has been received.';
369
+ return htmlWithHeaders(renderSubmissionResultHtml(message, false), 201, cors);
370
+ }
371
+ return jsonWithHeaders({
372
+ data: {
373
+ success: true,
374
+ submissionId: result.submissionId,
375
+ entryNumber: result.entryNumber,
376
+ confirmation: result.confirmation,
377
+ },
378
+ }, 201, cors);
379
+ }
380
+ catch (err) {
381
+ if (err instanceof SubmissionValidationError) {
382
+ if (requestPrefersHtmlResponse(request)) {
383
+ return htmlWithHeaders(renderSubmissionResultHtml('Please check the form and try again.', true), 422, cors);
384
+ }
385
+ return jsonWithHeaders({ error: 'Validation failed.', code: 'VALIDATION_ERROR', details: err.fieldErrors }, 422, cors);
386
+ }
387
+ return internalError(err);
388
+ }
389
+ }
390
+ /** Native HTML form posts typically prefer HTML; fetch/XHR clients send Accept: application/json. */
391
+ export function requestPrefersHtmlResponse(request) {
392
+ const accept = request.headers.get('accept') ?? '';
393
+ if (accept.includes('application/json') && !accept.includes('text/html'))
394
+ return false;
395
+ const contentType = request.headers.get('content-type') ?? '';
396
+ if (contentType.includes('application/x-www-form-urlencoded') ||
397
+ contentType.includes('multipart/form-data')) {
398
+ return !accept.includes('application/json') || accept.includes('text/html');
399
+ }
400
+ return accept.includes('text/html') && !accept.includes('application/json');
401
+ }
402
+ function escapeHtmlText(value) {
403
+ return value
404
+ .replace(/&/g, '&amp;')
405
+ .replace(/</g, '&lt;')
406
+ .replace(/>/g, '&gt;')
407
+ .replace(/"/g, '&quot;');
408
+ }
409
+ function renderSubmissionResultHtml(message, isError) {
410
+ const title = isError ? 'Submission error' : 'Thank you';
411
+ const role = isError ? 'alert' : 'status';
412
+ return `<!DOCTYPE html>
413
+ <html lang="en">
414
+ <head>
415
+ <meta charset="utf-8" />
416
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
417
+ <title>${escapeHtmlText(title)}</title>
418
+ </head>
419
+ <body>
420
+ <main><p role="${role}">${escapeHtmlText(message)}</p></main>
421
+ </body>
422
+ </html>`;
423
+ }
424
+ function htmlWithHeaders(body, status, extra) {
425
+ return new Response(body, {
426
+ status,
427
+ headers: {
428
+ ...SECURITY_HEADERS,
429
+ 'Content-Type': 'text/html; charset=utf-8',
430
+ ...extra,
431
+ },
432
+ });
433
+ }
434
+ const formLimiterGlobal = createRateLimiter({ maxRequests: 10, windowMs: 60_000 });
435
+ //# sourceMappingURL=forms.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"forms.js","sourceRoot":"","sources":["../../../src/api/route-helpers/forms.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,87 @@
1
+ export declare const logger: import("../../diagnostics/logger.js").ScopedLogger;
2
+ export declare function json(data: unknown, status?: number): Response;
3
+ /**
4
+ * Variant of `json()` that emits the Phase-5.5 public-read
5
+ * `Cache-Control` header when the active CMS config opts in.
6
+ *
7
+ * - Session-cookie requests always get `private, no-store`.
8
+ * - API-key / unauthenticated requests get
9
+ * `public, s-maxage=N, stale-while-revalidate=M` when
10
+ * `cache.publicReads.enabled` is true.
11
+ * - Otherwise no `Cache-Control` header is set (i.e. the response is
12
+ * uncacheable downstream, matching the pre-5.5 behaviour).
13
+ *
14
+ * Use this for the public read endpoints (`/collections/:slug`,
15
+ * `/collections/:slug/:id`, `/globals/:slug`, `/resolve`). Mutating
16
+ * endpoints stay on the plain `json()` so the CDN never caches a write
17
+ * response by accident.
18
+ */
19
+ export declare function jsonWithCache(data: unknown, request: Request, status?: number): Response;
20
+ export declare function errorResponse(message: string, status: number): Response;
21
+ export declare function internalError(err: unknown, context?: string): Response;
22
+ /**
23
+ * Map a thrown action-layer error to the right HTTP status. The data layer
24
+ * throws plain `Error`s with stable, human-readable prefixes for client-fixable
25
+ * problems (publish validation, access/permission, not-found); those are 4xx
26
+ * and the message is safe to return verbatim. Anything else falls through to
27
+ * {@link internalError} (500, generic message, logged).
28
+ */
29
+ export declare function actionError(err: unknown, context?: string): Response;
30
+ export declare function clampPageSize(raw: number | string | null, max?: number, fallback?: number): number;
31
+ /**
32
+ * Clamp a 1-based list `page` query param. Negative / zero / NaN values must
33
+ * never reach Prisma `skip` (negative OFFSET → validation error → opaque 500).
34
+ * Mirrors forms/users/redirects (`Math.max(1, …)`).
35
+ */
36
+ export declare function clampPage(raw: number | string | null | undefined, fallback?: number): number;
37
+ /** Parse a JSON object body; invalid JSON or a non-object yields a 400. */
38
+ export declare function readJsonBody(request: Request): Promise<{
39
+ ok: true;
40
+ data: Record<string, unknown>;
41
+ } | {
42
+ ok: false;
43
+ error: Response;
44
+ }>;
45
+ export declare function asRecord(value: unknown): Record<string, unknown>;
46
+ export declare function hasModel(d: any, name: string): boolean;
47
+ /** Format a number compactly, e.g. 8400 -> "8.4K", 1_200_000 -> "1.2M". */
48
+ export declare function formatCompactNumber(n: number): string;
49
+ /** Minimal CSV line parser supporting double-quoted fields with escaped quotes. */
50
+ export declare function parseCsvLine(line: string): string[];
51
+ export declare function modelNotAvailable(name: string): Response;
52
+ /**
53
+ * XML-escape a value for safe inclusion in sitemap content. Sitemaps reject
54
+ * unescaped ampersands and angle brackets; URLs frequently contain `&` query
55
+ * separators, so this is non-optional.
56
+ */
57
+ export declare function escapeXml(value: string): string;
58
+ /**
59
+ * URLs per sitemap file. The sitemaps protocol caps a single file at 50,000
60
+ * URLs, but the child-sitemap route must load each row's full `data` JSON blob
61
+ * (for path/noindex/images) into memory to build the XML — at 45k rows that is
62
+ * hundreds of MB per request on an unauthenticated, crawler-hit endpoint. We
63
+ * cap well below the protocol limit to bound per-request memory; collections
64
+ * larger than this are split across multiple `?page=N` files referenced from
65
+ * the sitemap index, so no URLs are lost.
66
+ */
67
+ export declare const SITEMAP_PAGE_SIZE = 10000;
68
+ /**
69
+ * Log unexpected query failures from the `safe*` wrappers.
70
+ *
71
+ * The wrappers exist so an optional Prisma model (e.g. a delegate
72
+ * that older schemas don't define) doesn't blow up the route — they
73
+ * return the empty value (`0` / `[]`) when the model isn't available.
74
+ * That defensive contract historically swallowed *every* error,
75
+ * including Prisma's "Unknown argument" rejections that flag a real
76
+ * application bug (see the `relationLoadStrategy` regression
77
+ * discovered while landing Phase 5.5 #5). Logging the underlying
78
+ * error preserves the defensive return semantics while making the
79
+ * actual class of bug visible in Vercel + Sentry logs.
80
+ *
81
+ * Kept private to this module — it's a logging contract, not a
82
+ * public API.
83
+ */
84
+ export declare function logSafeQueryFailure(scope: string, err: unknown): void;
85
+ export declare function safeCount(model: any, where?: Record<string, unknown>): Promise<number>;
86
+ export declare function safeFindMany<T>(model: any, args: Record<string, unknown>): Promise<T[]>;
87
+ //# sourceMappingURL=http.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../../src/api/route-helpers/http.ts"],"names":[],"mappings":"AAOA,eAAO,MAAM,MAAM,oDAAsB,CAAA;AAEzC,wBAAgB,IAAI,CAAC,IAAI,EAAE,OAAO,EAAE,MAAM,SAAM,GAAG,QAAQ,CAK1D;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,SAAM,GAAG,QAAQ,CAKrF;AAED,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,QAAQ,CAEvE;AAED,wBAAgB,aAAa,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,QAAQ,CAatE;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,QAAQ,CAgBpE;AA0BD,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,EAAE,GAAG,SAAM,EAAE,QAAQ,SAAK,GAAG,MAAM,CAG3F;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,EAAE,QAAQ,SAAI,GAAG,MAAM,CAIvF;AAED,2EAA2E;AAC3E,wBAAsB,YAAY,CAChC,OAAO,EAAE,OAAO,GACf,OAAO,CAAC;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,QAAQ,CAAA;CAAE,CAAC,CAUvF;AAED,wBAAgB,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAIhE;AAED,wBAAgB,QAAQ,CAAC,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAMtD;AAED,2EAA2E;AAC3E,wBAAgB,mBAAmB,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAKrD;AAED,mFAAmF;AACnF,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CA4BnD;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ,CAOxD;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAO/C;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,iBAAiB,QAAQ,CAAA;AAEtC;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,GAAG,IAAI,CAUrE;AAED,wBAAsB,SAAS,CAAC,KAAK,EAAE,GAAG,EAAE,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,CAe5F;AAED,wBAAsB,YAAY,CAAC,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,CAAC,EAAE,CAAC,CAe7F"}