@prenta/core 7.7.1 → 7.7.2
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.
- package/CHANGELOG.md +6 -0
- package/dist/api/route-helpers/auth.d.ts +131 -0
- package/dist/api/route-helpers/auth.d.ts.map +1 -0
- package/dist/api/route-helpers/auth.js +505 -0
- package/dist/api/route-helpers/auth.js.map +1 -0
- package/dist/api/route-helpers/authoring.d.ts +32 -0
- package/dist/api/route-helpers/authoring.d.ts.map +1 -0
- package/dist/api/route-helpers/authoring.js +99 -0
- package/dist/api/route-helpers/authoring.js.map +1 -0
- package/dist/api/route-helpers/forms.d.ts +46 -0
- package/dist/api/route-helpers/forms.d.ts.map +1 -0
- package/dist/api/route-helpers/forms.js +435 -0
- package/dist/api/route-helpers/forms.js.map +1 -0
- package/dist/api/route-helpers/http.d.ts +87 -0
- package/dist/api/route-helpers/http.d.ts.map +1 -0
- package/dist/api/route-helpers/http.js +286 -0
- package/dist/api/route-helpers/http.js.map +1 -0
- package/dist/api/route-helpers/media.d.ts +37 -0
- package/dist/api/route-helpers/media.d.ts.map +1 -0
- package/dist/api/route-helpers/media.js +189 -0
- package/dist/api/route-helpers/media.js.map +1 -0
- package/dist/api/route-helpers/page-shape.d.ts +31 -0
- package/dist/api/route-helpers/page-shape.d.ts.map +1 -0
- package/dist/api/route-helpers/page-shape.js +98 -0
- package/dist/api/route-helpers/page-shape.js.map +1 -0
- package/dist/api/route-helpers.d.ts +8 -358
- package/dist/api/route-helpers.d.ts.map +1 -1
- package/dist/api/route-helpers.js +7 -1592
- package/dist/api/route-helpers.js.map +1 -1
- package/dist/api/routes/users/handlers/api-keys.d.ts +4 -0
- package/dist/api/routes/users/handlers/api-keys.d.ts.map +1 -0
- package/dist/api/routes/users/handlers/api-keys.js +164 -0
- package/dist/api/routes/users/handlers/api-keys.js.map +1 -0
- package/dist/api/routes/users/handlers/invites.d.ts +7 -0
- package/dist/api/routes/users/handlers/invites.d.ts.map +1 -0
- package/dist/api/routes/users/handlers/invites.js +201 -0
- package/dist/api/routes/users/handlers/invites.js.map +1 -0
- package/dist/api/routes/users/handlers/users-admin.d.ts +7 -0
- package/dist/api/routes/users/handlers/users-admin.d.ts.map +1 -0
- package/dist/api/routes/users/handlers/users-admin.js +310 -0
- package/dist/api/routes/users/handlers/users-admin.js.map +1 -0
- package/dist/api/routes/users/handlers/users-detail.d.ts +16 -0
- package/dist/api/routes/users/handlers/users-detail.d.ts.map +1 -0
- package/dist/api/routes/users/handlers/users-detail.js +525 -0
- package/dist/api/routes/users/handlers/users-detail.js.map +1 -0
- package/dist/api/routes/users.d.ts +4 -0
- package/dist/api/routes/users.d.ts.map +1 -1
- package/dist/api/routes/users.js +38 -1177
- package/dist/api/routes/users.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../../src/api/route-helpers/auth.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { PrentaDB } from '../../db/client-types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Build the system/user prompt for an inline co-author action. Kept
|
|
4
|
+
* deterministic and small so the governed runtime can route it to any
|
|
5
|
+
* configured provider/model.
|
|
6
|
+
*/
|
|
7
|
+
export declare function buildCoauthorPrompt(action: 'rewrite' | 'expand' | 'compress' | 'proofread', body: {
|
|
8
|
+
text?: string;
|
|
9
|
+
style?: string;
|
|
10
|
+
tone?: string;
|
|
11
|
+
instructions?: string;
|
|
12
|
+
targetLength?: number;
|
|
13
|
+
}): {
|
|
14
|
+
system: string;
|
|
15
|
+
user: string;
|
|
16
|
+
maxTokens: number;
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Common helper for the read endpoints. Reads the `?populate=` query param,
|
|
20
|
+
* fetches the target collection's field schema, and expands every relation
|
|
21
|
+
* reference into a {@link RelationSummary}. When the caller didn't ask for
|
|
22
|
+
* population (or the doc has no `data` field) we short-circuit and return
|
|
23
|
+
* the doc untouched.
|
|
24
|
+
*
|
|
25
|
+
* Lives here (not in `actions.ts`) because the rest of the actions API
|
|
26
|
+
* stays purely DB-shaped — population is an HTTP concern.
|
|
27
|
+
*/
|
|
28
|
+
export declare function maybePopulate(request: Request, collection: string, doc: Record<string, unknown> | null, dbInstance: PrentaDB, viewer?: {
|
|
29
|
+
id?: string;
|
|
30
|
+
role?: string;
|
|
31
|
+
}): Promise<Record<string, unknown> | null>;
|
|
32
|
+
//# sourceMappingURL=authoring.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"authoring.d.ts","sourceRoot":"","sources":["../../../src/api/route-helpers/authoring.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAA;AAGxD;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,SAAS,GAAG,QAAQ,GAAG,UAAU,GAAG,WAAW,EACvD,IAAI,EAAE;IACJ,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB,GACA;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAuDrD;AAED;;;;;;;;;GASG;AACH,wBAAsB,aAAa,CACjC,OAAO,EAAE,OAAO,EAChB,UAAU,EAAE,MAAM,EAClB,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,EACnC,UAAU,EAAE,QAAQ,EACpB,MAAM,CAAC,EAAE;IAAE,EAAE,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,GACtC,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC,CA4BzC"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { buildRelationLookup } from '../../actions.js';
|
|
2
|
+
import { populateRelations, parsePopulateParam } from '../../fields/relations.js';
|
|
3
|
+
import { getPrentaConfig } from '../../config/runtime.js';
|
|
4
|
+
import { logger } from './http.js';
|
|
5
|
+
/**
|
|
6
|
+
* Build the system/user prompt for an inline co-author action. Kept
|
|
7
|
+
* deterministic and small so the governed runtime can route it to any
|
|
8
|
+
* configured provider/model.
|
|
9
|
+
*/
|
|
10
|
+
export function buildCoauthorPrompt(action, body) {
|
|
11
|
+
const text = body.text ?? '';
|
|
12
|
+
switch (action) {
|
|
13
|
+
case 'expand': {
|
|
14
|
+
const hint = body.instructions ? ` Follow this guidance: ${body.instructions}.` : '';
|
|
15
|
+
return {
|
|
16
|
+
system: 'You are an expert writer. Expand the user\u2019s text with more detail and depth ' +
|
|
17
|
+
'while preserving its meaning and voice.' +
|
|
18
|
+
hint +
|
|
19
|
+
' Return only the expanded text, with no preamble.',
|
|
20
|
+
user: text,
|
|
21
|
+
maxTokens: 2048,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
case 'compress': {
|
|
25
|
+
const hint = typeof body.targetLength === 'number' && body.targetLength > 0
|
|
26
|
+
? ` Aim for about ${body.targetLength} words.`
|
|
27
|
+
: '';
|
|
28
|
+
return {
|
|
29
|
+
system: 'You are an expert editor. Tighten the user\u2019s text, removing redundancy while ' +
|
|
30
|
+
'preserving the key information and voice.' +
|
|
31
|
+
hint +
|
|
32
|
+
' Return only the edited text, with no preamble.',
|
|
33
|
+
user: text,
|
|
34
|
+
maxTokens: 1024,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
case 'proofread':
|
|
38
|
+
return {
|
|
39
|
+
system: 'You are a meticulous proofreader. Correct grammar, spelling, and punctuation in the ' +
|
|
40
|
+
'user\u2019s text. Preserve its meaning and voice. Return only the corrected text, ' +
|
|
41
|
+
'with no preamble.',
|
|
42
|
+
user: text,
|
|
43
|
+
maxTokens: 2048,
|
|
44
|
+
};
|
|
45
|
+
case 'rewrite':
|
|
46
|
+
default: {
|
|
47
|
+
const style = body.style ? ` Write in a ${body.style} style.` : '';
|
|
48
|
+
const tone = body.tone ? ` Use a ${body.tone} tone.` : '';
|
|
49
|
+
return {
|
|
50
|
+
system: 'You are an expert editor. Rewrite the user\u2019s text to improve clarity and flow ' +
|
|
51
|
+
'while preserving its meaning.' +
|
|
52
|
+
style +
|
|
53
|
+
tone +
|
|
54
|
+
' Return only the rewritten text, with no preamble.',
|
|
55
|
+
user: text,
|
|
56
|
+
maxTokens: 2048,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Common helper for the read endpoints. Reads the `?populate=` query param,
|
|
63
|
+
* fetches the target collection's field schema, and expands every relation
|
|
64
|
+
* reference into a {@link RelationSummary}. When the caller didn't ask for
|
|
65
|
+
* population (or the doc has no `data` field) we short-circuit and return
|
|
66
|
+
* the doc untouched.
|
|
67
|
+
*
|
|
68
|
+
* Lives here (not in `actions.ts`) because the rest of the actions API
|
|
69
|
+
* stays purely DB-shaped — population is an HTTP concern.
|
|
70
|
+
*/
|
|
71
|
+
export async function maybePopulate(request, collection, doc, dbInstance, viewer) {
|
|
72
|
+
if (!doc)
|
|
73
|
+
return doc;
|
|
74
|
+
const url = new URL(request.url);
|
|
75
|
+
const opts = parsePopulateParam(url.searchParams.get('populate'));
|
|
76
|
+
if (!opts)
|
|
77
|
+
return doc;
|
|
78
|
+
const cfg = getPrentaConfig();
|
|
79
|
+
const fields = cfg?.collections?.[collection]?.fields;
|
|
80
|
+
if (!fields)
|
|
81
|
+
return doc;
|
|
82
|
+
const data = doc.data && typeof doc.data === 'object' ? doc.data : null;
|
|
83
|
+
if (!data)
|
|
84
|
+
return doc;
|
|
85
|
+
try {
|
|
86
|
+
const populated = await populateRelations(fields, data, buildRelationLookup(dbInstance, { viewer }), opts);
|
|
87
|
+
return { ...doc, data: populated };
|
|
88
|
+
}
|
|
89
|
+
catch (err) {
|
|
90
|
+
// Never let a populate failure mask the underlying document — log and
|
|
91
|
+
// return the unpopulated doc.
|
|
92
|
+
logger.error('populate failed', {
|
|
93
|
+
collection,
|
|
94
|
+
error: err instanceof Error ? err.message : String(err),
|
|
95
|
+
});
|
|
96
|
+
return doc;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
//# sourceMappingURL=authoring.js.map
|
|
@@ -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, '&')
|
|
405
|
+
.replace(/</g, '<')
|
|
406
|
+
.replace(/>/g, '>')
|
|
407
|
+
.replace(/"/g, '"');
|
|
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
|