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 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/providers/broadcast.ts"],"sourcesContent":["import type { EmailProvider, SendEmailParams } from './types'\nimport { EmailProviderError } from './types'\nimport type { Subscriber, BroadcastProviderConfig } from '../types'\n\nexport class BroadcastProvider implements EmailProvider {\n private apiUrl: string\n private token: string\n private fromAddress: string\n private fromName: string\n private isDevelopment: boolean\n\n constructor(config: BroadcastProviderConfig & { \n fromAddress: string\n fromName: string \n }) {\n this.apiUrl = config.apiUrl.replace(/\\/$/, '') // Remove trailing slash\n this.isDevelopment = process.env.NODE_ENV !== 'production'\n this.token = this.isDevelopment \n ? config.tokens.development || config.tokens.production || ''\n : config.tokens.production || config.tokens.development || ''\n this.fromAddress = config.fromAddress\n this.fromName = config.fromName\n }\n\n getProvider(): string {\n return 'broadcast'\n }\n\n async send(params: SendEmailParams): Promise<void> {\n try {\n const from = params.from || {\n email: this.fromAddress,\n name: this.fromName,\n }\n\n const recipients = Array.isArray(params.to) ? params.to : [params.to]\n \n // Broadcast expects a specific format\n const response = await fetch(`${this.apiUrl}/api/v1/emails`, {\n method: 'POST',\n headers: {\n 'Authorization': `Bearer ${this.token}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n from_email: from.email,\n from_name: from.name,\n to: recipients,\n subject: params.subject,\n html_body: params.html,\n text_body: params.text,\n reply_to: params.replyTo,\n }),\n })\n\n if (!response.ok) {\n const error = await response.text()\n throw new Error(`Broadcast API error: ${response.status} - ${error}`)\n }\n } catch (error: unknown) {\n throw new EmailProviderError(\n `Failed to send email via Broadcast: ${error instanceof Error ? error.message : 'Unknown error'}`,\n 'broadcast',\n error\n )\n }\n }\n\n async addContact(contact: Subscriber): Promise<void> {\n try {\n const response = await fetch(`${this.apiUrl}/api/v1/contacts`, {\n method: 'POST',\n headers: {\n 'Authorization': `Bearer ${this.token}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n email: contact.email,\n name: contact.name,\n status: contact.subscriptionStatus === 'active' ? 'subscribed' : 'unsubscribed',\n metadata: {\n locale: contact.locale,\n source: contact.source,\n ...contact.utmParameters,\n },\n }),\n })\n\n if (!response.ok) {\n const error = await response.text()\n throw new Error(`Broadcast API error: ${response.status} - ${error}`)\n }\n } catch (error: unknown) {\n throw new EmailProviderError(\n `Failed to add contact to Broadcast: ${error instanceof Error ? error.message : 'Unknown error'}`,\n 'broadcast',\n error\n )\n }\n }\n\n async updateContact(contact: Subscriber): Promise<void> {\n try {\n // First, try to find the contact\n const searchResponse = await fetch(\n `${this.apiUrl}/api/v1/contacts?email=${encodeURIComponent(contact.email)}`,\n {\n headers: {\n 'Authorization': `Bearer ${this.token}`,\n },\n }\n )\n\n if (!searchResponse.ok) {\n // If contact doesn't exist, create it\n await this.addContact(contact)\n return\n }\n\n const contacts = await searchResponse.json()\n const existingContact = contacts.data?.[0]\n\n if (!existingContact) {\n await this.addContact(contact)\n return\n }\n\n // Update existing contact\n const response = await fetch(`${this.apiUrl}/api/v1/contacts/${existingContact.id}`, {\n method: 'PUT',\n headers: {\n 'Authorization': `Bearer ${this.token}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n email: contact.email,\n name: contact.name,\n status: contact.subscriptionStatus === 'active' ? 'subscribed' : 'unsubscribed',\n metadata: {\n locale: contact.locale,\n source: contact.source,\n ...contact.utmParameters,\n },\n }),\n })\n\n if (!response.ok) {\n const error = await response.text()\n throw new Error(`Broadcast API error: ${response.status} - ${error}`)\n }\n } catch (error: unknown) {\n throw new EmailProviderError(\n `Failed to update contact in Broadcast: ${error instanceof Error ? error.message : 'Unknown error'}`,\n 'broadcast',\n error\n )\n }\n }\n\n async removeContact(email: string): Promise<void> {\n try {\n // First, find the contact\n const searchResponse = await fetch(\n `${this.apiUrl}/api/v1/contacts?email=${encodeURIComponent(email)}`,\n {\n headers: {\n 'Authorization': `Bearer ${this.token}`,\n },\n }\n )\n\n if (!searchResponse.ok) {\n // Contact doesn't exist, nothing to remove\n return\n }\n\n const contacts = await searchResponse.json()\n const contact = contacts.data?.[0]\n\n if (!contact) {\n return\n }\n\n // Delete the contact\n const response = await fetch(`${this.apiUrl}/api/v1/contacts/${contact.id}`, {\n method: 'DELETE',\n headers: {\n 'Authorization': `Bearer ${this.token}`,\n },\n })\n\n if (!response.ok) {\n const error = await response.text()\n throw new Error(`Broadcast API error: ${response.status} - ${error}`)\n }\n } catch (error: unknown) {\n throw new EmailProviderError(\n `Failed to remove contact from Broadcast: ${error instanceof Error ? error.message : 'Unknown error'}`,\n 'broadcast',\n error\n )\n }\n }\n}"],"names":["EmailProviderError","BroadcastProvider","apiUrl","token","fromAddress","fromName","isDevelopment","config","replace","process","env","NODE_ENV","tokens","development","production","getProvider","send","params","from","email","name","recipients","Array","isArray","to","response","fetch","method","headers","body","JSON","stringify","from_email","from_name","subject","html_body","html","text_body","text","reply_to","replyTo","ok","error","Error","status","message","addContact","contact","subscriptionStatus","metadata","locale","source","utmParameters","updateContact","searchResponse","encodeURIComponent","contacts","json","existingContact","data","id","removeContact"],"mappings":"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"}
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
import { ResendProvider } from './resend';
|
|
2
|
-
import { BroadcastProvider } from './broadcast';
|
|
3
|
-
export * from './types';
|
|
4
|
-
export class EmailService {
|
|
5
|
-
provider;
|
|
6
|
-
constructor(config){
|
|
7
|
-
this.provider = this.createProvider(config);
|
|
8
|
-
}
|
|
9
|
-
createProvider(config) {
|
|
10
|
-
const baseConfig = {
|
|
11
|
-
fromAddress: config.fromAddress,
|
|
12
|
-
fromName: config.fromName
|
|
13
|
-
};
|
|
14
|
-
switch(config.provider){
|
|
15
|
-
case 'resend':
|
|
16
|
-
if (!config.resend) {
|
|
17
|
-
throw new Error('Resend configuration is required when using Resend provider');
|
|
18
|
-
}
|
|
19
|
-
return new ResendProvider({
|
|
20
|
-
...config.resend,
|
|
21
|
-
...baseConfig
|
|
22
|
-
});
|
|
23
|
-
case 'broadcast':
|
|
24
|
-
if (!config.broadcast) {
|
|
25
|
-
throw new Error('Broadcast configuration is required when using Broadcast provider');
|
|
26
|
-
}
|
|
27
|
-
return new BroadcastProvider({
|
|
28
|
-
...config.broadcast,
|
|
29
|
-
...baseConfig
|
|
30
|
-
});
|
|
31
|
-
default:
|
|
32
|
-
throw new Error(`Unknown email provider: ${config.provider}`);
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
async send(params) {
|
|
36
|
-
return this.provider.send(params);
|
|
37
|
-
}
|
|
38
|
-
async addContact(contact) {
|
|
39
|
-
return this.provider.addContact(contact);
|
|
40
|
-
}
|
|
41
|
-
async updateContact(contact) {
|
|
42
|
-
return this.provider.updateContact(contact);
|
|
43
|
-
}
|
|
44
|
-
async removeContact(email) {
|
|
45
|
-
return this.provider.removeContact(email);
|
|
46
|
-
}
|
|
47
|
-
getProvider() {
|
|
48
|
-
return this.provider.getProvider();
|
|
49
|
-
}
|
|
50
|
-
/**
|
|
51
|
-
* Update the provider configuration
|
|
52
|
-
* Useful when settings are changed in the admin UI
|
|
53
|
-
*/ updateConfig(config) {
|
|
54
|
-
this.provider = this.createProvider(config);
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
/**
|
|
58
|
-
* Create email service from plugin configuration
|
|
59
|
-
*/ export function createEmailService(config) {
|
|
60
|
-
return new EmailService(config);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
//# sourceMappingURL=index.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/providers/index.ts"],"sourcesContent":["import type { EmailProvider, EmailServiceConfig, SendEmailParams } from './types'\nimport type { Subscriber } from '../types'\nimport { ResendProvider } from './resend'\nimport { BroadcastProvider } from './broadcast'\n\nexport * from './types'\n\nexport class EmailService {\n private provider: EmailProvider\n\n constructor(config: EmailServiceConfig) {\n this.provider = this.createProvider(config)\n }\n\n private createProvider(config: EmailServiceConfig): EmailProvider {\n const baseConfig = {\n fromAddress: config.fromAddress,\n fromName: config.fromName,\n }\n\n switch (config.provider) {\n case 'resend':\n if (!config.resend) {\n throw new Error('Resend configuration is required when using Resend provider')\n }\n return new ResendProvider({\n ...config.resend,\n ...baseConfig,\n })\n\n case 'broadcast':\n if (!config.broadcast) {\n throw new Error('Broadcast configuration is required when using Broadcast provider')\n }\n return new BroadcastProvider({\n ...config.broadcast,\n ...baseConfig,\n })\n\n default:\n throw new Error(`Unknown email provider: ${config.provider}`)\n }\n }\n\n async send(params: SendEmailParams): Promise<void> {\n return this.provider.send(params)\n }\n\n async addContact(contact: Subscriber): Promise<void> {\n return this.provider.addContact(contact)\n }\n\n async updateContact(contact: Subscriber): Promise<void> {\n return this.provider.updateContact(contact)\n }\n\n async removeContact(email: string): Promise<void> {\n return this.provider.removeContact(email)\n }\n\n getProvider(): string {\n return this.provider.getProvider()\n }\n\n /**\n * Update the provider configuration\n * Useful when settings are changed in the admin UI\n */\n updateConfig(config: EmailServiceConfig): void {\n this.provider = this.createProvider(config)\n }\n}\n\n/**\n * Create email service from plugin configuration\n */\nexport function createEmailService(config: EmailServiceConfig): EmailService {\n return new EmailService(config)\n}"],"names":["ResendProvider","BroadcastProvider","EmailService","provider","config","createProvider","baseConfig","fromAddress","fromName","resend","Error","broadcast","send","params","addContact","contact","updateContact","removeContact","email","getProvider","updateConfig","createEmailService"],"mappings":"AAEA,SAASA,cAAc,QAAQ,WAAU;AACzC,SAASC,iBAAiB,QAAQ,cAAa;AAE/C,cAAc,UAAS;AAEvB,OAAO,MAAMC;IACHC,SAAuB;IAE/B,YAAYC,MAA0B,CAAE;QACtC,IAAI,CAACD,QAAQ,GAAG,IAAI,CAACE,cAAc,CAACD;IACtC;IAEQC,eAAeD,MAA0B,EAAiB;QAChE,MAAME,aAAa;YACjBC,aAAaH,OAAOG,WAAW;YAC/BC,UAAUJ,OAAOI,QAAQ;QAC3B;QAEA,OAAQJ,OAAOD,QAAQ;YACrB,KAAK;gBACH,IAAI,CAACC,OAAOK,MAAM,EAAE;oBAClB,MAAM,IAAIC,MAAM;gBAClB;gBACA,OAAO,IAAIV,eAAe;oBACxB,GAAGI,OAAOK,MAAM;oBAChB,GAAGH,UAAU;gBACf;YAEF,KAAK;gBACH,IAAI,CAACF,OAAOO,SAAS,EAAE;oBACrB,MAAM,IAAID,MAAM;gBAClB;gBACA,OAAO,IAAIT,kBAAkB;oBAC3B,GAAGG,OAAOO,SAAS;oBACnB,GAAGL,UAAU;gBACf;YAEF;gBACE,MAAM,IAAII,MAAM,CAAC,wBAAwB,EAAEN,OAAOD,QAAQ,EAAE;QAChE;IACF;IAEA,MAAMS,KAAKC,MAAuB,EAAiB;QACjD,OAAO,IAAI,CAACV,QAAQ,CAACS,IAAI,CAACC;IAC5B;IAEA,MAAMC,WAAWC,OAAmB,EAAiB;QACnD,OAAO,IAAI,CAACZ,QAAQ,CAACW,UAAU,CAACC;IAClC;IAEA,MAAMC,cAAcD,OAAmB,EAAiB;QACtD,OAAO,IAAI,CAACZ,QAAQ,CAACa,aAAa,CAACD;IACrC;IAEA,MAAME,cAAcC,KAAa,EAAiB;QAChD,OAAO,IAAI,CAACf,QAAQ,CAACc,aAAa,CAACC;IACrC;IAEAC,cAAsB;QACpB,OAAO,IAAI,CAAChB,QAAQ,CAACgB,WAAW;IAClC;IAEA;;;GAGC,GACDC,aAAahB,MAA0B,EAAQ;QAC7C,IAAI,CAACD,QAAQ,GAAG,IAAI,CAACE,cAAc,CAACD;IACtC;AACF;AAEA;;CAEC,GACD,OAAO,SAASiB,mBAAmBjB,MAA0B;IAC3D,OAAO,IAAIF,aAAaE;AAC1B"}
|
|
@@ -1,122 +0,0 @@
|
|
|
1
|
-
import { Resend } from 'resend';
|
|
2
|
-
import { EmailProviderError } from './types';
|
|
3
|
-
export class ResendProvider {
|
|
4
|
-
client;
|
|
5
|
-
audienceIds;
|
|
6
|
-
fromAddress;
|
|
7
|
-
fromName;
|
|
8
|
-
isDevelopment;
|
|
9
|
-
constructor(config){
|
|
10
|
-
this.client = new Resend(config.apiKey);
|
|
11
|
-
this.audienceIds = config.audienceIds || {};
|
|
12
|
-
this.fromAddress = config.fromAddress;
|
|
13
|
-
this.fromName = config.fromName;
|
|
14
|
-
this.isDevelopment = process.env.NODE_ENV !== 'production';
|
|
15
|
-
}
|
|
16
|
-
getProvider() {
|
|
17
|
-
return 'resend';
|
|
18
|
-
}
|
|
19
|
-
async send(params) {
|
|
20
|
-
try {
|
|
21
|
-
const from = params.from || {
|
|
22
|
-
email: this.fromAddress,
|
|
23
|
-
name: this.fromName
|
|
24
|
-
};
|
|
25
|
-
if (!params.html && !params.text) {
|
|
26
|
-
throw new Error('Either html or text content is required');
|
|
27
|
-
}
|
|
28
|
-
await this.client.emails.send({
|
|
29
|
-
from: `${from.name} <${from.email}>`,
|
|
30
|
-
to: Array.isArray(params.to) ? params.to : [
|
|
31
|
-
params.to
|
|
32
|
-
],
|
|
33
|
-
subject: params.subject,
|
|
34
|
-
html: params.html || '',
|
|
35
|
-
text: params.text,
|
|
36
|
-
replyTo: params.replyTo
|
|
37
|
-
});
|
|
38
|
-
} catch (error) {
|
|
39
|
-
throw new EmailProviderError(`Failed to send email via Resend: ${error instanceof Error ? error.message : 'Unknown error'}`, 'resend', error);
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
async addContact(contact) {
|
|
43
|
-
try {
|
|
44
|
-
const audienceId = this.getAudienceId(contact.locale);
|
|
45
|
-
if (!audienceId) {
|
|
46
|
-
console.warn(`No audience ID configured for locale: ${contact.locale}`);
|
|
47
|
-
return;
|
|
48
|
-
}
|
|
49
|
-
await this.client.contacts.create({
|
|
50
|
-
email: contact.email,
|
|
51
|
-
firstName: contact.name?.split(' ')[0],
|
|
52
|
-
lastName: contact.name?.split(' ').slice(1).join(' '),
|
|
53
|
-
unsubscribed: contact.subscriptionStatus === 'unsubscribed',
|
|
54
|
-
audienceId
|
|
55
|
-
});
|
|
56
|
-
} catch (error) {
|
|
57
|
-
throw new EmailProviderError(`Failed to add contact to Resend: ${error instanceof Error ? error.message : 'Unknown error'}`, 'resend', error);
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
async updateContact(contact) {
|
|
61
|
-
try {
|
|
62
|
-
const audienceId = this.getAudienceId(contact.locale);
|
|
63
|
-
if (!audienceId) {
|
|
64
|
-
console.warn(`No audience ID configured for locale: ${contact.locale}`);
|
|
65
|
-
return;
|
|
66
|
-
}
|
|
67
|
-
// Resend requires finding the contact first
|
|
68
|
-
const contacts = await this.client.contacts.list({
|
|
69
|
-
audienceId
|
|
70
|
-
});
|
|
71
|
-
const existingContact = contacts.data?.data?.find((c)=>c.email === contact.email);
|
|
72
|
-
if (existingContact) {
|
|
73
|
-
await this.client.contacts.update({
|
|
74
|
-
id: existingContact.id,
|
|
75
|
-
audienceId,
|
|
76
|
-
firstName: contact.name?.split(' ')[0],
|
|
77
|
-
lastName: contact.name?.split(' ').slice(1).join(' '),
|
|
78
|
-
unsubscribed: contact.subscriptionStatus === 'unsubscribed'
|
|
79
|
-
});
|
|
80
|
-
} else {
|
|
81
|
-
// If contact doesn't exist, add them
|
|
82
|
-
await this.addContact(contact);
|
|
83
|
-
}
|
|
84
|
-
} catch (error) {
|
|
85
|
-
throw new EmailProviderError(`Failed to update contact in Resend: ${error instanceof Error ? error.message : 'Unknown error'}`, 'resend', error);
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
async removeContact(email) {
|
|
89
|
-
try {
|
|
90
|
-
// Resend doesn't have a direct remove method, so we unsubscribe instead
|
|
91
|
-
// First, we need to find the contact across all audiences
|
|
92
|
-
for(const locale in this.audienceIds){
|
|
93
|
-
const audienceId = this.getAudienceId(locale);
|
|
94
|
-
if (!audienceId) continue;
|
|
95
|
-
const contacts = await this.client.contacts.list({
|
|
96
|
-
audienceId
|
|
97
|
-
});
|
|
98
|
-
const contact = contacts.data?.data?.find((c)=>c.email === email);
|
|
99
|
-
if (contact) {
|
|
100
|
-
await this.client.contacts.update({
|
|
101
|
-
id: contact.id,
|
|
102
|
-
audienceId,
|
|
103
|
-
unsubscribed: true
|
|
104
|
-
});
|
|
105
|
-
break;
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
} catch (error) {
|
|
109
|
-
throw new EmailProviderError(`Failed to remove contact from Resend: ${error instanceof Error ? error.message : 'Unknown error'}`, 'resend', error);
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
getAudienceId(locale) {
|
|
113
|
-
const localeKey = locale || 'en';
|
|
114
|
-
if (!this.audienceIds) return undefined;
|
|
115
|
-
const localeConfig = this.audienceIds[localeKey];
|
|
116
|
-
if (!localeConfig) return undefined;
|
|
117
|
-
const audienceId = this.isDevelopment ? localeConfig.development || localeConfig.production : localeConfig.production || localeConfig.development;
|
|
118
|
-
return audienceId;
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
//# sourceMappingURL=resend.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/providers/resend.ts"],"sourcesContent":["import { Resend } from 'resend'\nimport type { EmailProvider, SendEmailParams } from './types'\nimport { EmailProviderError } from './types'\nimport type { Subscriber, ResendProviderConfig } from '../types'\n\nexport class ResendProvider implements EmailProvider {\n private client: Resend\n private audienceIds: ResendProviderConfig['audienceIds']\n private fromAddress: string\n private fromName: string\n private isDevelopment: boolean\n\n constructor(config: ResendProviderConfig & { \n fromAddress: string\n fromName: string \n }) {\n this.client = new Resend(config.apiKey)\n this.audienceIds = config.audienceIds || {}\n this.fromAddress = config.fromAddress\n this.fromName = config.fromName\n this.isDevelopment = process.env.NODE_ENV !== 'production'\n }\n\n getProvider(): string {\n return 'resend'\n }\n\n async send(params: SendEmailParams): Promise<void> {\n try {\n const from = params.from || {\n email: this.fromAddress,\n name: this.fromName,\n }\n\n if (!params.html && !params.text) {\n throw new Error('Either html or text content is required')\n }\n\n await this.client.emails.send({\n from: `${from.name} <${from.email}>`,\n to: Array.isArray(params.to) ? params.to : [params.to],\n subject: params.subject,\n html: params.html || '',\n text: params.text,\n replyTo: params.replyTo,\n })\n } catch (error: unknown) {\n throw new EmailProviderError(\n `Failed to send email via Resend: ${error instanceof Error ? error.message : 'Unknown error'}`,\n 'resend',\n error\n )\n }\n }\n\n async addContact(contact: Subscriber): Promise<void> {\n try {\n const audienceId = this.getAudienceId(contact.locale)\n if (!audienceId) {\n console.warn(`No audience ID configured for locale: ${contact.locale}`)\n return\n }\n\n await this.client.contacts.create({\n email: contact.email,\n firstName: contact.name?.split(' ')[0],\n lastName: contact.name?.split(' ').slice(1).join(' '),\n unsubscribed: contact.subscriptionStatus === 'unsubscribed',\n audienceId,\n })\n } catch (error: unknown) {\n throw new EmailProviderError(\n `Failed to add contact to Resend: ${error instanceof Error ? error.message : 'Unknown error'}`,\n 'resend',\n error\n )\n }\n }\n\n async updateContact(contact: Subscriber): Promise<void> {\n try {\n const audienceId = this.getAudienceId(contact.locale)\n if (!audienceId) {\n console.warn(`No audience ID configured for locale: ${contact.locale}`)\n return\n }\n\n // Resend requires finding the contact first\n const contacts = await this.client.contacts.list({ audienceId })\n const existingContact = contacts.data?.data?.find(c => c.email === contact.email)\n\n if (existingContact) {\n await this.client.contacts.update({\n id: existingContact.id,\n audienceId,\n firstName: contact.name?.split(' ')[0],\n lastName: contact.name?.split(' ').slice(1).join(' '),\n unsubscribed: contact.subscriptionStatus === 'unsubscribed',\n })\n } else {\n // If contact doesn't exist, add them\n await this.addContact(contact)\n }\n } catch (error: unknown) {\n throw new EmailProviderError(\n `Failed to update contact in Resend: ${error instanceof Error ? error.message : 'Unknown error'}`,\n 'resend',\n error\n )\n }\n }\n\n async removeContact(email: string): Promise<void> {\n try {\n // Resend doesn't have a direct remove method, so we unsubscribe instead\n // First, we need to find the contact across all audiences\n for (const locale in this.audienceIds) {\n const audienceId = this.getAudienceId(locale)\n if (!audienceId) continue\n\n const contacts = await this.client.contacts.list({ audienceId })\n const contact = contacts.data?.data?.find(c => c.email === email)\n\n if (contact) {\n await this.client.contacts.update({\n id: contact.id,\n audienceId,\n unsubscribed: true,\n })\n break\n }\n }\n } catch (error: unknown) {\n throw new EmailProviderError(\n `Failed to remove contact from Resend: ${error instanceof Error ? error.message : 'Unknown error'}`,\n 'resend',\n error\n )\n }\n }\n\n private getAudienceId(locale?: string): string | undefined {\n const localeKey = locale || 'en'\n if (!this.audienceIds) return undefined\n \n const localeConfig = this.audienceIds[localeKey]\n if (!localeConfig) return undefined\n\n const audienceId = this.isDevelopment \n ? (localeConfig.development || localeConfig.production)\n : (localeConfig.production || localeConfig.development)\n \n return audienceId\n }\n}"],"names":["Resend","EmailProviderError","ResendProvider","client","audienceIds","fromAddress","fromName","isDevelopment","config","apiKey","process","env","NODE_ENV","getProvider","send","params","from","email","name","html","text","Error","emails","to","Array","isArray","subject","replyTo","error","message","addContact","contact","audienceId","getAudienceId","locale","console","warn","contacts","create","firstName","split","lastName","slice","join","unsubscribed","subscriptionStatus","updateContact","list","existingContact","data","find","c","update","id","removeContact","localeKey","undefined","localeConfig","development","production"],"mappings":"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"}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
export class EmailProviderError extends Error {
|
|
2
|
-
provider;
|
|
3
|
-
originalError;
|
|
4
|
-
constructor(message, provider, originalError){
|
|
5
|
-
super(message);
|
|
6
|
-
this.name = 'EmailProviderError';
|
|
7
|
-
this.provider = provider;
|
|
8
|
-
this.originalError = originalError;
|
|
9
|
-
}
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
//# sourceMappingURL=types.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/providers/types.ts"],"sourcesContent":["import type { Subscriber } from '../types'\n\nexport interface EmailProvider {\n send(params: SendEmailParams): Promise<void>\n addContact(contact: Subscriber): Promise<void>\n updateContact(contact: Subscriber): Promise<void>\n removeContact(email: string): Promise<void>\n getProvider(): string\n}\n\nexport interface SendEmailParams {\n to: string | string[]\n subject: string\n html?: string\n text?: string\n react?: React.ReactElement\n from?: {\n email: string\n name?: string\n }\n replyTo?: string\n}\n\nexport interface EmailServiceConfig {\n provider: 'resend' | 'broadcast' | string\n fromAddress: string\n fromName: string\n replyTo?: string\n resend?: {\n apiKey: string\n audienceIds?: Record<string, { production?: string; development?: string }>\n }\n broadcast?: {\n apiUrl: string\n tokens: {\n production?: string\n development?: string\n }\n }\n}\n\nexport class EmailProviderError extends Error {\n provider: string\n originalError?: any\n\n constructor(message: string, provider: string, originalError?: any) {\n super(message)\n this.name = 'EmailProviderError'\n this.provider = provider\n this.originalError = originalError\n }\n}"],"names":["EmailProviderError","Error","provider","originalError","message","name"],"mappings":"AAyCA,OAAO,MAAMA,2BAA2BC;IACtCC,SAAgB;IAChBC,cAAmB;IAEnB,YAAYC,OAAe,EAAEF,QAAgB,EAAEC,aAAmB,CAAE;QAClE,KAAK,CAACC;QACN,IAAI,CAACC,IAAI,GAAG;QACZ,IAAI,CAACH,QAAQ,GAAGA;QAChB,IAAI,CAACC,aAAa,GAAGA;IACvB;AACF"}
|
|
@@ -1,105 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
-
import React from 'react';
|
|
3
|
-
import { Body, Container, Head, Html, Preview, Section, Text, Link, Hr } from '@react-email/components';
|
|
4
|
-
export const baseStyles = {
|
|
5
|
-
main: {
|
|
6
|
-
backgroundColor: '#ffffff',
|
|
7
|
-
fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif'
|
|
8
|
-
},
|
|
9
|
-
container: {
|
|
10
|
-
margin: '0 auto',
|
|
11
|
-
padding: '20px 0 48px',
|
|
12
|
-
maxWidth: '600px'
|
|
13
|
-
},
|
|
14
|
-
content: {
|
|
15
|
-
padding: '0 20px'
|
|
16
|
-
},
|
|
17
|
-
footer: {
|
|
18
|
-
padding: '32px 20px',
|
|
19
|
-
textAlign: 'center'
|
|
20
|
-
},
|
|
21
|
-
footerText: {
|
|
22
|
-
color: '#8898aa',
|
|
23
|
-
fontSize: '12px',
|
|
24
|
-
lineHeight: '16px',
|
|
25
|
-
margin: '0'
|
|
26
|
-
},
|
|
27
|
-
footerLink: {
|
|
28
|
-
color: '#8898aa',
|
|
29
|
-
textDecoration: 'underline'
|
|
30
|
-
},
|
|
31
|
-
hr: {
|
|
32
|
-
borderColor: '#e6ebf1',
|
|
33
|
-
margin: '32px 0'
|
|
34
|
-
}
|
|
35
|
-
};
|
|
36
|
-
export const BaseTemplate = ({ preview, children, footer })=>{
|
|
37
|
-
return /*#__PURE__*/ _jsxs(Html, {
|
|
38
|
-
children: [
|
|
39
|
-
/*#__PURE__*/ _jsx(Head, {}),
|
|
40
|
-
preview && /*#__PURE__*/ _jsx(Preview, {
|
|
41
|
-
children: preview
|
|
42
|
-
}),
|
|
43
|
-
/*#__PURE__*/ _jsx(Body, {
|
|
44
|
-
style: baseStyles.main,
|
|
45
|
-
children: /*#__PURE__*/ _jsxs(Container, {
|
|
46
|
-
style: baseStyles.container,
|
|
47
|
-
children: [
|
|
48
|
-
/*#__PURE__*/ _jsx(Section, {
|
|
49
|
-
style: baseStyles.content,
|
|
50
|
-
children: children
|
|
51
|
-
}),
|
|
52
|
-
footer && /*#__PURE__*/ _jsxs(_Fragment, {
|
|
53
|
-
children: [
|
|
54
|
-
/*#__PURE__*/ _jsx(Hr, {
|
|
55
|
-
style: baseStyles.hr
|
|
56
|
-
}),
|
|
57
|
-
/*#__PURE__*/ _jsxs(Section, {
|
|
58
|
-
style: baseStyles.footer,
|
|
59
|
-
children: [
|
|
60
|
-
(footer.unsubscribeUrl || footer.preferencesUrl) && /*#__PURE__*/ _jsxs(Text, {
|
|
61
|
-
style: baseStyles.footerText,
|
|
62
|
-
children: [
|
|
63
|
-
footer.preferencesUrl && /*#__PURE__*/ _jsxs(_Fragment, {
|
|
64
|
-
children: [
|
|
65
|
-
/*#__PURE__*/ _jsx(Link, {
|
|
66
|
-
href: footer.preferencesUrl,
|
|
67
|
-
style: baseStyles.footerLink,
|
|
68
|
-
children: "Manage preferences"
|
|
69
|
-
}),
|
|
70
|
-
footer.unsubscribeUrl && ' • '
|
|
71
|
-
]
|
|
72
|
-
}),
|
|
73
|
-
footer.unsubscribeUrl && /*#__PURE__*/ _jsx(Link, {
|
|
74
|
-
href: footer.unsubscribeUrl,
|
|
75
|
-
style: baseStyles.footerLink,
|
|
76
|
-
children: "Unsubscribe"
|
|
77
|
-
})
|
|
78
|
-
]
|
|
79
|
-
}),
|
|
80
|
-
footer.address && /*#__PURE__*/ _jsx(Text, {
|
|
81
|
-
style: {
|
|
82
|
-
...baseStyles.footerText,
|
|
83
|
-
marginTop: '16px'
|
|
84
|
-
},
|
|
85
|
-
children: footer.address
|
|
86
|
-
}),
|
|
87
|
-
footer.copyright && /*#__PURE__*/ _jsx(Text, {
|
|
88
|
-
style: {
|
|
89
|
-
...baseStyles.footerText,
|
|
90
|
-
marginTop: '8px'
|
|
91
|
-
},
|
|
92
|
-
children: footer.copyright
|
|
93
|
-
})
|
|
94
|
-
]
|
|
95
|
-
})
|
|
96
|
-
]
|
|
97
|
-
})
|
|
98
|
-
]
|
|
99
|
-
})
|
|
100
|
-
})
|
|
101
|
-
]
|
|
102
|
-
});
|
|
103
|
-
};
|
|
104
|
-
|
|
105
|
-
//# sourceMappingURL=BaseTemplate.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/templates/BaseTemplate.tsx"],"sourcesContent":["import React from 'react'\nimport {\n Body,\n Container,\n Head,\n Html,\n Preview,\n Section,\n Text,\n Link,\n Hr,\n} from '@react-email/components'\n\nexport interface BaseTemplateProps {\n preview?: string\n children: React.ReactNode\n footer?: {\n unsubscribeUrl?: string\n preferencesUrl?: string\n address?: string\n copyright?: string\n }\n}\n\nexport const baseStyles = {\n main: {\n backgroundColor: '#ffffff',\n fontFamily:\n '-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, sans-serif',\n },\n container: {\n margin: '0 auto',\n padding: '20px 0 48px',\n maxWidth: '600px',\n },\n content: {\n padding: '0 20px',\n },\n footer: {\n padding: '32px 20px',\n textAlign: 'center' as const,\n },\n footerText: {\n color: '#8898aa',\n fontSize: '12px',\n lineHeight: '16px',\n margin: '0',\n },\n footerLink: {\n color: '#8898aa',\n textDecoration: 'underline',\n },\n hr: {\n borderColor: '#e6ebf1',\n margin: '32px 0',\n },\n}\n\nexport const BaseTemplate: React.FC<BaseTemplateProps> = ({\n preview,\n children,\n footer,\n}) => {\n return (\n <Html>\n <Head />\n {preview && <Preview>{preview}</Preview>}\n <Body style={baseStyles.main}>\n <Container style={baseStyles.container}>\n <Section style={baseStyles.content}>\n {children}\n </Section>\n \n {footer && (\n <>\n <Hr style={baseStyles.hr} />\n <Section style={baseStyles.footer}>\n {(footer.unsubscribeUrl || footer.preferencesUrl) && (\n <Text style={baseStyles.footerText}>\n {footer.preferencesUrl && (\n <>\n <Link\n href={footer.preferencesUrl}\n style={baseStyles.footerLink}\n >\n Manage preferences\n </Link>\n {footer.unsubscribeUrl && ' • '}\n </>\n )}\n {footer.unsubscribeUrl && (\n <Link\n href={footer.unsubscribeUrl}\n style={baseStyles.footerLink}\n >\n Unsubscribe\n </Link>\n )}\n </Text>\n )}\n \n {footer.address && (\n <Text style={{ ...baseStyles.footerText, marginTop: '16px' }}>\n {footer.address}\n </Text>\n )}\n \n {footer.copyright && (\n <Text style={{ ...baseStyles.footerText, marginTop: '8px' }}>\n {footer.copyright}\n </Text>\n )}\n </Section>\n </>\n )}\n </Container>\n </Body>\n </Html>\n )\n}"],"names":["React","Body","Container","Head","Html","Preview","Section","Text","Link","Hr","baseStyles","main","backgroundColor","fontFamily","container","margin","padding","maxWidth","content","footer","textAlign","footerText","color","fontSize","lineHeight","footerLink","textDecoration","hr","borderColor","BaseTemplate","preview","children","style","unsubscribeUrl","preferencesUrl","href","address","marginTop","copyright"],"mappings":";AAAA,OAAOA,WAAW,QAAO;AACzB,SACEC,IAAI,EACJC,SAAS,EACTC,IAAI,EACJC,IAAI,EACJC,OAAO,EACPC,OAAO,EACPC,IAAI,EACJC,IAAI,EACJC,EAAE,QACG,0BAAyB;AAahC,OAAO,MAAMC,aAAa;IACxBC,MAAM;QACJC,iBAAiB;QACjBC,YACE;IACJ;IACAC,WAAW;QACTC,QAAQ;QACRC,SAAS;QACTC,UAAU;IACZ;IACAC,SAAS;QACPF,SAAS;IACX;IACAG,QAAQ;QACNH,SAAS;QACTI,WAAW;IACb;IACAC,YAAY;QACVC,OAAO;QACPC,UAAU;QACVC,YAAY;QACZT,QAAQ;IACV;IACAU,YAAY;QACVH,OAAO;QACPI,gBAAgB;IAClB;IACAC,IAAI;QACFC,aAAa;QACbb,QAAQ;IACV;AACF,EAAC;AAED,OAAO,MAAMc,eAA4C,CAAC,EACxDC,OAAO,EACPC,QAAQ,EACRZ,MAAM,EACP;IACC,qBACE,MAACf;;0BACC,KAACD;YACA2B,yBAAW,KAACzB;0BAASyB;;0BACtB,KAAC7B;gBAAK+B,OAAOtB,WAAWC,IAAI;0BAC1B,cAAA,MAACT;oBAAU8B,OAAOtB,WAAWI,SAAS;;sCACpC,KAACR;4BAAQ0B,OAAOtB,WAAWQ,OAAO;sCAC/Ba;;wBAGFZ,wBACC;;8CACE,KAACV;oCAAGuB,OAAOtB,WAAWiB,EAAE;;8CACxB,MAACrB;oCAAQ0B,OAAOtB,WAAWS,MAAM;;wCAC7BA,CAAAA,OAAOc,cAAc,IAAId,OAAOe,cAAc,AAAD,mBAC7C,MAAC3B;4CAAKyB,OAAOtB,WAAWW,UAAU;;gDAC/BF,OAAOe,cAAc,kBACpB;;sEACE,KAAC1B;4DACC2B,MAAMhB,OAAOe,cAAc;4DAC3BF,OAAOtB,WAAWe,UAAU;sEAC7B;;wDAGAN,OAAOc,cAAc,IAAI;;;gDAG7Bd,OAAOc,cAAc,kBACpB,KAACzB;oDACC2B,MAAMhB,OAAOc,cAAc;oDAC3BD,OAAOtB,WAAWe,UAAU;8DAC7B;;;;wCAONN,OAAOiB,OAAO,kBACb,KAAC7B;4CAAKyB,OAAO;gDAAE,GAAGtB,WAAWW,UAAU;gDAAEgB,WAAW;4CAAO;sDACxDlB,OAAOiB,OAAO;;wCAIlBjB,OAAOmB,SAAS,kBACf,KAAC/B;4CAAKyB,OAAO;gDAAE,GAAGtB,WAAWW,UAAU;gDAAEgB,WAAW;4CAAM;sDACvDlB,OAAOmB,SAAS;;;;;;;;;;;AAUrC,EAAC"}
|
|
@@ -1,178 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import React from 'react';
|
|
3
|
-
import { Heading, Text, Button, Section } from '@react-email/components';
|
|
4
|
-
import { BaseTemplate } from './BaseTemplate';
|
|
5
|
-
const magicLinkStyles = {
|
|
6
|
-
heading: {
|
|
7
|
-
fontSize: '28px',
|
|
8
|
-
fontWeight: '700',
|
|
9
|
-
color: '#1a1a1a',
|
|
10
|
-
margin: '0 0 16px 0'
|
|
11
|
-
},
|
|
12
|
-
text: {
|
|
13
|
-
fontSize: '16px',
|
|
14
|
-
lineHeight: '24px',
|
|
15
|
-
color: '#4a4a4a',
|
|
16
|
-
margin: '0 0 16px 0'
|
|
17
|
-
},
|
|
18
|
-
button: {
|
|
19
|
-
backgroundColor: '#0066cc',
|
|
20
|
-
borderRadius: '6px',
|
|
21
|
-
color: '#ffffff',
|
|
22
|
-
fontSize: '16px',
|
|
23
|
-
fontWeight: '600',
|
|
24
|
-
textDecoration: 'none',
|
|
25
|
-
textAlign: 'center',
|
|
26
|
-
display: 'block',
|
|
27
|
-
width: '100%',
|
|
28
|
-
padding: '16px 24px',
|
|
29
|
-
margin: '32px 0'
|
|
30
|
-
},
|
|
31
|
-
codeSection: {
|
|
32
|
-
backgroundColor: '#f6f8fa',
|
|
33
|
-
borderRadius: '6px',
|
|
34
|
-
padding: '24px',
|
|
35
|
-
margin: '24px 0',
|
|
36
|
-
textAlign: 'center'
|
|
37
|
-
},
|
|
38
|
-
code: {
|
|
39
|
-
fontSize: '24px',
|
|
40
|
-
fontWeight: '700',
|
|
41
|
-
color: '#1a1a1a',
|
|
42
|
-
letterSpacing: '2px',
|
|
43
|
-
fontFamily: 'monospace'
|
|
44
|
-
},
|
|
45
|
-
warning: {
|
|
46
|
-
fontSize: '14px',
|
|
47
|
-
color: '#dc3545',
|
|
48
|
-
margin: '16px 0',
|
|
49
|
-
padding: '12px',
|
|
50
|
-
backgroundColor: '#f8d7da',
|
|
51
|
-
borderRadius: '4px'
|
|
52
|
-
},
|
|
53
|
-
expire: {
|
|
54
|
-
fontSize: '14px',
|
|
55
|
-
color: '#6c757d',
|
|
56
|
-
fontStyle: 'italic'
|
|
57
|
-
}
|
|
58
|
-
};
|
|
59
|
-
export const MagicLinkTemplate = ({ magicLinkUrl, subscriber })=>{
|
|
60
|
-
// Extract a verification code from the URL for fallback
|
|
61
|
-
const urlParams = new URL(magicLinkUrl).searchParams;
|
|
62
|
-
const token = urlParams.get('token');
|
|
63
|
-
const verificationCode = token ? token.slice(-6).toUpperCase() : 'XXXXXX';
|
|
64
|
-
return /*#__PURE__*/ _jsxs(BaseTemplate, {
|
|
65
|
-
preview: "Sign in to manage your newsletter preferences",
|
|
66
|
-
children: [
|
|
67
|
-
/*#__PURE__*/ _jsx(Heading, {
|
|
68
|
-
style: magicLinkStyles.heading,
|
|
69
|
-
children: "Sign in to your account"
|
|
70
|
-
}),
|
|
71
|
-
/*#__PURE__*/ _jsxs(Text, {
|
|
72
|
-
style: magicLinkStyles.text,
|
|
73
|
-
children: [
|
|
74
|
-
"Hi",
|
|
75
|
-
subscriber.name ? ` ${subscriber.name}` : '',
|
|
76
|
-
","
|
|
77
|
-
]
|
|
78
|
-
}),
|
|
79
|
-
/*#__PURE__*/ _jsx(Text, {
|
|
80
|
-
style: magicLinkStyles.text,
|
|
81
|
-
children: "You requested a sign-in link for your newsletter account. Click the button below to access your preferences:"
|
|
82
|
-
}),
|
|
83
|
-
/*#__PURE__*/ _jsx(Button, {
|
|
84
|
-
href: magicLinkUrl,
|
|
85
|
-
style: magicLinkStyles.button,
|
|
86
|
-
children: "Sign In to Your Account"
|
|
87
|
-
}),
|
|
88
|
-
/*#__PURE__*/ _jsxs(Section, {
|
|
89
|
-
style: magicLinkStyles.codeSection,
|
|
90
|
-
children: [
|
|
91
|
-
/*#__PURE__*/ _jsx(Text, {
|
|
92
|
-
style: {
|
|
93
|
-
...magicLinkStyles.text,
|
|
94
|
-
margin: '0 0 8px 0'
|
|
95
|
-
},
|
|
96
|
-
children: "Or use this verification code:"
|
|
97
|
-
}),
|
|
98
|
-
/*#__PURE__*/ _jsx(Text, {
|
|
99
|
-
style: magicLinkStyles.code,
|
|
100
|
-
children: verificationCode
|
|
101
|
-
})
|
|
102
|
-
]
|
|
103
|
-
}),
|
|
104
|
-
/*#__PURE__*/ _jsx(Text, {
|
|
105
|
-
style: magicLinkStyles.warning,
|
|
106
|
-
children: "If you didn't request this email, you can safely ignore it."
|
|
107
|
-
}),
|
|
108
|
-
/*#__PURE__*/ _jsx(Text, {
|
|
109
|
-
style: magicLinkStyles.expire,
|
|
110
|
-
children: "This link will expire in 7 days for your security."
|
|
111
|
-
})
|
|
112
|
-
]
|
|
113
|
-
});
|
|
114
|
-
};
|
|
115
|
-
// Export a function that creates a custom magic link template
|
|
116
|
-
export function createMagicLinkTemplate(customContent, customStyles) {
|
|
117
|
-
const mergedStyles = {
|
|
118
|
-
...magicLinkStyles,
|
|
119
|
-
...customStyles
|
|
120
|
-
};
|
|
121
|
-
return (props)=>{
|
|
122
|
-
const urlParams = new URL(props.magicLinkUrl).searchParams;
|
|
123
|
-
const token = urlParams.get('token');
|
|
124
|
-
const verificationCode = token ? token.slice(-6).toUpperCase() : 'XXXXXX';
|
|
125
|
-
return /*#__PURE__*/ _jsxs(BaseTemplate, {
|
|
126
|
-
preview: customContent?.heading || "Sign in to manage your newsletter preferences",
|
|
127
|
-
children: [
|
|
128
|
-
/*#__PURE__*/ _jsx(Heading, {
|
|
129
|
-
style: mergedStyles.heading,
|
|
130
|
-
children: customContent?.heading || 'Sign in to your account'
|
|
131
|
-
}),
|
|
132
|
-
/*#__PURE__*/ _jsxs(Text, {
|
|
133
|
-
style: mergedStyles.text,
|
|
134
|
-
children: [
|
|
135
|
-
"Hi",
|
|
136
|
-
props.subscriber.name ? ` ${props.subscriber.name}` : '',
|
|
137
|
-
","
|
|
138
|
-
]
|
|
139
|
-
}),
|
|
140
|
-
/*#__PURE__*/ _jsx(Text, {
|
|
141
|
-
style: mergedStyles.text,
|
|
142
|
-
children: customContent?.intro || 'You requested a sign-in link for your newsletter account. Click the button below to access your preferences:'
|
|
143
|
-
}),
|
|
144
|
-
/*#__PURE__*/ _jsx(Button, {
|
|
145
|
-
href: props.magicLinkUrl,
|
|
146
|
-
style: mergedStyles.button,
|
|
147
|
-
children: customContent?.buttonText || 'Sign In to Your Account'
|
|
148
|
-
}),
|
|
149
|
-
customContent?.includeCode !== false && /*#__PURE__*/ _jsxs(Section, {
|
|
150
|
-
style: mergedStyles.codeSection,
|
|
151
|
-
children: [
|
|
152
|
-
/*#__PURE__*/ _jsx(Text, {
|
|
153
|
-
style: {
|
|
154
|
-
...mergedStyles.text,
|
|
155
|
-
margin: '0 0 8px 0'
|
|
156
|
-
},
|
|
157
|
-
children: "Or use this verification code:"
|
|
158
|
-
}),
|
|
159
|
-
/*#__PURE__*/ _jsx(Text, {
|
|
160
|
-
style: mergedStyles.code,
|
|
161
|
-
children: verificationCode
|
|
162
|
-
})
|
|
163
|
-
]
|
|
164
|
-
}),
|
|
165
|
-
/*#__PURE__*/ _jsx(Text, {
|
|
166
|
-
style: mergedStyles.warning,
|
|
167
|
-
children: customContent?.warning || "If you didn't request this email, you can safely ignore it."
|
|
168
|
-
}),
|
|
169
|
-
/*#__PURE__*/ _jsx(Text, {
|
|
170
|
-
style: mergedStyles.expire,
|
|
171
|
-
children: customContent?.expireText || 'This link will expire in 7 days for your security.'
|
|
172
|
-
})
|
|
173
|
-
]
|
|
174
|
-
});
|
|
175
|
-
};
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
//# sourceMappingURL=MagicLinkTemplate.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/templates/MagicLinkTemplate.tsx"],"sourcesContent":["import React from 'react'\nimport {\n Heading,\n Text,\n Button,\n Section,\n} from '@react-email/components'\nimport { BaseTemplate } from './BaseTemplate'\nimport type { MagicLinkEmailProps } from '../types'\n\nconst magicLinkStyles = {\n heading: {\n fontSize: '28px',\n fontWeight: '700',\n color: '#1a1a1a',\n margin: '0 0 16px 0',\n },\n text: {\n fontSize: '16px',\n lineHeight: '24px',\n color: '#4a4a4a',\n margin: '0 0 16px 0',\n },\n button: {\n backgroundColor: '#0066cc',\n borderRadius: '6px',\n color: '#ffffff',\n fontSize: '16px',\n fontWeight: '600',\n textDecoration: 'none',\n textAlign: 'center' as const,\n display: 'block',\n width: '100%',\n padding: '16px 24px',\n margin: '32px 0',\n },\n codeSection: {\n backgroundColor: '#f6f8fa',\n borderRadius: '6px',\n padding: '24px',\n margin: '24px 0',\n textAlign: 'center' as const,\n },\n code: {\n fontSize: '24px',\n fontWeight: '700',\n color: '#1a1a1a',\n letterSpacing: '2px',\n fontFamily: 'monospace',\n },\n warning: {\n fontSize: '14px',\n color: '#dc3545',\n margin: '16px 0',\n padding: '12px',\n backgroundColor: '#f8d7da',\n borderRadius: '4px',\n },\n expire: {\n fontSize: '14px',\n color: '#6c757d',\n fontStyle: 'italic',\n },\n}\n\nexport const MagicLinkTemplate: React.FC<MagicLinkEmailProps> = ({\n magicLinkUrl,\n subscriber,\n}) => {\n // Extract a verification code from the URL for fallback\n const urlParams = new URL(magicLinkUrl).searchParams\n const token = urlParams.get('token')\n const verificationCode = token ? token.slice(-6).toUpperCase() : 'XXXXXX'\n\n return (\n <BaseTemplate\n preview=\"Sign in to manage your newsletter preferences\"\n >\n <Heading style={magicLinkStyles.heading}>\n Sign in to your account\n </Heading>\n \n <Text style={magicLinkStyles.text}>\n Hi{subscriber.name ? ` ${subscriber.name}` : ''},\n </Text>\n \n <Text style={magicLinkStyles.text}>\n You requested a sign-in link for your newsletter account. Click the button below to access your preferences:\n </Text>\n \n <Button\n href={magicLinkUrl}\n style={magicLinkStyles.button}\n >\n Sign In to Your Account\n </Button>\n \n <Section style={magicLinkStyles.codeSection}>\n <Text style={{ ...magicLinkStyles.text, margin: '0 0 8px 0' }}>\n Or use this verification code:\n </Text>\n <Text style={magicLinkStyles.code}>\n {verificationCode}\n </Text>\n </Section>\n \n <Text style={magicLinkStyles.warning}>\n If you didn't request this email, you can safely ignore it.\n </Text>\n \n <Text style={magicLinkStyles.expire}>\n This link will expire in 7 days for your security.\n </Text>\n </BaseTemplate>\n )\n}\n\n// Export a function that creates a custom magic link template\nexport function createMagicLinkTemplate(\n customContent?: {\n heading?: string\n intro?: string\n buttonText?: string\n warning?: string\n expireText?: string\n includeCode?: boolean\n },\n customStyles?: Partial<typeof magicLinkStyles>\n): React.FC<MagicLinkEmailProps> {\n const mergedStyles = {\n ...magicLinkStyles,\n ...customStyles,\n }\n \n return (props: MagicLinkEmailProps) => {\n const urlParams = new URL(props.magicLinkUrl).searchParams\n const token = urlParams.get('token')\n const verificationCode = token ? token.slice(-6).toUpperCase() : 'XXXXXX'\n \n return (\n <BaseTemplate\n preview={customContent?.heading || \"Sign in to manage your newsletter preferences\"}\n >\n <Heading style={mergedStyles.heading}>\n {customContent?.heading || 'Sign in to your account'}\n </Heading>\n \n <Text style={mergedStyles.text}>\n Hi{props.subscriber.name ? ` ${props.subscriber.name}` : ''},\n </Text>\n \n <Text style={mergedStyles.text}>\n {customContent?.intro || 'You requested a sign-in link for your newsletter account. Click the button below to access your preferences:'}\n </Text>\n \n <Button\n href={props.magicLinkUrl}\n style={mergedStyles.button}\n >\n {customContent?.buttonText || 'Sign In to Your Account'}\n </Button>\n \n {customContent?.includeCode !== false && (\n <Section style={mergedStyles.codeSection}>\n <Text style={{ ...mergedStyles.text, margin: '0 0 8px 0' }}>\n Or use this verification code:\n </Text>\n <Text style={mergedStyles.code}>\n {verificationCode}\n </Text>\n </Section>\n )}\n \n <Text style={mergedStyles.warning}>\n {customContent?.warning || \"If you didn't request this email, you can safely ignore it.\"}\n </Text>\n \n <Text style={mergedStyles.expire}>\n {customContent?.expireText || 'This link will expire in 7 days for your security.'}\n </Text>\n </BaseTemplate>\n )\n }\n}"],"names":["React","Heading","Text","Button","Section","BaseTemplate","magicLinkStyles","heading","fontSize","fontWeight","color","margin","text","lineHeight","button","backgroundColor","borderRadius","textDecoration","textAlign","display","width","padding","codeSection","code","letterSpacing","fontFamily","warning","expire","fontStyle","MagicLinkTemplate","magicLinkUrl","subscriber","urlParams","URL","searchParams","token","get","verificationCode","slice","toUpperCase","preview","style","name","href","createMagicLinkTemplate","customContent","customStyles","mergedStyles","props","intro","buttonText","includeCode","expireText"],"mappings":"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"}
|