payload-plugin-newsletter 0.3.2 → 0.4.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +44 -1
- package/CLAUDE.md +31 -19
- package/dist/client.cjs +899 -0
- package/dist/client.cjs.map +1 -0
- package/dist/client.d.cts +52 -0
- package/dist/client.d.ts +52 -0
- package/dist/client.js +867 -0
- package/dist/client.js.map +1 -0
- package/dist/components.cjs +899 -0
- package/dist/components.cjs.map +1 -0
- package/dist/components.d.cts +4 -0
- package/dist/components.d.ts +4 -0
- package/dist/components.js +867 -0
- package/dist/components.js.map +1 -0
- package/dist/index.cjs +2004 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +11 -0
- package/dist/index.d.ts +6 -5
- package/dist/index.js +1967 -0
- package/dist/index.js.map +1 -0
- package/dist/types.cjs +19 -0
- package/dist/types.cjs.map +1 -0
- package/dist/{types/index.d.ts → types.d.cts} +19 -17
- package/dist/types.d.ts +350 -0
- package/dist/types.js +1 -0
- package/dist/types.js.map +1 -0
- package/package.json +48 -25
- package/dist/.tsbuildinfo +0 -1
- package/dist/collections/NewsletterSettings.d.ts +0 -4
- package/dist/collections/NewsletterSettings.d.ts.map +0 -1
- package/dist/collections/Subscribers.d.ts +0 -4
- package/dist/collections/Subscribers.d.ts.map +0 -1
- package/dist/components/MagicLinkVerify.d.ts +0 -27
- package/dist/components/MagicLinkVerify.d.ts.map +0 -1
- package/dist/components/NewsletterForm.d.ts +0 -5
- package/dist/components/NewsletterForm.d.ts.map +0 -1
- package/dist/components/PreferencesForm.d.ts +0 -5
- package/dist/components/PreferencesForm.d.ts.map +0 -1
- package/dist/components/index.d.ts +0 -5
- package/dist/components/index.d.ts.map +0 -1
- package/dist/endpoints/index.d.ts +0 -4
- package/dist/endpoints/index.d.ts.map +0 -1
- package/dist/endpoints/preferences.d.ts +0 -5
- package/dist/endpoints/preferences.d.ts.map +0 -1
- package/dist/endpoints/subscribe.d.ts +0 -4
- package/dist/endpoints/subscribe.d.ts.map +0 -1
- package/dist/endpoints/unsubscribe.d.ts +0 -4
- package/dist/endpoints/unsubscribe.d.ts.map +0 -1
- package/dist/endpoints/verify-magic-link.d.ts +0 -4
- package/dist/endpoints/verify-magic-link.d.ts.map +0 -1
- package/dist/exports/client.d.ts +0 -6
- package/dist/exports/client.d.ts.map +0 -1
- package/dist/exports/components.d.ts +0 -2
- package/dist/exports/components.d.ts.map +0 -1
- package/dist/exports/types.d.ts +0 -2
- package/dist/exports/types.d.ts.map +0 -1
- package/dist/fields/newsletterScheduling.d.ts +0 -4
- package/dist/fields/newsletterScheduling.d.ts.map +0 -1
- package/dist/hooks/useNewsletterAuth.d.ts +0 -16
- package/dist/hooks/useNewsletterAuth.d.ts.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/providers/broadcast.d.ts +0 -19
- package/dist/providers/broadcast.d.ts.map +0 -1
- package/dist/providers/index.d.ts +0 -23
- package/dist/providers/index.d.ts.map +0 -1
- package/dist/providers/resend.d.ts +0 -20
- package/dist/providers/resend.d.ts.map +0 -1
- package/dist/providers/types.d.ts +0 -46
- package/dist/providers/types.d.ts.map +0 -1
- package/dist/src/__tests__/fixtures/newsletter-settings.js +0 -41
- package/dist/src/__tests__/fixtures/newsletter-settings.js.map +0 -1
- package/dist/src/__tests__/fixtures/subscribers.js +0 -70
- package/dist/src/__tests__/fixtures/subscribers.js.map +0 -1
- package/dist/src/__tests__/integration/collections/subscriber-hooks.test.js +0 -356
- package/dist/src/__tests__/integration/collections/subscriber-hooks.test.js.map +0 -1
- package/dist/src/__tests__/integration/endpoints/preferences.test.js +0 -266
- package/dist/src/__tests__/integration/endpoints/preferences.test.js.map +0 -1
- package/dist/src/__tests__/integration/endpoints/subscribe.test.js +0 -280
- package/dist/src/__tests__/integration/endpoints/subscribe.test.js.map +0 -1
- package/dist/src/__tests__/integration/endpoints/unsubscribe.test.js +0 -187
- package/dist/src/__tests__/integration/endpoints/unsubscribe.test.js.map +0 -1
- package/dist/src/__tests__/integration/endpoints/verify-magic-link.test.js +0 -188
- package/dist/src/__tests__/integration/endpoints/verify-magic-link.test.js.map +0 -1
- package/dist/src/__tests__/mocks/email-providers.js +0 -153
- package/dist/src/__tests__/mocks/email-providers.js.map +0 -1
- package/dist/src/__tests__/mocks/payload.js +0 -244
- package/dist/src/__tests__/mocks/payload.js.map +0 -1
- package/dist/src/__tests__/security/csrf-protection.test.js +0 -309
- package/dist/src/__tests__/security/csrf-protection.test.js.map +0 -1
- package/dist/src/__tests__/security/settings-access.test.js +0 -204
- package/dist/src/__tests__/security/settings-access.test.js.map +0 -1
- package/dist/src/__tests__/security/subscriber-access.test.js +0 -210
- package/dist/src/__tests__/security/subscriber-access.test.js.map +0 -1
- package/dist/src/__tests__/security/xss-prevention.test.js +0 -305
- package/dist/src/__tests__/security/xss-prevention.test.js.map +0 -1
- package/dist/src/__tests__/setup/integration.setup.js +0 -38
- package/dist/src/__tests__/setup/integration.setup.js.map +0 -1
- package/dist/src/__tests__/setup/unit.setup.js +0 -41
- package/dist/src/__tests__/setup/unit.setup.js.map +0 -1
- package/dist/src/__tests__/unit/utils/access.test.js +0 -116
- package/dist/src/__tests__/unit/utils/access.test.js.map +0 -1
- package/dist/src/__tests__/unit/utils/jwt.test.js +0 -238
- package/dist/src/__tests__/unit/utils/jwt.test.js.map +0 -1
- package/dist/src/collections/NewsletterSettings.js +0 -390
- package/dist/src/collections/NewsletterSettings.js.map +0 -1
- package/dist/src/collections/Subscribers.js +0 -309
- package/dist/src/collections/Subscribers.js.map +0 -1
- package/dist/src/components/MagicLinkVerify.js +0 -180
- package/dist/src/components/MagicLinkVerify.js.map +0 -1
- package/dist/src/components/NewsletterForm.js +0 -326
- package/dist/src/components/NewsletterForm.js.map +0 -1
- package/dist/src/components/PreferencesForm.js +0 -524
- package/dist/src/components/PreferencesForm.js.map +0 -1
- package/dist/src/components/index.js +0 -5
- package/dist/src/components/index.js.map +0 -1
- package/dist/src/endpoints/index.js +0 -17
- package/dist/src/endpoints/index.js.map +0 -1
- package/dist/src/endpoints/preferences.js +0 -136
- package/dist/src/endpoints/preferences.js.map +0 -1
- package/dist/src/endpoints/subscribe.js +0 -151
- package/dist/src/endpoints/subscribe.js.map +0 -1
- package/dist/src/endpoints/unsubscribe.js +0 -105
- package/dist/src/endpoints/unsubscribe.js.map +0 -1
- package/dist/src/endpoints/verify-magic-link.js +0 -103
- package/dist/src/endpoints/verify-magic-link.js.map +0 -1
- package/dist/src/exports/client.js +0 -7
- package/dist/src/exports/client.js.map +0 -1
- package/dist/src/exports/components.js +0 -6
- package/dist/src/exports/components.js.map +0 -1
- package/dist/src/exports/types.js +0 -3
- package/dist/src/exports/types.js.map +0 -1
- package/dist/src/fields/newsletterScheduling.js +0 -195
- package/dist/src/fields/newsletterScheduling.js.map +0 -1
- package/dist/src/hooks/useNewsletterAuth.js +0 -112
- package/dist/src/hooks/useNewsletterAuth.js.map +0 -1
- package/dist/src/index.js +0 -130
- package/dist/src/index.js.map +0 -1
- package/dist/src/providers/broadcast.js +0 -158
- package/dist/src/providers/broadcast.js.map +0 -1
- package/dist/src/providers/index.js +0 -63
- package/dist/src/providers/index.js.map +0 -1
- package/dist/src/providers/resend.js +0 -122
- package/dist/src/providers/resend.js.map +0 -1
- package/dist/src/providers/types.js +0 -12
- package/dist/src/providers/types.js.map +0 -1
- package/dist/src/templates/BaseTemplate.js +0 -105
- package/dist/src/templates/BaseTemplate.js.map +0 -1
- package/dist/src/templates/MagicLinkTemplate.js +0 -178
- package/dist/src/templates/MagicLinkTemplate.js.map +0 -1
- package/dist/src/templates/NewsletterTemplate.js +0 -150
- package/dist/src/templates/NewsletterTemplate.js.map +0 -1
- package/dist/src/templates/WelcomeTemplate.js +0 -192
- package/dist/src/templates/WelcomeTemplate.js.map +0 -1
- package/dist/src/templates/index.js +0 -6
- package/dist/src/templates/index.js.map +0 -1
- package/dist/src/types/index.js +0 -3
- package/dist/src/types/index.js.map +0 -1
- package/dist/src/utils/access.js +0 -80
- package/dist/src/utils/access.js.map +0 -1
- package/dist/src/utils/jwt.js +0 -91
- package/dist/src/utils/jwt.js.map +0 -1
- package/dist/src/utils/validation.js +0 -74
- package/dist/src/utils/validation.js.map +0 -1
- package/dist/templates/BaseTemplate.d.ts +0 -45
- package/dist/templates/BaseTemplate.d.ts.map +0 -1
- package/dist/templates/MagicLinkTemplate.d.ts +0 -67
- package/dist/templates/MagicLinkTemplate.d.ts.map +0 -1
- package/dist/templates/NewsletterTemplate.d.ts +0 -112
- package/dist/templates/NewsletterTemplate.d.ts.map +0 -1
- package/dist/templates/WelcomeTemplate.d.ts +0 -55
- package/dist/templates/WelcomeTemplate.d.ts.map +0 -1
- package/dist/templates/index.d.ts +0 -7
- package/dist/templates/index.d.ts.map +0 -1
- package/dist/types/index.d.ts.map +0 -1
- package/dist/utils/access.d.ts +0 -15
- package/dist/utils/access.d.ts.map +0 -1
- package/dist/utils/jwt.d.ts +0 -32
- package/dist/utils/jwt.d.ts.map +0 -1
- package/dist/utils/validation.d.ts +0 -25
- package/dist/utils/validation.d.ts.map +0 -1
|
@@ -1,136 +0,0 @@
|
|
|
1
|
-
import { verifySessionToken } from '../utils/jwt';
|
|
2
|
-
export const createPreferencesEndpoint = (config)=>{
|
|
3
|
-
return {
|
|
4
|
-
path: '/newsletter/preferences',
|
|
5
|
-
method: 'get',
|
|
6
|
-
handler: async (req, res)=>{
|
|
7
|
-
try {
|
|
8
|
-
// Get token from Authorization header
|
|
9
|
-
const authHeader = req.headers.authorization;
|
|
10
|
-
if (!authHeader || !authHeader.startsWith('Bearer ')) {
|
|
11
|
-
return res.status(401).json({
|
|
12
|
-
success: false,
|
|
13
|
-
error: 'Authorization required'
|
|
14
|
-
});
|
|
15
|
-
}
|
|
16
|
-
const token = authHeader.substring(7);
|
|
17
|
-
// Verify session token
|
|
18
|
-
let payload;
|
|
19
|
-
try {
|
|
20
|
-
payload = verifySessionToken(token);
|
|
21
|
-
} catch (error) {
|
|
22
|
-
return res.status(401).json({
|
|
23
|
-
success: false,
|
|
24
|
-
error: error instanceof Error ? error.message : 'Invalid token'
|
|
25
|
-
});
|
|
26
|
-
}
|
|
27
|
-
// Get subscriber - use synthetic user to ensure access control
|
|
28
|
-
const subscriber = await req.payload.findByID({
|
|
29
|
-
collection: config.subscribersSlug || 'subscribers',
|
|
30
|
-
id: payload.subscriberId,
|
|
31
|
-
overrideAccess: false,
|
|
32
|
-
user: {
|
|
33
|
-
collection: 'subscribers',
|
|
34
|
-
id: payload.subscriberId,
|
|
35
|
-
email: payload.email
|
|
36
|
-
}
|
|
37
|
-
});
|
|
38
|
-
if (!subscriber) {
|
|
39
|
-
return res.status(404).json({
|
|
40
|
-
success: false,
|
|
41
|
-
error: 'Subscriber not found'
|
|
42
|
-
});
|
|
43
|
-
}
|
|
44
|
-
res.json({
|
|
45
|
-
success: true,
|
|
46
|
-
subscriber: {
|
|
47
|
-
id: subscriber.id,
|
|
48
|
-
email: subscriber.email,
|
|
49
|
-
name: subscriber.name,
|
|
50
|
-
locale: subscriber.locale,
|
|
51
|
-
emailPreferences: subscriber.emailPreferences,
|
|
52
|
-
subscriptionStatus: subscriber.subscriptionStatus
|
|
53
|
-
}
|
|
54
|
-
});
|
|
55
|
-
} catch (error) {
|
|
56
|
-
console.error('Get preferences error:', error);
|
|
57
|
-
res.status(500).json({
|
|
58
|
-
success: false,
|
|
59
|
-
error: 'Failed to get preferences'
|
|
60
|
-
});
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
};
|
|
64
|
-
};
|
|
65
|
-
export const createUpdatePreferencesEndpoint = (config)=>{
|
|
66
|
-
return {
|
|
67
|
-
path: '/newsletter/preferences',
|
|
68
|
-
method: 'post',
|
|
69
|
-
handler: async (req, res)=>{
|
|
70
|
-
try {
|
|
71
|
-
// Get token from Authorization header
|
|
72
|
-
const authHeader = req.headers.authorization;
|
|
73
|
-
if (!authHeader || !authHeader.startsWith('Bearer ')) {
|
|
74
|
-
return res.status(401).json({
|
|
75
|
-
success: false,
|
|
76
|
-
error: 'Authorization required'
|
|
77
|
-
});
|
|
78
|
-
}
|
|
79
|
-
const token = authHeader.substring(7);
|
|
80
|
-
// Verify session token
|
|
81
|
-
let payload;
|
|
82
|
-
try {
|
|
83
|
-
payload = verifySessionToken(token);
|
|
84
|
-
} catch (error) {
|
|
85
|
-
return res.status(401).json({
|
|
86
|
-
success: false,
|
|
87
|
-
error: error instanceof Error ? error.message : 'Invalid token'
|
|
88
|
-
});
|
|
89
|
-
}
|
|
90
|
-
const { name, locale, emailPreferences } = req.body;
|
|
91
|
-
// Prepare update data
|
|
92
|
-
const updateData = {};
|
|
93
|
-
if (name !== undefined) {
|
|
94
|
-
updateData.name = name;
|
|
95
|
-
}
|
|
96
|
-
if (locale !== undefined) {
|
|
97
|
-
updateData.locale = locale;
|
|
98
|
-
}
|
|
99
|
-
if (emailPreferences !== undefined) {
|
|
100
|
-
updateData.emailPreferences = emailPreferences;
|
|
101
|
-
}
|
|
102
|
-
// Update subscriber - use synthetic user to ensure only updating own data
|
|
103
|
-
const subscriber = await req.payload.update({
|
|
104
|
-
collection: config.subscribersSlug || 'subscribers',
|
|
105
|
-
id: payload.subscriberId,
|
|
106
|
-
data: updateData,
|
|
107
|
-
overrideAccess: false,
|
|
108
|
-
user: {
|
|
109
|
-
collection: 'subscribers',
|
|
110
|
-
id: payload.subscriberId,
|
|
111
|
-
email: payload.email
|
|
112
|
-
}
|
|
113
|
-
});
|
|
114
|
-
res.json({
|
|
115
|
-
success: true,
|
|
116
|
-
subscriber: {
|
|
117
|
-
id: subscriber.id,
|
|
118
|
-
email: subscriber.email,
|
|
119
|
-
name: subscriber.name,
|
|
120
|
-
locale: subscriber.locale,
|
|
121
|
-
emailPreferences: subscriber.emailPreferences,
|
|
122
|
-
subscriptionStatus: subscriber.subscriptionStatus
|
|
123
|
-
}
|
|
124
|
-
});
|
|
125
|
-
} catch (error) {
|
|
126
|
-
console.error('Update preferences error:', error);
|
|
127
|
-
res.status(500).json({
|
|
128
|
-
success: false,
|
|
129
|
-
error: 'Failed to update preferences'
|
|
130
|
-
});
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
};
|
|
134
|
-
};
|
|
135
|
-
|
|
136
|
-
//# sourceMappingURL=preferences.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/endpoints/preferences.ts"],"sourcesContent":["import type { Endpoint, PayloadHandler } from 'payload'\nimport type { NewsletterPluginConfig } from '../types'\nimport { verifySessionToken } from '../utils/jwt'\n\nexport const createPreferencesEndpoint = (\n config: NewsletterPluginConfig\n): Endpoint => {\n return {\n path: '/newsletter/preferences',\n method: 'get',\n handler: (async (req: any, res: any) => {\n try {\n // Get token from Authorization header\n const authHeader = req.headers.authorization\n if (!authHeader || !authHeader.startsWith('Bearer ')) {\n return res.status(401).json({\n success: false,\n error: 'Authorization required',\n })\n }\n\n const token = authHeader.substring(7)\n\n // Verify session token\n let payload\n try {\n payload = verifySessionToken(token)\n } catch (error: unknown) {\n return res.status(401).json({\n success: false,\n error: error instanceof Error ? error.message : 'Invalid token',\n })\n }\n\n // Get subscriber - use synthetic user to ensure access control\n const subscriber = await req.payload.findByID({\n collection: config.subscribersSlug || 'subscribers',\n id: payload.subscriberId,\n overrideAccess: false,\n user: {\n collection: 'subscribers',\n id: payload.subscriberId,\n email: payload.email,\n },\n })\n\n if (!subscriber) {\n return res.status(404).json({\n success: false,\n error: 'Subscriber not found',\n })\n }\n\n res.json({\n success: true,\n subscriber: {\n id: subscriber.id,\n email: subscriber.email,\n name: subscriber.name,\n locale: subscriber.locale,\n emailPreferences: subscriber.emailPreferences,\n subscriptionStatus: subscriber.subscriptionStatus,\n },\n })\n } catch (error: unknown) {\n console.error('Get preferences error:', error)\n res.status(500).json({\n success: false,\n error: 'Failed to get preferences',\n })\n }\n }) as PayloadHandler,\n }\n}\n\nexport const createUpdatePreferencesEndpoint = (\n config: NewsletterPluginConfig\n): Endpoint => {\n return {\n path: '/newsletter/preferences',\n method: 'post',\n handler: (async (req: any, res: any) => {\n try {\n // Get token from Authorization header\n const authHeader = req.headers.authorization\n if (!authHeader || !authHeader.startsWith('Bearer ')) {\n return res.status(401).json({\n success: false,\n error: 'Authorization required',\n })\n }\n\n const token = authHeader.substring(7)\n\n // Verify session token\n let payload\n try {\n payload = verifySessionToken(token)\n } catch (error: unknown) {\n return res.status(401).json({\n success: false,\n error: error instanceof Error ? error.message : 'Invalid token',\n })\n }\n\n const { name, locale, emailPreferences } = req.body\n\n // Prepare update data\n const updateData: any = {}\n \n if (name !== undefined) {\n updateData.name = name\n }\n \n if (locale !== undefined) {\n updateData.locale = locale\n }\n \n if (emailPreferences !== undefined) {\n updateData.emailPreferences = emailPreferences\n }\n\n // Update subscriber - use synthetic user to ensure only updating own data\n const subscriber = await req.payload.update({\n collection: config.subscribersSlug || 'subscribers',\n id: payload.subscriberId,\n data: updateData,\n overrideAccess: false,\n user: {\n collection: 'subscribers',\n id: payload.subscriberId,\n email: payload.email,\n },\n })\n\n res.json({\n success: true,\n subscriber: {\n id: subscriber.id,\n email: subscriber.email,\n name: subscriber.name,\n locale: subscriber.locale,\n emailPreferences: subscriber.emailPreferences,\n subscriptionStatus: subscriber.subscriptionStatus,\n },\n })\n } catch (error: unknown) {\n console.error('Update preferences error:', error)\n res.status(500).json({\n success: false,\n error: 'Failed to update preferences',\n })\n }\n }) as PayloadHandler,\n }\n}"],"names":["verifySessionToken","createPreferencesEndpoint","config","path","method","handler","req","res","authHeader","headers","authorization","startsWith","status","json","success","error","token","substring","payload","Error","message","subscriber","findByID","collection","subscribersSlug","id","subscriberId","overrideAccess","user","email","name","locale","emailPreferences","subscriptionStatus","console","createUpdatePreferencesEndpoint","body","updateData","undefined","update","data"],"mappings":"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"}
|
|
@@ -1,151 +0,0 @@
|
|
|
1
|
-
import { isDomainAllowed, sanitizeInput, validateSubscriberData, extractUTMParams } from '../utils/validation';
|
|
2
|
-
export const createSubscribeEndpoint = (config)=>{
|
|
3
|
-
return {
|
|
4
|
-
path: '/newsletter/subscribe',
|
|
5
|
-
method: 'post',
|
|
6
|
-
handler: async (req, res)=>{
|
|
7
|
-
try {
|
|
8
|
-
const { email, name, source, preferences, leadMagnet, surveyResponses, metadata = {} } = req.body;
|
|
9
|
-
// Validate input
|
|
10
|
-
const validation = validateSubscriberData({
|
|
11
|
-
email,
|
|
12
|
-
name,
|
|
13
|
-
source
|
|
14
|
-
});
|
|
15
|
-
if (!validation.valid) {
|
|
16
|
-
return res.status(400).json({
|
|
17
|
-
success: false,
|
|
18
|
-
errors: validation.errors
|
|
19
|
-
});
|
|
20
|
-
}
|
|
21
|
-
// Check domain restrictions from active settings
|
|
22
|
-
// Settings are public info needed for validation, but we can still respect access control
|
|
23
|
-
const settingsResult = await req.payload.find({
|
|
24
|
-
collection: config.settingsSlug || 'newsletter-settings',
|
|
25
|
-
where: {
|
|
26
|
-
active: {
|
|
27
|
-
equals: true
|
|
28
|
-
}
|
|
29
|
-
},
|
|
30
|
-
limit: 1,
|
|
31
|
-
overrideAccess: false
|
|
32
|
-
});
|
|
33
|
-
const settings = settingsResult.docs[0];
|
|
34
|
-
const allowedDomains = settings?.allowedDomains?.map((d)=>d.domain) || [];
|
|
35
|
-
if (!isDomainAllowed(email, allowedDomains)) {
|
|
36
|
-
return res.status(400).json({
|
|
37
|
-
success: false,
|
|
38
|
-
error: 'Email domain not allowed'
|
|
39
|
-
});
|
|
40
|
-
}
|
|
41
|
-
// Check if already subscribed
|
|
42
|
-
// This needs admin access to check for existing email
|
|
43
|
-
const existing = await req.payload.find({
|
|
44
|
-
collection: config.subscribersSlug || 'subscribers',
|
|
45
|
-
where: {
|
|
46
|
-
email: {
|
|
47
|
-
equals: email.toLowerCase()
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
});
|
|
51
|
-
if (existing.docs.length > 0) {
|
|
52
|
-
const subscriber = existing.docs[0];
|
|
53
|
-
// If unsubscribed, don't allow resubscription via API
|
|
54
|
-
if (subscriber.subscriptionStatus === 'unsubscribed') {
|
|
55
|
-
return res.status(400).json({
|
|
56
|
-
success: false,
|
|
57
|
-
error: 'This email has been unsubscribed. Please contact support to resubscribe.'
|
|
58
|
-
});
|
|
59
|
-
}
|
|
60
|
-
return res.status(400).json({
|
|
61
|
-
success: false,
|
|
62
|
-
error: 'Already subscribed',
|
|
63
|
-
subscriber: {
|
|
64
|
-
id: subscriber.id,
|
|
65
|
-
email: subscriber.email,
|
|
66
|
-
subscriptionStatus: subscriber.subscriptionStatus
|
|
67
|
-
}
|
|
68
|
-
});
|
|
69
|
-
}
|
|
70
|
-
// Check IP rate limiting
|
|
71
|
-
const ipAddress = req.ip || req.connection.remoteAddress;
|
|
72
|
-
const maxPerIP = settings?.maxSubscribersPerIP || 10;
|
|
73
|
-
const ipSubscribers = await req.payload.find({
|
|
74
|
-
collection: config.subscribersSlug || 'subscribers',
|
|
75
|
-
where: {
|
|
76
|
-
'signupMetadata.ipAddress': {
|
|
77
|
-
equals: ipAddress
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
});
|
|
81
|
-
if (ipSubscribers.docs.length >= maxPerIP) {
|
|
82
|
-
return res.status(429).json({
|
|
83
|
-
success: false,
|
|
84
|
-
error: 'Too many subscriptions from this IP address'
|
|
85
|
-
});
|
|
86
|
-
}
|
|
87
|
-
// Extract UTM parameters
|
|
88
|
-
const referer = req.headers.referer || req.headers.referrer || '';
|
|
89
|
-
const utmParams = extractUTMParams(new URL(referer).searchParams);
|
|
90
|
-
// Prepare subscriber data
|
|
91
|
-
const subscriberData = {
|
|
92
|
-
email: email.toLowerCase(),
|
|
93
|
-
name: name ? sanitizeInput(name) : undefined,
|
|
94
|
-
locale: metadata.locale || config.i18n?.defaultLocale || 'en',
|
|
95
|
-
subscriptionStatus: settings?.requireDoubleOptIn ? 'pending' : 'active',
|
|
96
|
-
source: source || 'api',
|
|
97
|
-
emailPreferences: {
|
|
98
|
-
newsletter: true,
|
|
99
|
-
announcements: true,
|
|
100
|
-
...preferences || {}
|
|
101
|
-
},
|
|
102
|
-
signupMetadata: {
|
|
103
|
-
ipAddress,
|
|
104
|
-
userAgent: req.headers['user-agent'],
|
|
105
|
-
referrer: referer,
|
|
106
|
-
signupPage: metadata.signupPage || referer
|
|
107
|
-
}
|
|
108
|
-
};
|
|
109
|
-
// Add UTM parameters if tracking is enabled
|
|
110
|
-
if (config.features?.utmTracking?.enabled && Object.keys(utmParams).length > 0) {
|
|
111
|
-
subscriberData.utmParameters = utmParams;
|
|
112
|
-
}
|
|
113
|
-
// Add lead magnet if provided
|
|
114
|
-
if (config.features?.leadMagnets?.enabled && leadMagnet) {
|
|
115
|
-
subscriberData.leadMagnet = leadMagnet;
|
|
116
|
-
}
|
|
117
|
-
// Create subscriber
|
|
118
|
-
// Public endpoint needs to create subscribers
|
|
119
|
-
const subscriber = await req.payload.create({
|
|
120
|
-
collection: config.subscribersSlug || 'subscribers',
|
|
121
|
-
data: subscriberData
|
|
122
|
-
});
|
|
123
|
-
// Handle survey responses if provided
|
|
124
|
-
if (config.features?.surveys?.enabled && surveyResponses) {
|
|
125
|
-
// TODO: Store survey responses
|
|
126
|
-
}
|
|
127
|
-
// Send confirmation email if double opt-in
|
|
128
|
-
if (settings?.requireDoubleOptIn) {
|
|
129
|
-
// TODO: Send confirmation email with magic link
|
|
130
|
-
}
|
|
131
|
-
res.json({
|
|
132
|
-
success: true,
|
|
133
|
-
subscriber: {
|
|
134
|
-
id: subscriber.id,
|
|
135
|
-
email: subscriber.email,
|
|
136
|
-
subscriptionStatus: subscriber.subscriptionStatus
|
|
137
|
-
},
|
|
138
|
-
message: settings?.requireDoubleOptIn ? 'Please check your email to confirm your subscription' : 'Successfully subscribed'
|
|
139
|
-
});
|
|
140
|
-
} catch (error) {
|
|
141
|
-
console.error('Subscribe endpoint error:', error);
|
|
142
|
-
res.status(500).json({
|
|
143
|
-
success: false,
|
|
144
|
-
error: 'Failed to subscribe. Please try again.'
|
|
145
|
-
});
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
};
|
|
149
|
-
};
|
|
150
|
-
|
|
151
|
-
//# sourceMappingURL=subscribe.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/endpoints/subscribe.ts"],"sourcesContent":["import type { Endpoint, PayloadHandler } from 'payload'\nimport type { NewsletterPluginConfig } from '../types'\nimport { \n isDomainAllowed, \n sanitizeInput, \n validateSubscriberData,\n extractUTMParams \n} from '../utils/validation'\n\nexport const createSubscribeEndpoint = (\n config: NewsletterPluginConfig\n): Endpoint => {\n return {\n path: '/newsletter/subscribe',\n method: 'post',\n handler: (async (req: any, res: any) => {\n try {\n const { \n email, \n name, \n source,\n preferences,\n leadMagnet,\n surveyResponses,\n metadata = {}\n } = req.body\n\n // Validate input\n const validation = validateSubscriberData({ email, name, source })\n if (!validation.valid) {\n return res.status(400).json({\n success: false,\n errors: validation.errors,\n })\n }\n\n // Check domain restrictions from active settings\n // Settings are public info needed for validation, but we can still respect access control\n const settingsResult = await req.payload.find({\n collection: config.settingsSlug || 'newsletter-settings',\n where: {\n active: {\n equals: true,\n },\n },\n limit: 1,\n overrideAccess: false,\n // No user context for public endpoint\n })\n \n const settings = settingsResult.docs[0]\n\n const allowedDomains = settings?.allowedDomains?.map((d: any) => d.domain) || []\n if (!isDomainAllowed(email, allowedDomains)) {\n return res.status(400).json({\n success: false,\n error: 'Email domain not allowed',\n })\n }\n\n // Check if already subscribed\n // This needs admin access to check for existing email\n const existing = await req.payload.find({\n collection: config.subscribersSlug || 'subscribers',\n where: {\n email: {\n equals: email.toLowerCase(),\n },\n },\n // Keep overrideAccess: true for public subscription check\n })\n\n if (existing.docs.length > 0) {\n const subscriber = existing.docs[0]\n \n // If unsubscribed, don't allow resubscription via API\n if (subscriber.subscriptionStatus === 'unsubscribed') {\n return res.status(400).json({\n success: false,\n error: 'This email has been unsubscribed. Please contact support to resubscribe.',\n })\n }\n\n return res.status(400).json({\n success: false,\n error: 'Already subscribed',\n subscriber: {\n id: subscriber.id,\n email: subscriber.email,\n subscriptionStatus: subscriber.subscriptionStatus,\n },\n })\n }\n\n // Check IP rate limiting\n const ipAddress = req.ip || req.connection.remoteAddress\n const maxPerIP = settings?.maxSubscribersPerIP || 10\n\n const ipSubscribers = await req.payload.find({\n collection: config.subscribersSlug || 'subscribers',\n where: {\n 'signupMetadata.ipAddress': {\n equals: ipAddress,\n },\n },\n // Keep overrideAccess: true for rate limiting check\n })\n\n if (ipSubscribers.docs.length >= maxPerIP) {\n return res.status(429).json({\n success: false,\n error: 'Too many subscriptions from this IP address',\n })\n }\n\n // Extract UTM parameters\n const referer = req.headers.referer || req.headers.referrer || ''\n const utmParams = extractUTMParams(new URL(referer).searchParams)\n\n // Prepare subscriber data\n const subscriberData: any = {\n email: email.toLowerCase(),\n name: name ? sanitizeInput(name) : undefined,\n locale: metadata.locale || config.i18n?.defaultLocale || 'en',\n subscriptionStatus: settings?.requireDoubleOptIn ? 'pending' : 'active',\n source: source || 'api',\n emailPreferences: {\n newsletter: true,\n announcements: true,\n ...(preferences || {}),\n },\n signupMetadata: {\n ipAddress,\n userAgent: req.headers['user-agent'],\n referrer: referer,\n signupPage: metadata.signupPage || referer,\n },\n }\n\n // Add UTM parameters if tracking is enabled\n if (config.features?.utmTracking?.enabled && Object.keys(utmParams).length > 0) {\n subscriberData.utmParameters = utmParams\n }\n\n // Add lead magnet if provided\n if (config.features?.leadMagnets?.enabled && leadMagnet) {\n subscriberData.leadMagnet = leadMagnet\n }\n\n // Create subscriber\n // Public endpoint needs to create subscribers\n const subscriber = await req.payload.create({\n collection: config.subscribersSlug || 'subscribers',\n data: subscriberData,\n // Keep overrideAccess: true for public subscription\n })\n\n // Handle survey responses if provided\n if (config.features?.surveys?.enabled && surveyResponses) {\n // TODO: Store survey responses\n }\n\n // Send confirmation email if double opt-in\n if (settings?.requireDoubleOptIn) {\n // TODO: Send confirmation email with magic link\n }\n\n res.json({\n success: true,\n subscriber: {\n id: subscriber.id,\n email: subscriber.email,\n subscriptionStatus: subscriber.subscriptionStatus,\n },\n message: settings?.requireDoubleOptIn \n ? 'Please check your email to confirm your subscription'\n : 'Successfully subscribed',\n })\n } catch (error) {\n console.error('Subscribe endpoint error:', error)\n res.status(500).json({\n success: false,\n error: 'Failed to subscribe. Please try again.',\n })\n }\n }) as PayloadHandler,\n }\n}"],"names":["isDomainAllowed","sanitizeInput","validateSubscriberData","extractUTMParams","createSubscribeEndpoint","config","path","method","handler","req","res","email","name","source","preferences","leadMagnet","surveyResponses","metadata","body","validation","valid","status","json","success","errors","settingsResult","payload","find","collection","settingsSlug","where","active","equals","limit","overrideAccess","settings","docs","allowedDomains","map","d","domain","error","existing","subscribersSlug","toLowerCase","length","subscriber","subscriptionStatus","id","ipAddress","ip","connection","remoteAddress","maxPerIP","maxSubscribersPerIP","ipSubscribers","referer","headers","referrer","utmParams","URL","searchParams","subscriberData","undefined","locale","i18n","defaultLocale","requireDoubleOptIn","emailPreferences","newsletter","announcements","signupMetadata","userAgent","signupPage","features","utmTracking","enabled","Object","keys","utmParameters","leadMagnets","create","data","surveys","message","console"],"mappings":"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"}
|
|
@@ -1,105 +0,0 @@
|
|
|
1
|
-
import { isValidEmail } from '../utils/validation';
|
|
2
|
-
export const createUnsubscribeEndpoint = (config)=>{
|
|
3
|
-
return {
|
|
4
|
-
path: '/newsletter/unsubscribe',
|
|
5
|
-
method: 'post',
|
|
6
|
-
handler: async (req, res)=>{
|
|
7
|
-
try {
|
|
8
|
-
const { email, token } = req.body;
|
|
9
|
-
// Two methods: email or token
|
|
10
|
-
if (!email && !token) {
|
|
11
|
-
return res.status(400).json({
|
|
12
|
-
success: false,
|
|
13
|
-
error: 'Email or token is required'
|
|
14
|
-
});
|
|
15
|
-
}
|
|
16
|
-
let subscriber;
|
|
17
|
-
if (token) {
|
|
18
|
-
// Token-based unsubscribe (from email link)
|
|
19
|
-
try {
|
|
20
|
-
const jwt = await import('jsonwebtoken');
|
|
21
|
-
const payload = jwt.verify(token, process.env.JWT_SECRET || process.env.PAYLOAD_SECRET || '');
|
|
22
|
-
if (payload.type !== 'unsubscribe') {
|
|
23
|
-
throw new Error('Invalid token type');
|
|
24
|
-
}
|
|
25
|
-
// Token verified, so we can look up the subscriber
|
|
26
|
-
// Using overrideAccess: true here is OK since we verified the token
|
|
27
|
-
subscriber = await req.payload.findByID({
|
|
28
|
-
collection: config.subscribersSlug || 'subscribers',
|
|
29
|
-
id: payload.subscriberId
|
|
30
|
-
});
|
|
31
|
-
} catch {
|
|
32
|
-
return res.status(401).json({
|
|
33
|
-
success: false,
|
|
34
|
-
error: 'Invalid or expired unsubscribe link'
|
|
35
|
-
});
|
|
36
|
-
}
|
|
37
|
-
} else {
|
|
38
|
-
// Email-based unsubscribe
|
|
39
|
-
if (!isValidEmail(email)) {
|
|
40
|
-
return res.status(400).json({
|
|
41
|
-
success: false,
|
|
42
|
-
error: 'Invalid email format'
|
|
43
|
-
});
|
|
44
|
-
}
|
|
45
|
-
const result = await req.payload.find({
|
|
46
|
-
collection: config.subscribersSlug || 'subscribers',
|
|
47
|
-
where: {
|
|
48
|
-
email: {
|
|
49
|
-
equals: email.toLowerCase()
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
});
|
|
53
|
-
if (result.docs.length === 0) {
|
|
54
|
-
// Don't reveal if email exists or not
|
|
55
|
-
return res.json({
|
|
56
|
-
success: true,
|
|
57
|
-
message: 'If this email was subscribed, it has been unsubscribed.'
|
|
58
|
-
});
|
|
59
|
-
}
|
|
60
|
-
subscriber = result.docs[0];
|
|
61
|
-
}
|
|
62
|
-
if (!subscriber) {
|
|
63
|
-
return res.json({
|
|
64
|
-
success: true,
|
|
65
|
-
message: 'If this email was subscribed, it has been unsubscribed.'
|
|
66
|
-
});
|
|
67
|
-
}
|
|
68
|
-
// Check if already unsubscribed
|
|
69
|
-
if (subscriber.subscriptionStatus === 'unsubscribed') {
|
|
70
|
-
return res.json({
|
|
71
|
-
success: true,
|
|
72
|
-
message: 'Already unsubscribed'
|
|
73
|
-
});
|
|
74
|
-
}
|
|
75
|
-
// Update subscription status - use synthetic user to ensure proper access
|
|
76
|
-
await req.payload.update({
|
|
77
|
-
collection: config.subscribersSlug || 'subscribers',
|
|
78
|
-
id: subscriber.id,
|
|
79
|
-
data: {
|
|
80
|
-
subscriptionStatus: 'unsubscribed',
|
|
81
|
-
unsubscribedAt: new Date().toISOString()
|
|
82
|
-
},
|
|
83
|
-
overrideAccess: false,
|
|
84
|
-
user: {
|
|
85
|
-
collection: 'subscribers',
|
|
86
|
-
id: subscriber.id,
|
|
87
|
-
email: subscriber.email
|
|
88
|
-
}
|
|
89
|
-
});
|
|
90
|
-
res.json({
|
|
91
|
-
success: true,
|
|
92
|
-
message: 'Successfully unsubscribed'
|
|
93
|
-
});
|
|
94
|
-
} catch (error) {
|
|
95
|
-
console.error('Unsubscribe error:', error);
|
|
96
|
-
res.status(500).json({
|
|
97
|
-
success: false,
|
|
98
|
-
error: 'Failed to unsubscribe. Please try again.'
|
|
99
|
-
});
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
};
|
|
103
|
-
};
|
|
104
|
-
|
|
105
|
-
//# sourceMappingURL=unsubscribe.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/endpoints/unsubscribe.ts"],"sourcesContent":["import type { Endpoint, PayloadHandler } from 'payload'\nimport type { NewsletterPluginConfig } from '../types'\nimport { isValidEmail } from '../utils/validation'\n\nexport const createUnsubscribeEndpoint = (\n config: NewsletterPluginConfig\n): Endpoint => {\n return {\n path: '/newsletter/unsubscribe',\n method: 'post',\n handler: (async (req: any, res: any) => {\n try {\n const { email, token } = req.body\n\n // Two methods: email or token\n if (!email && !token) {\n return res.status(400).json({\n success: false,\n error: 'Email or token is required',\n })\n }\n\n let subscriber\n\n if (token) {\n // Token-based unsubscribe (from email link)\n try {\n const jwt = await import('jsonwebtoken')\n const payload = jwt.verify(\n token,\n process.env.JWT_SECRET || process.env.PAYLOAD_SECRET || ''\n ) as any\n\n if (payload.type !== 'unsubscribe') {\n throw new Error('Invalid token type')\n }\n\n // Token verified, so we can look up the subscriber\n // Using overrideAccess: true here is OK since we verified the token\n subscriber = await req.payload.findByID({\n collection: config.subscribersSlug || 'subscribers',\n id: payload.subscriberId,\n })\n } catch {\n return res.status(401).json({\n success: false,\n error: 'Invalid or expired unsubscribe link',\n })\n }\n } else {\n // Email-based unsubscribe\n if (!isValidEmail(email)) {\n return res.status(400).json({\n success: false,\n error: 'Invalid email format',\n })\n }\n\n const result = await req.payload.find({\n collection: config.subscribersSlug || 'subscribers',\n where: {\n email: {\n equals: email.toLowerCase(),\n },\n },\n })\n\n if (result.docs.length === 0) {\n // Don't reveal if email exists or not\n return res.json({\n success: true,\n message: 'If this email was subscribed, it has been unsubscribed.',\n })\n }\n\n subscriber = result.docs[0]\n }\n\n if (!subscriber) {\n return res.json({\n success: true,\n message: 'If this email was subscribed, it has been unsubscribed.',\n })\n }\n\n // Check if already unsubscribed\n if (subscriber.subscriptionStatus === 'unsubscribed') {\n return res.json({\n success: true,\n message: 'Already unsubscribed',\n })\n }\n\n // Update subscription status - use synthetic user to ensure proper access\n await req.payload.update({\n collection: config.subscribersSlug || 'subscribers',\n id: subscriber.id,\n data: {\n subscriptionStatus: 'unsubscribed',\n unsubscribedAt: new Date().toISOString(),\n },\n overrideAccess: false,\n user: {\n collection: 'subscribers',\n id: subscriber.id,\n email: subscriber.email,\n },\n })\n\n res.json({\n success: true,\n message: 'Successfully unsubscribed',\n })\n } catch (error: unknown) {\n console.error('Unsubscribe error:', error)\n res.status(500).json({\n success: false,\n error: 'Failed to unsubscribe. Please try again.',\n })\n }\n }) as PayloadHandler,\n }\n}"],"names":["isValidEmail","createUnsubscribeEndpoint","config","path","method","handler","req","res","email","token","body","status","json","success","error","subscriber","jwt","payload","verify","process","env","JWT_SECRET","PAYLOAD_SECRET","type","Error","findByID","collection","subscribersSlug","id","subscriberId","result","find","where","equals","toLowerCase","docs","length","message","subscriptionStatus","update","data","unsubscribedAt","Date","toISOString","overrideAccess","user","console"],"mappings":"AAEA,SAASA,YAAY,QAAQ,sBAAqB;AAElD,OAAO,MAAMC,4BAA4B,CACvCC;IAEA,OAAO;QACLC,MAAM;QACNC,QAAQ;QACRC,SAAU,OAAOC,KAAUC;YACzB,IAAI;gBACF,MAAM,EAAEC,KAAK,EAAEC,KAAK,EAAE,GAAGH,IAAII,IAAI;gBAEjC,8BAA8B;gBAC9B,IAAI,CAACF,SAAS,CAACC,OAAO;oBACpB,OAAOF,IAAII,MAAM,CAAC,KAAKC,IAAI,CAAC;wBAC1BC,SAAS;wBACTC,OAAO;oBACT;gBACF;gBAEA,IAAIC;gBAEJ,IAAIN,OAAO;oBACT,4CAA4C;oBAC5C,IAAI;wBACF,MAAMO,MAAM,MAAM,MAAM,CAAC;wBACzB,MAAMC,UAAUD,IAAIE,MAAM,CACxBT,OACAU,QAAQC,GAAG,CAACC,UAAU,IAAIF,QAAQC,GAAG,CAACE,cAAc,IAAI;wBAG1D,IAAIL,QAAQM,IAAI,KAAK,eAAe;4BAClC,MAAM,IAAIC,MAAM;wBAClB;wBAEA,mDAAmD;wBACnD,oEAAoE;wBACpET,aAAa,MAAMT,IAAIW,OAAO,CAACQ,QAAQ,CAAC;4BACtCC,YAAYxB,OAAOyB,eAAe,IAAI;4BACtCC,IAAIX,QAAQY,YAAY;wBAC1B;oBACF,EAAE,OAAM;wBACN,OAAOtB,IAAII,MAAM,CAAC,KAAKC,IAAI,CAAC;4BAC1BC,SAAS;4BACTC,OAAO;wBACT;oBACF;gBACF,OAAO;oBACL,0BAA0B;oBAC1B,IAAI,CAACd,aAAaQ,QAAQ;wBACxB,OAAOD,IAAII,MAAM,CAAC,KAAKC,IAAI,CAAC;4BAC1BC,SAAS;4BACTC,OAAO;wBACT;oBACF;oBAEA,MAAMgB,SAAS,MAAMxB,IAAIW,OAAO,CAACc,IAAI,CAAC;wBACpCL,YAAYxB,OAAOyB,eAAe,IAAI;wBACtCK,OAAO;4BACLxB,OAAO;gCACLyB,QAAQzB,MAAM0B,WAAW;4BAC3B;wBACF;oBACF;oBAEA,IAAIJ,OAAOK,IAAI,CAACC,MAAM,KAAK,GAAG;wBAC5B,sCAAsC;wBACtC,OAAO7B,IAAIK,IAAI,CAAC;4BACdC,SAAS;4BACTwB,SAAS;wBACX;oBACF;oBAEAtB,aAAae,OAAOK,IAAI,CAAC,EAAE;gBAC7B;gBAEA,IAAI,CAACpB,YAAY;oBACf,OAAOR,IAAIK,IAAI,CAAC;wBACdC,SAAS;wBACTwB,SAAS;oBACX;gBACF;gBAEA,gCAAgC;gBAChC,IAAItB,WAAWuB,kBAAkB,KAAK,gBAAgB;oBACpD,OAAO/B,IAAIK,IAAI,CAAC;wBACdC,SAAS;wBACTwB,SAAS;oBACX;gBACF;gBAEA,0EAA0E;gBAC1E,MAAM/B,IAAIW,OAAO,CAACsB,MAAM,CAAC;oBACvBb,YAAYxB,OAAOyB,eAAe,IAAI;oBACtCC,IAAIb,WAAWa,EAAE;oBACjBY,MAAM;wBACJF,oBAAoB;wBACpBG,gBAAgB,IAAIC,OAAOC,WAAW;oBACxC;oBACAC,gBAAgB;oBAChBC,MAAM;wBACJnB,YAAY;wBACZE,IAAIb,WAAWa,EAAE;wBACjBpB,OAAOO,WAAWP,KAAK;oBACzB;gBACF;gBAEAD,IAAIK,IAAI,CAAC;oBACPC,SAAS;oBACTwB,SAAS;gBACX;YACF,EAAE,OAAOvB,OAAgB;gBACvBgC,QAAQhC,KAAK,CAAC,sBAAsBA;gBACpCP,IAAII,MAAM,CAAC,KAAKC,IAAI,CAAC;oBACnBC,SAAS;oBACTC,OAAO;gBACT;YACF;QACF;IACF;AACF,EAAC"}
|
|
@@ -1,103 +0,0 @@
|
|
|
1
|
-
import { verifyMagicLinkToken, generateSessionToken } from '../utils/jwt';
|
|
2
|
-
export const createVerifyMagicLinkEndpoint = (config)=>{
|
|
3
|
-
return {
|
|
4
|
-
path: '/newsletter/verify-magic-link',
|
|
5
|
-
method: 'post',
|
|
6
|
-
handler: async (req, res)=>{
|
|
7
|
-
try {
|
|
8
|
-
const { token } = req.body;
|
|
9
|
-
if (!token) {
|
|
10
|
-
return res.status(400).json({
|
|
11
|
-
success: false,
|
|
12
|
-
error: 'Token is required'
|
|
13
|
-
});
|
|
14
|
-
}
|
|
15
|
-
// Verify the magic link token
|
|
16
|
-
let payload;
|
|
17
|
-
try {
|
|
18
|
-
payload = verifyMagicLinkToken(token);
|
|
19
|
-
} catch (error) {
|
|
20
|
-
return res.status(401).json({
|
|
21
|
-
success: false,
|
|
22
|
-
error: error instanceof Error ? error.message : 'Invalid token'
|
|
23
|
-
});
|
|
24
|
-
}
|
|
25
|
-
// Find the subscriber - token verified so we can use admin access for initial lookup
|
|
26
|
-
const subscriber = await req.payload.findByID({
|
|
27
|
-
collection: config.subscribersSlug || 'subscribers',
|
|
28
|
-
id: payload.subscriberId
|
|
29
|
-
});
|
|
30
|
-
if (!subscriber) {
|
|
31
|
-
return res.status(404).json({
|
|
32
|
-
success: false,
|
|
33
|
-
error: 'Subscriber not found'
|
|
34
|
-
});
|
|
35
|
-
}
|
|
36
|
-
// Check if email matches
|
|
37
|
-
if (subscriber.email !== payload.email) {
|
|
38
|
-
return res.status(401).json({
|
|
39
|
-
success: false,
|
|
40
|
-
error: 'Invalid token'
|
|
41
|
-
});
|
|
42
|
-
}
|
|
43
|
-
// Check if subscriber is active
|
|
44
|
-
if (subscriber.subscriptionStatus === 'unsubscribed') {
|
|
45
|
-
return res.status(403).json({
|
|
46
|
-
success: false,
|
|
47
|
-
error: 'This email has been unsubscribed'
|
|
48
|
-
});
|
|
49
|
-
}
|
|
50
|
-
// Create synthetic user for subscriber operations
|
|
51
|
-
const syntheticUser = {
|
|
52
|
-
collection: 'subscribers',
|
|
53
|
-
id: subscriber.id,
|
|
54
|
-
email: subscriber.email
|
|
55
|
-
};
|
|
56
|
-
// Update subscription status if pending
|
|
57
|
-
if (subscriber.subscriptionStatus === 'pending') {
|
|
58
|
-
await req.payload.update({
|
|
59
|
-
collection: config.subscribersSlug || 'subscribers',
|
|
60
|
-
id: subscriber.id,
|
|
61
|
-
data: {
|
|
62
|
-
subscriptionStatus: 'active'
|
|
63
|
-
},
|
|
64
|
-
overrideAccess: false,
|
|
65
|
-
user: syntheticUser
|
|
66
|
-
});
|
|
67
|
-
}
|
|
68
|
-
// Clear the magic link token
|
|
69
|
-
await req.payload.update({
|
|
70
|
-
collection: config.subscribersSlug || 'subscribers',
|
|
71
|
-
id: subscriber.id,
|
|
72
|
-
data: {
|
|
73
|
-
magicLinkToken: null,
|
|
74
|
-
magicLinkTokenExpiry: null
|
|
75
|
-
},
|
|
76
|
-
overrideAccess: false,
|
|
77
|
-
user: syntheticUser
|
|
78
|
-
});
|
|
79
|
-
// Generate session token
|
|
80
|
-
const sessionToken = generateSessionToken(String(subscriber.id), subscriber.email);
|
|
81
|
-
res.json({
|
|
82
|
-
success: true,
|
|
83
|
-
sessionToken,
|
|
84
|
-
subscriber: {
|
|
85
|
-
id: subscriber.id,
|
|
86
|
-
email: subscriber.email,
|
|
87
|
-
name: subscriber.name,
|
|
88
|
-
locale: subscriber.locale,
|
|
89
|
-
emailPreferences: subscriber.emailPreferences
|
|
90
|
-
}
|
|
91
|
-
});
|
|
92
|
-
} catch (error) {
|
|
93
|
-
console.error('Verify magic link error:', error);
|
|
94
|
-
res.status(500).json({
|
|
95
|
-
success: false,
|
|
96
|
-
error: 'Failed to verify magic link'
|
|
97
|
-
});
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
};
|
|
101
|
-
};
|
|
102
|
-
|
|
103
|
-
//# sourceMappingURL=verify-magic-link.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/endpoints/verify-magic-link.ts"],"sourcesContent":["import type { Endpoint, PayloadHandler } from 'payload'\nimport type { NewsletterPluginConfig } from '../types'\nimport { \n verifyMagicLinkToken, \n generateSessionToken \n} from '../utils/jwt'\n\nexport const createVerifyMagicLinkEndpoint = (\n config: NewsletterPluginConfig\n): Endpoint => {\n return {\n path: '/newsletter/verify-magic-link',\n method: 'post',\n handler: (async (req: any, res: any) => {\n try {\n const { token } = req.body\n\n if (!token) {\n return res.status(400).json({\n success: false,\n error: 'Token is required',\n })\n }\n\n // Verify the magic link token\n let payload\n try {\n payload = verifyMagicLinkToken(token)\n } catch (error: unknown) {\n return res.status(401).json({\n success: false,\n error: error instanceof Error ? error.message : 'Invalid token',\n })\n }\n\n // Find the subscriber - token verified so we can use admin access for initial lookup\n const subscriber = await req.payload.findByID({\n collection: config.subscribersSlug || 'subscribers',\n id: payload.subscriberId,\n // Keep overrideAccess: true for token verification\n })\n\n if (!subscriber) {\n return res.status(404).json({\n success: false,\n error: 'Subscriber not found',\n })\n }\n\n // Check if email matches\n if (subscriber.email !== payload.email) {\n return res.status(401).json({\n success: false,\n error: 'Invalid token',\n })\n }\n\n // Check if subscriber is active\n if (subscriber.subscriptionStatus === 'unsubscribed') {\n return res.status(403).json({\n success: false,\n error: 'This email has been unsubscribed',\n })\n }\n\n // Create synthetic user for subscriber operations\n const syntheticUser = {\n collection: 'subscribers',\n id: subscriber.id,\n email: subscriber.email,\n }\n\n // Update subscription status if pending\n if (subscriber.subscriptionStatus === 'pending') {\n await req.payload.update({\n collection: config.subscribersSlug || 'subscribers',\n id: subscriber.id,\n data: {\n subscriptionStatus: 'active',\n },\n overrideAccess: false,\n user: syntheticUser,\n })\n }\n\n // Clear the magic link token\n await req.payload.update({\n collection: config.subscribersSlug || 'subscribers',\n id: subscriber.id,\n data: {\n magicLinkToken: null,\n magicLinkTokenExpiry: null,\n },\n overrideAccess: false,\n user: syntheticUser,\n })\n\n // Generate session token\n const sessionToken = generateSessionToken(\n String(subscriber.id),\n subscriber.email\n )\n\n res.json({\n success: true,\n sessionToken,\n subscriber: {\n id: subscriber.id,\n email: subscriber.email,\n name: subscriber.name,\n locale: subscriber.locale,\n emailPreferences: subscriber.emailPreferences,\n },\n })\n } catch (error: unknown) {\n console.error('Verify magic link error:', error)\n res.status(500).json({\n success: false,\n error: 'Failed to verify magic link',\n })\n }\n }) as PayloadHandler,\n }\n}"],"names":["verifyMagicLinkToken","generateSessionToken","createVerifyMagicLinkEndpoint","config","path","method","handler","req","res","token","body","status","json","success","error","payload","Error","message","subscriber","findByID","collection","subscribersSlug","id","subscriberId","email","subscriptionStatus","syntheticUser","update","data","overrideAccess","user","magicLinkToken","magicLinkTokenExpiry","sessionToken","String","name","locale","emailPreferences","console"],"mappings":"AAEA,SACEA,oBAAoB,EACpBC,oBAAoB,QACf,eAAc;AAErB,OAAO,MAAMC,gCAAgC,CAC3CC;IAEA,OAAO;QACLC,MAAM;QACNC,QAAQ;QACRC,SAAU,OAAOC,KAAUC;YACzB,IAAI;gBACF,MAAM,EAAEC,KAAK,EAAE,GAAGF,IAAIG,IAAI;gBAE1B,IAAI,CAACD,OAAO;oBACV,OAAOD,IAAIG,MAAM,CAAC,KAAKC,IAAI,CAAC;wBAC1BC,SAAS;wBACTC,OAAO;oBACT;gBACF;gBAEA,8BAA8B;gBAC9B,IAAIC;gBACJ,IAAI;oBACFA,UAAUf,qBAAqBS;gBACjC,EAAE,OAAOK,OAAgB;oBACvB,OAAON,IAAIG,MAAM,CAAC,KAAKC,IAAI,CAAC;wBAC1BC,SAAS;wBACTC,OAAOA,iBAAiBE,QAAQF,MAAMG,OAAO,GAAG;oBAClD;gBACF;gBAEA,qFAAqF;gBACrF,MAAMC,aAAa,MAAMX,IAAIQ,OAAO,CAACI,QAAQ,CAAC;oBAC5CC,YAAYjB,OAAOkB,eAAe,IAAI;oBACtCC,IAAIP,QAAQQ,YAAY;gBAE1B;gBAEA,IAAI,CAACL,YAAY;oBACf,OAAOV,IAAIG,MAAM,CAAC,KAAKC,IAAI,CAAC;wBAC1BC,SAAS;wBACTC,OAAO;oBACT;gBACF;gBAEA,yBAAyB;gBACzB,IAAII,WAAWM,KAAK,KAAKT,QAAQS,KAAK,EAAE;oBACtC,OAAOhB,IAAIG,MAAM,CAAC,KAAKC,IAAI,CAAC;wBAC1BC,SAAS;wBACTC,OAAO;oBACT;gBACF;gBAEA,gCAAgC;gBAChC,IAAII,WAAWO,kBAAkB,KAAK,gBAAgB;oBACpD,OAAOjB,IAAIG,MAAM,CAAC,KAAKC,IAAI,CAAC;wBAC1BC,SAAS;wBACTC,OAAO;oBACT;gBACF;gBAEA,kDAAkD;gBAClD,MAAMY,gBAAgB;oBACpBN,YAAY;oBACZE,IAAIJ,WAAWI,EAAE;oBACjBE,OAAON,WAAWM,KAAK;gBACzB;gBAEA,wCAAwC;gBACxC,IAAIN,WAAWO,kBAAkB,KAAK,WAAW;oBAC/C,MAAMlB,IAAIQ,OAAO,CAACY,MAAM,CAAC;wBACvBP,YAAYjB,OAAOkB,eAAe,IAAI;wBACtCC,IAAIJ,WAAWI,EAAE;wBACjBM,MAAM;4BACJH,oBAAoB;wBACtB;wBACAI,gBAAgB;wBAChBC,MAAMJ;oBACR;gBACF;gBAEA,6BAA6B;gBAC7B,MAAMnB,IAAIQ,OAAO,CAACY,MAAM,CAAC;oBACvBP,YAAYjB,OAAOkB,eAAe,IAAI;oBACtCC,IAAIJ,WAAWI,EAAE;oBACjBM,MAAM;wBACJG,gBAAgB;wBAChBC,sBAAsB;oBACxB;oBACAH,gBAAgB;oBAChBC,MAAMJ;gBACR;gBAEA,yBAAyB;gBACzB,MAAMO,eAAehC,qBACnBiC,OAAOhB,WAAWI,EAAE,GACpBJ,WAAWM,KAAK;gBAGlBhB,IAAII,IAAI,CAAC;oBACPC,SAAS;oBACToB;oBACAf,YAAY;wBACVI,IAAIJ,WAAWI,EAAE;wBACjBE,OAAON,WAAWM,KAAK;wBACvBW,MAAMjB,WAAWiB,IAAI;wBACrBC,QAAQlB,WAAWkB,MAAM;wBACzBC,kBAAkBnB,WAAWmB,gBAAgB;oBAC/C;gBACF;YACF,EAAE,OAAOvB,OAAgB;gBACvBwB,QAAQxB,KAAK,CAAC,4BAA4BA;gBAC1CN,IAAIG,MAAM,CAAC,KAAKC,IAAI,CAAC;oBACnBC,SAAS;oBACTC,OAAO;gBACT;YACF;QACF;IACF;AACF,EAAC"}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
// React components
|
|
3
|
-
export { NewsletterForm, createNewsletterForm, PreferencesForm, createPreferencesForm, MagicLinkVerify, createMagicLinkVerify } from '../components';
|
|
4
|
-
// Hooks
|
|
5
|
-
export { useNewsletterAuth } from '../hooks/useNewsletterAuth';
|
|
6
|
-
|
|
7
|
-
//# sourceMappingURL=client.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/exports/client.ts"],"sourcesContent":["'use client'\n\n// React components\nexport { \n NewsletterForm, \n createNewsletterForm,\n PreferencesForm,\n createPreferencesForm,\n MagicLinkVerify,\n createMagicLinkVerify,\n} from '../components'\n\n// Hooks\nexport { useNewsletterAuth } from '../hooks/useNewsletterAuth'\n\n// Types for client-side use\nexport type {\n SignupFormProps,\n PreferencesFormProps,\n Subscriber,\n} from '../types'\n\nexport type {\n MagicLinkVerifyProps,\n} from '../components'\n\nexport type {\n UseNewsletterAuthOptions,\n UseNewsletterAuthReturn,\n} from '../hooks/useNewsletterAuth'"],"names":["NewsletterForm","createNewsletterForm","PreferencesForm","createPreferencesForm","MagicLinkVerify","createMagicLinkVerify","useNewsletterAuth"],"mappings":"AAAA;AAEA,mBAAmB;AACnB,SACEA,cAAc,EACdC,oBAAoB,EACpBC,eAAe,EACfC,qBAAqB,EACrBC,eAAe,EACfC,qBAAqB,QAChB,gBAAe;AAEtB,QAAQ;AACR,SAASC,iBAAiB,QAAQ,6BAA4B"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/exports/components.ts"],"sourcesContent":["'use client'\n\n// Re-export all components from the client export\n// This allows users to import directly from @payloadcms/plugin-newsletter/components\nexport * from './client'"],"names":[],"mappings":"AAAA;AAEA,kDAAkD;AAClD,qFAAqF;AACrF,cAAc,WAAU"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/exports/types.ts"],"sourcesContent":["export * from '../types'"],"names":[],"mappings":"AAAA,cAAc,WAAU"}
|