payload-plugin-marketing 0.9.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 (62) hide show
  1. package/README.md +252 -0
  2. package/dist/actions/factories.d.ts +18 -0
  3. package/dist/actions/factories.d.ts.map +1 -0
  4. package/dist/actions/index.cjs +2 -0
  5. package/dist/actions/index.cjs.map +1 -0
  6. package/dist/actions/index.d.ts +2 -0
  7. package/dist/actions/index.d.ts.map +1 -0
  8. package/dist/actions/index.js +2 -0
  9. package/dist/actions/index.js.map +1 -0
  10. package/dist/adapters/index.cjs +2 -0
  11. package/dist/adapters/index.cjs.map +1 -0
  12. package/dist/adapters/index.d.ts +3 -0
  13. package/dist/adapters/index.d.ts.map +1 -0
  14. package/dist/adapters/index.js +2 -0
  15. package/dist/adapters/index.js.map +1 -0
  16. package/dist/adapters/mailchimp.d.ts +45 -0
  17. package/dist/adapters/mailchimp.d.ts.map +1 -0
  18. package/dist/adapters/resend.d.ts +68 -0
  19. package/dist/adapters/resend.d.ts.map +1 -0
  20. package/dist/admin/components.d.ts +23 -0
  21. package/dist/admin/components.d.ts.map +1 -0
  22. package/dist/admin/index.cjs +2 -0
  23. package/dist/admin/index.cjs.map +1 -0
  24. package/dist/admin/index.d.ts +4 -0
  25. package/dist/admin/index.d.ts.map +1 -0
  26. package/dist/admin/index.js +2 -0
  27. package/dist/admin/index.js.map +1 -0
  28. package/dist/admin/views.d.ts +4 -0
  29. package/dist/admin/views.d.ts.map +1 -0
  30. package/dist/chunk-4RBNCG5Q.js +2 -0
  31. package/dist/chunk-4RBNCG5Q.js.map +1 -0
  32. package/dist/chunk-KBN7IE22.js +2 -0
  33. package/dist/chunk-KBN7IE22.js.map +1 -0
  34. package/dist/chunk-RBBHOL35.js +2 -0
  35. package/dist/chunk-RBBHOL35.js.map +1 -0
  36. package/dist/form-builder/fields.d.ts +7 -0
  37. package/dist/form-builder/fields.d.ts.map +1 -0
  38. package/dist/form-builder/hooks.d.ts +10 -0
  39. package/dist/form-builder/hooks.d.ts.map +1 -0
  40. package/dist/form-builder/index.cjs +2 -0
  41. package/dist/form-builder/index.cjs.map +1 -0
  42. package/dist/form-builder/index.d.ts +6 -0
  43. package/dist/form-builder/index.d.ts.map +1 -0
  44. package/dist/form-builder/index.js +2 -0
  45. package/dist/form-builder/index.js.map +1 -0
  46. package/dist/form-builder/mutate-collections.d.ts +4 -0
  47. package/dist/form-builder/mutate-collections.d.ts.map +1 -0
  48. package/dist/form-builder/mutate.d.ts +2 -0
  49. package/dist/form-builder/mutate.d.ts.map +1 -0
  50. package/dist/form-builder/submission.d.ts +34 -0
  51. package/dist/form-builder/submission.d.ts.map +1 -0
  52. package/dist/index.cjs +2 -0
  53. package/dist/index.cjs.map +1 -0
  54. package/dist/index.d.ts +7 -0
  55. package/dist/index.d.ts.map +1 -0
  56. package/dist/index.js +2 -0
  57. package/dist/index.js.map +1 -0
  58. package/dist/plugin.d.ts +3 -0
  59. package/dist/plugin.d.ts.map +1 -0
  60. package/dist/types.d.ts +152 -0
  61. package/dist/types.d.ts.map +1 -0
  62. package/package.json +107 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/form-builder/fields.ts","../src/form-builder/submission.ts","../src/form-builder/hooks.ts","../src/form-builder/mutate-collections.ts"],"sourcesContent":["import type { FieldOverride, MarketingBlockOptions, MarketingFormFieldOverrides } from \"../types\"\nimport type { Block, Field } from \"payload\"\n\nexport const CUSTOM_MARKETING_FIELD_NAMES = [\"url\", \"phone\", \"acceptance\"] as const\n\nfunction mergeField(base: Field, override?: FieldOverride): Field {\n if (!override) {\n return base\n }\n\n const { overrides, ...direct } = override\n return {\n ...base,\n ...direct,\n ...(overrides ?? {}),\n admin: {\n ...(\"admin\" in base ? base.admin : undefined),\n ...(direct.admin ?? {}),\n ...(overrides?.admin ?? {}),\n },\n } as Field\n}\n\nfunction row(fields: Field[]): Field {\n return { type: \"row\", fields } as Field\n}\n\nfunction textLikeBlock(\n slug: \"phone\" | \"url\",\n labels: Required<Block>[\"labels\"],\n options?: MarketingBlockOptions,\n): Block {\n const fields = options?.fields ?? {}\n const block: Block = {\n slug,\n labels: options?.labels ?? labels,\n fields: [\n row([\n mergeField(\n {\n name: \"name\",\n type: \"text\",\n label: \"Name (lowercase, no special characters)\",\n required: true,\n admin: { width: \"50%\" },\n },\n fields.name,\n ),\n mergeField(\n {\n name: \"label\",\n type: \"text\",\n label: \"Label\",\n localized: true,\n admin: { width: \"50%\" },\n },\n fields.label,\n ),\n ]),\n row([\n mergeField(\n {\n name: \"width\",\n type: \"number\",\n label: \"Field Width (percentage)\",\n admin: { width: \"33%\" },\n },\n fields.width,\n ),\n mergeField(\n {\n name: \"placeholder\",\n type: \"text\",\n label: \"Placeholder\",\n localized: true,\n admin: { width: \"33%\" },\n },\n fields.placeholder,\n ),\n mergeField(\n {\n name: \"defaultValue\",\n type: \"text\",\n label: \"Default Value\",\n localized: true,\n admin: { width: \"33%\" },\n },\n fields.defaultValue,\n ),\n ]),\n mergeField({ name: \"required\", type: \"checkbox\", label: \"Required\" }, fields.required),\n ],\n }\n\n return { ...block, ...(options?.overrides ?? {}) }\n}\n\nexport function createAcceptanceBlock(options?: MarketingBlockOptions): Block {\n const fields = options?.fields ?? {}\n const block: Block = {\n slug: \"acceptance\",\n labels: options?.labels ?? { singular: \"Acceptance\", plural: \"Acceptances\" },\n fields: [\n mergeField(\n {\n name: \"name\",\n type: \"text\",\n label: \"Name (lowercase, no special characters)\",\n required: true,\n admin: { width: \"50%\" },\n },\n fields.name,\n ),\n mergeField(\n {\n name: \"label\",\n type: \"richText\",\n label: \"Label\",\n localized: true,\n admin: { width: \"50%\" },\n },\n fields.label,\n ),\n row([\n mergeField(\n {\n name: \"width\",\n type: \"number\",\n label: \"Field Width (percentage)\",\n admin: { width: \"50%\" },\n },\n fields.width,\n ),\n mergeField({ name: \"required\", type: \"checkbox\", label: \"Required\" }, fields.required),\n ]),\n ],\n }\n\n return { ...block, ...(options?.overrides ?? {}) }\n}\n\nexport function createMarketingFormFields(\n overrides: MarketingFormFieldOverrides = {},\n): Record<(typeof CUSTOM_MARKETING_FIELD_NAMES)[number], Block> {\n return {\n url: textLikeBlock(\"url\", { singular: \"URL\", plural: \"URLs\" }, overrides.url || undefined),\n phone: textLikeBlock(\n \"phone\",\n { singular: \"Phone\", plural: \"Phones\" },\n overrides.phone || undefined,\n ),\n acceptance: createAcceptanceBlock(overrides.acceptance || undefined),\n }\n}\n\nexport function createMarketingBlocksForMutation(\n overrides: MarketingFormFieldOverrides = {},\n): Block[] {\n return Object.values(createMarketingFormFields(overrides))\n}\n","export const FORM_HONEYPOT_FIELD = \"__website\"\nexport const FORM_STARTED_AT_FIELD = \"__startedAt\"\nexport const MIN_SUBMISSION_TIME_MS = 1_500\n\nconst MAX_LENGTH_BY_BLOCK: Record<string, number> = {\n acceptance: 5,\n checkbox: 5,\n country: 200,\n date: 100,\n email: 320,\n message: 5_000,\n number: 64,\n payment: 1_000,\n phone: 50,\n select: 200,\n state: 200,\n text: 200,\n textarea: 5_000,\n upload: 1_000,\n url: 2_048,\n}\n\nexport interface ValidationFormField {\n blockType: string\n name?: string | null\n options?: Array<{ value: string }> | null\n required?: boolean | null\n}\n\nexport interface ValidationSubmissionField {\n field?: string | null\n value?: unknown\n}\n\nexport type SubmissionValidationResult =\n | { data: Array<{ field: string; value: string }>; ok: true }\n | { error: string; ok: false }\n\nfunction isControlField(fieldName: string): boolean {\n return fieldName === FORM_HONEYPOT_FIELD || fieldName === FORM_STARTED_AT_FIELD\n}\n\nfunction extractControlFields(submissionData: ValidationSubmissionField[]): {\n honeypot: string\n startedAt: string\n} {\n const honeypot = submissionData.find((entry) => entry.field === FORM_HONEYPOT_FIELD)?.value\n const startedAt = submissionData.find((entry) => entry.field === FORM_STARTED_AT_FIELD)?.value\n return {\n honeypot: typeof honeypot === \"string\" ? honeypot : \"\",\n startedAt:\n typeof startedAt === \"string\" || typeof startedAt === \"number\" ? String(startedAt) : \"\",\n }\n}\n\nfunction stringifySubmissionValue(value: unknown): string {\n if (typeof value === \"boolean\") {\n return String(value)\n }\n if (typeof value === \"number\" && Number.isFinite(value)) {\n return String(value)\n }\n return typeof value === \"string\" ? value.trim() : \"\"\n}\n\nfunction isValidFieldValue(field: ValidationFormField, value: string): boolean {\n if (!value) {\n return !field.required\n }\n if (value.length > (MAX_LENGTH_BY_BLOCK[field.blockType] ?? 1_000)) {\n return false\n }\n if (field.blockType === \"email\") {\n return /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(value)\n }\n if (field.blockType === \"url\") {\n try {\n new URL(value)\n return true\n } catch {\n return false\n }\n }\n if (field.blockType === \"number\") {\n return Number.isFinite(Number(value))\n }\n if (field.blockType === \"checkbox\" || field.blockType === \"acceptance\") {\n return value === \"true\" || value === \"false\"\n }\n if (field.blockType === \"select\" && field.options?.length) {\n return field.options.some((option) => option.value === value)\n }\n return true\n}\n\nfunction requiredValueIsPresent(field: ValidationFormField, value: string | undefined): boolean {\n if (!field.required) {\n return true\n }\n if (field.blockType === \"acceptance\") {\n return value === \"true\"\n }\n return Boolean(value)\n}\n\nexport function validateSubmissionInput(input: {\n formFields: ValidationFormField[]\n now: number\n submissionData: ValidationSubmissionField[] | null | undefined\n}): SubmissionValidationResult {\n const controlFields = extractControlFields(input.submissionData ?? [])\n if (controlFields.honeypot.trim()) {\n return { ok: false, error: \"Invalid submission.\" }\n }\n const startedAt = Number(controlFields.startedAt)\n if (!Number.isFinite(startedAt)) {\n return { ok: false, error: \"Invalid submission.\" }\n }\n if (input.now - startedAt < MIN_SUBMISSION_TIME_MS) {\n return { ok: false, error: \"Form submitted too quickly.\" }\n }\n\n const supportedFields = input.formFields.flatMap((field) =>\n field.name && field.blockType in MAX_LENGTH_BY_BLOCK ? [{ ...field, name: field.name }] : [],\n )\n const formFieldMap = new Map(supportedFields.map((field) => [field.name, field]))\n const normalized: Array<{ field: string; value: string }> = []\n const seenFields = new Set<string>()\n\n for (const entry of input.submissionData ?? []) {\n const fieldName = entry.field?.trim()\n if (!fieldName || isControlField(fieldName)) {\n continue\n }\n if (seenFields.has(fieldName)) {\n return { ok: false, error: `Field \"${fieldName}\" was submitted more than once.` }\n }\n seenFields.add(fieldName)\n const formField = formFieldMap.get(fieldName)\n if (!formField) {\n return { ok: false, error: `Unexpected field \"${fieldName}\".` }\n }\n const value = stringifySubmissionValue(entry.value)\n if (!isValidFieldValue(formField, value)) {\n return { ok: false, error: `Field \"${fieldName}\" is invalid.` }\n }\n normalized.push({ field: fieldName, value })\n }\n\n for (const field of supportedFields) {\n const value = normalized.find((entry) => entry.field === field.name)?.value\n if (!requiredValueIsPresent(field, value)) {\n return { ok: false, error: `Field \"${field.name}\" is required.` }\n }\n }\n\n return { ok: true, data: normalized }\n}\n\nexport function submissionDataToPlainRecord(\n submissionData: ValidationSubmissionField[],\n): Record<string, string> {\n return Object.fromEntries(\n submissionData.flatMap((entry) =>\n entry.field ? [[entry.field, stringifySubmissionValue(entry.value)]] : [],\n ),\n )\n}\n\nexport function substituteSubmissionPlaceholders(\n template: string,\n values: Record<string, string>,\n): string {\n return template.replace(\n /\\{\\{\\s*([\\w.-]+)\\s*\\}\\}/g,\n (_, fieldName: string) => values[fieldName] ?? \"\",\n )\n}\n\nexport function resolveCommaSeparatedSubmissionTags(\n tags: string | null | undefined,\n values: Record<string, string>,\n): string[] {\n return (tags ?? \"\")\n .split(\",\")\n .map((tag) => substituteSubmissionPlaceholders(tag, values).trim())\n .filter(Boolean)\n}\n","import {\n resolveCommaSeparatedSubmissionTags,\n submissionDataToPlainRecord,\n validateSubmissionInput,\n} from \"./submission\"\n\nimport type { MarketingAdapter } from \"../types\"\nimport type { CollectionBeforeChangeHook, PayloadRequest } from \"payload\"\n\ninterface FormSubmissionData {\n form?: unknown\n submissionData?: Array<{ field?: string | null; value?: unknown }>\n}\n\nfunction getStringField(data: FormSubmissionData, field: string): string | undefined {\n const value = data.submissionData?.find((row) => row.field === field)?.value\n if (typeof value === \"string\") {\n return value\n }\n if (value == null) {\n return undefined\n }\n if (typeof value === \"number\" && Number.isFinite(value)) {\n return String(value)\n }\n if (typeof value === \"boolean\") {\n return String(value)\n }\n return undefined\n}\n\ninterface HookOptions {\n formsSlug?: string\n minSubmitDurationMs?: number\n}\n\nasync function resolveMarketingForm(\n data: { form?: unknown },\n req: PayloadRequest,\n formsSlug = \"forms\",\n): Promise<unknown> {\n if (typeof data.form === \"string\") {\n return await req.payload.findByID({\n collection: formsSlug,\n depth: 0,\n id: data.form,\n overrideAccess: true,\n })\n }\n return data.form\n}\n\nexport function createValidateFormSubmissionHook(\n options: HookOptions = {},\n): CollectionBeforeChangeHook {\n return async ({ data, operation, req }) => {\n if (operation !== \"create\") {\n return data\n }\n const form = await resolveMarketingForm(data as { form?: unknown }, req, options.formsSlug)\n const result = validateSubmissionInput({\n formFields: ((form as { fields?: unknown[] } | undefined)?.fields ?? []) as never,\n now: Date.now(),\n submissionData: (data?.submissionData ?? []) as never,\n })\n if (!result.ok) {\n throw new Error(result.error)\n }\n data.submissionData = result.data\n return data\n }\n}\n\nexport function createCreateLeadHook(\n adapter: MarketingAdapter,\n options: HookOptions = {},\n): CollectionBeforeChangeHook {\n return async ({ data, operation, req }) => {\n if (operation !== \"create\") {\n return data\n }\n const form = await resolveMarketingForm(data as { form?: unknown }, req, options.formsSlug)\n const formRecord = form as\n | { audienceId?: string; event?: string; tags?: string | null }\n | undefined\n if (formRecord?.event !== \"lead\" || !formRecord.audienceId) {\n return data\n }\n\n const submission = data as FormSubmissionData\n const email = getStringField(submission, \"email\")\n if (!email) {\n return data\n }\n\n const fieldValues = submissionDataToPlainRecord(submission.submissionData ?? [])\n const tags = resolveCommaSeparatedSubmissionTags(formRecord.tags, fieldValues)\n await adapter.contacts.upsert({\n audienceId: formRecord.audienceId,\n email,\n firstName: getStringField(submission, \"firstName\"),\n lastName: getStringField(submission, \"lastName\"),\n properties: tags.length > 0 ? { tags: tags.join(\",\") } : undefined,\n subscribed: true,\n })\n return data\n }\n}\n","import { createMarketingFormFields } from \"./fields\"\nimport { createCreateLeadHook, createValidateFormSubmissionHook } from \"./hooks\"\n\nimport type { PayloadPluginMarketingOptions } from \"../types\"\nimport type { CollectionConfig, Field } from \"payload\"\n\nfunction isNamedField(field: Field, name: string): field is Field & { name: string } {\n return \"name\" in field && field.name === name\n}\n\nfunction hasSlug(item: unknown): item is { slug: string } {\n return Boolean(\n item && typeof item === \"object\" && \"slug\" in item && typeof item.slug === \"string\",\n )\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return Boolean(value && typeof value === \"object\")\n}\n\nfunction upsertField(fields: Field[], field: Field): Field[] {\n if (!(\"name\" in field) || !field.name) {\n return [...fields, field]\n }\n return fields.some((existing) => isNamedField(existing, field.name))\n ? fields.map((existing) => (isNamedField(existing, field.name) ? field : existing))\n : [...fields, field]\n}\n\nfunction createMarketingConfigFields(options: PayloadPluginMarketingOptions): Field[] {\n const audienceSelect = options.admin?.components?.audienceSelect ?? {\n path: \"payload-plugin-marketing/admin\",\n exportName: \"AudienceSelect\",\n }\n return [\n {\n name: \"event\",\n type: \"select\",\n defaultValue: \"submission\",\n options: [\n { label: \"Submission\", value: \"submission\" },\n { label: \"Lead\", value: \"lead\" },\n ],\n },\n {\n name: \"audienceId\",\n type: \"text\",\n label: \"Audience ID\",\n required: false,\n admin: {\n condition: (_data, siblingData) => siblingData?.event === \"lead\",\n components: { Field: audienceSelect },\n },\n validate: (value: unknown, { siblingData }: { siblingData?: { event?: string } } = {}) =>\n siblingData?.event === \"lead\" && !value ? \"Audience is required for lead forms.\" : true,\n },\n {\n name: \"tags\",\n type: \"textarea\",\n label: \"Tags\",\n admin: {\n condition: (_data, siblingData) => siblingData?.event === \"lead\",\n description: \"Optional comma-separated tags. Use {{fieldName}} to insert submitted values.\",\n },\n },\n ] as Field[]\n}\n\nfunction mutateFormsCollection(\n collection: CollectionConfig,\n options: PayloadPluginMarketingOptions,\n): CollectionConfig {\n const fields = [...collection.fields]\n const fieldsIndex = fields.findIndex(\n (field) => isNamedField(field, \"fields\") && field.type === \"blocks\",\n )\n if (fieldsIndex < 0) {\n if (options.formBuilder?.strict === false) {\n return collection\n }\n throw new Error(\n `Could not find a blocks field named \"fields\" on form-builder forms collection \"${collection.slug}\".`,\n )\n }\n\n const fieldsField = fields[fieldsIndex] as Field & { blocks: unknown[] }\n const existingBlocks = Array.isArray(fieldsField.blocks) ? fieldsField.blocks : []\n const blockOverrides = options.formBuilder?.fields ?? {}\n const overriddenExistingBlocks = existingBlocks.map((block) => {\n if (!hasSlug(block)) {\n return block\n }\n const override = blockOverrides[block.slug as keyof typeof blockOverrides]\n if (!override || !isRecord(block)) {\n return block\n }\n return {\n ...block,\n ...(override.overrides ?? {}),\n ...(override.labels ? { labels: override.labels } : {}),\n }\n })\n const existingSlugs = new Set(\n overriddenExistingBlocks.flatMap((block) => (hasSlug(block) ? [block.slug] : [])),\n )\n const marketingBlocks = Object.values(\n createMarketingFormFields(options.formBuilder?.fields),\n ).filter((block) => !existingSlugs.has(block.slug))\n\n fields[fieldsIndex] = {\n ...fieldsField,\n blocks: [...overriddenExistingBlocks, ...marketingBlocks],\n } as Field\n\n for (const field of createMarketingConfigFields(options)) {\n fields.splice(0, fields.length, ...upsertField(fields, field))\n }\n\n return { ...collection, fields }\n}\n\nfunction mutateSubmissionsCollection(\n collection: CollectionConfig,\n options: PayloadPluginMarketingOptions,\n): CollectionConfig {\n const hooks = collection.hooks ?? {}\n return {\n ...collection,\n hooks: {\n ...hooks,\n beforeChange: [\n ...(hooks.beforeChange ?? []),\n createValidateFormSubmissionHook({ formsSlug: options.formBuilder?.formsSlug }),\n createCreateLeadHook(options.adapter, { formsSlug: options.formBuilder?.formsSlug }),\n ],\n },\n }\n}\n\nexport function mutateFormBuilderCollections(\n collections: CollectionConfig[] | undefined,\n options: PayloadPluginMarketingOptions,\n): CollectionConfig[] | undefined {\n const formsSlug = options.formBuilder?.formsSlug ?? \"forms\"\n const submissionsSlug = options.formBuilder?.submissionsSlug ?? \"form-submissions\"\n const strict = options.formBuilder?.strict ?? true\n const list = collections ?? []\n const hasForms = list.some((collection) => collection.slug === formsSlug)\n const hasSubmissions = list.some((collection) => collection.slug === submissionsSlug)\n\n if (strict && !hasForms) {\n throw new Error(`Could not find form-builder forms collection \"${formsSlug}\".`)\n }\n if (strict && !hasSubmissions) {\n throw new Error(`Could not find form-builder submissions collection \"${submissionsSlug}\".`)\n }\n\n return list.map((collection) => {\n if (collection.slug === formsSlug) {\n return mutateFormsCollection(collection, options)\n }\n if (collection.slug === submissionsSlug) {\n return mutateSubmissionsCollection(collection, options)\n }\n return collection\n })\n}\n"],"mappings":"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","names":["mergeField","base","override","overrides","direct","row","fields","textLikeBlock","slug","labels","options","createAcceptanceBlock","createMarketingFormFields","FORM_HONEYPOT_FIELD","FORM_STARTED_AT_FIELD","MIN_SUBMISSION_TIME_MS","MAX_LENGTH_BY_BLOCK","isControlField","fieldName","extractControlFields","submissionData","honeypot","entry","startedAt","stringifySubmissionValue","value","isValidFieldValue","field","option","requiredValueIsPresent","validateSubmissionInput","input","controlFields","supportedFields","formFieldMap","normalized","seenFields","formField","submissionDataToPlainRecord","substituteSubmissionPlaceholders","template","values","_","resolveCommaSeparatedSubmissionTags","tags","tag","getStringField","data","field","value","row","resolveMarketingForm","req","formsSlug","createValidateFormSubmissionHook","options","operation","form","result","validateSubmissionInput","createCreateLeadHook","adapter","formRecord","submission","email","fieldValues","submissionDataToPlainRecord","tags","resolveCommaSeparatedSubmissionTags","isNamedField","field","name","hasSlug","item","isRecord","value","upsertField","fields","existing","createMarketingConfigFields","options","audienceSelect","_data","siblingData","mutateFormsCollection","collection","fieldsIndex","fieldsField","existingBlocks","blockOverrides","overriddenExistingBlocks","block","override","existingSlugs","marketingBlocks","createMarketingFormFields","mutateSubmissionsCollection","hooks","createValidateFormSubmissionHook","createCreateLeadHook","mutateFormBuilderCollections","collections","formsSlug","submissionsSlug","strict","list","hasForms","hasSubmissions"]}
