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.
Files changed (180) hide show
  1. package/CHANGELOG.md +44 -1
  2. package/CLAUDE.md +31 -19
  3. package/dist/client.cjs +899 -0
  4. package/dist/client.cjs.map +1 -0
  5. package/dist/client.d.cts +52 -0
  6. package/dist/client.d.ts +52 -0
  7. package/dist/client.js +867 -0
  8. package/dist/client.js.map +1 -0
  9. package/dist/components.cjs +899 -0
  10. package/dist/components.cjs.map +1 -0
  11. package/dist/components.d.cts +4 -0
  12. package/dist/components.d.ts +4 -0
  13. package/dist/components.js +867 -0
  14. package/dist/components.js.map +1 -0
  15. package/dist/index.cjs +2004 -0
  16. package/dist/index.cjs.map +1 -0
  17. package/dist/index.d.cts +11 -0
  18. package/dist/index.d.ts +6 -5
  19. package/dist/index.js +1967 -0
  20. package/dist/index.js.map +1 -0
  21. package/dist/types.cjs +19 -0
  22. package/dist/types.cjs.map +1 -0
  23. package/dist/{types/index.d.ts → types.d.cts} +19 -17
  24. package/dist/types.d.ts +350 -0
  25. package/dist/types.js +1 -0
  26. package/dist/types.js.map +1 -0
  27. package/package.json +48 -25
  28. package/dist/.tsbuildinfo +0 -1
  29. package/dist/collections/NewsletterSettings.d.ts +0 -4
  30. package/dist/collections/NewsletterSettings.d.ts.map +0 -1
  31. package/dist/collections/Subscribers.d.ts +0 -4
  32. package/dist/collections/Subscribers.d.ts.map +0 -1
  33. package/dist/components/MagicLinkVerify.d.ts +0 -27
  34. package/dist/components/MagicLinkVerify.d.ts.map +0 -1
  35. package/dist/components/NewsletterForm.d.ts +0 -5
  36. package/dist/components/NewsletterForm.d.ts.map +0 -1
  37. package/dist/components/PreferencesForm.d.ts +0 -5
  38. package/dist/components/PreferencesForm.d.ts.map +0 -1
  39. package/dist/components/index.d.ts +0 -5
  40. package/dist/components/index.d.ts.map +0 -1
  41. package/dist/endpoints/index.d.ts +0 -4
  42. package/dist/endpoints/index.d.ts.map +0 -1
  43. package/dist/endpoints/preferences.d.ts +0 -5
  44. package/dist/endpoints/preferences.d.ts.map +0 -1
  45. package/dist/endpoints/subscribe.d.ts +0 -4
  46. package/dist/endpoints/subscribe.d.ts.map +0 -1
  47. package/dist/endpoints/unsubscribe.d.ts +0 -4
  48. package/dist/endpoints/unsubscribe.d.ts.map +0 -1
  49. package/dist/endpoints/verify-magic-link.d.ts +0 -4
  50. package/dist/endpoints/verify-magic-link.d.ts.map +0 -1
  51. package/dist/exports/client.d.ts +0 -6
  52. package/dist/exports/client.d.ts.map +0 -1
  53. package/dist/exports/components.d.ts +0 -2
  54. package/dist/exports/components.d.ts.map +0 -1
  55. package/dist/exports/types.d.ts +0 -2
  56. package/dist/exports/types.d.ts.map +0 -1
  57. package/dist/fields/newsletterScheduling.d.ts +0 -4
  58. package/dist/fields/newsletterScheduling.d.ts.map +0 -1
  59. package/dist/hooks/useNewsletterAuth.d.ts +0 -16
  60. package/dist/hooks/useNewsletterAuth.d.ts.map +0 -1
  61. package/dist/index.d.ts.map +0 -1
  62. package/dist/providers/broadcast.d.ts +0 -19
  63. package/dist/providers/broadcast.d.ts.map +0 -1
  64. package/dist/providers/index.d.ts +0 -23
  65. package/dist/providers/index.d.ts.map +0 -1
  66. package/dist/providers/resend.d.ts +0 -20
  67. package/dist/providers/resend.d.ts.map +0 -1
  68. package/dist/providers/types.d.ts +0 -46
  69. package/dist/providers/types.d.ts.map +0 -1
  70. package/dist/src/__tests__/fixtures/newsletter-settings.js +0 -41
  71. package/dist/src/__tests__/fixtures/newsletter-settings.js.map +0 -1
  72. package/dist/src/__tests__/fixtures/subscribers.js +0 -70
  73. package/dist/src/__tests__/fixtures/subscribers.js.map +0 -1
  74. package/dist/src/__tests__/integration/collections/subscriber-hooks.test.js +0 -356
  75. package/dist/src/__tests__/integration/collections/subscriber-hooks.test.js.map +0 -1
  76. package/dist/src/__tests__/integration/endpoints/preferences.test.js +0 -266
  77. package/dist/src/__tests__/integration/endpoints/preferences.test.js.map +0 -1
  78. package/dist/src/__tests__/integration/endpoints/subscribe.test.js +0 -280
  79. package/dist/src/__tests__/integration/endpoints/subscribe.test.js.map +0 -1
  80. package/dist/src/__tests__/integration/endpoints/unsubscribe.test.js +0 -187
  81. package/dist/src/__tests__/integration/endpoints/unsubscribe.test.js.map +0 -1
  82. package/dist/src/__tests__/integration/endpoints/verify-magic-link.test.js +0 -188
  83. package/dist/src/__tests__/integration/endpoints/verify-magic-link.test.js.map +0 -1
  84. package/dist/src/__tests__/mocks/email-providers.js +0 -153
  85. package/dist/src/__tests__/mocks/email-providers.js.map +0 -1
  86. package/dist/src/__tests__/mocks/payload.js +0 -244
  87. package/dist/src/__tests__/mocks/payload.js.map +0 -1
  88. package/dist/src/__tests__/security/csrf-protection.test.js +0 -309
  89. package/dist/src/__tests__/security/csrf-protection.test.js.map +0 -1
  90. package/dist/src/__tests__/security/settings-access.test.js +0 -204
  91. package/dist/src/__tests__/security/settings-access.test.js.map +0 -1
  92. package/dist/src/__tests__/security/subscriber-access.test.js +0 -210
  93. package/dist/src/__tests__/security/subscriber-access.test.js.map +0 -1
  94. package/dist/src/__tests__/security/xss-prevention.test.js +0 -305
  95. package/dist/src/__tests__/security/xss-prevention.test.js.map +0 -1
  96. package/dist/src/__tests__/setup/integration.setup.js +0 -38
  97. package/dist/src/__tests__/setup/integration.setup.js.map +0 -1
  98. package/dist/src/__tests__/setup/unit.setup.js +0 -41
  99. package/dist/src/__tests__/setup/unit.setup.js.map +0 -1
  100. package/dist/src/__tests__/unit/utils/access.test.js +0 -116
  101. package/dist/src/__tests__/unit/utils/access.test.js.map +0 -1
  102. package/dist/src/__tests__/unit/utils/jwt.test.js +0 -238
  103. package/dist/src/__tests__/unit/utils/jwt.test.js.map +0 -1
  104. package/dist/src/collections/NewsletterSettings.js +0 -390
  105. package/dist/src/collections/NewsletterSettings.js.map +0 -1
  106. package/dist/src/collections/Subscribers.js +0 -309
  107. package/dist/src/collections/Subscribers.js.map +0 -1
  108. package/dist/src/components/MagicLinkVerify.js +0 -180
  109. package/dist/src/components/MagicLinkVerify.js.map +0 -1
  110. package/dist/src/components/NewsletterForm.js +0 -326
  111. package/dist/src/components/NewsletterForm.js.map +0 -1
  112. package/dist/src/components/PreferencesForm.js +0 -524
  113. package/dist/src/components/PreferencesForm.js.map +0 -1
  114. package/dist/src/components/index.js +0 -5
  115. package/dist/src/components/index.js.map +0 -1
  116. package/dist/src/endpoints/index.js +0 -17
  117. package/dist/src/endpoints/index.js.map +0 -1
  118. package/dist/src/endpoints/preferences.js +0 -136
  119. package/dist/src/endpoints/preferences.js.map +0 -1
  120. package/dist/src/endpoints/subscribe.js +0 -151
  121. package/dist/src/endpoints/subscribe.js.map +0 -1
  122. package/dist/src/endpoints/unsubscribe.js +0 -105
  123. package/dist/src/endpoints/unsubscribe.js.map +0 -1
  124. package/dist/src/endpoints/verify-magic-link.js +0 -103
  125. package/dist/src/endpoints/verify-magic-link.js.map +0 -1
  126. package/dist/src/exports/client.js +0 -7
  127. package/dist/src/exports/client.js.map +0 -1
  128. package/dist/src/exports/components.js +0 -6
  129. package/dist/src/exports/components.js.map +0 -1
  130. package/dist/src/exports/types.js +0 -3
  131. package/dist/src/exports/types.js.map +0 -1
  132. package/dist/src/fields/newsletterScheduling.js +0 -195
  133. package/dist/src/fields/newsletterScheduling.js.map +0 -1
  134. package/dist/src/hooks/useNewsletterAuth.js +0 -112
  135. package/dist/src/hooks/useNewsletterAuth.js.map +0 -1
  136. package/dist/src/index.js +0 -130
  137. package/dist/src/index.js.map +0 -1
  138. package/dist/src/providers/broadcast.js +0 -158
  139. package/dist/src/providers/broadcast.js.map +0 -1
  140. package/dist/src/providers/index.js +0 -63
  141. package/dist/src/providers/index.js.map +0 -1
  142. package/dist/src/providers/resend.js +0 -122
  143. package/dist/src/providers/resend.js.map +0 -1
  144. package/dist/src/providers/types.js +0 -12
  145. package/dist/src/providers/types.js.map +0 -1
  146. package/dist/src/templates/BaseTemplate.js +0 -105
  147. package/dist/src/templates/BaseTemplate.js.map +0 -1
  148. package/dist/src/templates/MagicLinkTemplate.js +0 -178
  149. package/dist/src/templates/MagicLinkTemplate.js.map +0 -1
  150. package/dist/src/templates/NewsletterTemplate.js +0 -150
  151. package/dist/src/templates/NewsletterTemplate.js.map +0 -1
  152. package/dist/src/templates/WelcomeTemplate.js +0 -192
  153. package/dist/src/templates/WelcomeTemplate.js.map +0 -1
  154. package/dist/src/templates/index.js +0 -6
  155. package/dist/src/templates/index.js.map +0 -1
  156. package/dist/src/types/index.js +0 -3
  157. package/dist/src/types/index.js.map +0 -1
  158. package/dist/src/utils/access.js +0 -80
  159. package/dist/src/utils/access.js.map +0 -1
  160. package/dist/src/utils/jwt.js +0 -91
  161. package/dist/src/utils/jwt.js.map +0 -1
  162. package/dist/src/utils/validation.js +0 -74
  163. package/dist/src/utils/validation.js.map +0 -1
  164. package/dist/templates/BaseTemplate.d.ts +0 -45
  165. package/dist/templates/BaseTemplate.d.ts.map +0 -1
  166. package/dist/templates/MagicLinkTemplate.d.ts +0 -67
  167. package/dist/templates/MagicLinkTemplate.d.ts.map +0 -1
  168. package/dist/templates/NewsletterTemplate.d.ts +0 -112
  169. package/dist/templates/NewsletterTemplate.d.ts.map +0 -1
  170. package/dist/templates/WelcomeTemplate.d.ts +0 -55
  171. package/dist/templates/WelcomeTemplate.d.ts.map +0 -1
  172. package/dist/templates/index.d.ts +0 -7
  173. package/dist/templates/index.d.ts.map +0 -1
  174. package/dist/types/index.d.ts.map +0 -1
  175. package/dist/utils/access.d.ts +0 -15
  176. package/dist/utils/access.d.ts.map +0 -1
  177. package/dist/utils/jwt.d.ts +0 -32
  178. package/dist/utils/jwt.d.ts.map +0 -1
  179. package/dist/utils/validation.d.ts +0 -25
  180. 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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"}