@mobilizehub/payload-plugin 0.1.0 → 0.3.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.
- package/dist/adapters/index.d.ts +1 -0
- package/dist/adapters/index.js +3 -0
- package/dist/adapters/index.js.map +1 -0
- package/dist/adapters/resend-adapter.d.ts +34 -0
- package/dist/adapters/resend-adapter.js +219 -0
- package/dist/adapters/resend-adapter.js.map +1 -0
- package/dist/collections/broadcasts/generateBroadcastsCollection.d.ts +3 -0
- package/dist/collections/broadcasts/generateBroadcastsCollection.js +241 -0
- package/dist/collections/broadcasts/generateBroadcastsCollection.js.map +1 -0
- package/dist/collections/emails/generateEmailsCollection.d.ts +3 -0
- package/dist/collections/emails/generateEmailsCollection.js +204 -0
- package/dist/collections/emails/generateEmailsCollection.js.map +1 -0
- package/dist/collections/emails/hooks/sync-status-from-activity.d.ts +5 -0
- package/dist/collections/emails/hooks/sync-status-from-activity.js +64 -0
- package/dist/collections/emails/hooks/sync-status-from-activity.js.map +1 -0
- package/dist/collections/pages/generatePagesCollection.d.ts +3 -0
- package/dist/collections/pages/generatePagesCollection.js +77 -0
- package/dist/collections/pages/generatePagesCollection.js.map +1 -0
- package/dist/collections/unsubscribe-tokens/generateUnsubscribeTokens.d.ts +2 -0
- package/dist/collections/unsubscribe-tokens/generateUnsubscribeTokens.js +48 -0
- package/dist/collections/unsubscribe-tokens/generateUnsubscribeTokens.js.map +1 -0
- package/dist/components/broadcast-metrics-card.d.ts +7 -0
- package/dist/components/broadcast-metrics-card.js +159 -0
- package/dist/components/broadcast-metrics-card.js.map +1 -0
- package/dist/components/broadcast-send-modal.d.ts +9 -0
- package/dist/components/broadcast-send-modal.js +51 -0
- package/dist/components/broadcast-send-modal.js.map +1 -0
- package/dist/components/broadcast-send-test-drawer.d.ts +7 -0
- package/dist/components/broadcast-send-test-drawer.js +154 -0
- package/dist/components/broadcast-send-test-drawer.js.map +1 -0
- package/dist/components/email-activity.d.ts +4 -0
- package/dist/components/email-activity.js +359 -0
- package/dist/components/email-activity.js.map +1 -0
- package/dist/components/email-preview.d.ts +2 -0
- package/dist/components/email-preview.js +95 -0
- package/dist/components/email-preview.js.map +1 -0
- package/dist/endpoints/sendBroadcastHandler.d.ts +9 -0
- package/dist/endpoints/sendBroadcastHandler.js +107 -0
- package/dist/endpoints/sendBroadcastHandler.js.map +1 -0
- package/dist/endpoints/sendTestBroadcastHandler.d.ts +10 -0
- package/dist/endpoints/sendTestBroadcastHandler.js +143 -0
- package/dist/endpoints/sendTestBroadcastHandler.js.map +1 -0
- package/dist/endpoints/unsubscribeHandler.d.ts +9 -0
- package/dist/endpoints/unsubscribeHandler.js +153 -0
- package/dist/endpoints/unsubscribeHandler.js.map +1 -0
- package/dist/exports/client.d.ts +3 -1
- package/dist/exports/client.js +3 -0
- package/dist/exports/client.js.map +1 -1
- package/dist/exports/rsc.d.ts +2 -1
- package/dist/exports/rsc.js +2 -0
- package/dist/exports/rsc.js.map +1 -1
- package/dist/fields/name.d.ts +5 -0
- package/dist/fields/name.js +12 -0
- package/dist/fields/name.js.map +1 -0
- package/dist/fields/publishedAt.d.ts +5 -0
- package/dist/fields/publishedAt.js +16 -0
- package/dist/fields/publishedAt.js.map +1 -0
- package/dist/fields/slug.d.ts +7 -0
- package/dist/fields/slug.js +47 -0
- package/dist/fields/slug.js.map +1 -0
- package/dist/fields/status.d.ts +5 -0
- package/dist/fields/status.js +25 -0
- package/dist/fields/status.js.map +1 -0
- package/dist/index.js +48 -3
- package/dist/index.js.map +1 -1
- package/dist/react/index.d.ts +1 -0
- package/dist/react/index.js +3 -0
- package/dist/react/index.js.map +1 -0
- package/dist/react/unsubscribe.d.ts +6 -0
- package/dist/react/unsubscribe.js +16 -0
- package/dist/react/unsubscribe.js.map +1 -0
- package/dist/tasks/sendBroadcastsTask.d.ts +11 -0
- package/dist/tasks/sendBroadcastsTask.js +196 -0
- package/dist/tasks/sendBroadcastsTask.js.map +1 -0
- package/dist/tasks/sendEmailTask.d.ts +9 -0
- package/dist/tasks/sendEmailTask.js +167 -0
- package/dist/tasks/sendEmailTask.js.map +1 -0
- package/dist/types/index.d.ts +133 -1
- package/dist/types/index.js.map +1 -1
- package/dist/utils/api-response.d.ts +72 -0
- package/dist/utils/api-response.js +66 -0
- package/dist/utils/api-response.js.map +1 -0
- package/dist/utils/email.d.ts +36 -0
- package/dist/utils/email.js +40 -0
- package/dist/utils/email.js.map +1 -0
- package/dist/utils/lexical.d.ts +13 -0
- package/dist/utils/lexical.js +27 -0
- package/dist/utils/lexical.js.map +1 -0
- package/dist/utils/unsubscribe-token.d.ts +67 -0
- package/dist/utils/unsubscribe-token.js +103 -0
- package/dist/utils/unsubscribe-token.js.map +1 -0
- package/package.json +20 -9
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import { formatFromAddress } from '../utils/email.js';
|
|
2
|
+
import { parseLexicalContent } from '../utils/lexical.js';
|
|
3
|
+
import { generateUnsubscribeToken } from '../utils/unsubscribe-token.js';
|
|
4
|
+
/**
|
|
5
|
+
* Resolves collection slugs from plugin config, falling back to defaults.
|
|
6
|
+
*/ function getCollectionSlugs(config) {
|
|
7
|
+
return {
|
|
8
|
+
broadcasts: config.broadcastsOverrides?.slug || 'broadcasts',
|
|
9
|
+
contacts: config.contactsOverrides?.slug || 'contacts',
|
|
10
|
+
emails: config.emailsOverrides?.slug || 'emails'
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Checks if an email record already exists for a broadcast-contact pair.
|
|
15
|
+
*/ async function checkEmailExists(payload, collection, broadcastId, contactId) {
|
|
16
|
+
const { docs } = await payload.find({
|
|
17
|
+
collection,
|
|
18
|
+
limit: 1,
|
|
19
|
+
where: {
|
|
20
|
+
and: [
|
|
21
|
+
{
|
|
22
|
+
broadcast: {
|
|
23
|
+
equals: broadcastId
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
contact: {
|
|
28
|
+
equals: contactId
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
]
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
return docs[0] ?? null;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Creates the send-email task configuration.
|
|
38
|
+
*
|
|
39
|
+
* Handles delivery of a single email for one contact within a broadcast.
|
|
40
|
+
* Queued by the send-broadcasts task, one job per contact.
|
|
41
|
+
*/ export const createSendEmailTask = (pluginConfig)=>{
|
|
42
|
+
const collections = getCollectionSlugs(pluginConfig);
|
|
43
|
+
return {
|
|
44
|
+
slug: 'send-email',
|
|
45
|
+
handler: async ({ input, req })=>{
|
|
46
|
+
const { payload } = req;
|
|
47
|
+
const logger = payload.logger;
|
|
48
|
+
const { broadcastId, contactId } = input;
|
|
49
|
+
// Skip if already processed (handles job retries)
|
|
50
|
+
const existingEmail = await checkEmailExists(payload, collections.emails, broadcastId, contactId);
|
|
51
|
+
if (existingEmail) {
|
|
52
|
+
logger.info(`Email already exists for broadcast ${broadcastId}, contact ${contactId} ` + `(email ID: ${existingEmail.id}, status: ${existingEmail.status})`);
|
|
53
|
+
return {
|
|
54
|
+
output: {
|
|
55
|
+
success: true
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
const [contact, broadcast] = await Promise.all([
|
|
60
|
+
payload.findByID({
|
|
61
|
+
id: contactId,
|
|
62
|
+
collection: collections.contacts
|
|
63
|
+
}),
|
|
64
|
+
payload.findByID({
|
|
65
|
+
id: broadcastId,
|
|
66
|
+
collection: collections.broadcasts
|
|
67
|
+
})
|
|
68
|
+
]);
|
|
69
|
+
if (!contact) {
|
|
70
|
+
throw new Error(`Contact ${contactId} not found`);
|
|
71
|
+
}
|
|
72
|
+
if (!broadcast) {
|
|
73
|
+
throw new Error(`Broadcast ${broadcastId} not found`);
|
|
74
|
+
}
|
|
75
|
+
const sender = pluginConfig.email({
|
|
76
|
+
payload
|
|
77
|
+
});
|
|
78
|
+
const fromAddress = formatFromAddress(broadcast.fromName, broadcast.fromAddress);
|
|
79
|
+
const tokenId = crypto.randomUUID();
|
|
80
|
+
const unsubscribeToken = generateUnsubscribeToken({
|
|
81
|
+
tokenId
|
|
82
|
+
});
|
|
83
|
+
const parsedContent = await parseLexicalContent(broadcast.content, payload.config);
|
|
84
|
+
const html = sender.render({
|
|
85
|
+
from: fromAddress,
|
|
86
|
+
html: parsedContent.html,
|
|
87
|
+
markdown: parsedContent.markdown,
|
|
88
|
+
plainText: parsedContent.plainText,
|
|
89
|
+
subject: broadcast.subject,
|
|
90
|
+
to: contact.email,
|
|
91
|
+
token: unsubscribeToken
|
|
92
|
+
});
|
|
93
|
+
const email = await payload.create({
|
|
94
|
+
collection: collections.emails,
|
|
95
|
+
data: {
|
|
96
|
+
broadcast: broadcast.id,
|
|
97
|
+
contact: contact.id,
|
|
98
|
+
from: fromAddress,
|
|
99
|
+
html,
|
|
100
|
+
status: 'queued',
|
|
101
|
+
subject: broadcast.subject,
|
|
102
|
+
to: contact.email
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
await payload.create({
|
|
106
|
+
collection: 'emailUnsubscribeTokens',
|
|
107
|
+
data: {
|
|
108
|
+
id: tokenId,
|
|
109
|
+
emailId: email.id
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
const result = await sender.sendEmail({
|
|
113
|
+
from: fromAddress,
|
|
114
|
+
html,
|
|
115
|
+
idempotencyKey: `broadcast-${broadcastId}-contact-${contactId}`,
|
|
116
|
+
markdown: parsedContent.markdown,
|
|
117
|
+
plainText: parsedContent.plainText,
|
|
118
|
+
previewText: broadcast.previewText,
|
|
119
|
+
replyTo: broadcast.replyTo,
|
|
120
|
+
subject: broadcast.subject,
|
|
121
|
+
to: contact.email,
|
|
122
|
+
token: unsubscribeToken
|
|
123
|
+
});
|
|
124
|
+
await payload.update({
|
|
125
|
+
id: email.id,
|
|
126
|
+
collection: collections.emails,
|
|
127
|
+
data: {
|
|
128
|
+
activity: [
|
|
129
|
+
{
|
|
130
|
+
type: 'sent',
|
|
131
|
+
timestamp: new Date().toISOString()
|
|
132
|
+
}
|
|
133
|
+
],
|
|
134
|
+
providerId: result?.providerId,
|
|
135
|
+
status: 'sent'
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
logger.info(`Sent email ${email.id} for broadcast ${broadcastId} to ${contact.email}`);
|
|
139
|
+
return {
|
|
140
|
+
output: {
|
|
141
|
+
success: true
|
|
142
|
+
}
|
|
143
|
+
};
|
|
144
|
+
},
|
|
145
|
+
inputSchema: [
|
|
146
|
+
{
|
|
147
|
+
name: 'contactId',
|
|
148
|
+
type: 'number',
|
|
149
|
+
required: true
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
name: 'broadcastId',
|
|
153
|
+
type: 'number',
|
|
154
|
+
required: true
|
|
155
|
+
}
|
|
156
|
+
],
|
|
157
|
+
outputSchema: [
|
|
158
|
+
{
|
|
159
|
+
name: 'success',
|
|
160
|
+
type: 'checkbox'
|
|
161
|
+
}
|
|
162
|
+
],
|
|
163
|
+
retries: 3
|
|
164
|
+
};
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
//# sourceMappingURL=sendEmailTask.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/tasks/sendEmailTask.ts"],"sourcesContent":["import type { SerializedEditorState } from '@payloadcms/richtext-lexical/lexical'\nimport type { BasePayload, TaskConfig } from 'payload'\n\nimport type { MobilizehubPluginConfig } from '../types/index.js'\n\nimport { formatFromAddress } from '../utils/email.js'\nimport { parseLexicalContent } from '../utils/lexical.js'\nimport { generateUnsubscribeToken } from '../utils/unsubscribe-token.js'\n\n/**\n * Resolves collection slugs from plugin config, falling back to defaults.\n */\nfunction getCollectionSlugs(config: MobilizehubPluginConfig) {\n return {\n broadcasts: config.broadcastsOverrides?.slug || 'broadcasts',\n contacts: config.contactsOverrides?.slug || 'contacts',\n emails: config.emailsOverrides?.slug || 'emails',\n }\n}\n\n/**\n * Checks if an email record already exists for a broadcast-contact pair.\n */\nasync function checkEmailExists(\n payload: BasePayload,\n collection: string,\n broadcastId: number | string,\n contactId: number | string,\n) {\n const { docs } = await payload.find({\n collection,\n limit: 1,\n where: {\n and: [{ broadcast: { equals: broadcastId } }, { contact: { equals: contactId } }],\n },\n })\n\n return docs[0] ?? null\n}\n\n/**\n * Creates the send-email task configuration.\n *\n * Handles delivery of a single email for one contact within a broadcast.\n * Queued by the send-broadcasts task, one job per contact.\n */\nexport const createSendEmailTask = (pluginConfig: MobilizehubPluginConfig): TaskConfig => {\n const collections = getCollectionSlugs(pluginConfig)\n\n return {\n slug: 'send-email',\n handler: async ({ input, req }) => {\n const { payload } = req\n const logger = payload.logger\n\n const { broadcastId, contactId } = input as { broadcastId: number; contactId: number }\n\n // Skip if already processed (handles job retries)\n const existingEmail = await checkEmailExists(\n payload,\n collections.emails,\n broadcastId,\n contactId,\n )\n\n if (existingEmail) {\n logger.info(\n `Email already exists for broadcast ${broadcastId}, contact ${contactId} ` +\n `(email ID: ${existingEmail.id}, status: ${existingEmail.status})`,\n )\n return { output: { success: true } }\n }\n\n const [contact, broadcast] = await Promise.all([\n payload.findByID({ id: contactId, collection: collections.contacts }),\n payload.findByID({ id: broadcastId, collection: collections.broadcasts }),\n ])\n\n if (!contact) {\n throw new Error(`Contact ${contactId} not found`)\n }\n if (!broadcast) {\n throw new Error(`Broadcast ${broadcastId} not found`)\n }\n\n const sender = pluginConfig.email({ payload })\n const fromAddress = formatFromAddress(broadcast.fromName, broadcast.fromAddress)\n\n const tokenId = crypto.randomUUID()\n const unsubscribeToken = generateUnsubscribeToken({ tokenId })\n\n const parsedContent = await parseLexicalContent(\n broadcast.content as SerializedEditorState,\n payload.config,\n )\n\n const html = sender.render({\n from: fromAddress,\n html: parsedContent.html,\n markdown: parsedContent.markdown,\n plainText: parsedContent.plainText,\n subject: broadcast.subject,\n to: contact.email,\n token: unsubscribeToken,\n })\n\n const email = await payload.create({\n collection: collections.emails,\n data: {\n broadcast: broadcast.id,\n contact: contact.id,\n from: fromAddress,\n html,\n status: 'queued',\n subject: broadcast.subject,\n to: contact.email,\n },\n })\n\n await payload.create({\n collection: 'emailUnsubscribeTokens',\n data: { id: tokenId, emailId: email.id },\n })\n\n const result = await sender.sendEmail({\n from: fromAddress,\n html,\n idempotencyKey: `broadcast-${broadcastId}-contact-${contactId}`,\n markdown: parsedContent.markdown,\n plainText: parsedContent.plainText,\n previewText: broadcast.previewText,\n replyTo: broadcast.replyTo,\n subject: broadcast.subject,\n to: contact.email,\n token: unsubscribeToken,\n })\n\n await payload.update({\n id: email.id,\n collection: collections.emails,\n data: {\n activity: [{ type: 'sent', timestamp: new Date().toISOString() }],\n providerId: result?.providerId,\n status: 'sent',\n },\n })\n\n logger.info(`Sent email ${email.id} for broadcast ${broadcastId} to ${contact.email}`)\n\n return { output: { success: true } }\n },\n inputSchema: [\n { name: 'contactId', type: 'number', required: true },\n { name: 'broadcastId', type: 'number', required: true },\n ],\n outputSchema: [{ name: 'success', type: 'checkbox' }],\n retries: 3,\n }\n}\n"],"names":["formatFromAddress","parseLexicalContent","generateUnsubscribeToken","getCollectionSlugs","config","broadcasts","broadcastsOverrides","slug","contacts","contactsOverrides","emails","emailsOverrides","checkEmailExists","payload","collection","broadcastId","contactId","docs","find","limit","where","and","broadcast","equals","contact","createSendEmailTask","pluginConfig","collections","handler","input","req","logger","existingEmail","info","id","status","output","success","Promise","all","findByID","Error","sender","email","fromAddress","fromName","tokenId","crypto","randomUUID","unsubscribeToken","parsedContent","content","html","render","from","markdown","plainText","subject","to","token","create","data","emailId","result","sendEmail","idempotencyKey","previewText","replyTo","update","activity","type","timestamp","Date","toISOString","providerId","inputSchema","name","required","outputSchema","retries"],"mappings":"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"}
|
package/dist/types/index.d.ts
CHANGED
|
@@ -1,12 +1,144 @@
|
|
|
1
|
-
import type { CollectionConfig, Field } from 'payload';
|
|
1
|
+
import type { BasePayload, Block, CollectionConfig, Field, PayloadRequest } from 'payload';
|
|
2
2
|
export type FieldsOverride = (args: {
|
|
3
3
|
defaultFields: Field[];
|
|
4
4
|
}) => Field[];
|
|
5
5
|
export type CollectionOverride = {
|
|
6
6
|
fields?: FieldsOverride;
|
|
7
7
|
} & Partial<Omit<CollectionConfig, 'fields'>>;
|
|
8
|
+
export type BlocksOverride = (args: {
|
|
9
|
+
defaultBlocks: Block[];
|
|
10
|
+
}) => Block[];
|
|
11
|
+
/**
|
|
12
|
+
* Contact type
|
|
13
|
+
*/
|
|
14
|
+
export type Contact = {
|
|
15
|
+
createdAt?: string;
|
|
16
|
+
email?: string;
|
|
17
|
+
emailOptIn: boolean;
|
|
18
|
+
firstName?: string;
|
|
19
|
+
id: number | string;
|
|
20
|
+
lastName?: string;
|
|
21
|
+
tags?: {
|
|
22
|
+
createdAt?: string;
|
|
23
|
+
id: number | string;
|
|
24
|
+
name?: string;
|
|
25
|
+
updatedAt?: string;
|
|
26
|
+
}[];
|
|
27
|
+
updatedAt?: string;
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* Unsubscribe token input structure
|
|
31
|
+
*/
|
|
32
|
+
export interface UnsubscribeTokenInput {
|
|
33
|
+
timestamp: number;
|
|
34
|
+
tokenId: string;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Unsubscribe token record structure
|
|
38
|
+
*/
|
|
39
|
+
export type UnsubscribeTokenRecord = {
|
|
40
|
+
emailId?: number | string;
|
|
41
|
+
expiresAt?: string;
|
|
42
|
+
id: string;
|
|
43
|
+
};
|
|
44
|
+
/**
|
|
45
|
+
* Email activity types
|
|
46
|
+
*/
|
|
47
|
+
export type EmailStatus = 'bounced' | 'complained' | 'delivered' | 'failed' | 'queued' | 'sent' | 'unsubscribed';
|
|
48
|
+
/**
|
|
49
|
+
* Email activity types from providers
|
|
50
|
+
*/
|
|
51
|
+
export type EmailActivityType = 'bounced' | 'clicked' | 'complained' | 'delivered' | 'delivery_delayed' | 'failed' | 'opened' | 'received' | 'sent';
|
|
52
|
+
/**
|
|
53
|
+
* Email message structure
|
|
54
|
+
*/
|
|
55
|
+
export type EmailMessage = {
|
|
56
|
+
from: string;
|
|
57
|
+
html: string;
|
|
58
|
+
idempotencyKey?: string;
|
|
59
|
+
markdown?: string;
|
|
60
|
+
plainText?: string;
|
|
61
|
+
previewText?: string;
|
|
62
|
+
replyTo?: string;
|
|
63
|
+
subject: string;
|
|
64
|
+
to: string;
|
|
65
|
+
token?: string;
|
|
66
|
+
};
|
|
67
|
+
/**
|
|
68
|
+
* Result of a webhook call
|
|
69
|
+
*/
|
|
70
|
+
export type WebhookResult = {
|
|
71
|
+
body?: unknown;
|
|
72
|
+
status: number;
|
|
73
|
+
};
|
|
74
|
+
/**
|
|
75
|
+
* Email adapter interface for sending emails
|
|
76
|
+
*/
|
|
77
|
+
export type EmailAdapter = ({ payload }: {
|
|
78
|
+
payload: BasePayload;
|
|
79
|
+
}) => {
|
|
80
|
+
defaultFromAddress: string;
|
|
81
|
+
defaultFromName: string;
|
|
82
|
+
name: string;
|
|
83
|
+
render: (args: EmailMessage) => string;
|
|
84
|
+
sendEmail: (args: EmailMessage) => Promise<{
|
|
85
|
+
providerId: string;
|
|
86
|
+
} | void>;
|
|
87
|
+
webhookHandler?: (req: PayloadRequest) => Promise<void | WebhookResult>;
|
|
88
|
+
};
|
|
8
89
|
export type MobilizehubPluginConfig = {
|
|
90
|
+
broadcastConfig?: {
|
|
91
|
+
/**
|
|
92
|
+
* Batch size for processing contacts in the broadcasts task.
|
|
93
|
+
* Higher values process faster but use more memory.
|
|
94
|
+
* @default 100
|
|
95
|
+
*/
|
|
96
|
+
batchSize?: number;
|
|
97
|
+
/**
|
|
98
|
+
* Optional custom queue name for the broadcasts task
|
|
99
|
+
* @default 'send-broadcasts'
|
|
100
|
+
*/
|
|
101
|
+
broadcastQueueName?: string;
|
|
102
|
+
/**
|
|
103
|
+
* Optional custom queue name for the email sending task
|
|
104
|
+
* @default 'send-email'
|
|
105
|
+
*/
|
|
106
|
+
emailQueueName?: string;
|
|
107
|
+
/**
|
|
108
|
+
* Cron schedule for the broadcasts task
|
|
109
|
+
* On schedule the task will run to process and send pending broadcasts
|
|
110
|
+
* @default '5 * * * *' (every 5 minutes)
|
|
111
|
+
*/
|
|
112
|
+
taskSchedule?: string;
|
|
113
|
+
};
|
|
114
|
+
/**
|
|
115
|
+
* Overrides for the broadcasts collection
|
|
116
|
+
*/
|
|
117
|
+
broadcastsOverrides?: CollectionOverride;
|
|
118
|
+
/**
|
|
119
|
+
* Overrides for the contacts collection
|
|
120
|
+
*/
|
|
9
121
|
contactsOverrides?: CollectionOverride;
|
|
122
|
+
/**
|
|
123
|
+
* Disable the plugin
|
|
124
|
+
*/
|
|
10
125
|
disabled?: boolean;
|
|
126
|
+
/**
|
|
127
|
+
* Email adapter for sending emails
|
|
128
|
+
*/
|
|
129
|
+
email: EmailAdapter;
|
|
130
|
+
/**
|
|
131
|
+
* Overrides for the emails collection
|
|
132
|
+
*/
|
|
133
|
+
emailsOverrides?: CollectionOverride;
|
|
134
|
+
/**
|
|
135
|
+
* Overrides for the pages collection
|
|
136
|
+
*/
|
|
137
|
+
pagesOverrides?: {
|
|
138
|
+
blocks?: BlocksOverride;
|
|
139
|
+
} & CollectionOverride;
|
|
140
|
+
/**
|
|
141
|
+
* Overrides for the tags collection
|
|
142
|
+
*/
|
|
11
143
|
tagsOverrides?: CollectionOverride;
|
|
12
144
|
};
|
package/dist/types/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/types/index.ts"],"sourcesContent":["import type { CollectionConfig, Field } from 'payload'\n\nexport type FieldsOverride = (args: { defaultFields: Field[] }) => Field[]\n\nexport type CollectionOverride = { fields?: FieldsOverride } & Partial<\n Omit<CollectionConfig, 'fields'>\n>\nexport type MobilizehubPluginConfig = {\n contactsOverrides?: CollectionOverride\n disabled?: boolean\n tagsOverrides?: CollectionOverride\n}\n"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../../src/types/index.ts"],"sourcesContent":["import type { BasePayload, Block, CollectionConfig, Field, PayloadRequest } from 'payload'\n\nexport type FieldsOverride = (args: { defaultFields: Field[] }) => Field[]\n\nexport type CollectionOverride = { fields?: FieldsOverride } & Partial<\n Omit<CollectionConfig, 'fields'>\n>\n\nexport type BlocksOverride = (args: { defaultBlocks: Block[] }) => Block[]\n\n/**\n * Contact type\n */\nexport type Contact = {\n createdAt?: string\n email?: string\n emailOptIn: boolean\n firstName?: string\n id: number | string\n lastName?: string\n tags?: {\n createdAt?: string\n id: number | string\n name?: string\n updatedAt?: string\n }[]\n updatedAt?: string\n}\n\n/**\n * Unsubscribe token input structure\n */\nexport interface UnsubscribeTokenInput {\n timestamp: number\n tokenId: string\n}\n\n/**\n * Unsubscribe token record structure\n */\nexport type UnsubscribeTokenRecord = {\n emailId?: number | string\n expiresAt?: string\n id: string\n}\n\n/**\n * Email activity types\n */\nexport type EmailStatus =\n | 'bounced'\n | 'complained'\n | 'delivered'\n | 'failed'\n | 'queued'\n | 'sent'\n | 'unsubscribed'\n\n/**\n * Email activity types from providers\n */\nexport type EmailActivityType =\n | 'bounced'\n | 'clicked'\n | 'complained'\n | 'delivered'\n | 'delivery_delayed'\n | 'failed'\n | 'opened'\n | 'received'\n | 'sent'\n\n/**\n * Email message structure\n */\nexport type EmailMessage = {\n from: string\n html: string\n idempotencyKey?: string\n markdown?: string\n plainText?: string\n previewText?: string\n replyTo?: string\n subject: string\n to: string\n token?: string\n}\n\n/**\n * Result of a webhook call\n */\nexport type WebhookResult = {\n body?: unknown\n status: number\n}\n\n/**\n * Email adapter interface for sending emails\n */\nexport type EmailAdapter = ({ payload }: { payload: BasePayload }) => {\n defaultFromAddress: string\n defaultFromName: string\n name: string\n render: (args: EmailMessage) => string\n sendEmail: (args: EmailMessage) => Promise<{ providerId: string } | void>\n webhookHandler?: (req: PayloadRequest) => Promise<void | WebhookResult>\n}\n\nexport type MobilizehubPluginConfig = {\n broadcastConfig?: {\n /**\n * Batch size for processing contacts in the broadcasts task.\n * Higher values process faster but use more memory.\n * @default 100\n */\n batchSize?: number\n /**\n * Optional custom queue name for the broadcasts task\n * @default 'send-broadcasts'\n */\n broadcastQueueName?: string\n /**\n * Optional custom queue name for the email sending task\n * @default 'send-email'\n */\n emailQueueName?: string\n /**\n * Cron schedule for the broadcasts task\n * On schedule the task will run to process and send pending broadcasts\n * @default '5 * * * *' (every 5 minutes)\n */\n taskSchedule?: string\n }\n /**\n * Overrides for the broadcasts collection\n */\n broadcastsOverrides?: CollectionOverride\n\n /**\n * Overrides for the contacts collection\n */\n contactsOverrides?: CollectionOverride\n /**\n * Disable the plugin\n */\n disabled?: boolean\n /**\n * Email adapter for sending emails\n */\n email: EmailAdapter\n /**\n * Overrides for the emails collection\n */\n emailsOverrides?: CollectionOverride\n /**\n * Overrides for the pages collection\n */\n pagesOverrides?: { blocks?: BlocksOverride } & CollectionOverride\n /**\n * Overrides for the tags collection\n */\n tagsOverrides?: CollectionOverride\n /**\n *\n */\n}\n"],"names":[],"mappings":"AA4GA,WAyDC"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Standard API success response format
|
|
3
|
+
* @template T - Type of the data payload
|
|
4
|
+
*/
|
|
5
|
+
export type ApiSuccessResponse<T = unknown> = {
|
|
6
|
+
data?: T;
|
|
7
|
+
success: true;
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* Standard API error response format
|
|
11
|
+
*/
|
|
12
|
+
export type ApiErrorResponse = {
|
|
13
|
+
error: {
|
|
14
|
+
/** Error code constant (e.g., 'BAD_REQUEST', 'UNAUTHORIZED') */
|
|
15
|
+
code: string;
|
|
16
|
+
/** Human-readable error message */
|
|
17
|
+
message: string;
|
|
18
|
+
};
|
|
19
|
+
success: false;
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* Union type for all API responses
|
|
23
|
+
* @template T - Type of the data payload for success responses
|
|
24
|
+
*/
|
|
25
|
+
export type ApiResponse<T = unknown> = ApiErrorResponse | ApiSuccessResponse<T>;
|
|
26
|
+
/**
|
|
27
|
+
* Create a standardized success response
|
|
28
|
+
*
|
|
29
|
+
* @template T - Type of the response data
|
|
30
|
+
* @param data - Optional data payload to include in the response
|
|
31
|
+
* @param status - HTTP status code (default: 200)
|
|
32
|
+
* @returns Response object with JSON body
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* ```typescript
|
|
36
|
+
* return successResponse({ message: 'Email sent successfully' }, 200)
|
|
37
|
+
* // Returns: { success: true, data: { message: 'Email sent successfully' } }
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
export declare function successResponse<T>(data?: T, status?: number): Response;
|
|
41
|
+
/**
|
|
42
|
+
* Create a standardized error response
|
|
43
|
+
*
|
|
44
|
+
* @param code - Error code from ErrorCodes constant
|
|
45
|
+
* @param message - Human-readable error message
|
|
46
|
+
* @param status - HTTP status code (default: 400)
|
|
47
|
+
* @returns Response object with JSON error body
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* ```typescript
|
|
51
|
+
* return errorResponse(ErrorCodes.UNAUTHORIZED, 'You must be logged in', 401)
|
|
52
|
+
* // Returns: { success: false, error: { code: 'UNAUTHORIZED', message: '...' } }
|
|
53
|
+
* ```
|
|
54
|
+
*/
|
|
55
|
+
export declare function errorResponse(code: string, message: string, status?: number): Response;
|
|
56
|
+
/**
|
|
57
|
+
* Standard error codes used across the MobilizeHub plugin API
|
|
58
|
+
*/
|
|
59
|
+
export declare const ErrorCodes: {
|
|
60
|
+
readonly BAD_REQUEST: "BAD_REQUEST";
|
|
61
|
+
readonly BROADCAST_INVALID_STATUS: "BROADCAST_INVALID_STATUS";
|
|
62
|
+
readonly BROADCAST_NOT_FOUND: "BROADCAST_NOT_FOUND";
|
|
63
|
+
readonly CONTACT_NOT_FOUND: "CONTACT_NOT_FOUND";
|
|
64
|
+
readonly EMAIL_SEND_FAILED: "EMAIL_SEND_FAILED";
|
|
65
|
+
readonly INTERNAL_ERROR: "INTERNAL_ERROR";
|
|
66
|
+
readonly NOT_FOUND: "NOT_FOUND";
|
|
67
|
+
readonly RATE_LIMITED: "RATE_LIMITED";
|
|
68
|
+
readonly TOKEN_EXPIRED: "TOKEN_EXPIRED";
|
|
69
|
+
readonly TOKEN_INVALID: "TOKEN_INVALID";
|
|
70
|
+
readonly UNAUTHORIZED: "UNAUTHORIZED";
|
|
71
|
+
readonly VALIDATION_ERROR: "VALIDATION_ERROR";
|
|
72
|
+
};
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Standard API success response format
|
|
3
|
+
* @template T - Type of the data payload
|
|
4
|
+
*/ /**
|
|
5
|
+
* Create a standardized success response
|
|
6
|
+
*
|
|
7
|
+
* @template T - Type of the response data
|
|
8
|
+
* @param data - Optional data payload to include in the response
|
|
9
|
+
* @param status - HTTP status code (default: 200)
|
|
10
|
+
* @returns Response object with JSON body
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```typescript
|
|
14
|
+
* return successResponse({ message: 'Email sent successfully' }, 200)
|
|
15
|
+
* // Returns: { success: true, data: { message: 'Email sent successfully' } }
|
|
16
|
+
* ```
|
|
17
|
+
*/ export function successResponse(data, status = 200) {
|
|
18
|
+
return Response.json({
|
|
19
|
+
data,
|
|
20
|
+
success: true
|
|
21
|
+
}, {
|
|
22
|
+
status
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Create a standardized error response
|
|
27
|
+
*
|
|
28
|
+
* @param code - Error code from ErrorCodes constant
|
|
29
|
+
* @param message - Human-readable error message
|
|
30
|
+
* @param status - HTTP status code (default: 400)
|
|
31
|
+
* @returns Response object with JSON error body
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* ```typescript
|
|
35
|
+
* return errorResponse(ErrorCodes.UNAUTHORIZED, 'You must be logged in', 401)
|
|
36
|
+
* // Returns: { success: false, error: { code: 'UNAUTHORIZED', message: '...' } }
|
|
37
|
+
* ```
|
|
38
|
+
*/ export function errorResponse(code, message, status = 400) {
|
|
39
|
+
return Response.json({
|
|
40
|
+
error: {
|
|
41
|
+
code,
|
|
42
|
+
message
|
|
43
|
+
},
|
|
44
|
+
success: false
|
|
45
|
+
}, {
|
|
46
|
+
status
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Standard error codes used across the MobilizeHub plugin API
|
|
51
|
+
*/ export const ErrorCodes = {
|
|
52
|
+
BAD_REQUEST: 'BAD_REQUEST',
|
|
53
|
+
BROADCAST_INVALID_STATUS: 'BROADCAST_INVALID_STATUS',
|
|
54
|
+
BROADCAST_NOT_FOUND: 'BROADCAST_NOT_FOUND',
|
|
55
|
+
CONTACT_NOT_FOUND: 'CONTACT_NOT_FOUND',
|
|
56
|
+
EMAIL_SEND_FAILED: 'EMAIL_SEND_FAILED',
|
|
57
|
+
INTERNAL_ERROR: 'INTERNAL_ERROR',
|
|
58
|
+
NOT_FOUND: 'NOT_FOUND',
|
|
59
|
+
RATE_LIMITED: 'RATE_LIMITED',
|
|
60
|
+
TOKEN_EXPIRED: 'TOKEN_EXPIRED',
|
|
61
|
+
TOKEN_INVALID: 'TOKEN_INVALID',
|
|
62
|
+
UNAUTHORIZED: 'UNAUTHORIZED',
|
|
63
|
+
VALIDATION_ERROR: 'VALIDATION_ERROR'
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
//# sourceMappingURL=api-response.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/utils/api-response.ts"],"sourcesContent":["/**\n * Standard API success response format\n * @template T - Type of the data payload\n */\nexport type ApiSuccessResponse<T = unknown> = {\n data?: T\n success: true\n}\n\n/**\n * Standard API error response format\n */\nexport type ApiErrorResponse = {\n error: {\n /** Error code constant (e.g., 'BAD_REQUEST', 'UNAUTHORIZED') */\n code: string\n /** Human-readable error message */\n message: string\n }\n success: false\n}\n\n/**\n * Union type for all API responses\n * @template T - Type of the data payload for success responses\n */\nexport type ApiResponse<T = unknown> = ApiErrorResponse | ApiSuccessResponse<T>\n\n/**\n * Create a standardized success response\n *\n * @template T - Type of the response data\n * @param data - Optional data payload to include in the response\n * @param status - HTTP status code (default: 200)\n * @returns Response object with JSON body\n *\n * @example\n * ```typescript\n * return successResponse({ message: 'Email sent successfully' }, 200)\n * // Returns: { success: true, data: { message: 'Email sent successfully' } }\n * ```\n */\nexport function successResponse<T>(data?: T, status = 200): Response {\n return Response.json({ data, success: true }, { status })\n}\n\n/**\n * Create a standardized error response\n *\n * @param code - Error code from ErrorCodes constant\n * @param message - Human-readable error message\n * @param status - HTTP status code (default: 400)\n * @returns Response object with JSON error body\n *\n * @example\n * ```typescript\n * return errorResponse(ErrorCodes.UNAUTHORIZED, 'You must be logged in', 401)\n * // Returns: { success: false, error: { code: 'UNAUTHORIZED', message: '...' } }\n * ```\n */\nexport function errorResponse(code: string, message: string, status = 400): Response {\n return Response.json({ error: { code, message }, success: false }, { status })\n}\n\n/**\n * Standard error codes used across the MobilizeHub plugin API\n */\nexport const ErrorCodes = {\n BAD_REQUEST: 'BAD_REQUEST',\n BROADCAST_INVALID_STATUS: 'BROADCAST_INVALID_STATUS',\n BROADCAST_NOT_FOUND: 'BROADCAST_NOT_FOUND',\n CONTACT_NOT_FOUND: 'CONTACT_NOT_FOUND',\n EMAIL_SEND_FAILED: 'EMAIL_SEND_FAILED',\n INTERNAL_ERROR: 'INTERNAL_ERROR',\n NOT_FOUND: 'NOT_FOUND',\n RATE_LIMITED: 'RATE_LIMITED',\n TOKEN_EXPIRED: 'TOKEN_EXPIRED',\n TOKEN_INVALID: 'TOKEN_INVALID',\n UNAUTHORIZED: 'UNAUTHORIZED',\n VALIDATION_ERROR: 'VALIDATION_ERROR',\n} as const\n"],"names":["successResponse","data","status","Response","json","success","errorResponse","code","message","error","ErrorCodes","BAD_REQUEST","BROADCAST_INVALID_STATUS","BROADCAST_NOT_FOUND","CONTACT_NOT_FOUND","EMAIL_SEND_FAILED","INTERNAL_ERROR","NOT_FOUND","RATE_LIMITED","TOKEN_EXPIRED","TOKEN_INVALID","UNAUTHORIZED","VALIDATION_ERROR"],"mappings":"AAAA;;;CAGC,GAyBD;;;;;;;;;;;;;CAaC,GACD,OAAO,SAASA,gBAAmBC,IAAQ,EAAEC,SAAS,GAAG;IACvD,OAAOC,SAASC,IAAI,CAAC;QAAEH;QAAMI,SAAS;IAAK,GAAG;QAAEH;IAAO;AACzD;AAEA;;;;;;;;;;;;;CAaC,GACD,OAAO,SAASI,cAAcC,IAAY,EAAEC,OAAe,EAAEN,SAAS,GAAG;IACvE,OAAOC,SAASC,IAAI,CAAC;QAAEK,OAAO;YAAEF;YAAMC;QAAQ;QAAGH,SAAS;IAAM,GAAG;QAAEH;IAAO;AAC9E;AAEA;;CAEC,GACD,OAAO,MAAMQ,aAAa;IACxBC,aAAa;IACbC,0BAA0B;IAC1BC,qBAAqB;IACrBC,mBAAmB;IACnBC,mBAAmB;IACnBC,gBAAgB;IAChBC,WAAW;IACXC,cAAc;IACdC,eAAe;IACfC,eAAe;IACfC,cAAc;IACdC,kBAAkB;AACpB,EAAU"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Formats an email address with an optional display name according to RFC 5322.
|
|
3
|
+
*
|
|
4
|
+
* @param fromName - The display name to show (e.g., "John Doe")
|
|
5
|
+
* @param fromAddress - The actual email address (e.g., "john@example.com")
|
|
6
|
+
* @returns Formatted email string. If fromName is provided: `"John Doe" <john@example.com>`
|
|
7
|
+
* Otherwise just returns the email address.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```typescript
|
|
11
|
+
* formatFromAddress("Acme Corp", "hello@acme.com")
|
|
12
|
+
* // Returns: '"Acme Corp" <hello@acme.com>'
|
|
13
|
+
*
|
|
14
|
+
* formatFromAddress("", "hello@acme.com")
|
|
15
|
+
* // Returns: 'hello@acme.com'
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
export declare function formatFromAddress(fromName: string, fromAddress: string): string;
|
|
19
|
+
/**
|
|
20
|
+
* Validates if a string is a properly formatted email address.
|
|
21
|
+
*
|
|
22
|
+
* Uses a permissive regex that catches most invalid formats while allowing
|
|
23
|
+
* valid edge cases like plus-addressing (user+tag@domain.com).
|
|
24
|
+
*
|
|
25
|
+
* @param email - The string to validate
|
|
26
|
+
* @returns `true` if the string appears to be a valid email format
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* ```typescript
|
|
30
|
+
* isValidEmail("user@example.com") // true
|
|
31
|
+
* isValidEmail("user+tag@example.com") // true
|
|
32
|
+
* isValidEmail("invalid") // false
|
|
33
|
+
* isValidEmail("missing@domain") // false
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
export declare function isValidEmail(email: string): boolean;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Formats an email address with an optional display name according to RFC 5322.
|
|
3
|
+
*
|
|
4
|
+
* @param fromName - The display name to show (e.g., "John Doe")
|
|
5
|
+
* @param fromAddress - The actual email address (e.g., "john@example.com")
|
|
6
|
+
* @returns Formatted email string. If fromName is provided: `"John Doe" <john@example.com>`
|
|
7
|
+
* Otherwise just returns the email address.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```typescript
|
|
11
|
+
* formatFromAddress("Acme Corp", "hello@acme.com")
|
|
12
|
+
* // Returns: '"Acme Corp" <hello@acme.com>'
|
|
13
|
+
*
|
|
14
|
+
* formatFromAddress("", "hello@acme.com")
|
|
15
|
+
* // Returns: 'hello@acme.com'
|
|
16
|
+
* ```
|
|
17
|
+
*/ export function formatFromAddress(fromName, fromAddress) {
|
|
18
|
+
return fromName ? `"${fromName}" <${fromAddress}>` : fromAddress;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Validates if a string is a properly formatted email address.
|
|
22
|
+
*
|
|
23
|
+
* Uses a permissive regex that catches most invalid formats while allowing
|
|
24
|
+
* valid edge cases like plus-addressing (user+tag@domain.com).
|
|
25
|
+
*
|
|
26
|
+
* @param email - The string to validate
|
|
27
|
+
* @returns `true` if the string appears to be a valid email format
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* ```typescript
|
|
31
|
+
* isValidEmail("user@example.com") // true
|
|
32
|
+
* isValidEmail("user+tag@example.com") // true
|
|
33
|
+
* isValidEmail("invalid") // false
|
|
34
|
+
* isValidEmail("missing@domain") // false
|
|
35
|
+
* ```
|
|
36
|
+
*/ export function isValidEmail(email) {
|
|
37
|
+
return /^[^\s@]+@[^\s@][^\s.@]*\.[^\s@]+$/.test(email);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
//# sourceMappingURL=email.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/utils/email.ts"],"sourcesContent":["/**\n * Formats an email address with an optional display name according to RFC 5322.\n *\n * @param fromName - The display name to show (e.g., \"John Doe\")\n * @param fromAddress - The actual email address (e.g., \"john@example.com\")\n * @returns Formatted email string. If fromName is provided: `\"John Doe\" <john@example.com>`\n * Otherwise just returns the email address.\n *\n * @example\n * ```typescript\n * formatFromAddress(\"Acme Corp\", \"hello@acme.com\")\n * // Returns: '\"Acme Corp\" <hello@acme.com>'\n *\n * formatFromAddress(\"\", \"hello@acme.com\")\n * // Returns: 'hello@acme.com'\n * ```\n */\nexport function formatFromAddress(fromName: string, fromAddress: string): string {\n return fromName ? `\"${fromName}\" <${fromAddress}>` : fromAddress\n}\n\n/**\n * Validates if a string is a properly formatted email address.\n *\n * Uses a permissive regex that catches most invalid formats while allowing\n * valid edge cases like plus-addressing (user+tag@domain.com).\n *\n * @param email - The string to validate\n * @returns `true` if the string appears to be a valid email format\n *\n * @example\n * ```typescript\n * isValidEmail(\"user@example.com\") // true\n * isValidEmail(\"user+tag@example.com\") // true\n * isValidEmail(\"invalid\") // false\n * isValidEmail(\"missing@domain\") // false\n * ```\n */\nexport function isValidEmail(email: string): boolean {\n return /^[^\\s@]+@[^\\s@][^\\s.@]*\\.[^\\s@]+$/.test(email)\n}\n"],"names":["formatFromAddress","fromName","fromAddress","isValidEmail","email","test"],"mappings":"AAAA;;;;;;;;;;;;;;;;CAgBC,GACD,OAAO,SAASA,kBAAkBC,QAAgB,EAAEC,WAAmB;IACrE,OAAOD,WAAW,CAAC,CAAC,EAAEA,SAAS,GAAG,EAAEC,YAAY,CAAC,CAAC,GAAGA;AACvD;AAEA;;;;;;;;;;;;;;;;CAgBC,GACD,OAAO,SAASC,aAAaC,KAAa;IACxC,OAAO,oCAAoCC,IAAI,CAACD;AAClD"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { SerializedEditorState } from '@payloadcms/richtext-lexical/lexical';
|
|
2
|
+
import type { Payload } from 'payload';
|
|
3
|
+
/**
|
|
4
|
+
* Parses Lexical editor content into multiple formats (HTML, Markdown, Plain Text)
|
|
5
|
+
* @param content - The serialized Lexical editor state
|
|
6
|
+
* @param payloadConfig - The Payload CMS configuration
|
|
7
|
+
* @returns Parsed content in HTML, Markdown, and Plain Text formats
|
|
8
|
+
*/
|
|
9
|
+
export declare function parseLexicalContent(content: SerializedEditorState, payloadConfig: Payload['config']): Promise<{
|
|
10
|
+
html: string;
|
|
11
|
+
markdown: string;
|
|
12
|
+
plainText: string;
|
|
13
|
+
}>;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { convertLexicalToMarkdown, editorConfigFactory } from '@payloadcms/richtext-lexical';
|
|
2
|
+
import { convertLexicalToHTML } from '@payloadcms/richtext-lexical/html';
|
|
3
|
+
import { convertLexicalToPlaintext } from '@payloadcms/richtext-lexical/plaintext';
|
|
4
|
+
/**
|
|
5
|
+
* Parses Lexical editor content into multiple formats (HTML, Markdown, Plain Text)
|
|
6
|
+
* @param content - The serialized Lexical editor state
|
|
7
|
+
* @param payloadConfig - The Payload CMS configuration
|
|
8
|
+
* @returns Parsed content in HTML, Markdown, and Plain Text formats
|
|
9
|
+
*/ export async function parseLexicalContent(content, payloadConfig) {
|
|
10
|
+
const editorConfig = await editorConfigFactory.default({
|
|
11
|
+
config: payloadConfig
|
|
12
|
+
});
|
|
13
|
+
return {
|
|
14
|
+
html: convertLexicalToHTML({
|
|
15
|
+
data: content
|
|
16
|
+
}),
|
|
17
|
+
markdown: convertLexicalToMarkdown({
|
|
18
|
+
data: content,
|
|
19
|
+
editorConfig
|
|
20
|
+
}),
|
|
21
|
+
plainText: convertLexicalToPlaintext({
|
|
22
|
+
data: content
|
|
23
|
+
})
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
//# sourceMappingURL=lexical.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/utils/lexical.ts"],"sourcesContent":["import type { SerializedEditorState } from '@payloadcms/richtext-lexical/lexical'\nimport type { Payload } from 'payload'\n\nimport { convertLexicalToMarkdown, editorConfigFactory } from '@payloadcms/richtext-lexical'\nimport { convertLexicalToHTML } from '@payloadcms/richtext-lexical/html'\nimport { convertLexicalToPlaintext } from '@payloadcms/richtext-lexical/plaintext'\n\n/**\n * Parses Lexical editor content into multiple formats (HTML, Markdown, Plain Text)\n * @param content - The serialized Lexical editor state\n * @param payloadConfig - The Payload CMS configuration\n * @returns Parsed content in HTML, Markdown, and Plain Text formats\n */\nexport async function parseLexicalContent(\n content: SerializedEditorState,\n payloadConfig: Payload['config'],\n): Promise<{\n html: string\n markdown: string\n plainText: string\n}> {\n const editorConfig = await editorConfigFactory.default({ config: payloadConfig })\n\n return {\n html: convertLexicalToHTML({ data: content }),\n markdown: convertLexicalToMarkdown({ data: content, editorConfig }),\n plainText: convertLexicalToPlaintext({ data: content }),\n }\n}\n"],"names":["convertLexicalToMarkdown","editorConfigFactory","convertLexicalToHTML","convertLexicalToPlaintext","parseLexicalContent","content","payloadConfig","editorConfig","default","config","html","data","markdown","plainText"],"mappings":"AAGA,SAASA,wBAAwB,EAAEC,mBAAmB,QAAQ,+BAA8B;AAC5F,SAASC,oBAAoB,QAAQ,oCAAmC;AACxE,SAASC,yBAAyB,QAAQ,yCAAwC;AAElF;;;;;CAKC,GACD,OAAO,eAAeC,oBACpBC,OAA8B,EAC9BC,aAAgC;IAMhC,MAAMC,eAAe,MAAMN,oBAAoBO,OAAO,CAAC;QAAEC,QAAQH;IAAc;IAE/E,OAAO;QACLI,MAAMR,qBAAqB;YAAES,MAAMN;QAAQ;QAC3CO,UAAUZ,yBAAyB;YAAEW,MAAMN;YAASE;QAAa;QACjEM,WAAWV,0BAA0B;YAAEQ,MAAMN;QAAQ;IACvD;AACF"}
|