@contractspec/bundle.marketing 1.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (216) hide show
  1. package/.turbo/turbo-build$colon$types.log +1 -0
  2. package/.turbo/turbo-build.log +175 -0
  3. package/.turbo/turbo-lint.log +3 -0
  4. package/AGENTS.md +36 -0
  5. package/CHANGELOG.md +416 -0
  6. package/README.md +57 -0
  7. package/dist/components/marketing/ChangelogPage.d.ts +21 -0
  8. package/dist/components/marketing/ChangelogPage.d.ts.map +1 -0
  9. package/dist/components/marketing/ChangelogPage.js +65 -0
  10. package/dist/components/marketing/ChangelogPage.js.map +1 -0
  11. package/dist/components/marketing/CofounderPage.d.ts +7 -0
  12. package/dist/components/marketing/CofounderPage.d.ts.map +1 -0
  13. package/dist/components/marketing/CofounderPage.js +468 -0
  14. package/dist/components/marketing/CofounderPage.js.map +1 -0
  15. package/dist/components/marketing/ContactClient.d.ts +7 -0
  16. package/dist/components/marketing/ContactClient.d.ts.map +1 -0
  17. package/dist/components/marketing/ContactClient.js +158 -0
  18. package/dist/components/marketing/ContactClient.js.map +1 -0
  19. package/dist/components/marketing/ContributePage.d.ts +9 -0
  20. package/dist/components/marketing/ContributePage.d.ts.map +1 -0
  21. package/dist/components/marketing/ContributePage.js +362 -0
  22. package/dist/components/marketing/ContributePage.js.map +1 -0
  23. package/dist/components/marketing/DesignPartnerPage.d.ts +9 -0
  24. package/dist/components/marketing/DesignPartnerPage.d.ts.map +1 -0
  25. package/dist/components/marketing/DesignPartnerPage.js +215 -0
  26. package/dist/components/marketing/DesignPartnerPage.js.map +1 -0
  27. package/dist/components/marketing/LandingPage.d.ts +7 -0
  28. package/dist/components/marketing/LandingPage.d.ts.map +1 -0
  29. package/dist/components/marketing/LandingPage.js +38 -0
  30. package/dist/components/marketing/LandingPage.js.map +1 -0
  31. package/dist/components/marketing/PricingClient.d.ts +7 -0
  32. package/dist/components/marketing/PricingClient.d.ts.map +1 -0
  33. package/dist/components/marketing/PricingClient.js +521 -0
  34. package/dist/components/marketing/PricingClient.js.map +1 -0
  35. package/dist/components/marketing/ProductClientPage.d.ts +7 -0
  36. package/dist/components/marketing/ProductClientPage.d.ts.map +1 -0
  37. package/dist/components/marketing/ProductClientPage.js +460 -0
  38. package/dist/components/marketing/ProductClientPage.js.map +1 -0
  39. package/dist/components/marketing/index.d.ts +11 -0
  40. package/dist/components/marketing/index.js +12 -0
  41. package/dist/components/marketing/pricing-thinking-modal.d.ts +16 -0
  42. package/dist/components/marketing/pricing-thinking-modal.d.ts.map +1 -0
  43. package/dist/components/marketing/pricing-thinking-modal.js +202 -0
  44. package/dist/components/marketing/pricing-thinking-modal.js.map +1 -0
  45. package/dist/components/marketing/sections/AudienceSection.d.ts +7 -0
  46. package/dist/components/marketing/sections/AudienceSection.d.ts.map +1 -0
  47. package/dist/components/marketing/sections/AudienceSection.js +68 -0
  48. package/dist/components/marketing/sections/AudienceSection.js.map +1 -0
  49. package/dist/components/marketing/sections/CorePositioningSection.d.ts +7 -0
  50. package/dist/components/marketing/sections/CorePositioningSection.d.ts.map +1 -0
  51. package/dist/components/marketing/sections/CorePositioningSection.js +59 -0
  52. package/dist/components/marketing/sections/CorePositioningSection.js.map +1 -0
  53. package/dist/components/marketing/sections/CtaSection.d.ts +7 -0
  54. package/dist/components/marketing/sections/CtaSection.d.ts.map +1 -0
  55. package/dist/components/marketing/sections/CtaSection.js +54 -0
  56. package/dist/components/marketing/sections/CtaSection.js.map +1 -0
  57. package/dist/components/marketing/sections/DevelopersSection.d.ts +7 -0
  58. package/dist/components/marketing/sections/DevelopersSection.d.ts.map +1 -0
  59. package/dist/components/marketing/sections/DevelopersSection.js +45 -0
  60. package/dist/components/marketing/sections/DevelopersSection.js.map +1 -0
  61. package/dist/components/marketing/sections/FearsSection.d.ts +7 -0
  62. package/dist/components/marketing/sections/FearsSection.d.ts.map +1 -0
  63. package/dist/components/marketing/sections/FearsSection.js +48 -0
  64. package/dist/components/marketing/sections/FearsSection.js.map +1 -0
  65. package/dist/components/marketing/sections/HeroMarketingSection.d.ts +7 -0
  66. package/dist/components/marketing/sections/HeroMarketingSection.d.ts.map +1 -0
  67. package/dist/components/marketing/sections/HeroMarketingSection.js +77 -0
  68. package/dist/components/marketing/sections/HeroMarketingSection.js.map +1 -0
  69. package/dist/components/marketing/sections/IconGridSection.d.ts +45 -0
  70. package/dist/components/marketing/sections/IconGridSection.d.ts.map +1 -0
  71. package/dist/components/marketing/sections/IconGridSection.js +44 -0
  72. package/dist/components/marketing/sections/IconGridSection.js.map +1 -0
  73. package/dist/components/marketing/sections/OutputsSection.d.ts +7 -0
  74. package/dist/components/marketing/sections/OutputsSection.d.ts.map +1 -0
  75. package/dist/components/marketing/sections/OutputsSection.js +59 -0
  76. package/dist/components/marketing/sections/OutputsSection.js.map +1 -0
  77. package/dist/components/marketing/sections/ProblemSection.d.ts +7 -0
  78. package/dist/components/marketing/sections/ProblemSection.d.ts.map +1 -0
  79. package/dist/components/marketing/sections/ProblemSection.js +46 -0
  80. package/dist/components/marketing/sections/ProblemSection.js.map +1 -0
  81. package/dist/components/marketing/sections/SolutionSection.d.ts +7 -0
  82. package/dist/components/marketing/sections/SolutionSection.d.ts.map +1 -0
  83. package/dist/components/marketing/sections/SolutionSection.js +46 -0
  84. package/dist/components/marketing/sections/SolutionSection.js.map +1 -0
  85. package/dist/components/marketing/sections/StepsSection.d.ts +7 -0
  86. package/dist/components/marketing/sections/StepsSection.d.ts.map +1 -0
  87. package/dist/components/marketing/sections/StepsSection.js +52 -0
  88. package/dist/components/marketing/sections/StepsSection.js.map +1 -0
  89. package/dist/components/marketing/waitlist-section.d.ts +15 -0
  90. package/dist/components/marketing/waitlist-section.d.ts.map +1 -0
  91. package/dist/components/marketing/waitlist-section.js +578 -0
  92. package/dist/components/marketing/waitlist-section.js.map +1 -0
  93. package/dist/components/templates/TemplatesClientPage.d.ts +7 -0
  94. package/dist/components/templates/TemplatesClientPage.d.ts.map +1 -0
  95. package/dist/components/templates/TemplatesClientPage.js +625 -0
  96. package/dist/components/templates/TemplatesClientPage.js.map +1 -0
  97. package/dist/components/templates/TemplatesPage.d.ts +7 -0
  98. package/dist/components/templates/TemplatesPage.d.ts.map +1 -0
  99. package/dist/components/templates/TemplatesPage.js +125 -0
  100. package/dist/components/templates/TemplatesPage.js.map +1 -0
  101. package/dist/components/templates/TemplatesPreviewModal.d.ts +15 -0
  102. package/dist/components/templates/TemplatesPreviewModal.d.ts.map +1 -0
  103. package/dist/components/templates/TemplatesPreviewModal.js +137 -0
  104. package/dist/components/templates/TemplatesPreviewModal.js.map +1 -0
  105. package/dist/components/templates/index.d.ts +4 -0
  106. package/dist/components/templates/index.js +5 -0
  107. package/dist/index.d.ts +29 -0
  108. package/dist/index.js +28 -0
  109. package/dist/libs/email/client.d.ts +15 -0
  110. package/dist/libs/email/client.d.ts.map +1 -0
  111. package/dist/libs/email/client.js +113 -0
  112. package/dist/libs/email/client.js.map +1 -0
  113. package/dist/libs/email/contact.d.ts +7 -0
  114. package/dist/libs/email/contact.d.ts.map +1 -0
  115. package/dist/libs/email/contact.js +71 -0
  116. package/dist/libs/email/contact.js.map +1 -0
  117. package/dist/libs/email/newsletter.d.ts +7 -0
  118. package/dist/libs/email/newsletter.d.ts.map +1 -0
  119. package/dist/libs/email/newsletter.js +95 -0
  120. package/dist/libs/email/newsletter.js.map +1 -0
  121. package/dist/libs/email/types.d.ts +53 -0
  122. package/dist/libs/email/types.d.ts.map +1 -0
  123. package/dist/libs/email/types.js +1 -0
  124. package/dist/libs/email/utils.d.ts +6 -0
  125. package/dist/libs/email/utils.d.ts.map +1 -0
  126. package/dist/libs/email/utils.js +7 -0
  127. package/dist/libs/email/utils.js.map +1 -0
  128. package/dist/libs/email/waitlist-application.d.ts +7 -0
  129. package/dist/libs/email/waitlist-application.d.ts.map +1 -0
  130. package/dist/libs/email/waitlist-application.js +170 -0
  131. package/dist/libs/email/waitlist-application.js.map +1 -0
  132. package/dist/libs/email/waitlist.d.ts +7 -0
  133. package/dist/libs/email/waitlist.d.ts.map +1 -0
  134. package/dist/libs/email/waitlist.js +105 -0
  135. package/dist/libs/email/waitlist.js.map +1 -0
  136. package/dist/libs/pricing-examples.d.ts +22 -0
  137. package/dist/libs/pricing-examples.d.ts.map +1 -0
  138. package/dist/libs/pricing-examples.js +21 -0
  139. package/dist/libs/pricing-examples.js.map +1 -0
  140. package/dist/registry/engine.d.ts +17 -0
  141. package/dist/registry/engine.d.ts.map +1 -0
  142. package/dist/registry/engine.js +24 -0
  143. package/dist/registry/engine.js.map +1 -0
  144. package/dist/registry/factory.d.ts +64 -0
  145. package/dist/registry/factory.d.ts.map +1 -0
  146. package/dist/registry/factory.js +61 -0
  147. package/dist/registry/factory.js.map +1 -0
  148. package/dist/registry/index.d.ts +8 -0
  149. package/dist/registry/index.js +8 -0
  150. package/dist/registry/registry-docs.d.ts +15 -0
  151. package/dist/registry/registry-docs.d.ts.map +1 -0
  152. package/dist/registry/registry-docs.js +305 -0
  153. package/dist/registry/registry-docs.js.map +1 -0
  154. package/dist/registry/registry-landing.d.ts +19 -0
  155. package/dist/registry/registry-landing.d.ts.map +1 -0
  156. package/dist/registry/registry-landing.js +95 -0
  157. package/dist/registry/registry-landing.js.map +1 -0
  158. package/dist/registry/registry.d.ts +30 -0
  159. package/dist/registry/registry.d.ts.map +1 -0
  160. package/dist/registry/registry.js +61 -0
  161. package/dist/registry/registry.js.map +1 -0
  162. package/dist/registry/types.d.ts +19 -0
  163. package/dist/registry/types.d.ts.map +1 -0
  164. package/dist/registry/types.js +0 -0
  165. package/dist/registry/utils.d.ts +31 -0
  166. package/dist/registry/utils.d.ts.map +1 -0
  167. package/dist/registry/utils.js +54 -0
  168. package/dist/registry/utils.js.map +1 -0
  169. package/package.json +151 -0
  170. package/src/components/marketing/ChangelogPage.tsx +110 -0
  171. package/src/components/marketing/CofounderPage.tsx +409 -0
  172. package/src/components/marketing/ContactClient.tsx +174 -0
  173. package/src/components/marketing/ContributePage.tsx +319 -0
  174. package/src/components/marketing/DesignPartnerPage.tsx +181 -0
  175. package/src/components/marketing/LandingPage.tsx +30 -0
  176. package/src/components/marketing/PricingClient.tsx +446 -0
  177. package/src/components/marketing/ProductClientPage.tsx +391 -0
  178. package/src/components/marketing/index.ts +10 -0
  179. package/src/components/marketing/pricing-thinking-modal.tsx +224 -0
  180. package/src/components/marketing/sections/AudienceSection.tsx +66 -0
  181. package/src/components/marketing/sections/CorePositioningSection.tsx +44 -0
  182. package/src/components/marketing/sections/CtaSection.tsx +57 -0
  183. package/src/components/marketing/sections/DevelopersSection.tsx +38 -0
  184. package/src/components/marketing/sections/FearsSection.tsx +45 -0
  185. package/src/components/marketing/sections/HeroMarketingSection.tsx +73 -0
  186. package/src/components/marketing/sections/IconGridSection.tsx +91 -0
  187. package/src/components/marketing/sections/OutputsSection.tsx +59 -0
  188. package/src/components/marketing/sections/ProblemSection.tsx +47 -0
  189. package/src/components/marketing/sections/SolutionSection.tsx +47 -0
  190. package/src/components/marketing/sections/StepsSection.tsx +55 -0
  191. package/src/components/marketing/waitlist-section.tsx +606 -0
  192. package/src/components/templates/TemplatesClientPage.tsx +711 -0
  193. package/src/components/templates/TemplatesPage.tsx +129 -0
  194. package/src/components/templates/TemplatesPreviewModal.tsx +260 -0
  195. package/src/components/templates/index.ts +3 -0
  196. package/src/index.ts +15 -0
  197. package/src/libs/email/client.test.ts +107 -0
  198. package/src/libs/email/client.ts +146 -0
  199. package/src/libs/email/contact.ts +80 -0
  200. package/src/libs/email/newsletter.ts +108 -0
  201. package/src/libs/email/types.ts +59 -0
  202. package/src/libs/email/utils.ts +8 -0
  203. package/src/libs/email/waitlist-application.ts +192 -0
  204. package/src/libs/email/waitlist.ts +118 -0
  205. package/src/libs/pricing-examples.ts +19 -0
  206. package/src/registry/engine.ts +38 -0
  207. package/src/registry/factory.ts +110 -0
  208. package/src/registry/index.ts +7 -0
  209. package/src/registry/registry-docs.ts +843 -0
  210. package/src/registry/registry-landing.ts +118 -0
  211. package/src/registry/registry.ts +85 -0
  212. package/src/registry/types.ts +17 -0
  213. package/src/registry/utils.ts +99 -0
  214. package/tsconfig.json +13 -0
  215. package/tsconfig.tsbuildinfo +1 -0
  216. package/tsdown.config.js +10 -0