@@ -0,0 +1,2 @@
1
+ import{createHash as w}from"crypto";function p(n){return w("md5").update(n.toLowerCase()).digest("hex")}function f(n){let a=n.includes("-")?n.split("-").pop():void 0;if(!a)throw new Error("MAILCHIMP_API_KEY must include a datacenter suffix (e.g. key-us21).");return a}function y(n){let a=n?.tags;return a==null?[]:String(a).split(",").map(e=>e.trim()).filter(Boolean)}function o(n,a=""){return typeof n=="string"?n:typeof n=="number"&&Number.isFinite(n)?String(n):a}function b(n){let a=!1,e=async()=>{let t=n.client??(await import("@mailchimp/mailchimp_marketing")).default;return a||(t.setConfig({apiKey:n.apiKey,server:f(n.apiKey)}),a=!0),t},r=`https://${f(n.apiKey)}.admin.mailchimp.com`;return{provider:"mailchimp",label:"Mailchimp",urls:{audiences:`${r}/audience/`,broadcasts:`${r}/campaigns/`},audiences:{async create(t){await(await e()).lists.createList({name:t.name,permission_reminder:`You're receiving this email because you opted in via ${n.siteName}.`,email_type_option:!0,contact:{company:n.siteName,address1:"Address on file",city:"N/A",state:"N/A",zip:"00000",country:"US"},campaign_defaults:{from_name:n.siteName,from_email:n.defaultSender,subject:" ",language:"en"}})},async delete(t){await(await e()).lists.deleteList(t.audienceId)},async get(t){let s=await(await e()).lists.getList(t);return{id:s.id,name:s.name}},async list(){return((await(await e()).lists.getAllLists({count:500})).lists??[]).map(s=>({id:s.id,name:s.name}))}},contacts:{async delete(t){await(await e()).lists.deleteListMember(t.audienceId,t.contactId)},async list(t){return((await(await e()).lists.getListMembersInfo(t.audienceId)).members??[]).map(i=>{let d=i.merge_fields;return{createdAt:typeof i.timestamp_signup=="string"?i.timestamp_signup:void 0,email:o(i.email_address),firstName:typeof d?.FNAME=="string"?d.FNAME:null,id:o(i.id,o(i.email_address)),lastName:typeof d?.LNAME=="string"?d.LNAME:null,subscribed:i.status==="subscribed"}})},async upsert(t){let s=await e(),i=t.id??p(t.email),d=t.id?t.subscribed?"subscribed":"unsubscribed":t.subscribed?"subscribed":"pending";await s.lists.setListMember(t.audienceId,i,{email_address:t.email,status:d,merge_fields:{FNAME:t.firstName??"",LNAME:t.lastName??""}},{skipMergeValidation:!0});let m=y(t.properties);m.length>0&&await s.lists.updateListMemberTags(t.audienceId,p(t.email),{tags:m.map(l=>({name:l,status:"active"}))})}},broadcasts:{async create(t){let s=await e(),i=t.templateId!=null&&String(t.templateId).trim()!==""?String(t.templateId).trim():void 0,d;if(i!=null){let l=t.html;if(l!=null&&l!=="")throw new Error("Mailchimp broadcast: use either templateId (cloud template) or html, not both.");let g=Number.parseInt(i,10);if(!Number.isFinite(g))throw new Error(`Invalid Mailchimp template id: "${i}".`);d=g}let m=await s.campaigns.create({type:"regular",recipients:{list_id:t.audienceId},settings:{authenticate:!0,auto_footer:!1,from_email:n.defaultSender,from_name:n.siteName,inline_css:!1,reply_to:t.replyTo?.trim()||n.defaultSender,subject_line:t.subject,title:t.name,to_name:"*|FNAME|*"}});if(!m.id)throw new Error("Mailchimp did not return a campaign id.");d!=null?await s.campaigns.setContent(m.id,{template:{id:d}}):await s.campaigns.setContent(m.id,{html:t.html??""})},async delete(t){await(await e()).campaigns.remove(t.broadcastId)},async list(){return((await(await e()).campaigns.list({count:500})).campaigns??[]).map(s=>{let i=s.settings,d=typeof s.send_time=="string"?s.send_time:null;return{id:o(s.id),name:o(i?.title,o(s.id)),scheduledAt:d,sentAt:d,status:s.status==="save"?"draft":o(s.status,"draft")}})},async send(t){let s=await e(),i=t.scheduledAt?.trim();i?await s.campaigns.schedule(t.broadcastId,{schedule_time:i}):await s.campaigns.send(t.broadcastId)}}}}function c(n){let a=typeof n=="object"&&n&&"error"in n?n.error:void 0;if(a&&typeof a=="object"&&"message"in a)throw new Error(String(a.message))}function u(n,a){return typeof n=="string"?n:typeof n=="number"&&Number.isFinite(n)?String(n):a}function h(n){return{id:u(n.id,""),name:u(n.name,""),scheduledAt:typeof n.scheduled_at=="string"?n.scheduled_at:null,sentAt:typeof n.sent_at=="string"?n.sent_at:null,status:u(n.status,"draft")}}function k(n){let a=async()=>{if(n.client)return n.client;let e=await import("resend");return new e.Resend(n.apiKey)};return{provider:"resend",label:"Resend",urls:{audiences:"https://resend.com/audiences",audience:e=>`https://resend.com/audiences/${e}`,broadcasts:"https://resend.com/broadcasts",broadcast:e=>`https://resend.com/broadcasts/${e}`},audiences:{async create(e){c(await(await a()).segments.create({name:e.name}))},async delete(e){c(await(await a()).segments.remove(e.audienceId))},async get(e){let r=await(await a()).segments.get(e);return c(r),r.data?{id:r.data.id,name:r.data.name}:null},async list(){let e=await(await a()).segments.list();return c(e),e.data?.data??[]}},contacts:{async delete(e){c(await(await a()).contacts.remove({audienceId:e.audienceId,id:e.contactId}))},async list(e){let r=await(await a()).contacts.list({audienceId:e.audienceId});return c(r),(r.data?.data??[]).map(t=>({createdAt:typeof t.created_at=="string"?t.created_at:void 0,email:u(t.email,""),firstName:typeof t.first_name=="string"?t.first_name:null,id:String(t.id),lastName:typeof t.last_name=="string"?t.last_name:null,subscribed:t.unsubscribed===!1}))},async upsert(e){let r=await a(),t=!e.subscribed,s={audienceId:e.audienceId,email:e.email,firstName:e.firstName,lastName:e.lastName,unsubscribed:t};c(e.id?await r.contacts.update({...s,id:e.id}):await r.contacts.create(s))}},broadcasts:{async create(e){if(e.templateId!=null&&String(e.templateId).trim()!=="")throw new Error("Resend broadcasts do not support templateId; use html or react, or use the Mailchimp adapter for cloud templates.");c(await(await a()).broadcasts.create({audienceId:e.audienceId,from:n.defaultSender,html:e.html,name:e.name,react:e.react,replyTo:e.replyTo,subject:e.subject}))},async delete(e){c(await(await a()).broadcasts.remove(e.broadcastId))},async list(){let e=await(await a()).broadcasts.list();return c(e),(e.data?.data??[]).map(r=>h(r))},async send(e){c(await(await a()).broadcasts.send(e.broadcastId,{scheduledAt:e.scheduledAt}))}}}}export{b as a,k as b};
2
+ //# sourceMappingURL=chunk-KBN7IE22.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/adapters/mailchimp.ts","../src/adapters/resend.ts"],"sourcesContent":["import { createHash } from \"node:crypto\"\n\nimport type { MarketingAdapter } from \"../types\"\n\ninterface MailchimpLike {\n campaigns: {\n create(input: unknown): Promise<{ id?: string }>\n list(input?: unknown): Promise<{ campaigns?: Array<Record<string, unknown>> }>\n remove(id: string): Promise<unknown>\n schedule(id: string, input: unknown): Promise<unknown>\n send(id: string): Promise<unknown>\n setContent(id: string, input: unknown): Promise<unknown>\n }\n lists: {\n createList(input: unknown): Promise<unknown>\n deleteList(id: string): Promise<unknown>\n deleteListMember(listId: string, contactId: string): Promise<unknown>\n getAllLists(input?: unknown): Promise<{ lists?: Array<{ id: string; name: string }> }>\n getList(id: string): Promise<{ id: string; name: string }>\n getListMembersInfo(input: string): Promise<{ members?: Array<Record<string, unknown>> }>\n setListMember(listId: string, hash: string, input: unknown, options?: unknown): Promise<unknown>\n updateListMemberTags(listId: string, hash: string, input: unknown): Promise<unknown>\n }\n setConfig(input: unknown): void\n}\n\nexport interface MailchimpAdapterOptions {\n apiKey: string\n client?: MailchimpLike\n defaultSender: string\n siteName: string\n}\n\nfunction subscriberHash(email: string): string {\n return createHash(\"md5\").update(email.toLowerCase()).digest(\"hex\")\n}\n\nfunction serverFromApiKey(apiKey: string): string {\n const server = apiKey.includes(\"-\") ? apiKey.split(\"-\").pop() : undefined\n if (!server) {\n throw new Error(\"MAILCHIMP_API_KEY must include a datacenter suffix (e.g. key-us21).\")\n }\n return server\n}\n\nfunction tagNamesFromProperties(properties?: Record<string, string | number | null>): string[] {\n const raw = properties?.tags\n if (raw == null) {\n return []\n }\n return String(raw)\n .split(\",\")\n .map((tag) => tag.trim())\n .filter(Boolean)\n}\n\nfunction stringValue(value: unknown, fallback = \"\"): string {\n if (typeof value === \"string\") {\n return value\n }\n if (typeof value === \"number\" && Number.isFinite(value)) {\n return String(value)\n }\n return fallback\n}\n\nexport function mailchimpAdapter(options: MailchimpAdapterOptions): MarketingAdapter {\n let configured = false\n const getClient = async (): Promise<MailchimpLike> => {\n const client =\n options.client ??\n ((await import(\"@mailchimp/mailchimp_marketing\")) as { default: MailchimpLike }).default\n if (!configured) {\n client.setConfig({ apiKey: options.apiKey, server: serverFromApiKey(options.apiKey) })\n configured = true\n }\n return client\n }\n const adminBase = `https://${serverFromApiKey(options.apiKey)}.admin.mailchimp.com`\n\n return {\n provider: \"mailchimp\",\n label: \"Mailchimp\",\n urls: {\n audiences: `${adminBase}/audience/`,\n broadcasts: `${adminBase}/campaigns/`,\n },\n audiences: {\n async create(input) {\n await (\n await getClient()\n ).lists.createList({\n name: input.name,\n permission_reminder: `You're receiving this email because you opted in via ${options.siteName}.`,\n email_type_option: true,\n contact: {\n company: options.siteName,\n address1: \"Address on file\",\n city: \"N/A\",\n state: \"N/A\",\n zip: \"00000\",\n country: \"US\",\n },\n campaign_defaults: {\n from_name: options.siteName,\n from_email: options.defaultSender,\n subject: \" \",\n language: \"en\",\n },\n })\n },\n async delete(input) {\n await (await getClient()).lists.deleteList(input.audienceId)\n },\n async get(id) {\n const list = await (await getClient()).lists.getList(id)\n return { id: list.id, name: list.name }\n },\n async list() {\n const result = await (await getClient()).lists.getAllLists({ count: 500 })\n return (result.lists ?? []).map((list) => ({ id: list.id, name: list.name }))\n },\n },\n contacts: {\n async delete(input) {\n await (await getClient()).lists.deleteListMember(input.audienceId, input.contactId)\n },\n async list(input) {\n const result = await (await getClient()).lists.getListMembersInfo(input.audienceId)\n return (result.members ?? []).map((member) => {\n const mergeFields = member.merge_fields as Record<string, unknown> | undefined\n return {\n createdAt:\n typeof member.timestamp_signup === \"string\" ? member.timestamp_signup : undefined,\n email: stringValue(member.email_address),\n firstName: typeof mergeFields?.FNAME === \"string\" ? mergeFields.FNAME : null,\n id: stringValue(member.id, stringValue(member.email_address)),\n lastName: typeof mergeFields?.LNAME === \"string\" ? mergeFields.LNAME : null,\n subscribed: member.status === \"subscribed\",\n }\n })\n },\n async upsert(input) {\n const client = await getClient()\n const hash = input.id ?? subscriberHash(input.email)\n const status = input.id\n ? input.subscribed\n ? \"subscribed\"\n : \"unsubscribed\"\n : input.subscribed\n ? \"subscribed\"\n : \"pending\"\n await client.lists.setListMember(\n input.audienceId,\n hash,\n {\n email_address: input.email,\n status,\n merge_fields: { FNAME: input.firstName ?? \"\", LNAME: input.lastName ?? \"\" },\n },\n { skipMergeValidation: true },\n )\n const tags = tagNamesFromProperties(input.properties)\n if (tags.length > 0) {\n await client.lists.updateListMemberTags(input.audienceId, subscriberHash(input.email), {\n tags: tags.map((name) => ({ name, status: \"active\" })),\n })\n }\n },\n },\n broadcasts: {\n async create(input) {\n const client = await getClient()\n const templateIdRaw =\n input.templateId != null && String(input.templateId).trim() !== \"\"\n ? String(input.templateId).trim()\n : undefined\n let templateIdParsed: number | undefined\n if (templateIdRaw != null) {\n const html = input.html\n if (html != null && html !== \"\") {\n throw new Error(\n \"Mailchimp broadcast: use either templateId (cloud template) or html, not both.\",\n )\n }\n const parsed = Number.parseInt(templateIdRaw, 10)\n if (!Number.isFinite(parsed)) {\n throw new Error(`Invalid Mailchimp template id: \"${templateIdRaw}\".`)\n }\n templateIdParsed = parsed\n }\n const campaign = await client.campaigns.create({\n type: \"regular\",\n recipients: { list_id: input.audienceId },\n settings: {\n authenticate: true,\n auto_footer: false,\n from_email: options.defaultSender,\n from_name: options.siteName,\n inline_css: false,\n reply_to: input.replyTo?.trim() || options.defaultSender,\n subject_line: input.subject,\n title: input.name,\n to_name: \"*|FNAME|*\",\n },\n })\n if (!campaign.id) {\n throw new Error(\"Mailchimp did not return a campaign id.\")\n }\n if (templateIdParsed != null) {\n await client.campaigns.setContent(campaign.id, {\n template: { id: templateIdParsed },\n })\n } else {\n await client.campaigns.setContent(campaign.id, { html: input.html ?? \"\" })\n }\n },\n async delete(input) {\n await (await getClient()).campaigns.remove(input.broadcastId)\n },\n async list() {\n const result = await (await getClient()).campaigns.list({ count: 500 })\n return (result.campaigns ?? []).map((campaign) => {\n const settings = campaign.settings as Record<string, unknown> | undefined\n const sentAt = typeof campaign.send_time === \"string\" ? campaign.send_time : null\n return {\n id: stringValue(campaign.id),\n name: stringValue(settings?.title, stringValue(campaign.id)),\n scheduledAt: sentAt,\n sentAt,\n status: campaign.status === \"save\" ? \"draft\" : stringValue(campaign.status, \"draft\"),\n }\n })\n },\n async send(input) {\n const client = await getClient()\n const scheduledAt = input.scheduledAt?.trim()\n if (scheduledAt) {\n await client.campaigns.schedule(input.broadcastId, { schedule_time: scheduledAt })\n } else {\n await client.campaigns.send(input.broadcastId)\n }\n },\n },\n }\n}\n","import type { MarketingAdapter, MarketingBroadcast } from \"../types\"\n\ninterface ResendLike {\n broadcasts: {\n create(input: unknown): Promise<unknown>\n list(): Promise<{\n data?: { data?: Array<Record<string, unknown>> }\n error?: { message?: string }\n }>\n remove(id: string): Promise<unknown>\n send(id: string, input: unknown): Promise<unknown>\n }\n contacts: {\n create(input: unknown): Promise<{ data?: { id?: string }; error?: { message?: string } }>\n list(\n input: unknown,\n ): Promise<{ data?: { data?: Array<Record<string, unknown>> }; error?: { message?: string } }>\n remove(input: unknown): Promise<unknown>\n update(input: unknown): Promise<unknown>\n }\n segments: {\n create(input: unknown): Promise<unknown>\n get(id: string): Promise<{ data?: { id: string; name: string }; error?: { message?: string } }>\n list(): Promise<{\n data?: { data?: Array<{ id: string; name: string }> }\n error?: { message?: string }\n }>\n remove(id: string): Promise<unknown>\n }\n}\n\nexport interface ResendAdapterOptions {\n apiKey?: string\n client?: ResendLike\n defaultSender?: string\n}\n\nfunction assertNoResendError(result: unknown) {\n const error = typeof result === \"object\" && result && \"error\" in result ? result.error : undefined\n if (error && typeof error === \"object\" && \"message\" in error) {\n throw new Error(String(error.message))\n }\n}\n\nfunction stringifyFromRecord(value: unknown, fallback: string): string {\n if (typeof value === \"string\") {\n return value\n }\n if (typeof value === \"number\" && Number.isFinite(value)) {\n return String(value)\n }\n return fallback\n}\n\nfunction mapBroadcast(row: Record<string, unknown>): MarketingBroadcast {\n return {\n id: stringifyFromRecord(row.id, \"\"),\n name: stringifyFromRecord(row.name, \"\"),\n scheduledAt: typeof row.scheduled_at === \"string\" ? row.scheduled_at : null,\n sentAt: typeof row.sent_at === \"string\" ? row.sent_at : null,\n status: stringifyFromRecord(row.status, \"draft\"),\n }\n}\n\nexport function resendAdapter(options: ResendAdapterOptions): MarketingAdapter {\n const getClient = async (): Promise<ResendLike> => {\n if (options.client) {\n return options.client\n }\n const resendModule = (await import(\"resend\")) as { Resend: new (key?: string) => unknown }\n return new resendModule.Resend(options.apiKey) as ResendLike\n }\n\n return {\n provider: \"resend\",\n label: \"Resend\",\n urls: {\n audiences: \"https://resend.com/audiences\",\n audience: (id) => `https://resend.com/audiences/${id}`,\n broadcasts: \"https://resend.com/broadcasts\",\n broadcast: (id) => `https://resend.com/broadcasts/${id}`,\n },\n audiences: {\n async create(input) {\n assertNoResendError(await (await getClient()).segments.create({ name: input.name }))\n },\n async delete(input) {\n assertNoResendError(await (await getClient()).segments.remove(input.audienceId))\n },\n async get(id) {\n const result = await (await getClient()).segments.get(id)\n assertNoResendError(result)\n return result.data ? { id: result.data.id, name: result.data.name } : null\n },\n async list() {\n const result = await (await getClient()).segments.list()\n assertNoResendError(result)\n return result.data?.data ?? []\n },\n },\n contacts: {\n async delete(input) {\n assertNoResendError(\n await (\n await getClient()\n ).contacts.remove({ audienceId: input.audienceId, id: input.contactId }),\n )\n },\n async list(input) {\n const result = await (await getClient()).contacts.list({ audienceId: input.audienceId })\n assertNoResendError(result)\n return (result.data?.data ?? []).map((row) => ({\n createdAt: typeof row.created_at === \"string\" ? row.created_at : undefined,\n email: stringifyFromRecord(row.email, \"\"),\n firstName: typeof row.first_name === \"string\" ? row.first_name : null,\n id: String(row.id),\n lastName: typeof row.last_name === \"string\" ? row.last_name : null,\n subscribed: row.unsubscribed === false,\n }))\n },\n async upsert(input) {\n const client = await getClient()\n const unsubscribed = !input.subscribed\n const payload = {\n audienceId: input.audienceId,\n email: input.email,\n firstName: input.firstName,\n lastName: input.lastName,\n unsubscribed,\n }\n assertNoResendError(\n input.id\n ? await client.contacts.update({ ...payload, id: input.id })\n : await client.contacts.create(payload),\n )\n },\n },\n broadcasts: {\n async create(input) {\n if (input.templateId != null && String(input.templateId).trim() !== \"\") {\n throw new Error(\n \"Resend broadcasts do not support templateId; use html or react, or use the Mailchimp adapter for cloud templates.\",\n )\n }\n assertNoResendError(\n await (\n await getClient()\n ).broadcasts.create({\n audienceId: input.audienceId,\n from: options.defaultSender,\n html: input.html,\n name: input.name,\n react: input.react,\n replyTo: input.replyTo,\n subject: input.subject,\n }),\n )\n },\n async delete(input) {\n assertNoResendError(await (await getClient()).broadcasts.remove(input.broadcastId))\n },\n async list() {\n const result = await (await getClient()).broadcasts.list()\n assertNoResendError(result)\n return (result.data?.data ?? []).map((row) => mapBroadcast(row))\n },\n async send(input) {\n assertNoResendError(\n await (\n await getClient()\n ).broadcasts.send(input.broadcastId, { scheduledAt: input.scheduledAt }),\n )\n },\n },\n }\n}\n"],"mappings":"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","names":["createHash","subscriberHash","email","serverFromApiKey","apiKey","server","tagNamesFromProperties","properties","raw","tag","stringValue","value","fallback","mailchimpAdapter","options","configured","getClient","client","adminBase","input","id","list","member","mergeFields","hash","status","tags","name","templateIdRaw","templateIdParsed","html","parsed","campaign","settings","sentAt","scheduledAt","assertNoResendError","result","error","stringifyFromRecord","value","fallback","mapBroadcast","row","resendAdapter","options","getClient","resendModule","id","input","client","unsubscribed","payload"]}
@@ -0,0 +1,2 @@
1
+ function a({adapter:t}){return{async createAudience(e){return await t.audiences.create(e),!0},async createBroadcast(e){return await t.broadcasts.create(e),!0},async deleteAudience(e){return await t.audiences.delete(e),!0},async deleteBroadcast(e){return await t.broadcasts.delete(e),!0},async deleteContact(e){return await t.contacts.delete(e),!0},async newsletterSubscribe(e){let n=e.audienceId??(await t.audiences.list())[0]?.id;if(!n)throw new Error("No audience found. Create one in the admin first.");return await t.contacts.upsert({audienceId:n,email:e.email,subscribed:!0}),!0},async sendBroadcast(e){return await t.broadcasts.send(e),!0},async updateContact(e){return await t.contacts.upsert(e),!0}}}export{a};
2
+ //# sourceMappingURL=chunk-RBBHOL35.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/actions/factories.ts"],"sourcesContent":["import type {\n CreateAudienceInput,\n CreateBroadcastInput,\n DeleteAudienceInput,\n DeleteBroadcastInput,\n DeleteContactInput,\n MarketingAdapter,\n SendBroadcastInput,\n UpsertContactInput,\n} from \"../types\"\n\nexport interface CreateMarketingActionsOptions {\n adapter: MarketingAdapter\n}\n\nexport function createMarketingActions({ adapter }: CreateMarketingActionsOptions) {\n return {\n async createAudience(input: CreateAudienceInput) {\n await adapter.audiences.create(input)\n return true\n },\n async createBroadcast(input: CreateBroadcastInput) {\n await adapter.broadcasts.create(input)\n return true\n },\n async deleteAudience(input: DeleteAudienceInput) {\n await adapter.audiences.delete(input)\n return true\n },\n async deleteBroadcast(input: DeleteBroadcastInput) {\n await adapter.broadcasts.delete(input)\n return true\n },\n async deleteContact(input: DeleteContactInput) {\n await adapter.contacts.delete(input)\n return true\n },\n async newsletterSubscribe(input: { audienceId?: string; email: string }) {\n const audienceId = input.audienceId ?? (await adapter.audiences.list())[0]?.id\n if (!audienceId) {\n throw new Error(\"No audience found. Create one in the admin first.\")\n }\n await adapter.contacts.upsert({ audienceId, email: input.email, subscribed: true })\n return true\n },\n async sendBroadcast(input: SendBroadcastInput) {\n await adapter.broadcasts.send(input)\n return true\n },\n async updateContact(input: UpsertContactInput) {\n await adapter.contacts.upsert(input)\n return true\n },\n }\n}\n"],"mappings":"AAeO,SAASA,EAAuB,CAAE,QAAAC,CAAQ,EAAkC,CACjF,MAAO,CACL,MAAM,eAAeC,EAA4B,CAC/C,aAAMD,EAAQ,UAAU,OAAOC,CAAK,EAC7B,EACT,EACA,MAAM,gBAAgBA,EAA6B,CACjD,aAAMD,EAAQ,WAAW,OAAOC,CAAK,EAC9B,EACT,EACA,MAAM,eAAeA,EAA4B,CAC/C,aAAMD,EAAQ,UAAU,OAAOC,CAAK,EAC7B,EACT,EACA,MAAM,gBAAgBA,EAA6B,CACjD,aAAMD,EAAQ,WAAW,OAAOC,CAAK,EAC9B,EACT,EACA,MAAM,cAAcA,EAA2B,CAC7C,aAAMD,EAAQ,SAAS,OAAOC,CAAK,EAC5B,EACT,EACA,MAAM,oBAAoBA,EAA+C,CACvE,IAAMC,EAAaD,EAAM,aAAe,MAAMD,EAAQ,UAAU,KAAK,GAAG,CAAC,GAAG,GAC5E,GAAI,CAACE,EACH,MAAM,IAAI,MAAM,mDAAmD,EAErE,aAAMF,EAAQ,SAAS,OAAO,CAAE,WAAAE,EAAY,MAAOD,EAAM,MAAO,WAAY,EAAK,CAAC,EAC3E,EACT,EACA,MAAM,cAAcA,EAA2B,CAC7C,aAAMD,EAAQ,WAAW,KAAKC,CAAK,EAC5B,EACT,EACA,MAAM,cAAcA,EAA2B,CAC7C,aAAMD,EAAQ,SAAS,OAAOC,CAAK,EAC5B,EACT,CACF,CACF","names":["createMarketingActions","adapter","input","audienceId"]}
@@ -0,0 +1,7 @@
1
+ import type { MarketingBlockOptions, MarketingFormFieldOverrides } from "../types";
2
+ import type { Block } from "payload";
3
+ export declare const CUSTOM_MARKETING_FIELD_NAMES: readonly ["url", "phone", "acceptance"];
4
+ export declare function createAcceptanceBlock(options?: MarketingBlockOptions): Block;
5
+ export declare function createMarketingFormFields(overrides?: MarketingFormFieldOverrides): Record<(typeof CUSTOM_MARKETING_FIELD_NAMES)[number], Block>;
6
+ export declare function createMarketingBlocksForMutation(overrides?: MarketingFormFieldOverrides): Block[];
7
+ //# sourceMappingURL=fields.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fields.d.ts","sourceRoot":"","sources":["../../src/form-builder/fields.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAiB,qBAAqB,EAAE,2BAA2B,EAAE,MAAM,UAAU,CAAA;AACjG,OAAO,KAAK,EAAE,KAAK,EAAS,MAAM,SAAS,CAAA;AAE3C,eAAO,MAAM,4BAA4B,yCAA0C,CAAA;AA8FnF,wBAAgB,qBAAqB,CAAC,OAAO,CAAC,EAAE,qBAAqB,GAAG,KAAK,CA0C5E;AAED,wBAAgB,yBAAyB,CACvC,SAAS,GAAE,2BAAgC,GAC1C,MAAM,CAAC,CAAC,OAAO,4BAA4B,CAAC,CAAC,MAAM,CAAC,EAAE,KAAK,CAAC,CAU9D;AAED,wBAAgB,gCAAgC,CAC9C,SAAS,GAAE,2BAAgC,GAC1C,KAAK,EAAE,CAET"}
@@ -0,0 +1,10 @@
1
+ import type { MarketingAdapter } from "../types";
2
+ import type { CollectionBeforeChangeHook } from "payload";
3
+ interface HookOptions {
4
+ formsSlug?: string;
5
+ minSubmitDurationMs?: number;
6
+ }
7
+ export declare function createValidateFormSubmissionHook(options?: HookOptions): CollectionBeforeChangeHook;
8
+ export declare function createCreateLeadHook(adapter: MarketingAdapter, options?: HookOptions): CollectionBeforeChangeHook;
9
+ export {};
10
+ //# sourceMappingURL=hooks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../../src/form-builder/hooks.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAA;AAChD,OAAO,KAAK,EAAE,0BAA0B,EAAkB,MAAM,SAAS,CAAA;AAwBzE,UAAU,WAAW;IACnB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,mBAAmB,CAAC,EAAE,MAAM,CAAA;CAC7B;AAkBD,wBAAgB,gCAAgC,CAC9C,OAAO,GAAE,WAAgB,GACxB,0BAA0B,CAiB5B;AAED,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,gBAAgB,EACzB,OAAO,GAAE,WAAgB,GACxB,0BAA0B,CA+B5B"}
@@ -0,0 +1,2 @@
1
+ "use strict";var w=Object.defineProperty;var D=Object.getOwnPropertyDescriptor;var N=Object.getOwnPropertyNames;var V=Object.prototype.hasOwnProperty;var E=(e,n)=>{for(var r in n)w(e,r,{get:n[r],enumerable:!0})},P=(e,n,r,t)=>{if(n&&typeof n=="object"||typeof n=="function")for(let a of N(n))!V.call(e,a)&&a!==r&&w(e,a,{get:()=>n[a],enumerable:!(t=D(n,a))||t.enumerable});return e};var q=e=>P(w({},"__esModule",{value:!0}),e);var W={};E(W,{FORM_HONEYPOT_FIELD:()=>p,FORM_STARTED_AT_FIELD:()=>g,MIN_SUBMISSION_TIME_MS:()=>O,createAcceptanceBlock:()=>x,createCreateLeadHook:()=>S,createMarketingFormFields:()=>f,createValidateFormSubmissionHook:()=>y,extendFormBuilderCollections:()=>h,mutateFormBuilderCollections:()=>h,resolveCommaSeparatedSubmissionTags:()=>F,submissionDataToPlainRecord:()=>k,substituteSubmissionPlaceholders:()=>B,validateSubmissionInput:()=>b});module.exports=q(W);function d(e,n){if(!n)return e;let{overrides:r,...t}=n;return{...e,...t,...r??{},admin:{..."admin"in e?e.admin:void 0,...t.admin??{},...r?.admin??{}}}}function M(e){return{type:"row",fields:e}}function v(e,n,r){let t=r?.fields??{};return{...{slug:e,labels:r?.labels??n,fields:[M([d({name:"name",type:"text",label:"Name (lowercase, no special characters)",required:!0,admin:{width:"50%"}},t.name),d({name:"label",type:"text",label:"Label",localized:!0,admin:{width:"50%"}},t.label)]),M([d({name:"width",type:"number",label:"Field Width (percentage)",admin:{width:"33%"}},t.width),d({name:"placeholder",type:"text",label:"Placeholder",localized:!0,admin:{width:"33%"}},t.placeholder),d({name:"defaultValue",type:"text",label:"Default Value",localized:!0,admin:{width:"33%"}},t.defaultValue)]),d({name:"required",type:"checkbox",label:"Required"},t.required)]},...r?.overrides??{}}}function x(e){let n=e?.fields??{};return{...{slug:"acceptance",labels:e?.labels??{singular:"Acceptance",plural:"Acceptances"},fields:[d({name:"name",type:"text",label:"Name (lowercase, no special characters)",required:!0,admin:{width:"50%"}},n.name),d({name:"label",type:"richText",label:"Label",localized:!0,admin:{width:"50%"}},n.label),M([d({name:"width",type:"number",label:"Field Width (percentage)",admin:{width:"50%"}},n.width),d({name:"required",type:"checkbox",label:"Required"},n.required)])]},...e?.overrides??{}}}function f(e={}){return{url:v("url",{singular:"URL",plural:"URLs"},e.url||void 0),phone:v("phone",{singular:"Phone",plural:"Phones"},e.phone||void 0),acceptance:x(e.acceptance||void 0)}}var p="__website",g="__startedAt",O=1500,I={acceptance:5,checkbox:5,country:200,date:100,email:320,message:5e3,number:64,payment:1e3,phone:50,select:200,state:200,text:200,textarea:5e3,upload:1e3,url:2048};function L(e){return e===p||e===g}function H(e){let n=e.find(t=>t.field===p)?.value,r=e.find(t=>t.field===g)?.value;return{honeypot:typeof n=="string"?n:"",startedAt:typeof r=="string"||typeof r=="number"?String(r):""}}function T(e){return typeof e=="boolean"||typeof e=="number"&&Number.isFinite(e)?String(e):typeof e=="string"?e.trim():""}function U(e,n){if(!n)return!e.required;if(n.length>(I[e.blockType]??1e3))return!1;if(e.blockType==="email")return/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(n);if(e.blockType==="url")try{return new URL(n),!0}catch{return!1}return e.blockType==="number"?Number.isFinite(Number(n)):e.blockType==="checkbox"||e.blockType==="acceptance"?n==="true"||n==="false":e.blockType==="select"&&e.options?.length?e.options.some(r=>r.value===n):!0}function $(e,n){return e.required?e.blockType==="acceptance"?n==="true":!!n:!0}function b(e){let n=H(e.submissionData??[]);if(n.honeypot.trim())return{ok:!1,error:"Invalid submission."};let r=Number(n.startedAt);if(!Number.isFinite(r))return{ok:!1,error:"Invalid submission."};if(e.now-r<1500)return{ok:!1,error:"Form submitted too quickly."};let t=e.formFields.flatMap(o=>o.name&&o.blockType in I?[{...o,name:o.name}]:[]),a=new Map(t.map(o=>[o.name,o])),l=[],u=new Set;for(let o of e.submissionData??[]){let i=o.field?.trim();if(!i||L(i))continue;if(u.has(i))return{ok:!1,error:`Field "${i}" was submitted more than once.`};u.add(i);let c=a.get(i);if(!c)return{ok:!1,error:`Unexpected field "${i}".`};let s=T(o.value);if(!U(c,s))return{ok:!1,error:`Field "${i}" is invalid.`};l.push({field:i,value:s})}for(let o of t){let i=l.find(c=>c.field===o.name)?.value;if(!$(o,i))return{ok:!1,error:`Field "${o.name}" is required.`}}return{ok:!0,data:l}}function k(e){return Object.fromEntries(e.flatMap(n=>n.field?[[n.field,T(n.value)]]:[]))}function B(e,n){return e.replace(/\{\{\s*([\w.-]+)\s*\}\}/g,(r,t)=>n[t]??"")}function F(e,n){return(e??"").split(",").map(r=>B(r,n).trim()).filter(Boolean)}function C(e,n){let r=e.submissionData?.find(t=>t.field===n)?.value;if(typeof r=="string")return r;if(r!=null&&(typeof r=="number"&&Number.isFinite(r)||typeof r=="boolean"))return String(r)}async function A(e,n,r="forms"){return typeof e.form=="string"?await n.payload.findByID({collection:r,depth:0,id:e.form,overrideAccess:!0}):e.form}function y(e={}){return async({data:n,operation:r,req:t})=>{if(r!=="create")return n;let a=await A(n,t,e.formsSlug),l=b({formFields:a?.fields??[],now:Date.now(),submissionData:n?.submissionData??[]});if(!l.ok)throw new Error(l.error);return n.submissionData=l.data,n}}function S(e,n={}){return async({data:r,operation:t,req:a})=>{if(t!=="create")return r;let u=await A(r,a,n.formsSlug);if(u?.event!=="lead"||!u.audienceId)return r;let o=r,i=C(o,"email");if(!i)return r;let c=k(o.submissionData??[]),s=F(u.tags,c);return await e.contacts.upsert({audienceId:u.audienceId,email:i,firstName:C(o,"firstName"),lastName:C(o,"lastName"),properties:s.length>0?{tags:s.join(",")}:void 0,subscribed:!0}),r}}function _(e,n){return"name"in e&&e.name===n}function R(e){return!!(e&&typeof e=="object"&&"slug"in e&&typeof e.slug=="string")}function j(e){return!!(e&&typeof e=="object")}function z(e,n){return!("name"in n)||!n.name?[...e,n]:e.some(r=>_(r,n.name))?e.map(r=>_(r,n.name)?n:r):[...e,n]}function G(e){let n=e.admin?.components?.audienceSelect??{path:"payload-plugin-marketing/admin",exportName:"AudienceSelect"};return[{name:"event",type:"select",defaultValue:"submission",options:[{label:"Submission",value:"submission"},{label:"Lead",value:"lead"}]},{name:"audienceId",type:"text",label:"Audience ID",required:!1,admin:{condition:(r,t)=>t?.event==="lead",components:{Field:n}},validate:(r,{siblingData:t}={})=>t?.event==="lead"&&!r?"Audience is required for lead forms.":!0},{name:"tags",type:"textarea",label:"Tags",admin:{condition:(r,t)=>t?.event==="lead",description:"Optional comma-separated tags. Use {{fieldName}} to insert submitted values."}}]}function K(e,n){let r=[...e.fields],t=r.findIndex(s=>_(s,"fields")&&s.type==="blocks");if(t<0){if(n.formBuilder?.strict===!1)return e;throw new Error(`Could not find a blocks field named "fields" on form-builder forms collection "${e.slug}".`)}let a=r[t],l=Array.isArray(a.blocks)?a.blocks:[],u=n.formBuilder?.fields??{},o=l.map(s=>{if(!R(s))return s;let m=u[s.slug];return!m||!j(s)?s:{...s,...m.overrides??{},...m.labels?{labels:m.labels}:{}}}),i=new Set(o.flatMap(s=>R(s)?[s.slug]:[])),c=Object.values(f(n.formBuilder?.fields)).filter(s=>!i.has(s.slug));r[t]={...a,blocks:[...o,...c]};for(let s of G(n))r.splice(0,r.length,...z(r,s));return{...e,fields:r}}function Y(e,n){let r=e.hooks??{};return{...e,hooks:{...r,beforeChange:[...r.beforeChange??[],y({formsSlug:n.formBuilder?.formsSlug}),S(n.adapter,{formsSlug:n.formBuilder?.formsSlug})]}}}function h(e,n){let r=n.formBuilder?.formsSlug??"forms",t=n.formBuilder?.submissionsSlug??"form-submissions",a=n.formBuilder?.strict??!0,l=e??[],u=l.some(i=>i.slug===r),o=l.some(i=>i.slug===t);if(a&&!u)throw new Error(`Could not find form-builder forms collection "${r}".`);if(a&&!o)throw new Error(`Could not find form-builder submissions collection "${t}".`);return l.map(i=>i.slug===r?K(i,n):i.slug===t?Y(i,n):i)}0&&(module.exports={FORM_HONEYPOT_FIELD,FORM_STARTED_AT_FIELD,MIN_SUBMISSION_TIME_MS,createAcceptanceBlock,createCreateLeadHook,createMarketingFormFields,createValidateFormSubmissionHook,extendFormBuilderCollections,mutateFormBuilderCollections,resolveCommaSeparatedSubmissionTags,submissionDataToPlainRecord,substituteSubmissionPlaceholders,validateSubmissionInput});
2
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/form-builder/index.ts","../../src/form-builder/fields.ts","../../src/form-builder/submission.ts","../../src/form-builder/hooks.ts","../../src/form-builder/mutate-collections.ts"],"sourcesContent":["export { createAcceptanceBlock, createMarketingFormFields } from \"./fields\"\nexport { createCreateLeadHook, createValidateFormSubmissionHook } from \"./hooks\"\nexport { extendFormBuilderCollections } from \"./mutate\"\nexport { mutateFormBuilderCollections } from \"./mutate-collections\"\nexport {\n FORM_HONEYPOT_FIELD,\n FORM_STARTED_AT_FIELD,\n MIN_SUBMISSION_TIME_MS,\n resolveCommaSeparatedSubmissionTags,\n submissionDataToPlainRecord,\n substituteSubmissionPlaceholders,\n validateSubmissionInput,\n type SubmissionValidationResult,\n type ValidationFormField,\n type ValidationSubmissionField,\n} from \"./submission\"\n","import type { FieldOverride, MarketingBlockOptions, MarketingFormFieldOverrides } from \"../types\"\nimport type { Block, Field } from \"payload\"\n\nexport const CUSTOM_MARKETING_FIELD_NAMES = [\"url\", \"phone\", \"acceptance\"] as const\n\nfunction mergeField(base: Field, override?: FieldOverride): Field {\n if (!override) {\n return base\n }\n\n const { overrides, ...direct } = override\n return {\n ...base,\n ...direct,\n ...(overrides ?? {}),\n admin: {\n ...(\"admin\" in base ? base.admin : undefined),\n ...(direct.admin ?? {}),\n ...(overrides?.admin ?? {}),\n },\n } as Field\n}\n\nfunction row(fields: Field[]): Field {\n return { type: \"row\", fields } as Field\n}\n\nfunction textLikeBlock(\n slug: \"phone\" | \"url\",\n labels: Required<Block>[\"labels\"],\n options?: MarketingBlockOptions,\n): Block {\n const fields = options?.fields ?? {}\n const block: Block = {\n slug,\n labels: options?.labels ?? labels,\n fields: [\n row([\n mergeField(\n {\n name: \"name\",\n type: \"text\",\n label: \"Name (lowercase, no special characters)\",\n required: true,\n admin: { width: \"50%\" },\n },\n fields.name,\n ),\n mergeField(\n {\n name: \"label\",\n type: \"text\",\n label: \"Label\",\n localized: true,\n admin: { width: \"50%\" },\n },\n fields.label,\n ),\n ]),\n row([\n mergeField(\n {\n name: \"width\",\n type: \"number\",\n label: \"Field Width (percentage)\",\n admin: { width: \"33%\" },\n },\n fields.width,\n ),\n mergeField(\n {\n name: \"placeholder\",\n type: \"text\",\n label: \"Placeholder\",\n localized: true,\n admin: { width: \"33%\" },\n },\n fields.placeholder,\n ),\n mergeField(\n {\n name: \"defaultValue\",\n type: \"text\",\n label: \"Default Value\",\n localized: true,\n admin: { width: \"33%\" },\n },\n fields.defaultValue,\n ),\n ]),\n mergeField({ name: \"required\", type: \"checkbox\", label: \"Required\" }, fields.required),\n ],\n }\n\n return { ...block, ...(options?.overrides ?? {}) }\n}\n\nexport function createAcceptanceBlock(options?: MarketingBlockOptions): Block {\n const fields = options?.fields ?? {}\n const block: Block = {\n slug: \"acceptance\",\n labels: options?.labels ?? { singular: \"Acceptance\", plural: \"Acceptances\" },\n fields: [\n mergeField(\n {\n name: \"name\",\n type: \"text\",\n label: \"Name (lowercase, no special characters)\",\n required: true,\n admin: { width: \"50%\" },\n },\n fields.name,\n ),\n mergeField(\n {\n name: \"label\",\n type: \"richText\",\n label: \"Label\",\n localized: true,\n admin: { width: \"50%\" },\n },\n fields.label,\n ),\n row([\n mergeField(\n {\n name: \"width\",\n type: \"number\",\n label: \"Field Width (percentage)\",\n admin: { width: \"50%\" },\n },\n fields.width,\n ),\n mergeField({ name: \"required\", type: \"checkbox\", label: \"Required\" }, fields.required),\n ]),\n ],\n }\n\n return { ...block, ...(options?.overrides ?? {}) }\n}\n\nexport function createMarketingFormFields(\n overrides: MarketingFormFieldOverrides = {},\n): Record<(typeof CUSTOM_MARKETING_FIELD_NAMES)[number], Block> {\n return {\n url: textLikeBlock(\"url\", { singular: \"URL\", plural: \"URLs\" }, overrides.url || undefined),\n phone: textLikeBlock(\n \"phone\",\n { singular: \"Phone\", plural: \"Phones\" },\n overrides.phone || undefined,\n ),\n acceptance: createAcceptanceBlock(overrides.acceptance || undefined),\n }\n}\n\nexport function createMarketingBlocksForMutation(\n overrides: MarketingFormFieldOverrides = {},\n): Block[] {\n return Object.values(createMarketingFormFields(overrides))\n}\n","export const FORM_HONEYPOT_FIELD = \"__website\"\nexport const FORM_STARTED_AT_FIELD = \"__startedAt\"\nexport const MIN_SUBMISSION_TIME_MS = 1_500\n\nconst MAX_LENGTH_BY_BLOCK: Record<string, number> = {\n acceptance: 5,\n checkbox: 5,\n country: 200,\n date: 100,\n email: 320,\n message: 5_000,\n number: 64,\n payment: 1_000,\n phone: 50,\n select: 200,\n state: 200,\n text: 200,\n textarea: 5_000,\n upload: 1_000,\n url: 2_048,\n}\n\nexport interface ValidationFormField {\n blockType: string\n name?: string | null\n options?: Array<{ value: string }> | null\n required?: boolean | null\n}\n\nexport interface ValidationSubmissionField {\n field?: string | null\n value?: unknown\n}\n\nexport type SubmissionValidationResult =\n | { data: Array<{ field: string; value: string }>; ok: true }\n | { error: string; ok: false }\n\nfunction isControlField(fieldName: string): boolean {\n return fieldName === FORM_HONEYPOT_FIELD || fieldName === FORM_STARTED_AT_FIELD\n}\n\nfunction extractControlFields(submissionData: ValidationSubmissionField[]): {\n honeypot: string\n startedAt: string\n} {\n const honeypot = submissionData.find((entry) => entry.field === FORM_HONEYPOT_FIELD)?.value\n const startedAt = submissionData.find((entry) => entry.field === FORM_STARTED_AT_FIELD)?.value\n return {\n honeypot: typeof honeypot === \"string\" ? honeypot : \"\",\n startedAt:\n typeof startedAt === \"string\" || typeof startedAt === \"number\" ? String(startedAt) : \"\",\n }\n}\n\nfunction stringifySubmissionValue(value: unknown): string {\n if (typeof value === \"boolean\") {\n return String(value)\n }\n if (typeof value === \"number\" && Number.isFinite(value)) {\n return String(value)\n }\n return typeof value === \"string\" ? value.trim() : \"\"\n}\n\nfunction isValidFieldValue(field: ValidationFormField, value: string): boolean {\n if (!value) {\n return !field.required\n }\n if (value.length > (MAX_LENGTH_BY_BLOCK[field.blockType] ?? 1_000)) {\n return false\n }\n if (field.blockType === \"email\") {\n return /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(value)\n }\n if (field.blockType === \"url\") {\n try {\n new URL(value)\n return true\n } catch {\n return false\n }\n }\n if (field.blockType === \"number\") {\n return Number.isFinite(Number(value))\n }\n if (field.blockType === \"checkbox\" || field.blockType === \"acceptance\") {\n return value === \"true\" || value === \"false\"\n }\n if (field.blockType === \"select\" && field.options?.length) {\n return field.options.some((option) => option.value === value)\n }\n return true\n}\n\nfunction requiredValueIsPresent(field: ValidationFormField, value: string | undefined): boolean {\n if (!field.required) {\n return true\n }\n if (field.blockType === \"acceptance\") {\n return value === \"true\"\n }\n return Boolean(value)\n}\n\nexport function validateSubmissionInput(input: {\n formFields: ValidationFormField[]\n now: number\n submissionData: ValidationSubmissionField[] | null | undefined\n}): SubmissionValidationResult {\n const controlFields = extractControlFields(input.submissionData ?? [])\n if (controlFields.honeypot.trim()) {\n return { ok: false, error: \"Invalid submission.\" }\n }\n const startedAt = Number(controlFields.startedAt)\n if (!Number.isFinite(startedAt)) {\n return { ok: false, error: \"Invalid submission.\" }\n }\n if (input.now - startedAt < MIN_SUBMISSION_TIME_MS) {\n return { ok: false, error: \"Form submitted too quickly.\" }\n }\n\n const supportedFields = input.formFields.flatMap((field) =>\n field.name && field.blockType in MAX_LENGTH_BY_BLOCK ? [{ ...field, name: field.name }] : [],\n )\n const formFieldMap = new Map(supportedFields.map((field) => [field.name, field]))\n const normalized: Array<{ field: string; value: string }> = []\n const seenFields = new Set<string>()\n\n for (const entry of input.submissionData ?? []) {\n const fieldName = entry.field?.trim()\n if (!fieldName || isControlField(fieldName)) {\n continue\n }\n if (seenFields.has(fieldName)) {\n return { ok: false, error: `Field \"${fieldName}\" was submitted more than once.` }\n }\n seenFields.add(fieldName)\n const formField = formFieldMap.get(fieldName)\n if (!formField) {\n return { ok: false, error: `Unexpected field \"${fieldName}\".` }\n }\n const value = stringifySubmissionValue(entry.value)\n if (!isValidFieldValue(formField, value)) {\n return { ok: false, error: `Field \"${fieldName}\" is invalid.` }\n }\n normalized.push({ field: fieldName, value })\n }\n\n for (const field of supportedFields) {\n const value = normalized.find((entry) => entry.field === field.name)?.value\n if (!requiredValueIsPresent(field, value)) {\n return { ok: false, error: `Field \"${field.name}\" is required.` }\n }\n }\n\n return { ok: true, data: normalized }\n}\n\nexport function submissionDataToPlainRecord(\n submissionData: ValidationSubmissionField[],\n): Record<string, string> {\n return Object.fromEntries(\n submissionData.flatMap((entry) =>\n entry.field ? [[entry.field, stringifySubmissionValue(entry.value)]] : [],\n ),\n )\n}\n\nexport function substituteSubmissionPlaceholders(\n template: string,\n values: Record<string, string>,\n): string {\n return template.replace(\n /\\{\\{\\s*([\\w.-]+)\\s*\\}\\}/g,\n (_, fieldName: string) => values[fieldName] ?? \"\",\n )\n}\n\nexport function resolveCommaSeparatedSubmissionTags(\n tags: string | null | undefined,\n values: Record<string, string>,\n): string[] {\n return (tags ?? \"\")\n .split(\",\")\n .map((tag) => substituteSubmissionPlaceholders(tag, values).trim())\n .filter(Boolean)\n}\n","import {\n resolveCommaSeparatedSubmissionTags,\n submissionDataToPlainRecord,\n validateSubmissionInput,\n} from \"./submission\"\n\nimport type { MarketingAdapter } from \"../types\"\nimport type { CollectionBeforeChangeHook, PayloadRequest } from \"payload\"\n\ninterface FormSubmissionData {\n form?: unknown\n submissionData?: Array<{ field?: string | null; value?: unknown }>\n}\n\nfunction getStringField(data: FormSubmissionData, field: string): string | undefined {\n const value = data.submissionData?.find((row) => row.field === field)?.value\n if (typeof value === \"string\") {\n return value\n }\n if (value == null) {\n return undefined\n }\n if (typeof value === \"number\" && Number.isFinite(value)) {\n return String(value)\n }\n if (typeof value === \"boolean\") {\n return String(value)\n }\n return undefined\n}\n\ninterface HookOptions {\n formsSlug?: string\n minSubmitDurationMs?: number\n}\n\nasync function resolveMarketingForm(\n data: { form?: unknown },\n req: PayloadRequest,\n formsSlug = \"forms\",\n): Promise<unknown> {\n if (typeof data.form === \"string\") {\n return await req.payload.findByID({\n collection: formsSlug,\n depth: 0,\n id: data.form,\n overrideAccess: true,\n })\n }\n return data.form\n}\n\nexport function createValidateFormSubmissionHook(\n options: HookOptions = {},\n): CollectionBeforeChangeHook {\n return async ({ data, operation, req }) => {\n if (operation !== \"create\") {\n return data\n }\n const form = await resolveMarketingForm(data as { form?: unknown }, req, options.formsSlug)\n const result = validateSubmissionInput({\n formFields: ((form as { fields?: unknown[] } | undefined)?.fields ?? []) as never,\n now: Date.now(),\n submissionData: (data?.submissionData ?? []) as never,\n })\n if (!result.ok) {\n throw new Error(result.error)\n }\n data.submissionData = result.data\n return data\n }\n}\n\nexport function createCreateLeadHook(\n adapter: MarketingAdapter,\n options: HookOptions = {},\n): CollectionBeforeChangeHook {\n return async ({ data, operation, req }) => {\n if (operation !== \"create\") {\n return data\n }\n const form = await resolveMarketingForm(data as { form?: unknown }, req, options.formsSlug)\n const formRecord = form as\n | { audienceId?: string; event?: string; tags?: string | null }\n | undefined\n if (formRecord?.event !== \"lead\" || !formRecord.audienceId) {\n return data\n }\n\n const submission = data as FormSubmissionData\n const email = getStringField(submission, \"email\")\n if (!email) {\n return data\n }\n\n const fieldValues = submissionDataToPlainRecord(submission.submissionData ?? [])\n const tags = resolveCommaSeparatedSubmissionTags(formRecord.tags, fieldValues)\n await adapter.contacts.upsert({\n audienceId: formRecord.audienceId,\n email,\n firstName: getStringField(submission, \"firstName\"),\n lastName: getStringField(submission, \"lastName\"),\n properties: tags.length > 0 ? { tags: tags.join(\",\") } : undefined,\n subscribed: true,\n })\n return data\n }\n}\n","import { createMarketingFormFields } from \"./fields\"\nimport { createCreateLeadHook, createValidateFormSubmissionHook } from \"./hooks\"\n\nimport type { PayloadPluginMarketingOptions } from \"../types\"\nimport type { CollectionConfig, Field } from \"payload\"\n\nfunction isNamedField(field: Field, name: string): field is Field & { name: string } {\n return \"name\" in field && field.name === name\n}\n\nfunction hasSlug(item: unknown): item is { slug: string } {\n return Boolean(\n item && typeof item === \"object\" && \"slug\" in item && typeof item.slug === \"string\",\n )\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return Boolean(value && typeof value === \"object\")\n}\n\nfunction upsertField(fields: Field[], field: Field): Field[] {\n if (!(\"name\" in field) || !field.name) {\n return [...fields, field]\n }\n return fields.some((existing) => isNamedField(existing, field.name))\n ? fields.map((existing) => (isNamedField(existing, field.name) ? field : existing))\n : [...fields, field]\n}\n\nfunction createMarketingConfigFields(options: PayloadPluginMarketingOptions): Field[] {\n const audienceSelect = options.admin?.components?.audienceSelect ?? {\n path: \"payload-plugin-marketing/admin\",\n exportName: \"AudienceSelect\",\n }\n return [\n {\n name: \"event\",\n type: \"select\",\n defaultValue: \"submission\",\n options: [\n { label: \"Submission\", value: \"submission\" },\n { label: \"Lead\", value: \"lead\" },\n ],\n },\n {\n name: \"audienceId\",\n type: \"text\",\n label: \"Audience ID\",\n required: false,\n admin: {\n condition: (_data, siblingData) => siblingData?.event === \"lead\",\n components: { Field: audienceSelect },\n },\n validate: (value: unknown, { siblingData }: { siblingData?: { event?: string } } = {}) =>\n siblingData?.event === \"lead\" && !value ? \"Audience is required for lead forms.\" : true,\n },\n {\n name: \"tags\",\n type: \"textarea\",\n label: \"Tags\",\n admin: {\n condition: (_data, siblingData) => siblingData?.event === \"lead\",\n description: \"Optional comma-separated tags. Use {{fieldName}} to insert submitted values.\",\n },\n },\n ] as Field[]\n}\n\nfunction mutateFormsCollection(\n collection: CollectionConfig,\n options: PayloadPluginMarketingOptions,\n): CollectionConfig {\n const fields = [...collection.fields]\n const fieldsIndex = fields.findIndex(\n (field) => isNamedField(field, \"fields\") && field.type === \"blocks\",\n )\n if (fieldsIndex < 0) {\n if (options.formBuilder?.strict === false) {\n return collection\n }\n throw new Error(\n `Could not find a blocks field named \"fields\" on form-builder forms collection \"${collection.slug}\".`,\n )\n }\n\n const fieldsField = fields[fieldsIndex] as Field & { blocks: unknown[] }\n const existingBlocks = Array.isArray(fieldsField.blocks) ? fieldsField.blocks : []\n const blockOverrides = options.formBuilder?.fields ?? {}\n const overriddenExistingBlocks = existingBlocks.map((block) => {\n if (!hasSlug(block)) {\n return block\n }\n const override = blockOverrides[block.slug as keyof typeof blockOverrides]\n if (!override || !isRecord(block)) {\n return block\n }\n return {\n ...block,\n ...(override.overrides ?? {}),\n ...(override.labels ? { labels: override.labels } : {}),\n }\n })\n const existingSlugs = new Set(\n overriddenExistingBlocks.flatMap((block) => (hasSlug(block) ? [block.slug] : [])),\n )\n const marketingBlocks = Object.values(\n createMarketingFormFields(options.formBuilder?.fields),\n ).filter((block) => !existingSlugs.has(block.slug))\n\n fields[fieldsIndex] = {\n ...fieldsField,\n blocks: [...overriddenExistingBlocks, ...marketingBlocks],\n } as Field\n\n for (const field of createMarketingConfigFields(options)) {\n fields.splice(0, fields.length, ...upsertField(fields, field))\n }\n\n return { ...collection, fields }\n}\n\nfunction mutateSubmissionsCollection(\n collection: CollectionConfig,\n options: PayloadPluginMarketingOptions,\n): CollectionConfig {\n const hooks = collection.hooks ?? {}\n return {\n ...collection,\n hooks: {\n ...hooks,\n beforeChange: [\n ...(hooks.beforeChange ?? []),\n createValidateFormSubmissionHook({ formsSlug: options.formBuilder?.formsSlug }),\n createCreateLeadHook(options.adapter, { formsSlug: options.formBuilder?.formsSlug }),\n ],\n },\n }\n}\n\nexport function mutateFormBuilderCollections(\n collections: CollectionConfig[] | undefined,\n options: PayloadPluginMarketingOptions,\n): CollectionConfig[] | undefined {\n const formsSlug = options.formBuilder?.formsSlug ?? \"forms\"\n const submissionsSlug = options.formBuilder?.submissionsSlug ?? \"form-submissions\"\n const strict = options.formBuilder?.strict ?? true\n const list = collections ?? []\n const hasForms = list.some((collection) => collection.slug === formsSlug)\n const hasSubmissions = list.some((collection) => collection.slug === submissionsSlug)\n\n if (strict && !hasForms) {\n throw new Error(`Could not find form-builder forms collection \"${formsSlug}\".`)\n }\n if (strict && !hasSubmissions) {\n throw new Error(`Could not find form-builder submissions collection \"${submissionsSlug}\".`)\n }\n\n return list.map((collection) => {\n if (collection.slug === formsSlug) {\n return mutateFormsCollection(collection, options)\n }\n if (collection.slug === submissionsSlug) {\n return mutateSubmissionsCollection(collection, options)\n }\n return collection\n })\n}\n"],"mappings":"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","names":["form_builder_exports","__export","FORM_HONEYPOT_FIELD","FORM_STARTED_AT_FIELD","MIN_SUBMISSION_TIME_MS","createAcceptanceBlock","createCreateLeadHook","createMarketingFormFields","createValidateFormSubmissionHook","mutateFormBuilderCollections","resolveCommaSeparatedSubmissionTags","submissionDataToPlainRecord","substituteSubmissionPlaceholders","validateSubmissionInput","__toCommonJS","mergeField","base","override","overrides","direct","row","fields","textLikeBlock","slug","labels","options","createAcceptanceBlock","createMarketingFormFields","FORM_HONEYPOT_FIELD","FORM_STARTED_AT_FIELD","MIN_SUBMISSION_TIME_MS","MAX_LENGTH_BY_BLOCK","isControlField","fieldName","extractControlFields","submissionData","honeypot","entry","startedAt","stringifySubmissionValue","value","isValidFieldValue","field","option","requiredValueIsPresent","validateSubmissionInput","input","controlFields","supportedFields","formFieldMap","normalized","seenFields","formField","submissionDataToPlainRecord","substituteSubmissionPlaceholders","template","values","_","resolveCommaSeparatedSubmissionTags","tags","tag","getStringField","data","field","value","row","resolveMarketingForm","req","formsSlug","createValidateFormSubmissionHook","options","operation","form","result","validateSubmissionInput","createCreateLeadHook","adapter","formRecord","submission","email","fieldValues","submissionDataToPlainRecord","tags","resolveCommaSeparatedSubmissionTags","isNamedField","field","name","hasSlug","item","isRecord","value","upsertField","fields","existing","createMarketingConfigFields","options","audienceSelect","_data","siblingData","mutateFormsCollection","collection","fieldsIndex","fieldsField","existingBlocks","blockOverrides","overriddenExistingBlocks","block","override","existingSlugs","marketingBlocks","createMarketingFormFields","mutateSubmissionsCollection","hooks","createValidateFormSubmissionHook","createCreateLeadHook","mutateFormBuilderCollections","collections","formsSlug","submissionsSlug","strict","list","hasForms","hasSubmissions"]}
@@ -0,0 +1,6 @@
1
+ export { createAcceptanceBlock, createMarketingFormFields } from "./fields";
2
+ export { createCreateLeadHook, createValidateFormSubmissionHook } from "./hooks";
3
+ export { extendFormBuilderCollections } from "./mutate";
4
+ export { mutateFormBuilderCollections } from "./mutate-collections";
5
+ export { FORM_HONEYPOT_FIELD, FORM_STARTED_AT_FIELD, MIN_SUBMISSION_TIME_MS, resolveCommaSeparatedSubmissionTags, submissionDataToPlainRecord, substituteSubmissionPlaceholders, validateSubmissionInput, type SubmissionValidationResult, type ValidationFormField, type ValidationSubmissionField, } from "./submission";
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/form-builder/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,yBAAyB,EAAE,MAAM,UAAU,CAAA;AAC3E,OAAO,EAAE,oBAAoB,EAAE,gCAAgC,EAAE,MAAM,SAAS,CAAA;AAChF,OAAO,EAAE,4BAA4B,EAAE,MAAM,UAAU,CAAA;AACvD,OAAO,EAAE,4BAA4B,EAAE,MAAM,sBAAsB,CAAA;AACnE,OAAO,EACL,mBAAmB,EACnB,qBAAqB,EACrB,sBAAsB,EACtB,mCAAmC,EACnC,2BAA2B,EAC3B,gCAAgC,EAChC,uBAAuB,EACvB,KAAK,0BAA0B,EAC/B,KAAK,mBAAmB,EACxB,KAAK,yBAAyB,GAC/B,MAAM,cAAc,CAAA"}
@@ -0,0 +1,2 @@
1
+ import{a,b,c,d,e,f,g,h,i,j,k,l}from"../chunk-4RBNCG5Q.js";export{c as FORM_HONEYPOT_FIELD,d as FORM_STARTED_AT_FIELD,e as MIN_SUBMISSION_TIME_MS,a as createAcceptanceBlock,k as createCreateLeadHook,b as createMarketingFormFields,j as createValidateFormSubmissionHook,l as extendFormBuilderCollections,l as mutateFormBuilderCollections,i as resolveCommaSeparatedSubmissionTags,g as submissionDataToPlainRecord,h as substituteSubmissionPlaceholders,f as validateSubmissionInput};
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,4 @@
1
+ import type { PayloadPluginMarketingOptions } from "../types";
2
+ import type { CollectionConfig } from "payload";
3
+ export declare function mutateFormBuilderCollections(collections: CollectionConfig[] | undefined, options: PayloadPluginMarketingOptions): CollectionConfig[] | undefined;
4
+ //# sourceMappingURL=mutate-collections.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mutate-collections.d.ts","sourceRoot":"","sources":["../../src/form-builder/mutate-collections.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,6BAA6B,EAAE,MAAM,UAAU,CAAA;AAC7D,OAAO,KAAK,EAAE,gBAAgB,EAAS,MAAM,SAAS,CAAA;AAuItD,wBAAgB,4BAA4B,CAC1C,WAAW,EAAE,gBAAgB,EAAE,GAAG,SAAS,EAC3C,OAAO,EAAE,6BAA6B,GACrC,gBAAgB,EAAE,GAAG,SAAS,CAwBhC"}
@@ -0,0 +1,2 @@
1
+ export { mutateFormBuilderCollections as extendFormBuilderCollections } from "./mutate-collections";
2
+ //# sourceMappingURL=mutate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mutate.d.ts","sourceRoot":"","sources":["../../src/form-builder/mutate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,4BAA4B,IAAI,4BAA4B,EAAE,MAAM,sBAAsB,CAAA"}
@@ -0,0 +1,34 @@
1
+ export declare const FORM_HONEYPOT_FIELD = "__website";
2
+ export declare const FORM_STARTED_AT_FIELD = "__startedAt";
3
+ export declare const MIN_SUBMISSION_TIME_MS = 1500;
4
+ export interface ValidationFormField {
5
+ blockType: string;
6
+ name?: string | null;
7
+ options?: Array<{
8
+ value: string;
9
+ }> | null;
10
+ required?: boolean | null;
11
+ }
12
+ export interface ValidationSubmissionField {
13
+ field?: string | null;
14
+ value?: unknown;
15
+ }
16
+ export type SubmissionValidationResult = {
17
+ data: Array<{
18
+ field: string;
19
+ value: string;
20
+ }>;
21
+ ok: true;
22
+ } | {
23
+ error: string;
24
+ ok: false;
25
+ };
26
+ export declare function validateSubmissionInput(input: {
27
+ formFields: ValidationFormField[];
28
+ now: number;
29
+ submissionData: ValidationSubmissionField[] | null | undefined;
30
+ }): SubmissionValidationResult;
31
+ export declare function submissionDataToPlainRecord(submissionData: ValidationSubmissionField[]): Record<string, string>;
32
+ export declare function substituteSubmissionPlaceholders(template: string, values: Record<string, string>): string;
33
+ export declare function resolveCommaSeparatedSubmissionTags(tags: string | null | undefined, values: Record<string, string>): string[];
34
+ //# sourceMappingURL=submission.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"submission.d.ts","sourceRoot":"","sources":["../../src/form-builder/submission.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,mBAAmB,cAAc,CAAA;AAC9C,eAAO,MAAM,qBAAqB,gBAAgB,CAAA;AAClD,eAAO,MAAM,sBAAsB,OAAQ,CAAA;AAoB3C,MAAM,WAAW,mBAAmB;IAClC,SAAS,EAAE,MAAM,CAAA;IACjB,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,OAAO,CAAC,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,GAAG,IAAI,CAAA;IACzC,QAAQ,CAAC,EAAE,OAAO,GAAG,IAAI,CAAA;CAC1B;AAED,MAAM,WAAW,yBAAyB;IACxC,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACrB,KAAK,CAAC,EAAE,OAAO,CAAA;CAChB;AAED,MAAM,MAAM,0BAA0B,GAClC;IAAE,IAAI,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAAC,EAAE,EAAE,IAAI,CAAA;CAAE,GAC3D;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,KAAK,CAAA;CAAE,CAAA;AAqEhC,wBAAgB,uBAAuB,CAAC,KAAK,EAAE;IAC7C,UAAU,EAAE,mBAAmB,EAAE,CAAA;IACjC,GAAG,EAAE,MAAM,CAAA;IACX,cAAc,EAAE,yBAAyB,EAAE,GAAG,IAAI,GAAG,SAAS,CAAA;CAC/D,GAAG,0BAA0B,CAgD7B;AAED,wBAAgB,2BAA2B,CACzC,cAAc,EAAE,yBAAyB,EAAE,GAC1C,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAMxB;AAED,wBAAgB,gCAAgC,CAC9C,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC7B,MAAM,CAKR;AAED,wBAAgB,mCAAmC,CACjD,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAC/B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC7B,MAAM,EAAE,CAKV"}
package/dist/index.cjs ADDED
@@ -0,0 +1,2 @@
1
+ "use strict";var z=Object.create;var b=Object.defineProperty;var Y=Object.getOwnPropertyDescriptor;var G=Object.getOwnPropertyNames;var W=Object.getPrototypeOf,X=Object.prototype.hasOwnProperty;var J=(e,t)=>{for(var n in t)b(e,n,{get:t[n],enumerable:!0})},P=(e,t,n,i)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of G(t))!X.call(e,r)&&r!==n&&b(e,r,{get:()=>t[r],enumerable:!(i=Y(t,r))||i.enumerable});return e};var B=(e,t,n)=>(n=e!=null?z(W(e)):{},P(t||!e||!e.__esModule?b(n,"default",{value:e,enumerable:!0}):n,e)),Q=e=>P(b({},"__esModule",{value:!0}),e);var me={};J(me,{createAcceptanceBlock:()=>y,createMarketingActions:()=>h,createMarketingFormFields:()=>f,default:()=>_,mailchimpAdapter:()=>M,payloadMarketingPlugin:()=>_,resendAdapter:()=>F});module.exports=Q(me);function h({adapter:e}){return{async createAudience(t){return await e.audiences.create(t),!0},async createBroadcast(t){return await e.broadcasts.create(t),!0},async deleteAudience(t){return await e.audiences.delete(t),!0},async deleteBroadcast(t){return await e.broadcasts.delete(t),!0},async deleteContact(t){return await e.contacts.delete(t),!0},async newsletterSubscribe(t){let n=t.audienceId??(await e.audiences.list())[0]?.id;if(!n)throw new Error("No audience found. Create one in the admin first.");return await e.contacts.upsert({audienceId:n,email:t.email,subscribed:!0}),!0},async sendBroadcast(t){return await e.broadcasts.send(t),!0},async updateContact(t){return await e.contacts.upsert(t),!0}}}var L=require("crypto");function x(e){return(0,L.createHash)("md5").update(e.toLowerCase()).digest("hex")}function N(e){let t=e.includes("-")?e.split("-").pop():void 0;if(!t)throw new Error("MAILCHIMP_API_KEY must include a datacenter suffix (e.g. key-us21).");return t}function Z(e){let t=e?.tags;return t==null?[]:String(t).split(",").map(n=>n.trim()).filter(Boolean)}function p(e,t=""){return typeof e=="string"?e:typeof e=="number"&&Number.isFinite(e)?String(e):t}function M(e){let t=!1,n=async()=>{let r=e.client??(await import("@mailchimp/mailchimp_marketing")).default;return t||(r.setConfig({apiKey:e.apiKey,server:N(e.apiKey)}),t=!0),r},i=`https://${N(e.apiKey)}.admin.mailchimp.com`;return{provider:"mailchimp",label:"Mailchimp",urls:{audiences:`${i}/audience/`,broadcasts:`${i}/campaigns/`},audiences:{async create(r){await(await n()).lists.createList({name:r.name,permission_reminder:`You're receiving this email because you opted in via ${e.siteName}.`,email_type_option:!0,contact:{company:e.siteName,address1:"Address on file",city:"N/A",state:"N/A",zip:"00000",country:"US"},campaign_defaults:{from_name:e.siteName,from_email:e.defaultSender,subject:" ",language:"en"}})},async delete(r){await(await n()).lists.deleteList(r.audienceId)},async get(r){let a=await(await n()).lists.getList(r);return{id:a.id,name:a.name}},async list(){return((await(await n()).lists.getAllLists({count:500})).lists??[]).map(a=>({id:a.id,name:a.name}))}},contacts:{async delete(r){await(await n()).lists.deleteListMember(r.audienceId,r.contactId)},async list(r){return((await(await n()).lists.getListMembersInfo(r.audienceId)).members??[]).map(d=>{let s=d.merge_fields;return{createdAt:typeof d.timestamp_signup=="string"?d.timestamp_signup:void 0,email:p(d.email_address),firstName:typeof s?.FNAME=="string"?s.FNAME:null,id:p(d.id,p(d.email_address)),lastName:typeof s?.LNAME=="string"?s.LNAME:null,subscribed:d.status==="subscribed"}})},async upsert(r){let a=await n(),d=r.id??x(r.email),s=r.id?r.subscribed?"subscribed":"unsubscribed":r.subscribed?"subscribed":"pending";await a.lists.setListMember(r.audienceId,d,{email_address:r.email,status:s,merge_fields:{FNAME:r.firstName??"",LNAME:r.lastName??""}},{skipMergeValidation:!0});let o=Z(r.properties);o.length>0&&await a.lists.updateListMemberTags(r.audienceId,x(r.email),{tags:o.map(u=>({name:u,status:"active"}))})}},broadcasts:{async create(r){let a=await n(),d=r.templateId!=null&&String(r.templateId).trim()!==""?String(r.templateId).trim():void 0,s;if(d!=null){let u=r.html;if(u!=null&&u!=="")throw new Error("Mailchimp broadcast: use either templateId (cloud template) or html, not both.");let l=Number.parseInt(d,10);if(!Number.isFinite(l))throw new Error(`Invalid Mailchimp template id: "${d}".`);s=l}let o=await a.campaigns.create({type:"regular",recipients:{list_id:r.audienceId},settings:{authenticate:!0,auto_footer:!1,from_email:e.defaultSender,from_name:e.siteName,inline_css:!1,reply_to:r.replyTo?.trim()||e.defaultSender,subject_line:r.subject,title:r.name,to_name:"*|FNAME|*"}});if(!o.id)throw new Error("Mailchimp did not return a campaign id.");s!=null?await a.campaigns.setContent(o.id,{template:{id:s}}):await a.campaigns.setContent(o.id,{html:r.html??""})},async delete(r){await(await n()).campaigns.remove(r.broadcastId)},async list(){return((await(await n()).campaigns.list({count:500})).campaigns??[]).map(a=>{let d=a.settings,s=typeof a.send_time=="string"?a.send_time:null;return{id:p(a.id),name:p(d?.title,p(a.id)),scheduledAt:s,sentAt:s,status:a.status==="save"?"draft":p(a.status,"draft")}})},async send(r){let a=await n(),d=r.scheduledAt?.trim();d?await a.campaigns.schedule(r.broadcastId,{schedule_time:d}):await a.campaigns.send(r.broadcastId)}}}}function c(e){let t=typeof e=="object"&&e&&"error"in e?e.error:void 0;if(t&&typeof t=="object"&&"message"in t)throw new Error(String(t.message))}function k(e,t){return typeof e=="string"?e:typeof e=="number"&&Number.isFinite(e)?String(e):t}function ee(e){return{id:k(e.id,""),name:k(e.name,""),scheduledAt:typeof e.scheduled_at=="string"?e.scheduled_at:null,sentAt:typeof e.sent_at=="string"?e.sent_at:null,status:k(e.status,"draft")}}function F(e){let t=async()=>{if(e.client)return e.client;let n=await import("resend");return new n.Resend(e.apiKey)};return{provider:"resend",label:"Resend",urls:{audiences:"https://resend.com/audiences",audience:n=>`https://resend.com/audiences/${n}`,broadcasts:"https://resend.com/broadcasts",broadcast:n=>`https://resend.com/broadcasts/${n}`},audiences:{async create(n){c(await(await t()).segments.create({name:n.name}))},async delete(n){c(await(await t()).segments.remove(n.audienceId))},async get(n){let i=await(await t()).segments.get(n);return c(i),i.data?{id:i.data.id,name:i.data.name}:null},async list(){let n=await(await t()).segments.list();return c(n),n.data?.data??[]}},contacts:{async delete(n){c(await(await t()).contacts.remove({audienceId:n.audienceId,id:n.contactId}))},async list(n){let i=await(await t()).contacts.list({audienceId:n.audienceId});return c(i),(i.data?.data??[]).map(r=>({createdAt:typeof r.created_at=="string"?r.created_at:void 0,email:k(r.email,""),firstName:typeof r.first_name=="string"?r.first_name:null,id:String(r.id),lastName:typeof r.last_name=="string"?r.last_name:null,subscribed:r.unsubscribed===!1}))},async upsert(n){let i=await t(),r=!n.subscribed,a={audienceId:n.audienceId,email:n.email,firstName:n.firstName,lastName:n.lastName,unsubscribed:r};c(n.id?await i.contacts.update({...a,id:n.id}):await i.contacts.create(a))}},broadcasts:{async create(n){if(n.templateId!=null&&String(n.templateId).trim()!=="")throw new Error("Resend broadcasts do not support templateId; use html or react, or use the Mailchimp adapter for cloud templates.");c(await(await t()).broadcasts.create({audienceId:n.audienceId,from:e.defaultSender,html:n.html,name:n.name,react:n.react,replyTo:n.replyTo,subject:n.subject}))},async delete(n){c(await(await t()).broadcasts.remove(n.broadcastId))},async list(){let n=await(await t()).broadcasts.list();return c(n),(n.data?.data??[]).map(i=>ee(i))},async send(n){c(await(await t()).broadcasts.send(n.broadcastId,{scheduledAt:n.scheduledAt}))}}}}function m(e,t){if(!t)return e;let{overrides:n,...i}=t;return{...e,...i,...n??{},admin:{..."admin"in e?e.admin:void 0,...i.admin??{},...n?.admin??{}}}}function I(e){return{type:"row",fields:e}}function R(e,t,n){let i=n?.fields??{};return{...{slug:e,labels:n?.labels??t,fields:[I([m({name:"name",type:"text",label:"Name (lowercase, no special characters)",required:!0,admin:{width:"50%"}},i.name),m({name:"label",type:"text",label:"Label",localized:!0,admin:{width:"50%"}},i.label)]),I([m({name:"width",type:"number",label:"Field Width (percentage)",admin:{width:"33%"}},i.width),m({name:"placeholder",type:"text",label:"Placeholder",localized:!0,admin:{width:"33%"}},i.placeholder),m({name:"defaultValue",type:"text",label:"Default Value",localized:!0,admin:{width:"33%"}},i.defaultValue)]),m({name:"required",type:"checkbox",label:"Required"},i.required)]},...n?.overrides??{}}}function y(e){let t=e?.fields??{};return{...{slug:"acceptance",labels:e?.labels??{singular:"Acceptance",plural:"Acceptances"},fields:[m({name:"name",type:"text",label:"Name (lowercase, no special characters)",required:!0,admin:{width:"50%"}},t.name),m({name:"label",type:"richText",label:"Label",localized:!0,admin:{width:"50%"}},t.label),I([m({name:"width",type:"number",label:"Field Width (percentage)",admin:{width:"50%"}},t.width),m({name:"required",type:"checkbox",label:"Required"},t.required)])]},...e?.overrides??{}}}function f(e={}){return{url:R("url",{singular:"URL",plural:"URLs"},e.url||void 0),phone:R("phone",{singular:"Phone",plural:"Phones"},e.phone||void 0),acceptance:y(e.acceptance||void 0)}}var v="__website",O="__startedAt";var D={acceptance:5,checkbox:5,country:200,date:100,email:320,message:5e3,number:64,payment:1e3,phone:50,select:200,state:200,text:200,textarea:5e3,upload:1e3,url:2048};function te(e){return e===v||e===O}function ne(e){let t=e.find(i=>i.field===v)?.value,n=e.find(i=>i.field===O)?.value;return{honeypot:typeof t=="string"?t:"",startedAt:typeof n=="string"||typeof n=="number"?String(n):""}}function E(e){return typeof e=="boolean"||typeof e=="number"&&Number.isFinite(e)?String(e):typeof e=="string"?e.trim():""}function re(e,t){if(!t)return!e.required;if(t.length>(D[e.blockType]??1e3))return!1;if(e.blockType==="email")return/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(t);if(e.blockType==="url")try{return new URL(t),!0}catch{return!1}return e.blockType==="number"?Number.isFinite(Number(t)):e.blockType==="checkbox"||e.blockType==="acceptance"?t==="true"||t==="false":e.blockType==="select"&&e.options?.length?e.options.some(n=>n.value===t):!0}function ie(e,t){return e.required?e.blockType==="acceptance"?t==="true":!!t:!0}function T(e){let t=ne(e.submissionData??[]);if(t.honeypot.trim())return{ok:!1,error:"Invalid submission."};let n=Number(t.startedAt);if(!Number.isFinite(n))return{ok:!1,error:"Invalid submission."};if(e.now-n<1500)return{ok:!1,error:"Form submitted too quickly."};let i=e.formFields.flatMap(s=>s.name&&s.blockType in D?[{...s,name:s.name}]:[]),r=new Map(i.map(s=>[s.name,s])),a=[],d=new Set;for(let s of e.submissionData??[]){let o=s.field?.trim();if(!o||te(o))continue;if(d.has(o))return{ok:!1,error:`Field "${o}" was submitted more than once.`};d.add(o);let u=r.get(o);if(!u)return{ok:!1,error:`Unexpected field "${o}".`};let l=E(s.value);if(!re(u,l))return{ok:!1,error:`Field "${o}" is invalid.`};a.push({field:o,value:l})}for(let s of i){let o=a.find(u=>u.field===s.name)?.value;if(!ie(s,o))return{ok:!1,error:`Field "${s.name}" is required.`}}return{ok:!0,data:a}}function V(e){return Object.fromEntries(e.flatMap(t=>t.field?[[t.field,E(t.value)]]:[]))}function ae(e,t){return e.replace(/\{\{\s*([\w.-]+)\s*\}\}/g,(n,i)=>t[i]??"")}function q(e,t){return(e??"").split(",").map(n=>ae(n,t).trim()).filter(Boolean)}function A(e,t){let n=e.submissionData?.find(i=>i.field===t)?.value;if(typeof n=="string")return n;if(n!=null&&(typeof n=="number"&&Number.isFinite(n)||typeof n=="boolean"))return String(n)}async function H(e,t,n="forms"){return typeof e.form=="string"?await t.payload.findByID({collection:n,depth:0,id:e.form,overrideAccess:!0}):e.form}function $(e={}){return async({data:t,operation:n,req:i})=>{if(n!=="create")return t;let r=await H(t,i,e.formsSlug),a=T({formFields:r?.fields??[],now:Date.now(),submissionData:t?.submissionData??[]});if(!a.ok)throw new Error(a.error);return t.submissionData=a.data,t}}function j(e,t={}){return async({data:n,operation:i,req:r})=>{if(i!=="create")return n;let d=await H(n,r,t.formsSlug);if(d?.event!=="lead"||!d.audienceId)return n;let s=n,o=A(s,"email");if(!o)return n;let u=V(s.submissionData??[]),l=q(d.tags,u);return await e.contacts.upsert({audienceId:d.audienceId,email:o,firstName:A(s,"firstName"),lastName:A(s,"lastName"),properties:l.length>0?{tags:l.join(",")}:void 0,subscribed:!0}),n}}function S(e,t){return"name"in e&&e.name===t}function U(e){return!!(e&&typeof e=="object"&&"slug"in e&&typeof e.slug=="string")}function se(e){return!!(e&&typeof e=="object")}function oe(e,t){return!("name"in t)||!t.name?[...e,t]:e.some(n=>S(n,t.name))?e.map(n=>S(n,t.name)?t:n):[...e,t]}function de(e){let t=e.admin?.components?.audienceSelect??{path:"payload-plugin-marketing/admin",exportName:"AudienceSelect"};return[{name:"event",type:"select",defaultValue:"submission",options:[{label:"Submission",value:"submission"},{label:"Lead",value:"lead"}]},{name:"audienceId",type:"text",label:"Audience ID",required:!1,admin:{condition:(n,i)=>i?.event==="lead",components:{Field:t}},validate:(n,{siblingData:i}={})=>i?.event==="lead"&&!n?"Audience is required for lead forms.":!0},{name:"tags",type:"textarea",label:"Tags",admin:{condition:(n,i)=>i?.event==="lead",description:"Optional comma-separated tags. Use {{fieldName}} to insert submitted values."}}]}function le(e,t){let n=[...e.fields],i=n.findIndex(l=>S(l,"fields")&&l.type==="blocks");if(i<0){if(t.formBuilder?.strict===!1)return e;throw new Error(`Could not find a blocks field named "fields" on form-builder forms collection "${e.slug}".`)}let r=n[i],a=Array.isArray(r.blocks)?r.blocks:[],d=t.formBuilder?.fields??{},s=a.map(l=>{if(!U(l))return l;let g=d[l.slug];return!g||!se(l)?l:{...l,...g.overrides??{},...g.labels?{labels:g.labels}:{}}}),o=new Set(s.flatMap(l=>U(l)?[l.slug]:[])),u=Object.values(f(t.formBuilder?.fields)).filter(l=>!o.has(l.slug));n[i]={...r,blocks:[...s,...u]};for(let l of de(t))n.splice(0,n.length,...oe(n,l));return{...e,fields:n}}function ue(e,t){let n=e.hooks??{};return{...e,hooks:{...n,beforeChange:[...n.beforeChange??[],$({formsSlug:t.formBuilder?.formsSlug}),j(t.adapter,{formsSlug:t.formBuilder?.formsSlug})]}}}function K(e,t){let n=t.formBuilder?.formsSlug??"forms",i=t.formBuilder?.submissionsSlug??"form-submissions",r=t.formBuilder?.strict??!0,a=e??[],d=a.some(o=>o.slug===n),s=a.some(o=>o.slug===i);if(r&&!d)throw new Error(`Could not find form-builder forms collection "${n}".`);if(r&&!s)throw new Error(`Could not find form-builder submissions collection "${i}".`);return a.map(o=>o.slug===n?le(o,t):o.slug===i?ue(o,t):o)}function w(e,t){return{path:"payload-plugin-marketing/admin",exportName:e,...t?{clientProps:t}:{}}}function C(e,...t){return`/${[e.replace(/^\/+|\/+$/g,""),...t].filter(Boolean).join("/")}`}function ce(e,t){if(t.admin?.enabled===!1)return e;let n=t.admin?.basePath??"",i=t.admin?.components??{},r=i.marketingMenu??w("MarketingMenu",{basePath:n});return{...e,admin:{...e.admin??{},components:{...e.admin?.components??{},afterNavLinks:[...e.admin?.components?.afterNavLinks??[],r],views:{...e.admin?.components?.views??{},audienceList:{Component:i.audienceList??w("AudienceList"),path:C(n,"audience")},audienceDetail:{Component:i.audienceDetail??w("AudienceDetail"),path:C(n,"audience",":id")},broadcastList:{Component:i.broadcastList??w("BroadcastList"),path:C(n,"broadcast")}}}}}}function _(e){let t=n=>ce({...n,collections:K(n.collections,e)},e);return t.slug="marketing",t.order=10,t.options=e,t}0&&(module.exports={createAcceptanceBlock,createMarketingActions,createMarketingFormFields,mailchimpAdapter,payloadMarketingPlugin,resendAdapter});
2
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/actions/factories.ts","../src/adapters/mailchimp.ts","../src/adapters/resend.ts","../src/form-builder/fields.ts","../src/form-builder/submission.ts","../src/form-builder/hooks.ts","../src/form-builder/mutate-collections.ts","../src/plugin.ts"],"sourcesContent":["export { createMarketingActions } from \"./actions\"\nexport { mailchimpAdapter, resendAdapter } from \"./adapters\"\nexport { createAcceptanceBlock, createMarketingFormFields } from \"./form-builder\"\nexport { payloadMarketingPlugin } from \"./plugin\"\nexport type {\n CreateAudienceInput,\n CreateBroadcastInput,\n DeleteAudienceInput,\n DeleteBroadcastInput,\n DeleteContactInput,\n ListContactsInput,\n MarketingAdapter,\n MarketingAudience,\n MarketingBroadcast,\n MarketingContact,\n MarketingFormFieldOverrides,\n PayloadComponentOverride,\n PayloadPluginMarketingOptions,\n SendBroadcastInput,\n UpsertContactInput,\n} from \"./types\"\n\nexport { payloadMarketingPlugin as default } from \"./plugin\"\n","import type {\n CreateAudienceInput,\n CreateBroadcastInput,\n DeleteAudienceInput,\n DeleteBroadcastInput,\n DeleteContactInput,\n MarketingAdapter,\n SendBroadcastInput,\n UpsertContactInput,\n} from \"../types\"\n\nexport interface CreateMarketingActionsOptions {\n adapter: MarketingAdapter\n}\n\nexport function createMarketingActions({ adapter }: CreateMarketingActionsOptions) {\n return {\n async createAudience(input: CreateAudienceInput) {\n await adapter.audiences.create(input)\n return true\n },\n async createBroadcast(input: CreateBroadcastInput) {\n await adapter.broadcasts.create(input)\n return true\n },\n async deleteAudience(input: DeleteAudienceInput) {\n await adapter.audiences.delete(input)\n return true\n },\n async deleteBroadcast(input: DeleteBroadcastInput) {\n await adapter.broadcasts.delete(input)\n return true\n },\n async deleteContact(input: DeleteContactInput) {\n await adapter.contacts.delete(input)\n return true\n },\n async newsletterSubscribe(input: { audienceId?: string; email: string }) {\n const audienceId = input.audienceId ?? (await adapter.audiences.list())[0]?.id\n if (!audienceId) {\n throw new Error(\"No audience found. Create one in the admin first.\")\n }\n await adapter.contacts.upsert({ audienceId, email: input.email, subscribed: true })\n return true\n },\n async sendBroadcast(input: SendBroadcastInput) {\n await adapter.broadcasts.send(input)\n return true\n },\n async updateContact(input: UpsertContactInput) {\n await adapter.contacts.upsert(input)\n return true\n },\n }\n}\n","import { createHash } from \"node:crypto\"\n\nimport type { MarketingAdapter } from \"../types\"\n\ninterface MailchimpLike {\n campaigns: {\n create(input: unknown): Promise<{ id?: string }>\n list(input?: unknown): Promise<{ campaigns?: Array<Record<string, unknown>> }>\n remove(id: string): Promise<unknown>\n schedule(id: string, input: unknown): Promise<unknown>\n send(id: string): Promise<unknown>\n setContent(id: string, input: unknown): Promise<unknown>\n }\n lists: {\n createList(input: unknown): Promise<unknown>\n deleteList(id: string): Promise<unknown>\n deleteListMember(listId: string, contactId: string): Promise<unknown>\n getAllLists(input?: unknown): Promise<{ lists?: Array<{ id: string; name: string }> }>\n getList(id: string): Promise<{ id: string; name: string }>\n getListMembersInfo(input: string): Promise<{ members?: Array<Record<string, unknown>> }>\n setListMember(listId: string, hash: string, input: unknown, options?: unknown): Promise<unknown>\n updateListMemberTags(listId: string, hash: string, input: unknown): Promise<unknown>\n }\n setConfig(input: unknown): void\n}\n\nexport interface MailchimpAdapterOptions {\n apiKey: string\n client?: MailchimpLike\n defaultSender: string\n siteName: string\n}\n\nfunction subscriberHash(email: string): string {\n return createHash(\"md5\").update(email.toLowerCase()).digest(\"hex\")\n}\n\nfunction serverFromApiKey(apiKey: string): string {\n const server = apiKey.includes(\"-\") ? apiKey.split(\"-\").pop() : undefined\n if (!server) {\n throw new Error(\"MAILCHIMP_API_KEY must include a datacenter suffix (e.g. key-us21).\")\n }\n return server\n}\n\nfunction tagNamesFromProperties(properties?: Record<string, string | number | null>): string[] {\n const raw = properties?.tags\n if (raw == null) {\n return []\n }\n return String(raw)\n .split(\",\")\n .map((tag) => tag.trim())\n .filter(Boolean)\n}\n\nfunction stringValue(value: unknown, fallback = \"\"): string {\n if (typeof value === \"string\") {\n return value\n }\n if (typeof value === \"number\" && Number.isFinite(value)) {\n return String(value)\n }\n return fallback\n}\n\nexport function mailchimpAdapter(options: MailchimpAdapterOptions): MarketingAdapter {\n let configured = false\n const getClient = async (): Promise<MailchimpLike> => {\n const client =\n options.client ??\n ((await import(\"@mailchimp/mailchimp_marketing\")) as { default: MailchimpLike }).default\n if (!configured) {\n client.setConfig({ apiKey: options.apiKey, server: serverFromApiKey(options.apiKey) })\n configured = true\n }\n return client\n }\n const adminBase = `https://${serverFromApiKey(options.apiKey)}.admin.mailchimp.com`\n\n return {\n provider: \"mailchimp\",\n label: \"Mailchimp\",\n urls: {\n audiences: `${adminBase}/audience/`,\n broadcasts: `${adminBase}/campaigns/`,\n },\n audiences: {\n async create(input) {\n await (\n await getClient()\n ).lists.createList({\n name: input.name,\n permission_reminder: `You're receiving this email because you opted in via ${options.siteName}.`,\n email_type_option: true,\n contact: {\n company: options.siteName,\n address1: \"Address on file\",\n city: \"N/A\",\n state: \"N/A\",\n zip: \"00000\",\n country: \"US\",\n },\n campaign_defaults: {\n from_name: options.siteName,\n from_email: options.defaultSender,\n subject: \" \",\n language: \"en\",\n },\n })\n },\n async delete(input) {\n await (await getClient()).lists.deleteList(input.audienceId)\n },\n async get(id) {\n const list = await (await getClient()).lists.getList(id)\n return { id: list.id, name: list.name }\n },\n async list() {\n const result = await (await getClient()).lists.getAllLists({ count: 500 })\n return (result.lists ?? []).map((list) => ({ id: list.id, name: list.name }))\n },\n },\n contacts: {\n async delete(input) {\n await (await getClient()).lists.deleteListMember(input.audienceId, input.contactId)\n },\n async list(input) {\n const result = await (await getClient()).lists.getListMembersInfo(input.audienceId)\n return (result.members ?? []).map((member) => {\n const mergeFields = member.merge_fields as Record<string, unknown> | undefined\n return {\n createdAt:\n typeof member.timestamp_signup === \"string\" ? member.timestamp_signup : undefined,\n email: stringValue(member.email_address),\n firstName: typeof mergeFields?.FNAME === \"string\" ? mergeFields.FNAME : null,\n id: stringValue(member.id, stringValue(member.email_address)),\n lastName: typeof mergeFields?.LNAME === \"string\" ? mergeFields.LNAME : null,\n subscribed: member.status === \"subscribed\",\n }\n })\n },\n async upsert(input) {\n const client = await getClient()\n const hash = input.id ?? subscriberHash(input.email)\n const status = input.id\n ? input.subscribed\n ? \"subscribed\"\n : \"unsubscribed\"\n : input.subscribed\n ? \"subscribed\"\n : \"pending\"\n await client.lists.setListMember(\n input.audienceId,\n hash,\n {\n email_address: input.email,\n status,\n merge_fields: { FNAME: input.firstName ?? \"\", LNAME: input.lastName ?? \"\" },\n },\n { skipMergeValidation: true },\n )\n const tags = tagNamesFromProperties(input.properties)\n if (tags.length > 0) {\n await client.lists.updateListMemberTags(input.audienceId, subscriberHash(input.email), {\n tags: tags.map((name) => ({ name, status: \"active\" })),\n })\n }\n },\n },\n broadcasts: {\n async create(input) {\n const client = await getClient()\n const templateIdRaw =\n input.templateId != null && String(input.templateId).trim() !== \"\"\n ? String(input.templateId).trim()\n : undefined\n let templateIdParsed: number | undefined\n if (templateIdRaw != null) {\n const html = input.html\n if (html != null && html !== \"\") {\n throw new Error(\n \"Mailchimp broadcast: use either templateId (cloud template) or html, not both.\",\n )\n }\n const parsed = Number.parseInt(templateIdRaw, 10)\n if (!Number.isFinite(parsed)) {\n throw new Error(`Invalid Mailchimp template id: \"${templateIdRaw}\".`)\n }\n templateIdParsed = parsed\n }\n const campaign = await client.campaigns.create({\n type: \"regular\",\n recipients: { list_id: input.audienceId },\n settings: {\n authenticate: true,\n auto_footer: false,\n from_email: options.defaultSender,\n from_name: options.siteName,\n inline_css: false,\n reply_to: input.replyTo?.trim() || options.defaultSender,\n subject_line: input.subject,\n title: input.name,\n to_name: \"*|FNAME|*\",\n },\n })\n if (!campaign.id) {\n throw new Error(\"Mailchimp did not return a campaign id.\")\n }\n if (templateIdParsed != null) {\n await client.campaigns.setContent(campaign.id, {\n template: { id: templateIdParsed },\n })\n } else {\n await client.campaigns.setContent(campaign.id, { html: input.html ?? \"\" })\n }\n },\n async delete(input) {\n await (await getClient()).campaigns.remove(input.broadcastId)\n },\n async list() {\n const result = await (await getClient()).campaigns.list({ count: 500 })\n return (result.campaigns ?? []).map((campaign) => {\n const settings = campaign.settings as Record<string, unknown> | undefined\n const sentAt = typeof campaign.send_time === \"string\" ? campaign.send_time : null\n return {\n id: stringValue(campaign.id),\n name: stringValue(settings?.title, stringValue(campaign.id)),\n scheduledAt: sentAt,\n sentAt,\n status: campaign.status === \"save\" ? \"draft\" : stringValue(campaign.status, \"draft\"),\n }\n })\n },\n async send(input) {\n const client = await getClient()\n const scheduledAt = input.scheduledAt?.trim()\n if (scheduledAt) {\n await client.campaigns.schedule(input.broadcastId, { schedule_time: scheduledAt })\n } else {\n await client.campaigns.send(input.broadcastId)\n }\n },\n },\n }\n}\n","import type { MarketingAdapter, MarketingBroadcast } from \"../types\"\n\ninterface ResendLike {\n broadcasts: {\n create(input: unknown): Promise<unknown>\n list(): Promise<{\n data?: { data?: Array<Record<string, unknown>> }\n error?: { message?: string }\n }>\n remove(id: string): Promise<unknown>\n send(id: string, input: unknown): Promise<unknown>\n }\n contacts: {\n create(input: unknown): Promise<{ data?: { id?: string }; error?: { message?: string } }>\n list(\n input: unknown,\n ): Promise<{ data?: { data?: Array<Record<string, unknown>> }; error?: { message?: string } }>\n remove(input: unknown): Promise<unknown>\n update(input: unknown): Promise<unknown>\n }\n segments: {\n create(input: unknown): Promise<unknown>\n get(id: string): Promise<{ data?: { id: string; name: string }; error?: { message?: string } }>\n list(): Promise<{\n data?: { data?: Array<{ id: string; name: string }> }\n error?: { message?: string }\n }>\n remove(id: string): Promise<unknown>\n }\n}\n\nexport interface ResendAdapterOptions {\n apiKey?: string\n client?: ResendLike\n defaultSender?: string\n}\n\nfunction assertNoResendError(result: unknown) {\n const error = typeof result === \"object\" && result && \"error\" in result ? result.error : undefined\n if (error && typeof error === \"object\" && \"message\" in error) {\n throw new Error(String(error.message))\n }\n}\n\nfunction stringifyFromRecord(value: unknown, fallback: string): string {\n if (typeof value === \"string\") {\n return value\n }\n if (typeof value === \"number\" && Number.isFinite(value)) {\n return String(value)\n }\n return fallback\n}\n\nfunction mapBroadcast(row: Record<string, unknown>): MarketingBroadcast {\n return {\n id: stringifyFromRecord(row.id, \"\"),\n name: stringifyFromRecord(row.name, \"\"),\n scheduledAt: typeof row.scheduled_at === \"string\" ? row.scheduled_at : null,\n sentAt: typeof row.sent_at === \"string\" ? row.sent_at : null,\n status: stringifyFromRecord(row.status, \"draft\"),\n }\n}\n\nexport function resendAdapter(options: ResendAdapterOptions): MarketingAdapter {\n const getClient = async (): Promise<ResendLike> => {\n if (options.client) {\n return options.client\n }\n const resendModule = (await import(\"resend\")) as { Resend: new (key?: string) => unknown }\n return new resendModule.Resend(options.apiKey) as ResendLike\n }\n\n return {\n provider: \"resend\",\n label: \"Resend\",\n urls: {\n audiences: \"https://resend.com/audiences\",\n audience: (id) => `https://resend.com/audiences/${id}`,\n broadcasts: \"https://resend.com/broadcasts\",\n broadcast: (id) => `https://resend.com/broadcasts/${id}`,\n },\n audiences: {\n async create(input) {\n assertNoResendError(await (await getClient()).segments.create({ name: input.name }))\n },\n async delete(input) {\n assertNoResendError(await (await getClient()).segments.remove(input.audienceId))\n },\n async get(id) {\n const result = await (await getClient()).segments.get(id)\n assertNoResendError(result)\n return result.data ? { id: result.data.id, name: result.data.name } : null\n },\n async list() {\n const result = await (await getClient()).segments.list()\n assertNoResendError(result)\n return result.data?.data ?? []\n },\n },\n contacts: {\n async delete(input) {\n assertNoResendError(\n await (\n await getClient()\n ).contacts.remove({ audienceId: input.audienceId, id: input.contactId }),\n )\n },\n async list(input) {\n const result = await (await getClient()).contacts.list({ audienceId: input.audienceId })\n assertNoResendError(result)\n return (result.data?.data ?? []).map((row) => ({\n createdAt: typeof row.created_at === \"string\" ? row.created_at : undefined,\n email: stringifyFromRecord(row.email, \"\"),\n firstName: typeof row.first_name === \"string\" ? row.first_name : null,\n id: String(row.id),\n lastName: typeof row.last_name === \"string\" ? row.last_name : null,\n subscribed: row.unsubscribed === false,\n }))\n },\n async upsert(input) {\n const client = await getClient()\n const unsubscribed = !input.subscribed\n const payload = {\n audienceId: input.audienceId,\n email: input.email,\n firstName: input.firstName,\n lastName: input.lastName,\n unsubscribed,\n }\n assertNoResendError(\n input.id\n ? await client.contacts.update({ ...payload, id: input.id })\n : await client.contacts.create(payload),\n )\n },\n },\n broadcasts: {\n async create(input) {\n if (input.templateId != null && String(input.templateId).trim() !== \"\") {\n throw new Error(\n \"Resend broadcasts do not support templateId; use html or react, or use the Mailchimp adapter for cloud templates.\",\n )\n }\n assertNoResendError(\n await (\n await getClient()\n ).broadcasts.create({\n audienceId: input.audienceId,\n from: options.defaultSender,\n html: input.html,\n name: input.name,\n react: input.react,\n replyTo: input.replyTo,\n subject: input.subject,\n }),\n )\n },\n async delete(input) {\n assertNoResendError(await (await getClient()).broadcasts.remove(input.broadcastId))\n },\n async list() {\n const result = await (await getClient()).broadcasts.list()\n assertNoResendError(result)\n return (result.data?.data ?? []).map((row) => mapBroadcast(row))\n },\n async send(input) {\n assertNoResendError(\n await (\n await getClient()\n ).broadcasts.send(input.broadcastId, { scheduledAt: input.scheduledAt }),\n )\n },\n },\n }\n}\n","import type { FieldOverride, MarketingBlockOptions, MarketingFormFieldOverrides } from \"../types\"\nimport type { Block, Field } from \"payload\"\n\nexport const CUSTOM_MARKETING_FIELD_NAMES = [\"url\", \"phone\", \"acceptance\"] as const\n\nfunction mergeField(base: Field, override?: FieldOverride): Field {\n if (!override) {\n return base\n }\n\n const { overrides, ...direct } = override\n return {\n ...base,\n ...direct,\n ...(overrides ?? {}),\n admin: {\n ...(\"admin\" in base ? base.admin : undefined),\n ...(direct.admin ?? {}),\n ...(overrides?.admin ?? {}),\n },\n } as Field\n}\n\nfunction row(fields: Field[]): Field {\n return { type: \"row\", fields } as Field\n}\n\nfunction textLikeBlock(\n slug: \"phone\" | \"url\",\n labels: Required<Block>[\"labels\"],\n options?: MarketingBlockOptions,\n): Block {\n const fields = options?.fields ?? {}\n const block: Block = {\n slug,\n labels: options?.labels ?? labels,\n fields: [\n row([\n mergeField(\n {\n name: \"name\",\n type: \"text\",\n label: \"Name (lowercase, no special characters)\",\n required: true,\n admin: { width: \"50%\" },\n },\n fields.name,\n ),\n mergeField(\n {\n name: \"label\",\n type: \"text\",\n label: \"Label\",\n localized: true,\n admin: { width: \"50%\" },\n },\n fields.label,\n ),\n ]),\n row([\n mergeField(\n {\n name: \"width\",\n type: \"number\",\n label: \"Field Width (percentage)\",\n admin: { width: \"33%\" },\n },\n fields.width,\n ),\n mergeField(\n {\n name: \"placeholder\",\n type: \"text\",\n label: \"Placeholder\",\n localized: true,\n admin: { width: \"33%\" },\n },\n fields.placeholder,\n ),\n mergeField(\n {\n name: \"defaultValue\",\n type: \"text\",\n label: \"Default Value\",\n localized: true,\n admin: { width: \"33%\" },\n },\n fields.defaultValue,\n ),\n ]),\n mergeField({ name: \"required\", type: \"checkbox\", label: \"Required\" }, fields.required),\n ],\n }\n\n return { ...block, ...(options?.overrides ?? {}) }\n}\n\nexport function createAcceptanceBlock(options?: MarketingBlockOptions): Block {\n const fields = options?.fields ?? {}\n const block: Block = {\n slug: \"acceptance\",\n labels: options?.labels ?? { singular: \"Acceptance\", plural: \"Acceptances\" },\n fields: [\n mergeField(\n {\n name: \"name\",\n type: \"text\",\n label: \"Name (lowercase, no special characters)\",\n required: true,\n admin: { width: \"50%\" },\n },\n fields.name,\n ),\n mergeField(\n {\n name: \"label\",\n type: \"richText\",\n label: \"Label\",\n localized: true,\n admin: { width: \"50%\" },\n },\n fields.label,\n ),\n row([\n mergeField(\n {\n name: \"width\",\n type: \"number\",\n label: \"Field Width (percentage)\",\n admin: { width: \"50%\" },\n },\n fields.width,\n ),\n mergeField({ name: \"required\", type: \"checkbox\", label: \"Required\" }, fields.required),\n ]),\n ],\n }\n\n return { ...block, ...(options?.overrides ?? {}) }\n}\n\nexport function createMarketingFormFields(\n overrides: MarketingFormFieldOverrides = {},\n): Record<(typeof CUSTOM_MARKETING_FIELD_NAMES)[number], Block> {\n return {\n url: textLikeBlock(\"url\", { singular: \"URL\", plural: \"URLs\" }, overrides.url || undefined),\n phone: textLikeBlock(\n \"phone\",\n { singular: \"Phone\", plural: \"Phones\" },\n overrides.phone || undefined,\n ),\n acceptance: createAcceptanceBlock(overrides.acceptance || undefined),\n }\n}\n\nexport function createMarketingBlocksForMutation(\n overrides: MarketingFormFieldOverrides = {},\n): Block[] {\n return Object.values(createMarketingFormFields(overrides))\n}\n","export const FORM_HONEYPOT_FIELD = \"__website\"\nexport const FORM_STARTED_AT_FIELD = \"__startedAt\"\nexport const MIN_SUBMISSION_TIME_MS = 1_500\n\nconst MAX_LENGTH_BY_BLOCK: Record<string, number> = {\n acceptance: 5,\n checkbox: 5,\n country: 200,\n date: 100,\n email: 320,\n message: 5_000,\n number: 64,\n payment: 1_000,\n phone: 50,\n select: 200,\n state: 200,\n text: 200,\n textarea: 5_000,\n upload: 1_000,\n url: 2_048,\n}\n\nexport interface ValidationFormField {\n blockType: string\n name?: string | null\n options?: Array<{ value: string }> | null\n required?: boolean | null\n}\n\nexport interface ValidationSubmissionField {\n field?: string | null\n value?: unknown\n}\n\nexport type SubmissionValidationResult =\n | { data: Array<{ field: string; value: string }>; ok: true }\n | { error: string; ok: false }\n\nfunction isControlField(fieldName: string): boolean {\n return fieldName === FORM_HONEYPOT_FIELD || fieldName === FORM_STARTED_AT_FIELD\n}\n\nfunction extractControlFields(submissionData: ValidationSubmissionField[]): {\n honeypot: string\n startedAt: string\n} {\n const honeypot = submissionData.find((entry) => entry.field === FORM_HONEYPOT_FIELD)?.value\n const startedAt = submissionData.find((entry) => entry.field === FORM_STARTED_AT_FIELD)?.value\n return {\n honeypot: typeof honeypot === \"string\" ? honeypot : \"\",\n startedAt:\n typeof startedAt === \"string\" || typeof startedAt === \"number\" ? String(startedAt) : \"\",\n }\n}\n\nfunction stringifySubmissionValue(value: unknown): string {\n if (typeof value === \"boolean\") {\n return String(value)\n }\n if (typeof value === \"number\" && Number.isFinite(value)) {\n return String(value)\n }\n return typeof value === \"string\" ? value.trim() : \"\"\n}\n\nfunction isValidFieldValue(field: ValidationFormField, value: string): boolean {\n if (!value) {\n return !field.required\n }\n if (value.length > (MAX_LENGTH_BY_BLOCK[field.blockType] ?? 1_000)) {\n return false\n }\n if (field.blockType === \"email\") {\n return /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(value)\n }\n if (field.blockType === \"url\") {\n try {\n new URL(value)\n return true\n } catch {\n return false\n }\n }\n if (field.blockType === \"number\") {\n return Number.isFinite(Number(value))\n }\n if (field.blockType === \"checkbox\" || field.blockType === \"acceptance\") {\n return value === \"true\" || value === \"false\"\n }\n if (field.blockType === \"select\" && field.options?.length) {\n return field.options.some((option) => option.value === value)\n }\n return true\n}\n\nfunction requiredValueIsPresent(field: ValidationFormField, value: string | undefined): boolean {\n if (!field.required) {\n return true\n }\n if (field.blockType === \"acceptance\") {\n return value === \"true\"\n }\n return Boolean(value)\n}\n\nexport function validateSubmissionInput(input: {\n formFields: ValidationFormField[]\n now: number\n submissionData: ValidationSubmissionField[] | null | undefined\n}): SubmissionValidationResult {\n const controlFields = extractControlFields(input.submissionData ?? [])\n if (controlFields.honeypot.trim()) {\n return { ok: false, error: \"Invalid submission.\" }\n }\n const startedAt = Number(controlFields.startedAt)\n if (!Number.isFinite(startedAt)) {\n return { ok: false, error: \"Invalid submission.\" }\n }\n if (input.now - startedAt < MIN_SUBMISSION_TIME_MS) {\n return { ok: false, error: \"Form submitted too quickly.\" }\n }\n\n const supportedFields = input.formFields.flatMap((field) =>\n field.name && field.blockType in MAX_LENGTH_BY_BLOCK ? [{ ...field, name: field.name }] : [],\n )\n const formFieldMap = new Map(supportedFields.map((field) => [field.name, field]))\n const normalized: Array<{ field: string; value: string }> = []\n const seenFields = new Set<string>()\n\n for (const entry of input.submissionData ?? []) {\n const fieldName = entry.field?.trim()\n if (!fieldName || isControlField(fieldName)) {\n continue\n }\n if (seenFields.has(fieldName)) {\n return { ok: false, error: `Field \"${fieldName}\" was submitted more than once.` }\n }\n seenFields.add(fieldName)\n const formField = formFieldMap.get(fieldName)\n if (!formField) {\n return { ok: false, error: `Unexpected field \"${fieldName}\".` }\n }\n const value = stringifySubmissionValue(entry.value)\n if (!isValidFieldValue(formField, value)) {\n return { ok: false, error: `Field \"${fieldName}\" is invalid.` }\n }\n normalized.push({ field: fieldName, value })\n }\n\n for (const field of supportedFields) {\n const value = normalized.find((entry) => entry.field === field.name)?.value\n if (!requiredValueIsPresent(field, value)) {\n return { ok: false, error: `Field \"${field.name}\" is required.` }\n }\n }\n\n return { ok: true, data: normalized }\n}\n\nexport function submissionDataToPlainRecord(\n submissionData: ValidationSubmissionField[],\n): Record<string, string> {\n return Object.fromEntries(\n submissionData.flatMap((entry) =>\n entry.field ? [[entry.field, stringifySubmissionValue(entry.value)]] : [],\n ),\n )\n}\n\nexport function substituteSubmissionPlaceholders(\n template: string,\n values: Record<string, string>,\n): string {\n return template.replace(\n /\\{\\{\\s*([\\w.-]+)\\s*\\}\\}/g,\n (_, fieldName: string) => values[fieldName] ?? \"\",\n )\n}\n\nexport function resolveCommaSeparatedSubmissionTags(\n tags: string | null | undefined,\n values: Record<string, string>,\n): string[] {\n return (tags ?? \"\")\n .split(\",\")\n .map((tag) => substituteSubmissionPlaceholders(tag, values).trim())\n .filter(Boolean)\n}\n","import {\n resolveCommaSeparatedSubmissionTags,\n submissionDataToPlainRecord,\n validateSubmissionInput,\n} from \"./submission\"\n\nimport type { MarketingAdapter } from \"../types\"\nimport type { CollectionBeforeChangeHook, PayloadRequest } from \"payload\"\n\ninterface FormSubmissionData {\n form?: unknown\n submissionData?: Array<{ field?: string | null; value?: unknown }>\n}\n\nfunction getStringField(data: FormSubmissionData, field: string): string | undefined {\n const value = data.submissionData?.find((row) => row.field === field)?.value\n if (typeof value === \"string\") {\n return value\n }\n if (value == null) {\n return undefined\n }\n if (typeof value === \"number\" && Number.isFinite(value)) {\n return String(value)\n }\n if (typeof value === \"boolean\") {\n return String(value)\n }\n return undefined\n}\n\ninterface HookOptions {\n formsSlug?: string\n minSubmitDurationMs?: number\n}\n\nasync function resolveMarketingForm(\n data: { form?: unknown },\n req: PayloadRequest,\n formsSlug = \"forms\",\n): Promise<unknown> {\n if (typeof data.form === \"string\") {\n return await req.payload.findByID({\n collection: formsSlug,\n depth: 0,\n id: data.form,\n overrideAccess: true,\n })\n }\n return data.form\n}\n\nexport function createValidateFormSubmissionHook(\n options: HookOptions = {},\n): CollectionBeforeChangeHook {\n return async ({ data, operation, req }) => {\n if (operation !== \"create\") {\n return data\n }\n const form = await resolveMarketingForm(data as { form?: unknown }, req, options.formsSlug)\n const result = validateSubmissionInput({\n formFields: ((form as { fields?: unknown[] } | undefined)?.fields ?? []) as never,\n now: Date.now(),\n submissionData: (data?.submissionData ?? []) as never,\n })\n if (!result.ok) {\n throw new Error(result.error)\n }\n data.submissionData = result.data\n return data\n }\n}\n\nexport function createCreateLeadHook(\n adapter: MarketingAdapter,\n options: HookOptions = {},\n): CollectionBeforeChangeHook {\n return async ({ data, operation, req }) => {\n if (operation !== \"create\") {\n return data\n }\n const form = await resolveMarketingForm(data as { form?: unknown }, req, options.formsSlug)\n const formRecord = form as\n | { audienceId?: string; event?: string; tags?: string | null }\n | undefined\n if (formRecord?.event !== \"lead\" || !formRecord.audienceId) {\n return data\n }\n\n const submission = data as FormSubmissionData\n const email = getStringField(submission, \"email\")\n if (!email) {\n return data\n }\n\n const fieldValues = submissionDataToPlainRecord(submission.submissionData ?? [])\n const tags = resolveCommaSeparatedSubmissionTags(formRecord.tags, fieldValues)\n await adapter.contacts.upsert({\n audienceId: formRecord.audienceId,\n email,\n firstName: getStringField(submission, \"firstName\"),\n lastName: getStringField(submission, \"lastName\"),\n properties: tags.length > 0 ? { tags: tags.join(\",\") } : undefined,\n subscribed: true,\n })\n return data\n }\n}\n","import { createMarketingFormFields } from \"./fields\"\nimport { createCreateLeadHook, createValidateFormSubmissionHook } from \"./hooks\"\n\nimport type { PayloadPluginMarketingOptions } from \"../types\"\nimport type { CollectionConfig, Field } from \"payload\"\n\nfunction isNamedField(field: Field, name: string): field is Field & { name: string } {\n return \"name\" in field && field.name === name\n}\n\nfunction hasSlug(item: unknown): item is { slug: string } {\n return Boolean(\n item && typeof item === \"object\" && \"slug\" in item && typeof item.slug === \"string\",\n )\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return Boolean(value && typeof value === \"object\")\n}\n\nfunction upsertField(fields: Field[], field: Field): Field[] {\n if (!(\"name\" in field) || !field.name) {\n return [...fields, field]\n }\n return fields.some((existing) => isNamedField(existing, field.name))\n ? fields.map((existing) => (isNamedField(existing, field.name) ? field : existing))\n : [...fields, field]\n}\n\nfunction createMarketingConfigFields(options: PayloadPluginMarketingOptions): Field[] {\n const audienceSelect = options.admin?.components?.audienceSelect ?? {\n path: \"payload-plugin-marketing/admin\",\n exportName: \"AudienceSelect\",\n }\n return [\n {\n name: \"event\",\n type: \"select\",\n defaultValue: \"submission\",\n options: [\n { label: \"Submission\", value: \"submission\" },\n { label: \"Lead\", value: \"lead\" },\n ],\n },\n {\n name: \"audienceId\",\n type: \"text\",\n label: \"Audience ID\",\n required: false,\n admin: {\n condition: (_data, siblingData) => siblingData?.event === \"lead\",\n components: { Field: audienceSelect },\n },\n validate: (value: unknown, { siblingData }: { siblingData?: { event?: string } } = {}) =>\n siblingData?.event === \"lead\" && !value ? \"Audience is required for lead forms.\" : true,\n },\n {\n name: \"tags\",\n type: \"textarea\",\n label: \"Tags\",\n admin: {\n condition: (_data, siblingData) => siblingData?.event === \"lead\",\n description: \"Optional comma-separated tags. Use {{fieldName}} to insert submitted values.\",\n },\n },\n ] as Field[]\n}\n\nfunction mutateFormsCollection(\n collection: CollectionConfig,\n options: PayloadPluginMarketingOptions,\n): CollectionConfig {\n const fields = [...collection.fields]\n const fieldsIndex = fields.findIndex(\n (field) => isNamedField(field, \"fields\") && field.type === \"blocks\",\n )\n if (fieldsIndex < 0) {\n if (options.formBuilder?.strict === false) {\n return collection\n }\n throw new Error(\n `Could not find a blocks field named \"fields\" on form-builder forms collection \"${collection.slug}\".`,\n )\n }\n\n const fieldsField = fields[fieldsIndex] as Field & { blocks: unknown[] }\n const existingBlocks = Array.isArray(fieldsField.blocks) ? fieldsField.blocks : []\n const blockOverrides = options.formBuilder?.fields ?? {}\n const overriddenExistingBlocks = existingBlocks.map((block) => {\n if (!hasSlug(block)) {\n return block\n }\n const override = blockOverrides[block.slug as keyof typeof blockOverrides]\n if (!override || !isRecord(block)) {\n return block\n }\n return {\n ...block,\n ...(override.overrides ?? {}),\n ...(override.labels ? { labels: override.labels } : {}),\n }\n })\n const existingSlugs = new Set(\n overriddenExistingBlocks.flatMap((block) => (hasSlug(block) ? [block.slug] : [])),\n )\n const marketingBlocks = Object.values(\n createMarketingFormFields(options.formBuilder?.fields),\n ).filter((block) => !existingSlugs.has(block.slug))\n\n fields[fieldsIndex] = {\n ...fieldsField,\n blocks: [...overriddenExistingBlocks, ...marketingBlocks],\n } as Field\n\n for (const field of createMarketingConfigFields(options)) {\n fields.splice(0, fields.length, ...upsertField(fields, field))\n }\n\n return { ...collection, fields }\n}\n\nfunction mutateSubmissionsCollection(\n collection: CollectionConfig,\n options: PayloadPluginMarketingOptions,\n): CollectionConfig {\n const hooks = collection.hooks ?? {}\n return {\n ...collection,\n hooks: {\n ...hooks,\n beforeChange: [\n ...(hooks.beforeChange ?? []),\n createValidateFormSubmissionHook({ formsSlug: options.formBuilder?.formsSlug }),\n createCreateLeadHook(options.adapter, { formsSlug: options.formBuilder?.formsSlug }),\n ],\n },\n }\n}\n\nexport function mutateFormBuilderCollections(\n collections: CollectionConfig[] | undefined,\n options: PayloadPluginMarketingOptions,\n): CollectionConfig[] | undefined {\n const formsSlug = options.formBuilder?.formsSlug ?? \"forms\"\n const submissionsSlug = options.formBuilder?.submissionsSlug ?? \"form-submissions\"\n const strict = options.formBuilder?.strict ?? true\n const list = collections ?? []\n const hasForms = list.some((collection) => collection.slug === formsSlug)\n const hasSubmissions = list.some((collection) => collection.slug === submissionsSlug)\n\n if (strict && !hasForms) {\n throw new Error(`Could not find form-builder forms collection \"${formsSlug}\".`)\n }\n if (strict && !hasSubmissions) {\n throw new Error(`Could not find form-builder submissions collection \"${submissionsSlug}\".`)\n }\n\n return list.map((collection) => {\n if (collection.slug === formsSlug) {\n return mutateFormsCollection(collection, options)\n }\n if (collection.slug === submissionsSlug) {\n return mutateSubmissionsCollection(collection, options)\n }\n return collection\n })\n}\n","import { mutateFormBuilderCollections } from \"./form-builder/mutate-collections\"\n\nimport type { PayloadMarketingPlugin, PayloadPluginMarketingOptions } from \"./types\"\nimport type { Config } from \"payload\"\n\nfunction component(exportName: string, clientProps?: Record<string, unknown>) {\n return {\n path: \"payload-plugin-marketing/admin\",\n exportName,\n ...(clientProps ? { clientProps } : {}),\n }\n}\n\nfunction adminViewPath(basePath: string, ...segments: string[]): `/${string}` {\n const trimmed = basePath.replace(/^\\/+|\\/+$/g, \"\")\n const body = [trimmed, ...segments].filter(Boolean).join(\"/\")\n return `/${body}`\n}\n\nfunction withMarketingAdmin(config: Config, options: PayloadPluginMarketingOptions): Config {\n if (options.admin?.enabled === false) {\n return config\n }\n const basePath = options.admin?.basePath ?? \"\"\n const components = options.admin?.components ?? {}\n const menuComponent = components.marketingMenu ?? component(\"MarketingMenu\", { basePath })\n return {\n ...config,\n admin: {\n ...(config.admin ?? {}),\n components: {\n ...(config.admin?.components ?? {}),\n afterNavLinks: [\n ...((config.admin?.components?.afterNavLinks as unknown[]) ?? []),\n menuComponent,\n ],\n views: {\n ...((config.admin?.components?.views as Record<string, unknown> | undefined) ?? {}),\n audienceList: {\n Component: components.audienceList ?? component(\"AudienceList\"),\n path: adminViewPath(basePath, \"audience\"),\n },\n audienceDetail: {\n Component: components.audienceDetail ?? component(\"AudienceDetail\"),\n path: adminViewPath(basePath, \"audience\", \":id\"),\n },\n broadcastList: {\n Component: components.broadcastList ?? component(\"BroadcastList\"),\n path: adminViewPath(basePath, \"broadcast\"),\n },\n },\n },\n },\n } as Config\n}\n\nexport function payloadMarketingPlugin(\n options: PayloadPluginMarketingOptions,\n): PayloadMarketingPlugin {\n const plugin: PayloadMarketingPlugin = (config) =>\n withMarketingAdmin(\n {\n ...config,\n collections: mutateFormBuilderCollections(config.collections, options),\n },\n options,\n )\n plugin.slug = \"marketing\"\n plugin.order = 10\n plugin.options = options as unknown as Record<string, unknown>\n return plugin\n}\n"],"mappings":"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","names":["index_exports","__export","createAcceptanceBlock","createMarketingActions","createMarketingFormFields","payloadMarketingPlugin","mailchimpAdapter","resendAdapter","__toCommonJS","createMarketingActions","adapter","input","audienceId","import_node_crypto","subscriberHash","email","serverFromApiKey","apiKey","server","tagNamesFromProperties","properties","raw","tag","stringValue","value","fallback","mailchimpAdapter","options","configured","getClient","client","adminBase","input","id","list","member","mergeFields","hash","status","tags","name","templateIdRaw","templateIdParsed","html","parsed","campaign","settings","sentAt","scheduledAt","assertNoResendError","result","error","stringifyFromRecord","value","fallback","mapBroadcast","row","resendAdapter","options","getClient","resendModule","id","input","client","unsubscribed","payload","mergeField","base","override","overrides","direct","row","fields","textLikeBlock","slug","labels","options","createAcceptanceBlock","createMarketingFormFields","FORM_HONEYPOT_FIELD","FORM_STARTED_AT_FIELD","MAX_LENGTH_BY_BLOCK","isControlField","fieldName","FORM_HONEYPOT_FIELD","FORM_STARTED_AT_FIELD","extractControlFields","submissionData","honeypot","entry","startedAt","stringifySubmissionValue","value","isValidFieldValue","field","option","requiredValueIsPresent","validateSubmissionInput","input","controlFields","supportedFields","formFieldMap","normalized","seenFields","formField","submissionDataToPlainRecord","substituteSubmissionPlaceholders","template","values","_","resolveCommaSeparatedSubmissionTags","tags","tag","getStringField","data","field","value","row","resolveMarketingForm","req","formsSlug","createValidateFormSubmissionHook","options","operation","form","result","validateSubmissionInput","createCreateLeadHook","adapter","formRecord","submission","email","fieldValues","submissionDataToPlainRecord","tags","resolveCommaSeparatedSubmissionTags","isNamedField","field","name","hasSlug","item","isRecord","value","upsertField","fields","existing","createMarketingConfigFields","options","audienceSelect","_data","siblingData","mutateFormsCollection","collection","fieldsIndex","fieldsField","existingBlocks","blockOverrides","overriddenExistingBlocks","block","override","existingSlugs","marketingBlocks","createMarketingFormFields","mutateSubmissionsCollection","hooks","createValidateFormSubmissionHook","createCreateLeadHook","mutateFormBuilderCollections","collections","formsSlug","submissionsSlug","strict","list","hasForms","hasSubmissions","component","exportName","clientProps","adminViewPath","basePath","segments","withMarketingAdmin","config","options","components","menuComponent","payloadMarketingPlugin","plugin","mutateFormBuilderCollections"]}