@10x-media/form-builder 0.1.0-beta.6 → 0.1.0-beta.7
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 +73 -0
- package/dist/actions/buildActionBlocks.js +12 -9
- package/dist/actions/buildActionBlocks.js.map +1 -1
- package/dist/actions/builtin/confirmation.js +13 -68
- package/dist/actions/builtin/confirmation.js.map +1 -1
- package/dist/actions/builtin/emailAction.d.ts +17 -0
- package/dist/actions/builtin/emailAction.js +83 -0
- package/dist/actions/builtin/emailAction.js.map +1 -0
- package/dist/actions/builtin/emailTeam.js +14 -74
- package/dist/actions/builtin/emailTeam.js.map +1 -1
- package/dist/actions/builtin/index.d.ts +9 -12
- package/dist/actions/builtin/index.js +11 -11
- package/dist/actions/builtin/index.js.map +1 -1
- package/dist/actions/defineAction.d.ts +2 -2
- package/dist/actions/defineAction.js.map +1 -1
- package/dist/actions/emailRecipients.js +75 -31
- package/dist/actions/emailRecipients.js.map +1 -1
- package/dist/actions/registry.d.ts +2 -1
- package/dist/actions/registry.js +2 -6
- package/dist/actions/registry.js.map +1 -1
- package/dist/actions/task.js +5 -3
- package/dist/actions/task.js.map +1 -1
- package/dist/calc/evaluate.js +1 -2
- package/dist/calc/evaluate.js.map +1 -1
- package/dist/calc/normalizeCalc.js +1 -2
- package/dist/calc/normalizeCalc.js.map +1 -1
- package/dist/calc/types.js.map +1 -1
- package/dist/collections/buttonFields.js +1 -1
- package/dist/collections/formSubmissions.js +2 -1
- package/dist/collections/formSubmissions.js.map +1 -1
- package/dist/collections/forms.js +30 -99
- package/dist/collections/forms.js.map +1 -1
- package/dist/collections/formsEndpoints.js +101 -0
- package/dist/collections/formsEndpoints.js.map +1 -0
- package/dist/conditions/evaluate.js +1 -1
- package/dist/conditions/evaluate.js.map +1 -1
- package/dist/conditions/fieldTypes.d.ts +3 -1
- package/dist/conditions/fieldTypes.js +4 -1
- package/dist/conditions/fieldTypes.js.map +1 -1
- package/dist/conditions/normalizeConditions.js +18 -5
- package/dist/conditions/normalizeConditions.js.map +1 -1
- package/dist/consent/captureConsent.d.ts +7 -0
- package/dist/consent/captureConsent.js +7 -0
- package/dist/consent/captureConsent.js.map +1 -1
- package/dist/consent/consentSourcesField.d.ts +4 -0
- package/dist/consent/consentSourcesField.js +5 -1
- package/dist/consent/consentSourcesField.js.map +1 -1
- package/dist/consent/resolveConsentEntries.d.ts +1 -1
- package/dist/consent/resolveConsentEntries.js +1 -4
- package/dist/consent/resolveConsentEntries.js.map +1 -1
- package/dist/consent/resolveConsentSourcesRequest.js +0 -1
- package/dist/consent/resolveConsentSourcesRequest.js.map +1 -1
- package/dist/consent/resolveConsentStatements.d.ts +1 -1
- package/dist/consent/resolveConsentStatements.js.map +1 -1
- package/dist/consent/types.d.ts +9 -1
- package/dist/email/departmentsField.js +1 -1
- package/dist/exports/react.d.ts +3 -2
- package/dist/exports/react.js +3 -2
- package/dist/exports/rsc.js +1 -1
- package/dist/exports/types.d.ts +1 -1
- package/dist/fields/builtin/email.js +1 -1
- package/dist/fields/builtin/email.js.map +1 -1
- package/dist/fields/builtin/message.js +1 -1
- package/dist/fields/builtin/repeater.js +1 -1
- package/dist/fields/builtin/select.js +1 -1
- package/dist/fields/registry.d.ts +2 -1
- package/dist/fields/registry.js +2 -6
- package/dist/fields/registry.js.map +1 -1
- package/dist/fields/sharedConfig.js +1 -1
- package/dist/flow/normalizeFlow.js +7 -3
- package/dist/flow/normalizeFlow.js.map +1 -1
- package/dist/index.d.ts +4 -201
- package/dist/index.js +11 -4
- package/dist/index.js.map +1 -1
- package/dist/options.d.ts +228 -0
- package/dist/plugin/applyRegistryConfig.d.ts +11 -0
- package/dist/plugin/applyRegistryConfig.js +20 -0
- package/dist/plugin/applyRegistryConfig.js.map +1 -0
- package/dist/plugin/registerCollections.js +2 -1
- package/dist/plugin/registerCollections.js.map +1 -1
- package/dist/poll/buildPollOptionSourceFields.js +2 -2
- package/dist/poll/buildPollOptionSourceFields.js.map +1 -1
- package/dist/poll/definePollOptionSource.d.ts +2 -2
- package/dist/poll/definePollOptionSource.js.map +1 -1
- package/dist/poll/pollTypeRegistry.js +2 -4
- package/dist/poll/pollTypeRegistry.js.map +1 -1
- package/dist/poll/registry.d.ts +2 -1
- package/dist/poll/registry.js +2 -6
- package/dist/poll/registry.js.map +1 -1
- package/dist/poll/resolvePollOptionsRequest.js +0 -1
- package/dist/poll/resolvePollOptionsRequest.js.map +1 -1
- package/dist/prefill/valuesFromSearchParams.js +2 -7
- package/dist/prefill/valuesFromSearchParams.js.map +1 -1
- package/dist/react/Form.d.ts +3 -1
- package/dist/react/Form.js +93 -155
- package/dist/react/Form.js.map +1 -1
- package/dist/react/FormContext.d.ts +5 -1
- package/dist/react/FormContext.js.map +1 -1
- package/dist/react/FormFields.d.ts +18 -0
- package/dist/react/FormFields.js +114 -0
- package/dist/react/FormFields.js.map +1 -0
- package/dist/react/FormLayout.d.ts +4 -2
- package/dist/react/FormLayout.js +3 -2
- package/dist/react/FormLayout.js.map +1 -1
- package/dist/react/Poll.js +13 -3
- package/dist/react/Poll.js.map +1 -1
- package/dist/react/presentation/DialogSurface.js +1 -4
- package/dist/react/presentation/DialogSurface.js.map +1 -1
- package/dist/react/renderers/calculation.js +1 -3
- package/dist/react/renderers/calculation.js.map +1 -1
- package/dist/react/renderers/checkbox.js +1 -3
- package/dist/react/renderers/checkbox.js.map +1 -1
- package/dist/react/renderers/consent.js +2 -3
- package/dist/react/renderers/consent.js.map +1 -1
- package/dist/react/renderers/date.js +1 -3
- package/dist/react/renderers/date.js.map +1 -1
- package/dist/react/renderers/email.js +1 -3
- package/dist/react/renderers/email.js.map +1 -1
- package/dist/react/renderers/file.js +6 -7
- package/dist/react/renderers/file.js.map +1 -1
- package/dist/react/renderers/number.js +1 -3
- package/dist/react/renderers/number.js.map +1 -1
- package/dist/react/renderers/region.js +1 -3
- package/dist/react/renderers/region.js.map +1 -1
- package/dist/react/renderers/repeater.js +20 -4
- package/dist/react/renderers/repeater.js.map +1 -1
- package/dist/react/renderers/select.js +1 -3
- package/dist/react/renderers/select.js.map +1 -1
- package/dist/react/renderers/text.js +1 -3
- package/dist/react/renderers/text.js.map +1 -1
- package/dist/react/renderers/textarea.js +1 -3
- package/dist/react/renderers/textarea.js.map +1 -1
- package/dist/spam/constants.js +7 -1
- package/dist/spam/constants.js.map +1 -1
- package/dist/spam/resolveSpam.js +2 -1
- package/dist/spam/resolveSpam.js.map +1 -1
- package/dist/spam/spamGuard.js +22 -6
- package/dist/spam/spamGuard.js.map +1 -1
- package/dist/spam/types.d.ts +17 -2
- package/dist/submissions/coerceBoolean.js +14 -0
- package/dist/submissions/coerceBoolean.js.map +1 -0
- package/dist/submissions/runSubmission.js +7 -7
- package/dist/submissions/runSubmission.js.map +1 -1
- package/dist/submissions/validateSubmission.js +3 -2
- package/dist/submissions/validateSubmission.js.map +1 -1
- package/dist/translations/de.js +10 -0
- package/dist/translations/de.js.map +1 -1
- package/dist/translations/en.js +10 -0
- package/dist/translations/en.js.map +1 -1
- package/dist/translations/keys.d.ts +10 -0
- package/dist/translations/keys.js +10 -0
- package/dist/translations/keys.js.map +1 -1
- package/dist/translations/server.js +8 -1
- package/dist/translations/server.js.map +1 -1
- package/dist/uploads/captureFileRef.d.ts +10 -3
- package/dist/uploads/captureFileRef.js +18 -9
- package/dist/uploads/captureFileRef.js.map +1 -1
- package/dist/validation/builtin/email.js +1 -1
- package/dist/validation/builtin/email.js.map +1 -1
- package/dist/validation/builtin/notAlreadySubmitted.js +1 -0
- package/dist/validation/builtin/notAlreadySubmitted.js.map +1 -1
- package/dist/validation/emailPattern.js +10 -0
- package/dist/validation/emailPattern.js.map +1 -0
- package/dist/validation/registry.d.ts +2 -1
- package/dist/validation/registry.js +2 -9
- package/dist/validation/registry.js.map +1 -1
- package/package.json +4 -4
|
@@ -10,6 +10,11 @@ type CaptureFileRefArgs = {
|
|
|
10
10
|
config: FileFieldConfig;
|
|
11
11
|
req?: PayloadRequest; /** Resolved submitter identity; must match the upload's `owner` stamp when both are present. */
|
|
12
12
|
expectedOwner?: string;
|
|
13
|
+
/**
|
|
14
|
+
* Fail closed when a stamped upload's submitter cannot be identified (plugin `spam.uploadOwnership:
|
|
15
|
+
* 'strict'`). Default lenient: an unidentifiable submitter passes an owned upload through.
|
|
16
|
+
*/
|
|
17
|
+
strict?: boolean;
|
|
13
18
|
};
|
|
14
19
|
/**
|
|
15
20
|
* Load the referenced upload doc and run the pure trust-boundary check. The client sends only the id; the
|
|
@@ -17,9 +22,11 @@ type CaptureFileRefArgs = {
|
|
|
17
22
|
* upload carries an `owner` stamp AND the submitter is identifiable, the two must match, so an anonymous
|
|
18
23
|
* submitter cannot capture another identity's upload; a mismatch collapses to `missing`, indistinguishable
|
|
19
24
|
* from a deleted upload. When the submitter cannot be identified (no `expectedOwner`), ownership is not
|
|
20
|
-
* enforced (fail-open, consistent with rate-limiting): a proxy-configured deployment identifies
|
|
21
|
-
* request, so this only relaxes scoping where it could not be applied fairly anyway.
|
|
22
|
-
* (
|
|
25
|
+
* enforced by default (fail-open, consistent with rate-limiting): a proxy-configured deployment identifies
|
|
26
|
+
* every request, so this only relaxes scoping where it could not be applied fairly anyway. Under `strict`
|
|
27
|
+
* (plugin `spam.uploadOwnership: 'strict'`) a stamped upload is rejected even then, so an unverifiable
|
|
28
|
+
* claim can never capture an owned upload. Unstamped uploads (no identity at upload time, or a BYO
|
|
29
|
+
* collection without the field) pass unchanged in either mode.
|
|
23
30
|
*/
|
|
24
31
|
declare const captureFileRef: (args: CaptureFileRefArgs) => Promise<ResolveFileRefResult>;
|
|
25
32
|
//#endregion
|
|
@@ -6,12 +6,14 @@ import { resolveFileRef } from "./resolveFileRef.js";
|
|
|
6
6
|
* upload carries an `owner` stamp AND the submitter is identifiable, the two must match, so an anonymous
|
|
7
7
|
* submitter cannot capture another identity's upload; a mismatch collapses to `missing`, indistinguishable
|
|
8
8
|
* from a deleted upload. When the submitter cannot be identified (no `expectedOwner`), ownership is not
|
|
9
|
-
* enforced (fail-open, consistent with rate-limiting): a proxy-configured deployment identifies
|
|
10
|
-
* request, so this only relaxes scoping where it could not be applied fairly anyway.
|
|
11
|
-
* (
|
|
9
|
+
* enforced by default (fail-open, consistent with rate-limiting): a proxy-configured deployment identifies
|
|
10
|
+
* every request, so this only relaxes scoping where it could not be applied fairly anyway. Under `strict`
|
|
11
|
+
* (plugin `spam.uploadOwnership: 'strict'`) a stamped upload is rejected even then, so an unverifiable
|
|
12
|
+
* claim can never capture an owned upload. Unstamped uploads (no identity at upload time, or a BYO
|
|
13
|
+
* collection without the field) pass unchanged in either mode.
|
|
12
14
|
*/
|
|
13
15
|
const captureFileRef = async (args) => {
|
|
14
|
-
const { payload, collectionSlug, uploadId, config, req, expectedOwner } = args;
|
|
16
|
+
const { payload, collectionSlug, uploadId, config, req, expectedOwner, strict } = args;
|
|
15
17
|
const doc = await payload.findByID({
|
|
16
18
|
collection: collectionSlug,
|
|
17
19
|
id: uploadId,
|
|
@@ -19,12 +21,19 @@ const captureFileRef = async (args) => {
|
|
|
19
21
|
overrideAccess: true,
|
|
20
22
|
req
|
|
21
23
|
}).catch(() => null);
|
|
22
|
-
if (doc
|
|
24
|
+
if (doc) {
|
|
23
25
|
const owner = doc.owner;
|
|
24
|
-
if (typeof owner === "string" && owner.length > 0
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
26
|
+
if (typeof owner === "string" && owner.length > 0) {
|
|
27
|
+
if (expectedOwner == null) {
|
|
28
|
+
if (strict) return {
|
|
29
|
+
ok: false,
|
|
30
|
+
code: "missing"
|
|
31
|
+
};
|
|
32
|
+
} else if (owner !== expectedOwner) return {
|
|
33
|
+
ok: false,
|
|
34
|
+
code: "missing"
|
|
35
|
+
};
|
|
36
|
+
}
|
|
28
37
|
}
|
|
29
38
|
return resolveFileRef(doc, config);
|
|
30
39
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"captureFileRef.js","names":[],"sources":["../../src/uploads/captureFileRef.ts"],"sourcesContent":["import type { CollectionSlug, Payload, PayloadRequest } from 'payload'\nimport { type ResolveFileRefResult, resolveFileRef } from './resolveFileRef'\nimport type { FileFieldConfig } from './types'\n\nexport type CaptureFileRefArgs = {\n\tpayload: Payload\n\tcollectionSlug: string\n\tuploadId: string | number\n\tconfig: FileFieldConfig\n\treq?: PayloadRequest\n\t/** Resolved submitter identity; must match the upload's `owner` stamp when both are present. */\n\texpectedOwner?: string\n}\n\n/**\n * Load the referenced upload doc and run the pure trust-boundary check. The client sends only the id; the\n * filename/mimeType/filesize are read authoritatively from the stored doc, never from the client. When the\n * upload carries an `owner` stamp AND the submitter is identifiable, the two must match, so an anonymous\n * submitter cannot capture another identity's upload; a mismatch collapses to `missing`, indistinguishable\n * from a deleted upload. When the submitter cannot be identified (no `expectedOwner`), ownership is not\n * enforced (fail-open, consistent with rate-limiting): a proxy-configured deployment identifies
|
|
1
|
+
{"version":3,"file":"captureFileRef.js","names":[],"sources":["../../src/uploads/captureFileRef.ts"],"sourcesContent":["import type { CollectionSlug, Payload, PayloadRequest } from 'payload'\nimport { type ResolveFileRefResult, resolveFileRef } from './resolveFileRef'\nimport type { FileFieldConfig } from './types'\n\nexport type CaptureFileRefArgs = {\n\tpayload: Payload\n\tcollectionSlug: string\n\tuploadId: string | number\n\tconfig: FileFieldConfig\n\treq?: PayloadRequest\n\t/** Resolved submitter identity; must match the upload's `owner` stamp when both are present. */\n\texpectedOwner?: string\n\t/**\n\t * Fail closed when a stamped upload's submitter cannot be identified (plugin `spam.uploadOwnership:\n\t * 'strict'`). Default lenient: an unidentifiable submitter passes an owned upload through.\n\t */\n\tstrict?: boolean\n}\n\n/**\n * Load the referenced upload doc and run the pure trust-boundary check. The client sends only the id; the\n * filename/mimeType/filesize are read authoritatively from the stored doc, never from the client. When the\n * upload carries an `owner` stamp AND the submitter is identifiable, the two must match, so an anonymous\n * submitter cannot capture another identity's upload; a mismatch collapses to `missing`, indistinguishable\n * from a deleted upload. When the submitter cannot be identified (no `expectedOwner`), ownership is not\n * enforced by default (fail-open, consistent with rate-limiting): a proxy-configured deployment identifies\n * every request, so this only relaxes scoping where it could not be applied fairly anyway. Under `strict`\n * (plugin `spam.uploadOwnership: 'strict'`) a stamped upload is rejected even then, so an unverifiable\n * claim can never capture an owned upload. Unstamped uploads (no identity at upload time, or a BYO\n * collection without the field) pass unchanged in either mode.\n */\nexport const captureFileRef = async (args: CaptureFileRefArgs): Promise<ResolveFileRefResult> => {\n\tconst { payload, collectionSlug, uploadId, config, req, expectedOwner, strict } = args\n\tconst doc = await payload\n\t\t.findByID({\n\t\t\tcollection: collectionSlug as CollectionSlug,\n\t\t\tid: uploadId,\n\t\t\tdepth: 0,\n\t\t\toverrideAccess: true,\n\t\t\treq,\n\t\t})\n\t\t.catch(() => null)\n\tif (doc) {\n\t\tconst owner = (doc as { owner?: unknown }).owner\n\t\tconst stamped = typeof owner === 'string' && owner.length > 0\n\t\tif (stamped) {\n\t\t\tif (expectedOwner == null) {\n\t\t\t\tif (strict) {\n\t\t\t\t\treturn { ok: false, code: 'missing' }\n\t\t\t\t}\n\t\t\t} else if (owner !== expectedOwner) {\n\t\t\t\treturn { ok: false, code: 'missing' }\n\t\t\t}\n\t\t}\n\t}\n\treturn resolveFileRef(doc, config)\n}\n"],"mappings":";;;;;;;;;;;;;;AA+BA,MAAa,iBAAiB,OAAO,SAA4D;CAChG,MAAM,EAAE,SAAS,gBAAgB,UAAU,QAAQ,KAAK,eAAe,WAAW;CAClF,MAAM,MAAM,MAAM,QAChB,SAAS;EACT,YAAY;EACZ,IAAI;EACJ,OAAO;EACP,gBAAgB;EAChB;CACD,CAAC,EACA,YAAY,IAAI;CAClB,IAAI,KAAK;EACR,MAAM,QAAS,IAA4B;EAE3C,IADgB,OAAO,UAAU,YAAY,MAAM,SAAS;OAEvD,iBAAiB;QAChB,QACH,OAAO;KAAE,IAAI;KAAO,MAAM;IAAU;GAAA,OAE/B,IAAI,UAAU,eACpB,OAAO;IAAE,IAAI;IAAO,MAAM;GAAU;EAAA;CAGvC;CACA,OAAO,eAAe,KAAK,MAAM;AAClC"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { keys } from "../../translations/keys.js";
|
|
2
|
+
import { EMAIL_PATTERN } from "../emailPattern.js";
|
|
2
3
|
import { defineValidationRule } from "../defineValidationRule.js";
|
|
3
4
|
//#region src/validation/builtin/email.ts
|
|
4
|
-
const EMAIL_PATTERN = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
5
5
|
const emailRule = defineValidationRule({
|
|
6
6
|
type: "email",
|
|
7
7
|
label: keys.ruleEmail,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"email.js","names":[],"sources":["../../../src/validation/builtin/email.ts"],"sourcesContent":["import { keys } from '../../translations/keys'\nimport { defineValidationRule } from '../defineValidationRule'\
|
|
1
|
+
{"version":3,"file":"email.js","names":[],"sources":["../../../src/validation/builtin/email.ts"],"sourcesContent":["import { keys } from '../../translations/keys'\nimport { defineValidationRule } from '../defineValidationRule'\nimport { EMAIL_PATTERN } from '../emailPattern'\n\nexport const emailRule = defineValidationRule<Record<string, never>, string>({\n\ttype: 'email',\n\tlabel: keys.ruleEmail,\n\tdescription: keys.ruleEmailDescription,\n\tappliesTo: ['text', 'textarea', 'email'],\n\tdefaultMessage: keys.ruleEmailMessage,\n\tvalidate: ({ value, message }) =>\n\t\tvalue == null || value === '' || EMAIL_PATTERN.test(value) ? true : message(),\n})\n"],"mappings":";;;;AAIA,MAAa,YAAY,qBAAoD;CAC5E,MAAM;CACN,OAAO,KAAK;CACZ,aAAa,KAAK;CAClB,WAAW;EAAC;EAAQ;EAAY;CAAO;CACvC,gBAAgB,KAAK;CACrB,WAAW,EAAE,OAAO,cACnB,SAAS,QAAQ,UAAU,MAAM,cAAc,KAAK,KAAK,IAAI,OAAO,QAAQ;AAC9E,CAAC"}
|
|
@@ -21,6 +21,7 @@ const notAlreadySubmittedRule = defineValidationRule({
|
|
|
21
21
|
where: { form: { equals: formId } },
|
|
22
22
|
limit: SCAN_LIMIT,
|
|
23
23
|
depth: 0,
|
|
24
|
+
overrideAccess: true,
|
|
24
25
|
req
|
|
25
26
|
})).docs.some((doc) => {
|
|
26
27
|
return (doc.values ?? []).some((entry) => entry.field === field.name && entry.value === value);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"notAlreadySubmitted.js","names":[],"sources":["../../../src/validation/builtin/notAlreadySubmitted.ts"],"sourcesContent":["import { keys } from '../../translations/keys'\nimport { defineValidationRule } from '../defineValidationRule'\n\nconst FORM_SUBMISSIONS_SLUG = 'form-submissions'\nconst SCAN_LIMIT = 500\n\n/**\n * Server-only async exemplar: rejects a value already present for the same form. Scans up to\n * `SCAN_LIMIT` recent submissions in JS (the values live in a json column, so a portable DB query is\n * not available); a future phase can add an indexed dedup column for scale.\n */\nexport const notAlreadySubmittedRule = defineValidationRule<Record<string, never>, unknown>({\n\ttype: 'notAlreadySubmitted',\n\tlabel: keys.ruleNotAlreadySubmitted,\n\tdescription: keys.ruleNotAlreadySubmittedDescription,\n\tclient: false,\n\tdefaultMessage: keys.ruleNotAlreadySubmittedMessage,\n\tvalidate: async ({ value, field, payload, req, formId, message }) => {\n\t\tif (value == null || value === '' || !payload || formId == null) {\n\t\t\treturn true\n\t\t}\n\t\tconst result = await payload.find({\n\t\t\tcollection: FORM_SUBMISSIONS_SLUG,\n\t\t\twhere: { form: { equals: formId } },\n\t\t\tlimit: SCAN_LIMIT,\n\t\t\tdepth: 0,\n\t\t\treq,\n\t\t})\n\t\tconst clash = result.docs.some((doc) => {\n\t\t\tconst values = (doc as { values?: { field: string; value: unknown }[] }).values ?? []\n\t\t\treturn values.some((entry) => entry.field === field.name && entry.value === value)\n\t\t})\n\t\treturn clash ? message() : true\n\t},\n})\n"],"mappings":";;;AAGA,MAAM,wBAAwB;AAC9B,MAAM,aAAa;;;;;;AAOnB,MAAa,0BAA0B,qBAAqD;CAC3F,MAAM;CACN,OAAO,KAAK;CACZ,aAAa,KAAK;CAClB,QAAQ;CACR,gBAAgB,KAAK;CACrB,UAAU,OAAO,EAAE,OAAO,OAAO,SAAS,KAAK,QAAQ,cAAc;EACpE,IAAI,SAAS,QAAQ,UAAU,MAAM,CAAC,WAAW,UAAU,MAC1D,OAAO;
|
|
1
|
+
{"version":3,"file":"notAlreadySubmitted.js","names":[],"sources":["../../../src/validation/builtin/notAlreadySubmitted.ts"],"sourcesContent":["import { keys } from '../../translations/keys'\nimport { defineValidationRule } from '../defineValidationRule'\n\nconst FORM_SUBMISSIONS_SLUG = 'form-submissions'\nconst SCAN_LIMIT = 500\n\n/**\n * Server-only async exemplar: rejects a value already present for the same form. Scans up to\n * `SCAN_LIMIT` recent submissions in JS (the values live in a json column, so a portable DB query is\n * not available); a future phase can add an indexed dedup column for scale.\n */\nexport const notAlreadySubmittedRule = defineValidationRule<Record<string, never>, unknown>({\n\ttype: 'notAlreadySubmitted',\n\tlabel: keys.ruleNotAlreadySubmitted,\n\tdescription: keys.ruleNotAlreadySubmittedDescription,\n\tclient: false,\n\tdefaultMessage: keys.ruleNotAlreadySubmittedMessage,\n\tvalidate: async ({ value, field, payload, req, formId, message }) => {\n\t\tif (value == null || value === '' || !payload || formId == null) {\n\t\t\treturn true\n\t\t}\n\t\tconst result = await payload.find({\n\t\t\tcollection: FORM_SUBMISSIONS_SLUG,\n\t\t\twhere: { form: { equals: formId } },\n\t\t\tlimit: SCAN_LIMIT,\n\t\t\tdepth: 0,\n\t\t\t// Trusted internal dedup read: scan every prior submission of this form regardless of the\n\t\t\t// submitter's own access. This is the local-API default made explicit, matching the sibling\n\t\t\t// resolvePollOutcome/aggregateResponses reads; the `form` filter keeps it single-tenant.\n\t\t\toverrideAccess: true,\n\t\t\treq,\n\t\t})\n\t\tconst clash = result.docs.some((doc) => {\n\t\t\tconst values = (doc as { values?: { field: string; value: unknown }[] }).values ?? []\n\t\t\treturn values.some((entry) => entry.field === field.name && entry.value === value)\n\t\t})\n\t\treturn clash ? message() : true\n\t},\n})\n"],"mappings":";;;AAGA,MAAM,wBAAwB;AAC9B,MAAM,aAAa;;;;;;AAOnB,MAAa,0BAA0B,qBAAqD;CAC3F,MAAM;CACN,OAAO,KAAK;CACZ,aAAa,KAAK;CAClB,QAAQ;CACR,gBAAgB,KAAK;CACrB,UAAU,OAAO,EAAE,OAAO,OAAO,SAAS,KAAK,QAAQ,cAAc;EACpE,IAAI,SAAS,QAAQ,UAAU,MAAM,CAAC,WAAW,UAAU,MAC1D,OAAO;EAiBR,QAJc,MAXO,QAAQ,KAAK;GACjC,YAAY;GACZ,OAAO,EAAE,MAAM,EAAE,QAAQ,OAAO,EAAE;GAClC,OAAO;GACP,OAAO;GAIP,gBAAgB;GAChB;EACD,CAAC,GACoB,KAAK,MAAM,QAAQ;GAEvC,QADgB,IAAyD,UAAU,CAAC,GACtE,MAAM,UAAU,MAAM,UAAU,MAAM,QAAQ,MAAM,UAAU,KAAK;EAClF,CACW,IAAI,QAAQ,IAAI;CAC5B;AACD,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
//#region src/validation/emailPattern.ts
|
|
2
|
+
/**
|
|
3
|
+
* The email-format check shared by the `email` field type and the `email` validation rule, so the
|
|
4
|
+
* two never drift. A pragmatic "one @, one dot, no spaces" test, not a full RFC 5322 grammar.
|
|
5
|
+
*/
|
|
6
|
+
const EMAIL_PATTERN = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
7
|
+
//#endregion
|
|
8
|
+
export { EMAIL_PATTERN };
|
|
9
|
+
|
|
10
|
+
//# sourceMappingURL=emailPattern.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"emailPattern.js","names":[],"sources":["../../src/validation/emailPattern.ts"],"sourcesContent":["/**\n * The email-format check shared by the `email` field type and the `email` validation rule, so the\n * two never drift. A pragmatic \"one @, one dot, no spaces\" test, not a full RFC 5322 grammar.\n */\nexport const EMAIL_PATTERN = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/\n"],"mappings":";;;;;AAIA,MAAa,gBAAgB"}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
+
import { RegistryConfig } from "../plugin/applyRegistryConfig.js";
|
|
1
2
|
import { AnyValidationRuleDefinition } from "./types.js";
|
|
2
3
|
|
|
3
4
|
//#region src/validation/registry.d.ts
|
|
4
5
|
type ValidationRuleRegistry = Map<string, AnyValidationRuleDefinition>;
|
|
5
6
|
/** Per-rule opt-in: `false` removes a built-in, `true` keeps it, an object adds a new rule or replaces one. */
|
|
6
7
|
type ValidationRuleOption = boolean | AnyValidationRuleDefinition;
|
|
7
|
-
type ValidationRulesConfig =
|
|
8
|
+
type ValidationRulesConfig = RegistryConfig<AnyValidationRuleDefinition>;
|
|
8
9
|
//#endregion
|
|
9
10
|
export { ValidationRuleOption, ValidationRuleRegistry, ValidationRulesConfig };
|
|
10
11
|
//# sourceMappingURL=registry.d.ts.map
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { applyRegistryConfig } from "../plugin/applyRegistryConfig.js";
|
|
1
2
|
//#region src/validation/registry.ts
|
|
2
3
|
const buildRuleRegistry = (rules) => {
|
|
3
4
|
const registry = /* @__PURE__ */ new Map();
|
|
@@ -5,15 +6,7 @@ const buildRuleRegistry = (rules) => {
|
|
|
5
6
|
return registry;
|
|
6
7
|
};
|
|
7
8
|
/** Resolve the active rule registry from the built-in defaults and the plugin `rules` option. */
|
|
8
|
-
const resolveValidationRules = (defaults, config = {}) =>
|
|
9
|
-
const registry = buildRuleRegistry(defaults);
|
|
10
|
-
for (const [type, option] of Object.entries(config)) if (option === false) registry.delete(type);
|
|
11
|
-
else if (option === true) {} else registry.set(type, {
|
|
12
|
-
...option,
|
|
13
|
-
type
|
|
14
|
-
});
|
|
15
|
-
return registry;
|
|
16
|
-
};
|
|
9
|
+
const resolveValidationRules = (defaults, config = {}) => applyRegistryConfig(buildRuleRegistry(defaults), config);
|
|
17
10
|
//#endregion
|
|
18
11
|
export { buildRuleRegistry, resolveValidationRules };
|
|
19
12
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.js","names":[],"sources":["../../src/validation/registry.ts"],"sourcesContent":["import type { AnyValidationRuleDefinition } from './types'\n\nexport type ValidationRuleRegistry = Map<string, AnyValidationRuleDefinition>\n\n/** Per-rule opt-in: `false` removes a built-in, `true` keeps it, an object adds a new rule or replaces one. */\nexport type ValidationRuleOption = boolean | AnyValidationRuleDefinition\n\nexport type ValidationRulesConfig =
|
|
1
|
+
{"version":3,"file":"registry.js","names":[],"sources":["../../src/validation/registry.ts"],"sourcesContent":["import { applyRegistryConfig, type RegistryConfig } from '../plugin/applyRegistryConfig'\nimport type { AnyValidationRuleDefinition } from './types'\n\nexport type ValidationRuleRegistry = Map<string, AnyValidationRuleDefinition>\n\n/** Per-rule opt-in: `false` removes a built-in, `true` keeps it, an object adds a new rule or replaces one. */\nexport type ValidationRuleOption = boolean | AnyValidationRuleDefinition\n\nexport type ValidationRulesConfig = RegistryConfig<AnyValidationRuleDefinition>\n\nexport const buildRuleRegistry = (rules: AnyValidationRuleDefinition[]): ValidationRuleRegistry => {\n\tconst registry: ValidationRuleRegistry = new Map()\n\tfor (const rule of rules) {\n\t\tregistry.set(rule.type, rule)\n\t}\n\treturn registry\n}\n\n/** Resolve the active rule registry from the built-in defaults and the plugin `rules` option. */\nexport const resolveValidationRules = (\n\tdefaults: AnyValidationRuleDefinition[],\n\tconfig: ValidationRulesConfig = {}\n): ValidationRuleRegistry => applyRegistryConfig(buildRuleRegistry(defaults), config)\n"],"mappings":";;AAUA,MAAa,qBAAqB,UAAiE;CAClG,MAAM,2BAAmC,IAAI,IAAI;CACjD,KAAK,MAAM,QAAQ,OAClB,SAAS,IAAI,KAAK,MAAM,IAAI;CAE7B,OAAO;AACR;;AAGA,MAAa,0BACZ,UACA,SAAgC,CAAC,MACL,oBAAoB,kBAAkB,QAAQ,GAAG,MAAM"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@10x-media/form-builder",
|
|
3
|
-
"version": "0.1.0-beta.
|
|
3
|
+
"version": "0.1.0-beta.7",
|
|
4
4
|
"description": "End-to-end forms platform for Payload: author, validate, render, collect, aggregate, and act.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -93,10 +93,10 @@
|
|
|
93
93
|
"tsdown": "0.22.1",
|
|
94
94
|
"typescript": "5.9.3",
|
|
95
95
|
"vitest": "4.1.7",
|
|
96
|
-
"@10x-media/tsconfig": "0.0.0",
|
|
97
96
|
"@10x-media/payload-test-harness": "0.0.0",
|
|
98
|
-
"@10x-media/
|
|
99
|
-
"@10x-media/
|
|
97
|
+
"@10x-media/tsdown-config": "0.0.0",
|
|
98
|
+
"@10x-media/tsconfig": "0.0.0",
|
|
99
|
+
"@10x-media/vitest-config": "0.0.0"
|
|
100
100
|
},
|
|
101
101
|
"publishConfig": {
|
|
102
102
|
"access": "public"
|