@@ -0,0 +1,113 @@
1
+ import { Temv1alpha1, createClient } from "@scaleway/sdk";
2
+ import { Logger } from "@contractspec/lib.logger";
3
+
4
+ //#region src/libs/email/client.ts
5
+ const DEFAULT_FROM = {
6
+ email: "noreply@transactional.contractspec.io",
7
+ name: "ContractSpec"
8
+ };
9
+ const DEFAULT_TEAM_INBOX = {
10
+ email: "contact@contractspec.io",
11
+ name: "ContractSpec Team"
12
+ };
13
+ const DEFAULT_REGION = "fr-par";
14
+ let cachedConfig = null;
15
+ let cachedClient = null;
16
+ let apiFactory = (client) => new Temv1alpha1.API(client);
17
+ const mapRegion = (value) => {
18
+ const normalized = value?.trim().toLowerCase();
19
+ if (normalized === "par" || normalized === "fr-par") return "fr-par";
20
+ if (normalized === "ams" || normalized === "nl-ams") return "nl-ams";
21
+ if (normalized === "waw" || normalized === "pl-waw") return "pl-waw";
22
+ return DEFAULT_REGION;
23
+ };
24
+ const getEmailConfig = () => {
25
+ if (cachedConfig) return {
26
+ ok: true,
27
+ config: cachedConfig
28
+ };
29
+ const accessKey = process.env.SCALEWAY_ACCESS_KEY || process.env.SCALEWAY_ACCESS_KEY_QUEUE;
30
+ const secretKey = process.env.SCALEWAY_SECRET_KEY || process.env.SCALEWAY_SECRET_KEY_QUEUE;
31
+ const projectId = process.env.SCALEWAY_PROJECT_ID;
32
+ if (!accessKey || !secretKey || !projectId) return {
33
+ ok: false,
34
+ errorMessage: "Email service is not configured. Please contact us directly at contact@contractspec.io."
35
+ };
36
+ const region = mapRegion(process.env.SCALEWAY_REGION);
37
+ cachedConfig = {
38
+ accessKey,
39
+ secretKey,
40
+ projectId,
41
+ region,
42
+ defaultZone: `${region}-1`,
43
+ from: {
44
+ email: process.env.SCALEWAY_EMAIL_FROM_EMAIL ?? DEFAULT_FROM.email,
45
+ name: process.env.SCALEWAY_EMAIL_FROM_NAME ?? DEFAULT_FROM.name
46
+ },
47
+ teamInbox: {
48
+ email: process.env.SCALEWAY_EMAIL_TEAM_EMAIL ?? DEFAULT_TEAM_INBOX.email,
49
+ name: process.env.SCALEWAY_EMAIL_TEAM_NAME ?? DEFAULT_TEAM_INBOX.name
50
+ }
51
+ };
52
+ return {
53
+ ok: true,
54
+ config: cachedConfig
55
+ };
56
+ };
57
+ const getTemClient = (config) => {
58
+ if (cachedClient) return cachedClient;
59
+ const client = createClient({
60
+ accessKey: config.accessKey,
61
+ secretKey: config.secretKey,
62
+ defaultProjectId: config.projectId,
63
+ defaultRegion: config.region,
64
+ defaultZone: config.defaultZone
65
+ });
66
+ cachedClient = apiFactory(client);
67
+ return cachedClient;
68
+ };
69
+ const sendEmail = async (config, request) => {
70
+ try {
71
+ await getTemClient(config).createEmail({
72
+ region: config.region,
73
+ projectId: config.projectId,
74
+ from: config.from,
75
+ to: request.to,
76
+ subject: request.subject,
77
+ text: request.text,
78
+ html: request.html || request.text,
79
+ additionalHeaders: request.replyTo ? [{
80
+ key: "Reply-To",
81
+ value: request.replyTo
82
+ }] : void 0
83
+ });
84
+ return { success: true };
85
+ } catch (error) {
86
+ new Logger().error("scaleway_tem_email_send_failed", {
87
+ context: request.context ?? "email",
88
+ error: error instanceof Error ? error.message : error
89
+ });
90
+ return {
91
+ success: false,
92
+ error,
93
+ errorMessage: "Failed to send email via Scaleway."
94
+ };
95
+ }
96
+ };
97
+ const __internal = {
98
+ resetCaches() {
99
+ cachedClient = null;
100
+ cachedConfig = null;
101
+ apiFactory = (client) => new Temv1alpha1.API(client);
102
+ },
103
+ setApiFactory(factory) {
104
+ apiFactory = factory;
105
+ },
106
+ setClient(client) {
107
+ cachedClient = client;
108
+ }
109
+ };
110
+
111
+ //#endregion
112
+ export { __internal, getEmailConfig, sendEmail };
113
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","names":[],"sources":["../../../src/libs/email/client.ts"],"sourcesContent":["import { createClient, Temv1alpha1 } from '@scaleway/sdk';\nimport type { Region } from '@scaleway/sdk-client';\nimport { Logger } from '@contractspec/lib.logger';\nimport type {\n EmailAddress,\n EmailConfigResult,\n EmailSendOutcome,\n EmailServiceConfig,\n SendEmailRequest,\n} from './types';\n\nconst DEFAULT_FROM: EmailAddress = {\n email: 'noreply@transactional.contractspec.io',\n name: 'ContractSpec',\n};\n\nconst DEFAULT_TEAM_INBOX: EmailAddress = {\n email: 'contact@contractspec.io',\n name: 'ContractSpec Team',\n};\n\nconst DEFAULT_REGION: Region = 'fr-par';\n\ntype EmailApi = Pick<Temv1alpha1.API, 'createEmail'>;\n\nlet cachedConfig: EmailServiceConfig | null = null;\nlet cachedClient: EmailApi | null = null;\nlet apiFactory: (client: ReturnType<typeof createClient>) => EmailApi = (\n client\n) => new Temv1alpha1.API(client);\n\nconst mapRegion = (value?: string | null): Region => {\n const normalized = value?.trim().toLowerCase();\n if (normalized === 'par' || normalized === 'fr-par') return 'fr-par';\n if (normalized === 'ams' || normalized === 'nl-ams') return 'nl-ams';\n if (normalized === 'waw' || normalized === 'pl-waw') return 'pl-waw';\n return DEFAULT_REGION;\n};\n\nexport const getEmailConfig = (): EmailConfigResult => {\n if (cachedConfig) {\n return { ok: true, config: cachedConfig };\n }\n\n const accessKey =\n process.env.SCALEWAY_ACCESS_KEY || process.env.SCALEWAY_ACCESS_KEY_QUEUE;\n const secretKey =\n process.env.SCALEWAY_SECRET_KEY || process.env.SCALEWAY_SECRET_KEY_QUEUE;\n const projectId = process.env.SCALEWAY_PROJECT_ID;\n\n if (!accessKey || !secretKey || !projectId) {\n return {\n ok: false,\n errorMessage:\n 'Email service is not configured. Please contact us directly at contact@contractspec.io.',\n };\n }\n\n const region = mapRegion(process.env.SCALEWAY_REGION);\n\n cachedConfig = {\n accessKey,\n secretKey,\n projectId,\n region,\n defaultZone: `${region}-1`,\n from: {\n email: process.env.SCALEWAY_EMAIL_FROM_EMAIL ?? DEFAULT_FROM.email,\n name: process.env.SCALEWAY_EMAIL_FROM_NAME ?? DEFAULT_FROM.name,\n },\n teamInbox: {\n email: process.env.SCALEWAY_EMAIL_TEAM_EMAIL ?? DEFAULT_TEAM_INBOX.email,\n name: process.env.SCALEWAY_EMAIL_TEAM_NAME ?? DEFAULT_TEAM_INBOX.name,\n },\n };\n\n return { ok: true, config: cachedConfig };\n};\n\nconst getTemClient = (config: EmailServiceConfig): EmailApi => {\n if (cachedClient) {\n return cachedClient;\n }\n\n const client = createClient({\n accessKey: config.accessKey,\n secretKey: config.secretKey,\n defaultProjectId: config.projectId,\n defaultRegion: config.region,\n defaultZone: config.defaultZone,\n });\n\n cachedClient = apiFactory(client);\n return cachedClient;\n};\n\nexport const sendEmail = async (\n config: EmailServiceConfig,\n request: SendEmailRequest\n): Promise<EmailSendOutcome> => {\n try {\n const client = getTemClient(config);\n\n await client.createEmail({\n region: config.region,\n projectId: config.projectId,\n from: config.from,\n to: request.to,\n subject: request.subject,\n text: request.text,\n html: request.html || request.text,\n additionalHeaders: request.replyTo\n ? [{ key: 'Reply-To', value: request.replyTo }]\n : undefined,\n });\n\n return { success: true };\n } catch (error) {\n new Logger().error('scaleway_tem_email_send_failed', {\n context: request.context ?? 'email',\n error: error instanceof Error ? error.message : error,\n });\n return {\n success: false,\n error,\n errorMessage: 'Failed to send email via Scaleway.',\n };\n }\n};\n\nexport const __internal = {\n resetCaches() {\n cachedClient = null;\n cachedConfig = null;\n apiFactory = (client: ReturnType<typeof createClient>) =>\n new Temv1alpha1.API(client);\n },\n setApiFactory(\n factory: (client: ReturnType<typeof createClient>) => EmailApi\n ) {\n apiFactory = factory;\n },\n setClient(client: EmailApi) {\n cachedClient = client;\n },\n};\n"],"mappings":";;;;AAWA,MAAM,eAA6B;CACjC,OAAO;CACP,MAAM;CACP;AAED,MAAM,qBAAmC;CACvC,OAAO;CACP,MAAM;CACP;AAED,MAAM,iBAAyB;AAI/B,IAAI,eAA0C;AAC9C,IAAI,eAAgC;AACpC,IAAI,cACF,WACG,IAAI,YAAY,IAAI,OAAO;AAEhC,MAAM,aAAa,UAAkC;CACnD,MAAM,aAAa,OAAO,MAAM,CAAC,aAAa;AAC9C,KAAI,eAAe,SAAS,eAAe,SAAU,QAAO;AAC5D,KAAI,eAAe,SAAS,eAAe,SAAU,QAAO;AAC5D,KAAI,eAAe,SAAS,eAAe,SAAU,QAAO;AAC5D,QAAO;;AAGT,MAAa,uBAA0C;AACrD,KAAI,aACF,QAAO;EAAE,IAAI;EAAM,QAAQ;EAAc;CAG3C,MAAM,YACJ,QAAQ,IAAI,uBAAuB,QAAQ,IAAI;CACjD,MAAM,YACJ,QAAQ,IAAI,uBAAuB,QAAQ,IAAI;CACjD,MAAM,YAAY,QAAQ,IAAI;AAE9B,KAAI,CAAC,aAAa,CAAC,aAAa,CAAC,UAC/B,QAAO;EACL,IAAI;EACJ,cACE;EACH;CAGH,MAAM,SAAS,UAAU,QAAQ,IAAI,gBAAgB;AAErD,gBAAe;EACb;EACA;EACA;EACA;EACA,aAAa,GAAG,OAAO;EACvB,MAAM;GACJ,OAAO,QAAQ,IAAI,6BAA6B,aAAa;GAC7D,MAAM,QAAQ,IAAI,4BAA4B,aAAa;GAC5D;EACD,WAAW;GACT,OAAO,QAAQ,IAAI,6BAA6B,mBAAmB;GACnE,MAAM,QAAQ,IAAI,4BAA4B,mBAAmB;GAClE;EACF;AAED,QAAO;EAAE,IAAI;EAAM,QAAQ;EAAc;;AAG3C,MAAM,gBAAgB,WAAyC;AAC7D,KAAI,aACF,QAAO;CAGT,MAAM,SAAS,aAAa;EAC1B,WAAW,OAAO;EAClB,WAAW,OAAO;EAClB,kBAAkB,OAAO;EACzB,eAAe,OAAO;EACtB,aAAa,OAAO;EACrB,CAAC;AAEF,gBAAe,WAAW,OAAO;AACjC,QAAO;;AAGT,MAAa,YAAY,OACvB,QACA,YAC8B;AAC9B,KAAI;AAGF,QAFe,aAAa,OAAO,CAEtB,YAAY;GACvB,QAAQ,OAAO;GACf,WAAW,OAAO;GAClB,MAAM,OAAO;GACb,IAAI,QAAQ;GACZ,SAAS,QAAQ;GACjB,MAAM,QAAQ;GACd,MAAM,QAAQ,QAAQ,QAAQ;GAC9B,mBAAmB,QAAQ,UACvB,CAAC;IAAE,KAAK;IAAY,OAAO,QAAQ;IAAS,CAAC,GAC7C;GACL,CAAC;AAEF,SAAO,EAAE,SAAS,MAAM;UACjB,OAAO;AACd,MAAI,QAAQ,CAAC,MAAM,kCAAkC;GACnD,SAAS,QAAQ,WAAW;GAC5B,OAAO,iBAAiB,QAAQ,MAAM,UAAU;GACjD,CAAC;AACF,SAAO;GACL,SAAS;GACT;GACA,cAAc;GACf;;;AAIL,MAAa,aAAa;CACxB,cAAc;AACZ,iBAAe;AACf,iBAAe;AACf,gBAAc,WACZ,IAAI,YAAY,IAAI,OAAO;;CAE/B,cACE,SACA;AACA,eAAa;;CAEf,UAAU,QAAkB;AAC1B,iBAAe;;CAElB"}
@@ -0,0 +1,7 @@
1
+ import { SubmitContactFormResult } from "./types.js";
2
+
3
+ //#region src/libs/email/contact.d.ts
4
+ declare const submitContactForm: (formData: FormData) => Promise<SubmitContactFormResult>;
5
+ //#endregion
6
+ export { submitContactForm };
7
+ //# sourceMappingURL=contact.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contact.d.ts","names":[],"sources":["../../../src/libs/email/contact.ts"],"mappings":";;;cAWa,iBAAA,GACX,QAAA,EAAU,QAAA,KACT,OAAA,CAAQ,uBAAA"}
@@ -0,0 +1,71 @@
1
+ 'use server';
2
+
3
+ import { getEmailConfig, sendEmail } from "./client.js";
4
+ import { escapeHtml, formatMultilineHtml } from "./utils.js";
5
+
6
+ //#region src/libs/email/contact.ts
7
+ const CONTACT_MISSING_CONFIG = "Email service is not configured. Please contact us directly at contact@contractspec.io.";
8
+ const CONTACT_SEND_ERROR = "Failed to send message. Please contact us directly at contact@contractspec.io.";
9
+ const submitContactForm = async (formData) => {
10
+ const name = (formData.get("name") ?? "").toString().trim();
11
+ const email = (formData.get("email") ?? "").toString().trim();
12
+ const message = (formData.get("message") ?? "").toString().trim();
13
+ if (!email) return {
14
+ success: false,
15
+ text: "Please fill in all required fields."
16
+ };
17
+ const configResult = getEmailConfig();
18
+ if (!configResult.ok || !configResult.config) return {
19
+ success: false,
20
+ text: configResult.errorMessage ?? CONTACT_MISSING_CONFIG
21
+ };
22
+ const senderName = name || email;
23
+ const emailContentText = `
24
+ New contact form submission from ${senderName}
25
+
26
+ Contact Information:
27
+ - Name: ${name || "Not provided"}
28
+ - Email: ${email}
29
+
30
+ Message:
31
+ ${message || "No message provided"}
32
+
33
+ ---
34
+ Submitted via ContractSpec contact form
35
+ `.trim();
36
+ const emailContentHtml = `
37
+ <div style="font-family: sans-serif; max-width: 640px; margin: 0 auto;">
38
+ <h1 style="color: #8b5cf6; margin-bottom: 12px;">New contact form submission</h1>
39
+ <p style="margin: 0 0 12px;">From ${escapeHtml(senderName)}</p>
40
+ <h2 style="color: #8b5cf6; margin: 16px 0 8px;">Contact Information</h2>
41
+ <ul style="padding-left: 16px; line-height: 1.6; margin: 0 0 16px;">
42
+ <li>Name: ${escapeHtml(name || "Not provided")}</li>
43
+ <li>Email: ${escapeHtml(email)}</li>
44
+ </ul>
45
+ <h2 style="color: #8b5cf6; margin: 16px 0 8px;">Message</h2>
46
+ <div style="border: 1px solid #e5e7eb; border-radius: 8px; padding: 12px; background: #f9fafb; white-space: pre-wrap; line-height: 1.6;">
47
+ ${message ? formatMultilineHtml(message) : "No message provided"}
48
+ </div>
49
+ <p style="color: #6b7280; font-size: 12px; margin-top: 20px;">Submitted via ContractSpec contact form</p>
50
+ </div>
51
+ `;
52
+ if (!(await sendEmail(configResult.config, {
53
+ to: [configResult.config.teamInbox],
54
+ subject: `New Contact Form Message from ${senderName}`,
55
+ text: emailContentText,
56
+ html: emailContentHtml,
57
+ replyTo: email,
58
+ context: "contact-form"
59
+ })).success) return {
60
+ success: false,
61
+ text: CONTACT_SEND_ERROR
62
+ };
63
+ return {
64
+ success: true,
65
+ text: "Message sent successfully!"
66
+ };
67
+ };
68
+
69
+ //#endregion
70
+ export { submitContactForm };
71
+ //# sourceMappingURL=contact.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contact.js","names":[],"sources":["../../../src/libs/email/contact.ts"],"sourcesContent":["'use server';\n\nimport { getEmailConfig, sendEmail } from './client';\nimport { escapeHtml, formatMultilineHtml } from './utils';\nimport type { SubmitContactFormResult } from './types';\n\nconst CONTACT_MISSING_CONFIG =\n 'Email service is not configured. Please contact us directly at contact@contractspec.io.';\nconst CONTACT_SEND_ERROR =\n 'Failed to send message. Please contact us directly at contact@contractspec.io.';\n\nexport const submitContactForm = async (\n formData: FormData\n): Promise<SubmitContactFormResult> => {\n const name = (formData.get('name') ?? '').toString().trim();\n const email = (formData.get('email') ?? '').toString().trim();\n const message = (formData.get('message') ?? '').toString().trim();\n\n if (!email) {\n return {\n success: false,\n text: 'Please fill in all required fields.',\n };\n }\n\n const configResult = getEmailConfig();\n if (!configResult.ok || !configResult.config) {\n return {\n success: false,\n text: configResult.errorMessage ?? CONTACT_MISSING_CONFIG,\n };\n }\n\n const senderName = name || email;\n const emailContentText = `\nNew contact form submission from ${senderName}\n\nContact Information:\n- Name: ${name || 'Not provided'}\n- Email: ${email}\n\nMessage:\n${message || 'No message provided'}\n\n---\nSubmitted via ContractSpec contact form\n `.trim();\n\n const emailContentHtml = `\n <div style=\"font-family: sans-serif; max-width: 640px; margin: 0 auto;\">\n <h1 style=\"color: #8b5cf6; margin-bottom: 12px;\">New contact form submission</h1>\n <p style=\"margin: 0 0 12px;\">From ${escapeHtml(senderName)}</p>\n <h2 style=\"color: #8b5cf6; margin: 16px 0 8px;\">Contact Information</h2>\n <ul style=\"padding-left: 16px; line-height: 1.6; margin: 0 0 16px;\">\n <li>Name: ${escapeHtml(name || 'Not provided')}</li>\n <li>Email: ${escapeHtml(email)}</li>\n </ul>\n <h2 style=\"color: #8b5cf6; margin: 16px 0 8px;\">Message</h2>\n <div style=\"border: 1px solid #e5e7eb; border-radius: 8px; padding: 12px; background: #f9fafb; white-space: pre-wrap; line-height: 1.6;\">\n ${message ? formatMultilineHtml(message) : 'No message provided'}\n </div>\n <p style=\"color: #6b7280; font-size: 12px; margin-top: 20px;\">Submitted via ContractSpec contact form</p>\n </div>\n `;\n\n const sendResult = await sendEmail(configResult.config, {\n to: [configResult.config.teamInbox],\n subject: `New Contact Form Message from ${senderName}`,\n text: emailContentText,\n html: emailContentHtml,\n replyTo: email,\n context: 'contact-form',\n });\n\n if (!sendResult.success) {\n return { success: false, text: CONTACT_SEND_ERROR };\n }\n\n return { success: true, text: 'Message sent successfully!' };\n};\n"],"mappings":";;;;;;AAMA,MAAM,yBACJ;AACF,MAAM,qBACJ;AAEF,MAAa,oBAAoB,OAC/B,aACqC;CACrC,MAAM,QAAQ,SAAS,IAAI,OAAO,IAAI,IAAI,UAAU,CAAC,MAAM;CAC3D,MAAM,SAAS,SAAS,IAAI,QAAQ,IAAI,IAAI,UAAU,CAAC,MAAM;CAC7D,MAAM,WAAW,SAAS,IAAI,UAAU,IAAI,IAAI,UAAU,CAAC,MAAM;AAEjE,KAAI,CAAC,MACH,QAAO;EACL,SAAS;EACT,MAAM;EACP;CAGH,MAAM,eAAe,gBAAgB;AACrC,KAAI,CAAC,aAAa,MAAM,CAAC,aAAa,OACpC,QAAO;EACL,SAAS;EACT,MAAM,aAAa,gBAAgB;EACpC;CAGH,MAAM,aAAa,QAAQ;CAC3B,MAAM,mBAAmB;mCACQ,WAAW;;;UAGpC,QAAQ,eAAe;WACtB,MAAM;;;EAGf,WAAW,sBAAsB;;;;IAI/B,MAAM;CAER,MAAM,mBAAmB;;;0CAGe,WAAW,WAAW,CAAC;;;oBAG7C,WAAW,QAAQ,eAAe,CAAC;qBAClC,WAAW,MAAM,CAAC;;;;UAI7B,UAAU,oBAAoB,QAAQ,GAAG,sBAAsB;;;;;AAevE,KAAI,EATe,MAAM,UAAU,aAAa,QAAQ;EACtD,IAAI,CAAC,aAAa,OAAO,UAAU;EACnC,SAAS,iCAAiC;EAC1C,MAAM;EACN,MAAM;EACN,SAAS;EACT,SAAS;EACV,CAAC,EAEc,QACd,QAAO;EAAE,SAAS;EAAO,MAAM;EAAoB;AAGrD,QAAO;EAAE,SAAS;EAAM,MAAM;EAA8B"}
@@ -0,0 +1,7 @@
1
+ import { SubmitNewsletterResult } from "./types.js";
2
+
3
+ //#region src/libs/email/newsletter.d.ts
4
+ declare const subscribeToNewsletter: (formData: FormData) => Promise<SubmitNewsletterResult>;
5
+ //#endregion
6
+ export { subscribeToNewsletter };
7
+ //# sourceMappingURL=newsletter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"newsletter.d.ts","names":[],"sources":["../../../src/libs/email/newsletter.ts"],"mappings":";;;cAWa,qBAAA,GACX,QAAA,EAAU,QAAA,KACT,OAAA,CAAQ,sBAAA"}
@@ -0,0 +1,95 @@
1
+ 'use server';
2
+
3
+ import { getEmailConfig, sendEmail } from "./client.js";
4
+ import { formatMultilineHtml } from "./utils.js";
5
+
6
+ //#region src/libs/email/newsletter.ts
7
+ const NEWSLETTER_MISSING_CONFIG = "Newsletter service is not configured. Please try again later.";
8
+ const NEWSLETTER_SEND_ERROR = "Failed to subscribe. Please try again later or contact us directly.";
9
+ const subscribeToNewsletter = async (formData) => {
10
+ const email = (formData.get("email") ?? "").toString().trim();
11
+ if (!email || !email.includes("@")) return {
12
+ success: false,
13
+ text: "Please enter a valid email address."
14
+ };
15
+ const configResult = getEmailConfig();
16
+ if (!configResult.ok || !configResult.config) return {
17
+ success: false,
18
+ text: configResult.errorMessage ?? NEWSLETTER_MISSING_CONFIG
19
+ };
20
+ const welcomeText = `
21
+ Welcome to ContractSpec!
22
+
23
+ Thanks for subscribing to our newsletter. You'll receive updates on:
24
+
25
+ • New integrations (Stripe, OpenAI, Qdrant, and more)
26
+ • Product features and improvements
27
+ • New templates and examples
28
+ • Architecture insights and best practices
29
+ • Documentation updates
30
+
31
+ Stay tuned for exciting updates!
32
+
33
+ ---
34
+ ContractSpec Team
35
+ https://contractspec.io
36
+
37
+ Unsubscribe: Reply to this email with "unsubscribe"
38
+ `.trim();
39
+ if (!(await sendEmail(configResult.config, {
40
+ to: [{ email }],
41
+ subject: "Welcome to ContractSpec Newsletter",
42
+ text: welcomeText,
43
+ html: `
44
+ <div style="font-family: sans-serif; max-width: 640px; margin: 0 auto;">
45
+ <h1 style="color: #8b5cf6;">Welcome to ContractSpec!</h1>
46
+ <p>Thanks for subscribing to our newsletter. You'll receive updates on:</p>
47
+ <ul style="line-height: 1.8;">
48
+ <li>New integrations (Stripe, OpenAI, Qdrant, and more)</li>
49
+ <li>Product features and improvements</li>
50
+ <li>New templates and examples</li>
51
+ <li>Architecture insights and best practices</li>
52
+ <li>Documentation updates</li>
53
+ </ul>
54
+ <p>Stay tuned for exciting updates!</p>
55
+ <hr style="margin: 30px 0; border: none; border-top: 1px solid #e5e7eb;" />
56
+ <p style="color: #6b7280; font-size: 14px;">
57
+ ContractSpec Team<br />
58
+ <a href="https://contractspec.io" style="color: #8b5cf6;">contractspec.io</a>
59
+ </p>
60
+ <p style="color: #9ca3af; font-size: 12px;">
61
+ To unsubscribe, reply to this email with "unsubscribe"
62
+ </p>
63
+ </div>
64
+ `,
65
+ context: "newsletter-welcome"
66
+ })).success) return {
67
+ success: false,
68
+ text: NEWSLETTER_SEND_ERROR
69
+ };
70
+ const teamNotificationText = `New newsletter subscription from: ${email}`;
71
+ const teamNotificationHtml = `
72
+ <div style="font-family: sans-serif; max-width: 640px; margin: 0 auto;">
73
+ <p style="margin: 0 0 8px;">New newsletter subscription</p>
74
+ <p style="margin: 0;"><strong>Email:</strong> ${formatMultilineHtml(email)}</p>
75
+ </div>
76
+ `;
77
+ if (!(await sendEmail(configResult.config, {
78
+ to: [configResult.config.teamInbox],
79
+ subject: `New Newsletter Subscription: ${email}`,
80
+ text: teamNotificationText,
81
+ html: teamNotificationHtml,
82
+ context: "newsletter-team-notification"
83
+ })).success) return {
84
+ success: false,
85
+ text: NEWSLETTER_SEND_ERROR
86
+ };
87
+ return {
88
+ success: true,
89
+ text: "Successfully subscribed!"
90
+ };
91
+ };
92
+
93
+ //#endregion
94
+ export { subscribeToNewsletter };
95
+ //# sourceMappingURL=newsletter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"newsletter.js","names":[],"sources":["../../../src/libs/email/newsletter.ts"],"sourcesContent":["'use server';\n\nimport { getEmailConfig, sendEmail } from './client';\nimport { formatMultilineHtml } from './utils';\nimport type { SubmitNewsletterResult } from './types';\n\nconst NEWSLETTER_MISSING_CONFIG =\n 'Newsletter service is not configured. Please try again later.';\nconst NEWSLETTER_SEND_ERROR =\n 'Failed to subscribe. Please try again later or contact us directly.';\n\nexport const subscribeToNewsletter = async (\n formData: FormData\n): Promise<SubmitNewsletterResult> => {\n const email = (formData.get('email') ?? '').toString().trim();\n\n if (!email || !email.includes('@')) {\n return {\n success: false,\n text: 'Please enter a valid email address.',\n };\n }\n\n const configResult = getEmailConfig();\n if (!configResult.ok || !configResult.config) {\n return {\n success: false,\n text: configResult.errorMessage ?? NEWSLETTER_MISSING_CONFIG,\n };\n }\n\n const welcomeText = `\nWelcome to ContractSpec!\n\nThanks for subscribing to our newsletter. You'll receive updates on:\n\n• New integrations (Stripe, OpenAI, Qdrant, and more)\n• Product features and improvements\n• New templates and examples\n• Architecture insights and best practices\n• Documentation updates\n\nStay tuned for exciting updates!\n\n---\nContractSpec Team\nhttps://contractspec.io\n\nUnsubscribe: Reply to this email with \"unsubscribe\"\n `.trim();\n\n const welcomeHtml = `\n <div style=\"font-family: sans-serif; max-width: 640px; margin: 0 auto;\">\n <h1 style=\"color: #8b5cf6;\">Welcome to ContractSpec!</h1>\n <p>Thanks for subscribing to our newsletter. You'll receive updates on:</p>\n <ul style=\"line-height: 1.8;\">\n <li>New integrations (Stripe, OpenAI, Qdrant, and more)</li>\n <li>Product features and improvements</li>\n <li>New templates and examples</li>\n <li>Architecture insights and best practices</li>\n <li>Documentation updates</li>\n </ul>\n <p>Stay tuned for exciting updates!</p>\n <hr style=\"margin: 30px 0; border: none; border-top: 1px solid #e5e7eb;\" />\n <p style=\"color: #6b7280; font-size: 14px;\">\n ContractSpec Team<br />\n <a href=\"https://contractspec.io\" style=\"color: #8b5cf6;\">contractspec.io</a>\n </p>\n <p style=\"color: #9ca3af; font-size: 12px;\">\n To unsubscribe, reply to this email with \"unsubscribe\"\n </p>\n </div>\n `;\n\n const userSend = await sendEmail(configResult.config, {\n to: [{ email }],\n subject: 'Welcome to ContractSpec Newsletter',\n text: welcomeText,\n html: welcomeHtml,\n context: 'newsletter-welcome',\n });\n\n if (!userSend.success) {\n return { success: false, text: NEWSLETTER_SEND_ERROR };\n }\n\n const teamNotificationText = `New newsletter subscription from: ${email}`;\n const teamNotificationHtml = `\n <div style=\"font-family: sans-serif; max-width: 640px; margin: 0 auto;\">\n <p style=\"margin: 0 0 8px;\">New newsletter subscription</p>\n <p style=\"margin: 0;\"><strong>Email:</strong> ${formatMultilineHtml(email)}</p>\n </div>\n `;\n\n const teamSend = await sendEmail(configResult.config, {\n to: [configResult.config.teamInbox],\n subject: `New Newsletter Subscription: ${email}`,\n text: teamNotificationText,\n html: teamNotificationHtml,\n context: 'newsletter-team-notification',\n });\n\n if (!teamSend.success) {\n return { success: false, text: NEWSLETTER_SEND_ERROR };\n }\n\n return { success: true, text: 'Successfully subscribed!' };\n};\n"],"mappings":";;;;;;AAMA,MAAM,4BACJ;AACF,MAAM,wBACJ;AAEF,MAAa,wBAAwB,OACnC,aACoC;CACpC,MAAM,SAAS,SAAS,IAAI,QAAQ,IAAI,IAAI,UAAU,CAAC,MAAM;AAE7D,KAAI,CAAC,SAAS,CAAC,MAAM,SAAS,IAAI,CAChC,QAAO;EACL,SAAS;EACT,MAAM;EACP;CAGH,MAAM,eAAe,gBAAgB;AACrC,KAAI,CAAC,aAAa,MAAM,CAAC,aAAa,OACpC,QAAO;EACL,SAAS;EACT,MAAM,aAAa,gBAAgB;EACpC;CAGH,MAAM,cAAc;;;;;;;;;;;;;;;;;;IAkBlB,MAAM;AAiCR,KAAI,EARa,MAAM,UAAU,aAAa,QAAQ;EACpD,IAAI,CAAC,EAAE,OAAO,CAAC;EACf,SAAS;EACT,MAAM;EACN,MA3BkB;;;;;;;;;;;;;;;;;;;;;;EA4BlB,SAAS;EACV,CAAC,EAEY,QACZ,QAAO;EAAE,SAAS;EAAO,MAAM;EAAuB;CAGxD,MAAM,uBAAuB,qCAAqC;CAClE,MAAM,uBAAuB;;;sDAGuB,oBAAoB,MAAM,CAAC;;;AAY/E,KAAI,EARa,MAAM,UAAU,aAAa,QAAQ;EACpD,IAAI,CAAC,aAAa,OAAO,UAAU;EACnC,SAAS,gCAAgC;EACzC,MAAM;EACN,MAAM;EACN,SAAS;EACV,CAAC,EAEY,QACZ,QAAO;EAAE,SAAS;EAAO,MAAM;EAAuB;AAGxD,QAAO;EAAE,SAAS;EAAM,MAAM;EAA4B"}
@@ -0,0 +1,53 @@
1
+ import { Region } from "@scaleway/sdk-client";
2
+
3
+ //#region src/libs/email/types.d.ts
4
+ interface SubmitContactFormResult {
5
+ success: boolean;
6
+ text: string;
7
+ }
8
+ interface SubmitNewsletterResult {
9
+ success: boolean;
10
+ text: string;
11
+ }
12
+ interface SubmitWaitlistResult {
13
+ success: boolean;
14
+ text: string;
15
+ }
16
+ interface SubmitWaitlistApplicationResult {
17
+ success: boolean;
18
+ text: string;
19
+ }
20
+ interface EmailAddress {
21
+ email: string;
22
+ name?: string;
23
+ }
24
+ interface EmailServiceConfig {
25
+ accessKey: string;
26
+ secretKey: string;
27
+ projectId: string;
28
+ region: Region;
29
+ defaultZone: string;
30
+ from: EmailAddress;
31
+ teamInbox: EmailAddress;
32
+ }
33
+ interface EmailConfigResult {
34
+ ok: boolean;
35
+ config?: EmailServiceConfig;
36
+ errorMessage?: string;
37
+ }
38
+ interface SendEmailRequest {
39
+ to: EmailAddress[];
40
+ subject: string;
41
+ text: string;
42
+ html: string;
43
+ replyTo?: string;
44
+ context?: string;
45
+ }
46
+ interface EmailSendOutcome {
47
+ success: boolean;
48
+ error?: unknown;
49
+ errorMessage?: string;
50
+ }
51
+ //#endregion
52
+ export { EmailAddress, EmailConfigResult, EmailSendOutcome, EmailServiceConfig, SendEmailRequest, SubmitContactFormResult, SubmitNewsletterResult, SubmitWaitlistApplicationResult, SubmitWaitlistResult };
53
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","names":[],"sources":["../../../src/libs/email/types.ts"],"mappings":";;;UAIiB,uBAAA;EACf,OAAA;EACA,IAAA;AAAA;AAAA,UAGe,sBAAA;EACf,OAAA;EACA,IAAA;AAAA;AAAA,UAGe,oBAAA;EACf,OAAA;EACA,IAAA;AAAA;AAAA,UAGe,+BAAA;EACf,OAAA;EACA,IAAA;AAAA;AAAA,UAGe,YAAA;EACf,KAAA;EACA,IAAA;AAAA;AAAA,UAGe,kBAAA;EACf,SAAA;EACA,SAAA;EACA,SAAA;EACA,MAAA,EAAQ,MAAA;EACR,WAAA;EACA,IAAA,EAAM,YAAA;EACN,SAAA,EAAW,YAAA;AAAA;AAAA,UAGI,iBAAA;EACf,EAAA;EACA,MAAA,GAAS,kBAAA;EACT,YAAA;AAAA;AAAA,UAGe,gBAAA;EACf,EAAA,EAAI,YAAA;EACJ,OAAA;EACA,IAAA;EACA,IAAA;EACA,OAAA;EACA,OAAA;AAAA;AAAA,UAGe,gBAAA;EACf,OAAA;EACA,KAAA;EACA,YAAA;AAAA"}
@@ -0,0 +1 @@
1
+ 'use server';
@@ -0,0 +1,6 @@
1
+ //#region src/libs/email/utils.d.ts
2
+ declare const escapeHtml: (value: string) => string;
3
+ declare const formatMultilineHtml: (value: string) => string;
4
+ //#endregion
5
+ export { escapeHtml, formatMultilineHtml };
6
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","names":[],"sources":["../../../src/libs/email/utils.ts"],"mappings":";cAAa,UAAA,GAAc,KAAA;AAAA,cAMd,mBAAA,GAAuB,KAAA"}
@@ -0,0 +1,7 @@
1
+ //#region src/libs/email/utils.ts
2
+ const escapeHtml = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
3
+ const formatMultilineHtml = (value) => escapeHtml(value).replaceAll("\n", "<br />");
4
+
5
+ //#endregion
6
+ export { escapeHtml, formatMultilineHtml };
7
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.js","names":[],"sources":["../../../src/libs/email/utils.ts"],"sourcesContent":["export const escapeHtml = (value: string): string =>\n value\n .replaceAll('&', '&amp;')\n .replaceAll('<', '&lt;')\n .replaceAll('>', '&gt;');\n\nexport const formatMultilineHtml = (value: string): string =>\n escapeHtml(value).replaceAll('\\n', '<br />');\n"],"mappings":";AAAA,MAAa,cAAc,UACzB,MACG,WAAW,KAAK,QAAQ,CACxB,WAAW,KAAK,OAAO,CACvB,WAAW,KAAK,OAAO;AAE5B,MAAa,uBAAuB,UAClC,WAAW,MAAM,CAAC,WAAW,MAAM,SAAS"}
@@ -0,0 +1,7 @@
1
+ import { SubmitWaitlistApplicationResult } from "./types.js";
2
+
3
+ //#region src/libs/email/waitlist-application.d.ts
4
+ declare const submitWaitlistApplication: (formData: FormData) => Promise<SubmitWaitlistApplicationResult>;
5
+ //#endregion
6
+ export { submitWaitlistApplication };
7
+ //# sourceMappingURL=waitlist-application.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"waitlist-application.d.ts","names":[],"sources":["../../../src/libs/email/waitlist-application.ts"],"mappings":";;;cAWa,yBAAA,GACX,QAAA,EAAU,QAAA,KACT,OAAA,CAAQ,+BAAA"}
@@ -0,0 +1,170 @@
1
+ 'use server';
2
+
3
+ import { getEmailConfig, sendEmail } from "./client.js";
4
+ import { escapeHtml, formatMultilineHtml } from "./utils.js";
5
+
6
+ //#region src/libs/email/waitlist-application.ts
7
+ const APPLICATION_MISSING_CONFIG = "Waitlist application service is not configured. Please try again later.";
8
+ const APPLICATION_SEND_ERROR = "Failed to submit application. Please try again later or contact us directly.";
9
+ const submitWaitlistApplication = async (formData) => {
10
+ const email = (formData.get("email") ?? "").toString().trim();
11
+ const name = (formData.get("name") ?? "").toString().trim();
12
+ const company = (formData.get("company") ?? "").toString().trim();
13
+ const role = (formData.get("role") ?? "").toString().trim();
14
+ const useCase = (formData.get("useCase") ?? "").toString().trim();
15
+ const currentStack = (formData.get("currentStack") ?? "").toString().trim();
16
+ const whatBuilding = (formData.get("whatBuilding") ?? "").toString().trim();
17
+ const whatSolving = (formData.get("whatSolving") ?? "").toString().trim();
18
+ const teamSize = (formData.get("teamSize") ?? "").toString().trim();
19
+ const timeline = (formData.get("timeline") ?? "").toString().trim();
20
+ const openToSessions = formData.get("openToSessions") === "on";
21
+ const okayWithCaseStudies = formData.get("okayWithCaseStudies") === "on";
22
+ if (!email || !email.includes("@")) return {
23
+ success: false,
24
+ text: "Please enter a valid email address."
25
+ };
26
+ if (!name || !whatBuilding || !whatSolving) return {
27
+ success: false,
28
+ text: "Please fill in all required fields."
29
+ };
30
+ const configResult = getEmailConfig();
31
+ if (!configResult.ok || !configResult.config) return {
32
+ success: false,
33
+ text: configResult.errorMessage ?? APPLICATION_MISSING_CONFIG
34
+ };
35
+ const applicantText = `
36
+ You're on the list.
37
+
38
+ Thanks for applying to the ContractSpec design partner program. We're slowly onboarding design partners in waves. If your use case is a good fit, we'll reach out personally.
39
+
40
+ What happens next:
41
+ • We review applications weekly
42
+ • If selected, we'll reach out via email to schedule an intro call
43
+ • During early access, you'll get hands-on support and influence over the roadmap
44
+
45
+ In the meantime:
46
+ • Check out our docs: https://contractspec.io/docs
47
+ • Book a demo call: https://contractspec.io/contact
48
+
49
+ We're excited about the possibility of working together!
50
+
51
+ ---
52
+ ContractSpec Team
53
+ https://contractspec.io
54
+ `.trim();
55
+ if (!(await sendEmail(configResult.config, {
56
+ to: [{ email }],
57
+ subject: "You're on the ContractSpec design partner waitlist!",
58
+ text: applicantText,
59
+ html: `
60
+ <div style="font-family: sans-serif; max-width: 640px; margin: 0 auto;">
61
+ <h1 style="color: #8b5cf6;">You're on the list.</h1>
62
+ <p>Thanks for applying to the ContractSpec design partner program. We're slowly onboarding design partners in waves. If your use case is a good fit, we'll reach out personally.</p>
63
+ <h2 style="color: #8b5cf6; margin-top: 24px;">What happens next:</h2>
64
+ <ul style="line-height: 1.8;">
65
+ <li>We review applications weekly</li>
66
+ <li>If selected, we'll reach out via email to schedule an intro call</li>
67
+ <li>During early access, you'll get hands-on support and influence over the roadmap</li>
68
+ </ul>
69
+ <h2 style="color: #8b5cf6; margin-top: 24px;">In the meantime:</h2>
70
+ <ul style="line-height: 1.8;">
71
+ <li>Check out our <a href="https://contractspec.io/docs" style="color: #8b5cf6;">docs</a></li>
72
+ <li>Book a demo call: <a href="https://contractspec.io/contact" style="color: #8b5cf6;">contractspec.io/contact</a></li>
73
+ </ul>
74
+ <p>We're excited about the possibility of working together!</p>
75
+ <hr style="margin: 30px 0; border: none; border-top: 1px solid #e5e7eb;" />
76
+ <p style="color: #6b7280; font-size: 14px;">
77
+ ContractSpec Team<br />
78
+ <a href="https://contractspec.io" style="color: #8b5cf6;">contractspec.io</a>
79
+ </p>
80
+ </div>
81
+ `,
82
+ context: "waitlist-application-welcome"
83
+ })).success) return {
84
+ success: false,
85
+ text: APPLICATION_SEND_ERROR
86
+ };
87
+ const preferencesText = `
88
+ Open to 1:1 product/design sessions: ${openToSessions ? "Yes" : "No"}
89
+ Okay with anonymized case studies: ${okayWithCaseStudies ? "Yes" : "No"}
90
+ `.trim();
91
+ const teamEmailText = `
92
+ New Design Partner Waitlist Application
93
+
94
+ Contact Information:
95
+ - Name: ${name}
96
+ - Email: ${email}
97
+ ${company ? `- Company/Project: ${company}` : ""}
98
+ ${role ? `- Role: ${role}` : ""}
99
+
100
+ Application Details:
101
+ - What are you building with AI today?
102
+ ${whatBuilding}
103
+
104
+ - What do you hope ContractSpec will solve for you?
105
+ ${whatSolving}
106
+
107
+ - Primary use case: ${useCase || "Not specified"}
108
+ - Current stack: ${currentStack || "Not specified"}
109
+ - Team Size: ${teamSize || "Not specified"}
110
+ - Timeline: ${timeline || "Not specified"}
111
+
112
+ Preferences:
113
+ - Open to 1:1 product/design sessions: ${openToSessions ? "Yes" : "No"}
114
+ - Okay with anonymized case studies: ${okayWithCaseStudies ? "Yes" : "No"}
115
+
116
+ ---
117
+ Submitted via ContractSpec waitlist application form
118
+ `.trim();
119
+ const teamEmailHtml = `
120
+ <div style="font-family: sans-serif; max-width: 720px; margin: 0 auto;">
121
+ <h1 style="color: #8b5cf6;">New Design Partner Waitlist Application</h1>
122
+ <h2 style="color: #8b5cf6; margin: 16px 0 8px;">Contact Information</h2>
123
+ <ul style="padding-left: 16px; line-height: 1.6; margin: 0 0 16px;">
124
+ <li>Name: ${escapeHtml(name)}</li>
125
+ <li>Email: ${escapeHtml(email)}</li>
126
+ ${company ? `<li>Company/Project: ${escapeHtml(company)}</li>` : ""}
127
+ ${role ? `<li>Role: ${escapeHtml(role)}</li>` : ""}
128
+ </ul>
129
+ <h2 style="color: #8b5cf6; margin: 16px 0 8px;">Application Details</h2>
130
+ <p style="margin: 0 0 8px; font-weight: 600;">What are you building with AI today?</p>
131
+ <div style="border: 1px solid #e5e7eb; border-radius: 8px; padding: 12px; background: #f9fafb; white-space: pre-wrap; line-height: 1.6;">
132
+ ${formatMultilineHtml(whatBuilding)}
133
+ </div>
134
+ <p style="margin: 16px 0 8px; font-weight: 600;">What do you hope ContractSpec will solve for you?</p>
135
+ <div style="border: 1px solid #e5e7eb; border-radius: 8px; padding: 12px; background: #f9fafb; white-space: pre-wrap; line-height: 1.6;">
136
+ ${formatMultilineHtml(whatSolving)}
137
+ </div>
138
+ <ul style="padding-left: 16px; line-height: 1.6; margin: 16px 0;">
139
+ <li>Primary use case: ${escapeHtml(useCase || "Not specified")}</li>
140
+ <li>Current stack: ${escapeHtml(currentStack || "Not specified")}</li>
141
+ <li>Team Size: ${escapeHtml(teamSize || "Not specified")}</li>
142
+ <li>Timeline: ${escapeHtml(timeline || "Not specified")}</li>
143
+ </ul>
144
+ <h2 style="color: #8b5cf6; margin: 16px 0 8px;">Preferences</h2>
145
+ <div style="border: 1px solid #e5e7eb; border-radius: 8px; padding: 12px; background: #f9fafb; line-height: 1.6;">
146
+ ${formatMultilineHtml(preferencesText)}
147
+ </div>
148
+ <p style="color: #6b7280; font-size: 12px; margin-top: 20px;">Submitted via ContractSpec waitlist application form</p>
149
+ </div>
150
+ `;
151
+ if (!(await sendEmail(configResult.config, {
152
+ to: [configResult.config.teamInbox],
153
+ subject: `New Design Partner Application: ${name} (${email})`,
154
+ text: teamEmailText,
155
+ html: teamEmailHtml,
156
+ replyTo: email,
157
+ context: "waitlist-application-team-notification"
158
+ })).success) return {
159
+ success: false,
160
+ text: APPLICATION_SEND_ERROR
161
+ };
162
+ return {
163
+ success: true,
164
+ text: "Application submitted successfully!"
165
+ };
166
+ };
167
+
168
+ //#endregion
169
+ export { submitWaitlistApplication };
170
+ //# sourceMappingURL=waitlist-application.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"waitlist-application.js","names":[],"sources":["../../../src/libs/email/waitlist-application.ts"],"sourcesContent":["'use server';\n\nimport { getEmailConfig, sendEmail } from './client';\nimport { escapeHtml, formatMultilineHtml } from './utils';\nimport type { SubmitWaitlistApplicationResult } from './types';\n\nconst APPLICATION_MISSING_CONFIG =\n 'Waitlist application service is not configured. Please try again later.';\nconst APPLICATION_SEND_ERROR =\n 'Failed to submit application. Please try again later or contact us directly.';\n\nexport const submitWaitlistApplication = async (\n formData: FormData\n): Promise<SubmitWaitlistApplicationResult> => {\n const email = (formData.get('email') ?? '').toString().trim();\n const name = (formData.get('name') ?? '').toString().trim();\n const company = (formData.get('company') ?? '').toString().trim();\n const role = (formData.get('role') ?? '').toString().trim();\n const useCase = (formData.get('useCase') ?? '').toString().trim();\n const currentStack = (formData.get('currentStack') ?? '').toString().trim();\n const whatBuilding = (formData.get('whatBuilding') ?? '').toString().trim();\n const whatSolving = (formData.get('whatSolving') ?? '').toString().trim();\n const teamSize = (formData.get('teamSize') ?? '').toString().trim();\n const timeline = (formData.get('timeline') ?? '').toString().trim();\n\n const openToSessions = formData.get('openToSessions') === 'on';\n const okayWithCaseStudies = formData.get('okayWithCaseStudies') === 'on';\n\n if (!email || !email.includes('@')) {\n return {\n success: false,\n text: 'Please enter a valid email address.',\n };\n }\n\n if (!name || !whatBuilding || !whatSolving) {\n return {\n success: false,\n text: 'Please fill in all required fields.',\n };\n }\n\n const configResult = getEmailConfig();\n if (!configResult.ok || !configResult.config) {\n return {\n success: false,\n text: configResult.errorMessage ?? APPLICATION_MISSING_CONFIG,\n };\n }\n\n const applicantText = `\nYou're on the list.\n\nThanks for applying to the ContractSpec design partner program. We're slowly onboarding design partners in waves. If your use case is a good fit, we'll reach out personally.\n\nWhat happens next:\n• We review applications weekly\n• If selected, we'll reach out via email to schedule an intro call\n• During early access, you'll get hands-on support and influence over the roadmap\n\nIn the meantime:\n• Check out our docs: https://contractspec.io/docs\n• Book a demo call: https://contractspec.io/contact\n\nWe're excited about the possibility of working together!\n\n---\nContractSpec Team\nhttps://contractspec.io\n `.trim();\n\n const applicantHtml = `\n <div style=\"font-family: sans-serif; max-width: 640px; margin: 0 auto;\">\n <h1 style=\"color: #8b5cf6;\">You're on the list.</h1>\n <p>Thanks for applying to the ContractSpec design partner program. We're slowly onboarding design partners in waves. If your use case is a good fit, we'll reach out personally.</p>\n <h2 style=\"color: #8b5cf6; margin-top: 24px;\">What happens next:</h2>\n <ul style=\"line-height: 1.8;\">\n <li>We review applications weekly</li>\n <li>If selected, we'll reach out via email to schedule an intro call</li>\n <li>During early access, you'll get hands-on support and influence over the roadmap</li>\n </ul>\n <h2 style=\"color: #8b5cf6; margin-top: 24px;\">In the meantime:</h2>\n <ul style=\"line-height: 1.8;\">\n <li>Check out our <a href=\"https://contractspec.io/docs\" style=\"color: #8b5cf6;\">docs</a></li>\n <li>Book a demo call: <a href=\"https://contractspec.io/contact\" style=\"color: #8b5cf6;\">contractspec.io/contact</a></li>\n </ul>\n <p>We're excited about the possibility of working together!</p>\n <hr style=\"margin: 30px 0; border: none; border-top: 1px solid #e5e7eb;\" />\n <p style=\"color: #6b7280; font-size: 14px;\">\n ContractSpec Team<br />\n <a href=\"https://contractspec.io\" style=\"color: #8b5cf6;\">contractspec.io</a>\n </p>\n </div>\n `;\n\n const applicantSend = await sendEmail(configResult.config, {\n to: [{ email }],\n subject: \"You're on the ContractSpec design partner waitlist!\",\n text: applicantText,\n html: applicantHtml,\n context: 'waitlist-application-welcome',\n });\n\n if (!applicantSend.success) {\n return { success: false, text: APPLICATION_SEND_ERROR };\n }\n\n const preferencesText = `\nOpen to 1:1 product/design sessions: ${openToSessions ? 'Yes' : 'No'}\nOkay with anonymized case studies: ${okayWithCaseStudies ? 'Yes' : 'No'}\n `.trim();\n\n const teamEmailText = `\nNew Design Partner Waitlist Application\n\nContact Information:\n- Name: ${name}\n- Email: ${email}\n${company ? `- Company/Project: ${company}` : ''}\n${role ? `- Role: ${role}` : ''}\n\nApplication Details:\n- What are you building with AI today?\n${whatBuilding}\n\n- What do you hope ContractSpec will solve for you?\n${whatSolving}\n\n- Primary use case: ${useCase || 'Not specified'}\n- Current stack: ${currentStack || 'Not specified'}\n- Team Size: ${teamSize || 'Not specified'}\n- Timeline: ${timeline || 'Not specified'}\n\nPreferences:\n- Open to 1:1 product/design sessions: ${openToSessions ? 'Yes' : 'No'}\n- Okay with anonymized case studies: ${okayWithCaseStudies ? 'Yes' : 'No'}\n\n---\nSubmitted via ContractSpec waitlist application form\n `.trim();\n\n const teamEmailHtml = `\n <div style=\"font-family: sans-serif; max-width: 720px; margin: 0 auto;\">\n <h1 style=\"color: #8b5cf6;\">New Design Partner Waitlist Application</h1>\n <h2 style=\"color: #8b5cf6; margin: 16px 0 8px;\">Contact Information</h2>\n <ul style=\"padding-left: 16px; line-height: 1.6; margin: 0 0 16px;\">\n <li>Name: ${escapeHtml(name)}</li>\n <li>Email: ${escapeHtml(email)}</li>\n ${company ? `<li>Company/Project: ${escapeHtml(company)}</li>` : ''}\n ${role ? `<li>Role: ${escapeHtml(role)}</li>` : ''}\n </ul>\n <h2 style=\"color: #8b5cf6; margin: 16px 0 8px;\">Application Details</h2>\n <p style=\"margin: 0 0 8px; font-weight: 600;\">What are you building with AI today?</p>\n <div style=\"border: 1px solid #e5e7eb; border-radius: 8px; padding: 12px; background: #f9fafb; white-space: pre-wrap; line-height: 1.6;\">\n ${formatMultilineHtml(whatBuilding)}\n </div>\n <p style=\"margin: 16px 0 8px; font-weight: 600;\">What do you hope ContractSpec will solve for you?</p>\n <div style=\"border: 1px solid #e5e7eb; border-radius: 8px; padding: 12px; background: #f9fafb; white-space: pre-wrap; line-height: 1.6;\">\n ${formatMultilineHtml(whatSolving)}\n </div>\n <ul style=\"padding-left: 16px; line-height: 1.6; margin: 16px 0;\">\n <li>Primary use case: ${escapeHtml(useCase || 'Not specified')}</li>\n <li>Current stack: ${escapeHtml(currentStack || 'Not specified')}</li>\n <li>Team Size: ${escapeHtml(teamSize || 'Not specified')}</li>\n <li>Timeline: ${escapeHtml(timeline || 'Not specified')}</li>\n </ul>\n <h2 style=\"color: #8b5cf6; margin: 16px 0 8px;\">Preferences</h2>\n <div style=\"border: 1px solid #e5e7eb; border-radius: 8px; padding: 12px; background: #f9fafb; line-height: 1.6;\">\n ${formatMultilineHtml(preferencesText)}\n </div>\n <p style=\"color: #6b7280; font-size: 12px; margin-top: 20px;\">Submitted via ContractSpec waitlist application form</p>\n </div>\n `;\n\n const teamSend = await sendEmail(configResult.config, {\n to: [configResult.config.teamInbox],\n subject: `New Design Partner Application: ${name} (${email})`,\n text: teamEmailText,\n html: teamEmailHtml,\n replyTo: email,\n context: 'waitlist-application-team-notification',\n });\n\n if (!teamSend.success) {\n return { success: false, text: APPLICATION_SEND_ERROR };\n }\n\n return {\n success: true,\n text: 'Application submitted successfully!',\n };\n};\n"],"mappings":";;;;;;AAMA,MAAM,6BACJ;AACF,MAAM,yBACJ;AAEF,MAAa,4BAA4B,OACvC,aAC6C;CAC7C,MAAM,SAAS,SAAS,IAAI,QAAQ,IAAI,IAAI,UAAU,CAAC,MAAM;CAC7D,MAAM,QAAQ,SAAS,IAAI,OAAO,IAAI,IAAI,UAAU,CAAC,MAAM;CAC3D,MAAM,WAAW,SAAS,IAAI,UAAU,IAAI,IAAI,UAAU,CAAC,MAAM;CACjE,MAAM,QAAQ,SAAS,IAAI,OAAO,IAAI,IAAI,UAAU,CAAC,MAAM;CAC3D,MAAM,WAAW,SAAS,IAAI,UAAU,IAAI,IAAI,UAAU,CAAC,MAAM;CACjE,MAAM,gBAAgB,SAAS,IAAI,eAAe,IAAI,IAAI,UAAU,CAAC,MAAM;CAC3E,MAAM,gBAAgB,SAAS,IAAI,eAAe,IAAI,IAAI,UAAU,CAAC,MAAM;CAC3E,MAAM,eAAe,SAAS,IAAI,cAAc,IAAI,IAAI,UAAU,CAAC,MAAM;CACzE,MAAM,YAAY,SAAS,IAAI,WAAW,IAAI,IAAI,UAAU,CAAC,MAAM;CACnE,MAAM,YAAY,SAAS,IAAI,WAAW,IAAI,IAAI,UAAU,CAAC,MAAM;CAEnE,MAAM,iBAAiB,SAAS,IAAI,iBAAiB,KAAK;CAC1D,MAAM,sBAAsB,SAAS,IAAI,sBAAsB,KAAK;AAEpE,KAAI,CAAC,SAAS,CAAC,MAAM,SAAS,IAAI,CAChC,QAAO;EACL,SAAS;EACT,MAAM;EACP;AAGH,KAAI,CAAC,QAAQ,CAAC,gBAAgB,CAAC,YAC7B,QAAO;EACL,SAAS;EACT,MAAM;EACP;CAGH,MAAM,eAAe,gBAAgB;AACrC,KAAI,CAAC,aAAa,MAAM,CAAC,aAAa,OACpC,QAAO;EACL,SAAS;EACT,MAAM,aAAa,gBAAgB;EACpC;CAGH,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;IAmBpB,MAAM;AAkCR,KAAI,EARkB,MAAM,UAAU,aAAa,QAAQ;EACzD,IAAI,CAAC,EAAE,OAAO,CAAC;EACf,SAAS;EACT,MAAM;EACN,MA5BoB;;;;;;;;;;;;;;;;;;;;;;;EA6BpB,SAAS;EACV,CAAC,EAEiB,QACjB,QAAO;EAAE,SAAS;EAAO,MAAM;EAAwB;CAGzD,MAAM,kBAAkB;uCACa,iBAAiB,QAAQ,KAAK;qCAChC,sBAAsB,QAAQ,KAAK;IACpE,MAAM;CAER,MAAM,gBAAgB;;;;UAId,KAAK;WACJ,MAAM;EACf,UAAU,sBAAsB,YAAY,GAAG;EAC/C,OAAO,WAAW,SAAS,GAAG;;;;EAI9B,aAAa;;;EAGb,YAAY;;sBAEQ,WAAW,gBAAgB;mBAC9B,gBAAgB,gBAAgB;eACpC,YAAY,gBAAgB;cAC7B,YAAY,gBAAgB;;;yCAGD,iBAAiB,QAAQ,KAAK;uCAChC,sBAAsB,QAAQ,KAAK;;;;IAItE,MAAM;CAER,MAAM,gBAAgB;;;;;oBAKJ,WAAW,KAAK,CAAC;qBAChB,WAAW,MAAM,CAAC;UAC7B,UAAU,wBAAwB,WAAW,QAAQ,CAAC,SAAS,GAAG;UAClE,OAAO,aAAa,WAAW,KAAK,CAAC,SAAS,GAAG;;;;;UAKjD,oBAAoB,aAAa,CAAC;;;;UAIlC,oBAAoB,YAAY,CAAC;;;gCAGX,WAAW,WAAW,gBAAgB,CAAC;6BAC1C,WAAW,gBAAgB,gBAAgB,CAAC;yBAChD,WAAW,YAAY,gBAAgB,CAAC;wBACzC,WAAW,YAAY,gBAAgB,CAAC;;;;UAItD,oBAAoB,gBAAgB,CAAC;;;;;AAe7C,KAAI,EATa,MAAM,UAAU,aAAa,QAAQ;EACpD,IAAI,CAAC,aAAa,OAAO,UAAU;EACnC,SAAS,mCAAmC,KAAK,IAAI,MAAM;EAC3D,MAAM;EACN,MAAM;EACN,SAAS;EACT,SAAS;EACV,CAAC,EAEY,QACZ,QAAO;EAAE,SAAS;EAAO,MAAM;EAAwB;AAGzD,QAAO;EACL,SAAS;EACT,MAAM;EACP"}
@@ -0,0 +1,7 @@
1
+ import { SubmitWaitlistResult } from "./types.js";
2
+
3
+ //#region src/libs/email/waitlist.d.ts
4
+ declare const joinWaitlist: (formData: FormData) => Promise<SubmitWaitlistResult>;
5
+ //#endregion
6
+ export { joinWaitlist };
7
+ //# sourceMappingURL=waitlist.d.ts.map