@intelligo-dev/core 1.0.0-beta.1 → 1.0.0-beta.14

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 (356) hide show
  1. package/NOTICE +6 -0
  2. package/README.md +102 -0
  3. package/dist/attachments/errors.d.ts +7 -0
  4. package/dist/attachments/errors.d.ts.map +1 -0
  5. package/dist/attachments/errors.js +11 -0
  6. package/dist/attachments/errors.js.map +1 -0
  7. package/dist/attachments/index.d.ts +8 -0
  8. package/dist/attachments/index.d.ts.map +1 -0
  9. package/dist/attachments/index.js +7 -0
  10. package/dist/attachments/index.js.map +1 -0
  11. package/dist/attachments/service.d.ts +45 -0
  12. package/dist/attachments/service.d.ts.map +1 -0
  13. package/dist/attachments/service.js +100 -0
  14. package/dist/attachments/service.js.map +1 -0
  15. package/dist/attachments/types.d.ts +6 -0
  16. package/dist/attachments/types.d.ts.map +1 -0
  17. package/dist/attachments/types.js +2 -0
  18. package/dist/attachments/types.js.map +1 -0
  19. package/dist/conversations/errors.d.ts +2 -8
  20. package/dist/conversations/errors.d.ts.map +1 -1
  21. package/dist/conversations/errors.js +2 -8
  22. package/dist/conversations/errors.js.map +1 -1
  23. package/dist/conversations/index.d.ts +4 -12
  24. package/dist/conversations/index.d.ts.map +1 -1
  25. package/dist/conversations/index.js +2 -11
  26. package/dist/conversations/index.js.map +1 -1
  27. package/dist/conversations/service.d.ts +49 -61
  28. package/dist/conversations/service.d.ts.map +1 -1
  29. package/dist/conversations/service.js +110 -83
  30. package/dist/conversations/service.js.map +1 -1
  31. package/dist/conversations/types.d.ts +1 -4
  32. package/dist/conversations/types.d.ts.map +1 -1
  33. package/dist/conversations/types.js +0 -3
  34. package/dist/conversations/types.js.map +1 -1
  35. package/dist/db/client.d.ts +21 -10
  36. package/dist/db/client.d.ts.map +1 -1
  37. package/dist/db/client.js +43 -18
  38. package/dist/db/client.js.map +1 -1
  39. package/dist/db/index.d.ts +3 -3
  40. package/dist/db/index.d.ts.map +1 -1
  41. package/dist/db/index.js +3 -7
  42. package/dist/db/index.js.map +1 -1
  43. package/dist/db/schema/agents.d.ts +14 -51
  44. package/dist/db/schema/agents.d.ts.map +1 -1
  45. package/dist/db/schema/agents.js +9 -21
  46. package/dist/db/schema/agents.js.map +1 -1
  47. package/dist/db/schema/ai.d.ts +86 -1556
  48. package/dist/db/schema/ai.d.ts.map +1 -1
  49. package/dist/db/schema/ai.js +32 -236
  50. package/dist/db/schema/ai.js.map +1 -1
  51. package/dist/db/schema/auth.d.ts +5 -34
  52. package/dist/db/schema/auth.d.ts.map +1 -1
  53. package/dist/db/schema/auth.js +25 -56
  54. package/dist/db/schema/auth.js.map +1 -1
  55. package/dist/db/schema/billing.d.ts +339 -105
  56. package/dist/db/schema/billing.d.ts.map +1 -1
  57. package/dist/db/schema/billing.js +99 -58
  58. package/dist/db/schema/billing.js.map +1 -1
  59. package/dist/db/schema/feature-flags.d.ts +3 -12
  60. package/dist/db/schema/feature-flags.d.ts.map +1 -1
  61. package/dist/db/schema/feature-flags.js +3 -12
  62. package/dist/db/schema/feature-flags.js.map +1 -1
  63. package/dist/db/schema/identity.d.ts +12 -274
  64. package/dist/db/schema/identity.d.ts.map +1 -1
  65. package/dist/db/schema/identity.js +19 -104
  66. package/dist/db/schema/identity.js.map +1 -1
  67. package/dist/db/schema/index.d.ts +8 -15
  68. package/dist/db/schema/index.d.ts.map +1 -1
  69. package/dist/db/schema/index.js +12 -42
  70. package/dist/db/schema/index.js.map +1 -1
  71. package/dist/db/schema/notifications.d.ts +3 -17
  72. package/dist/db/schema/notifications.d.ts.map +1 -1
  73. package/dist/db/schema/notifications.js +3 -17
  74. package/dist/db/schema/notifications.js.map +1 -1
  75. package/dist/db/schema/usage.d.ts +94 -77
  76. package/dist/db/schema/usage.d.ts.map +1 -1
  77. package/dist/db/schema/usage.js +59 -89
  78. package/dist/db/schema/usage.js.map +1 -1
  79. package/dist/db/validate.d.ts +2 -11
  80. package/dist/db/validate.d.ts.map +1 -1
  81. package/dist/db/validate.js +6 -17
  82. package/dist/db/validate.js.map +1 -1
  83. package/dist/db/workspace-queries.d.ts +5 -29
  84. package/dist/db/workspace-queries.d.ts.map +1 -1
  85. package/dist/db/workspace-queries.js +5 -29
  86. package/dist/db/workspace-queries.js.map +1 -1
  87. package/dist/documents/classifier.d.ts +5 -12
  88. package/dist/documents/classifier.d.ts.map +1 -1
  89. package/dist/documents/classifier.js +16 -16
  90. package/dist/documents/classifier.js.map +1 -1
  91. package/dist/documents/errors.d.ts +2 -10
  92. package/dist/documents/errors.d.ts.map +1 -1
  93. package/dist/documents/errors.js +2 -10
  94. package/dist/documents/errors.js.map +1 -1
  95. package/dist/documents/index.d.ts +4 -13
  96. package/dist/documents/index.d.ts.map +1 -1
  97. package/dist/documents/index.js +3 -12
  98. package/dist/documents/index.js.map +1 -1
  99. package/dist/documents/service.d.ts +19 -26
  100. package/dist/documents/service.d.ts.map +1 -1
  101. package/dist/documents/service.js +44 -38
  102. package/dist/documents/service.js.map +1 -1
  103. package/dist/documents/types.d.ts +6 -10
  104. package/dist/documents/types.d.ts.map +1 -1
  105. package/dist/documents/types.js +0 -3
  106. package/dist/documents/types.js.map +1 -1
  107. package/dist/email/brand.d.ts +17 -0
  108. package/dist/email/brand.d.ts.map +1 -0
  109. package/dist/email/brand.js +9 -0
  110. package/dist/email/brand.js.map +1 -0
  111. package/dist/email/index.d.ts +4 -4
  112. package/dist/email/index.js +4 -4
  113. package/dist/email/provider.d.ts +1 -7
  114. package/dist/email/provider.d.ts.map +1 -1
  115. package/dist/email/provider.js +10 -19
  116. package/dist/email/provider.js.map +1 -1
  117. package/dist/email/send.d.ts +12 -12
  118. package/dist/email/send.d.ts.map +1 -1
  119. package/dist/email/send.js +5 -19
  120. package/dist/email/send.js.map +1 -1
  121. package/dist/email/senders.d.ts +17 -30
  122. package/dist/email/senders.d.ts.map +1 -1
  123. package/dist/email/senders.js +33 -47
  124. package/dist/email/senders.js.map +1 -1
  125. package/dist/email/templates/base-layout.d.ts +1 -1
  126. package/dist/email/templates/base-layout.d.ts.map +1 -1
  127. package/dist/email/templates/base-layout.js +4 -6
  128. package/dist/email/templates/base-layout.js.map +1 -1
  129. package/dist/email/templates/index.d.ts +10 -10
  130. package/dist/email/templates/index.d.ts.map +1 -1
  131. package/dist/email/templates/index.js +10 -16
  132. package/dist/email/templates/index.js.map +1 -1
  133. package/dist/email/templates/password-reset.d.ts +2 -2
  134. package/dist/email/templates/password-reset.d.ts.map +1 -1
  135. package/dist/email/templates/password-reset.js +10 -22
  136. package/dist/email/templates/password-reset.js.map +1 -1
  137. package/dist/email/templates/payment-failed.d.ts +2 -2
  138. package/dist/email/templates/payment-failed.d.ts.map +1 -1
  139. package/dist/email/templates/payment-failed.js +11 -24
  140. package/dist/email/templates/payment-failed.js.map +1 -1
  141. package/dist/email/templates/quota-warning.d.ts +4 -4
  142. package/dist/email/templates/quota-warning.d.ts.map +1 -1
  143. package/dist/email/templates/quota-warning.js +19 -39
  144. package/dist/email/templates/quota-warning.js.map +1 -1
  145. package/dist/email/templates/subscription-confirmed.d.ts +2 -2
  146. package/dist/email/templates/subscription-confirmed.d.ts.map +1 -1
  147. package/dist/email/templates/subscription-confirmed.js +13 -28
  148. package/dist/email/templates/subscription-confirmed.js.map +1 -1
  149. package/dist/email/templates/trial-expiry.d.ts +2 -2
  150. package/dist/email/templates/trial-expiry.d.ts.map +1 -1
  151. package/dist/email/templates/trial-expiry.js +12 -36
  152. package/dist/email/templates/trial-expiry.js.map +1 -1
  153. package/dist/email/templates/trial-warning.d.ts +2 -2
  154. package/dist/email/templates/trial-warning.d.ts.map +1 -1
  155. package/dist/email/templates/trial-warning.js +15 -32
  156. package/dist/email/templates/trial-warning.js.map +1 -1
  157. package/dist/email/templates/verify-email.d.ts +2 -2
  158. package/dist/email/templates/verify-email.d.ts.map +1 -1
  159. package/dist/email/templates/verify-email.js +10 -22
  160. package/dist/email/templates/verify-email.js.map +1 -1
  161. package/dist/email/templates/welcome.d.ts +2 -2
  162. package/dist/email/templates/welcome.d.ts.map +1 -1
  163. package/dist/email/templates/welcome.js +13 -20
  164. package/dist/email/templates/welcome.js.map +1 -1
  165. package/dist/email/templates/workspace-invitation.d.ts +2 -2
  166. package/dist/email/templates/workspace-invitation.d.ts.map +1 -1
  167. package/dist/email/templates/workspace-invitation.js +12 -26
  168. package/dist/email/templates/workspace-invitation.js.map +1 -1
  169. package/dist/env.d.ts +5 -10
  170. package/dist/env.d.ts.map +1 -1
  171. package/dist/env.js +41 -31
  172. package/dist/env.js.map +1 -1
  173. package/dist/identity/audit.d.ts +11 -24
  174. package/dist/identity/audit.d.ts.map +1 -1
  175. package/dist/identity/audit.js +13 -27
  176. package/dist/identity/audit.js.map +1 -1
  177. package/dist/identity/errors.d.ts +4 -12
  178. package/dist/identity/errors.d.ts.map +1 -1
  179. package/dist/identity/errors.js +2 -8
  180. package/dist/identity/errors.js.map +1 -1
  181. package/dist/identity/index.d.ts +6 -13
  182. package/dist/identity/index.d.ts.map +1 -1
  183. package/dist/identity/index.js +5 -12
  184. package/dist/identity/index.js.map +1 -1
  185. package/dist/identity/service.d.ts +29 -47
  186. package/dist/identity/service.d.ts.map +1 -1
  187. package/dist/identity/service.js +107 -79
  188. package/dist/identity/service.js.map +1 -1
  189. package/dist/identity/types.d.ts +28 -4
  190. package/dist/identity/types.d.ts.map +1 -1
  191. package/dist/identity/types.js +0 -3
  192. package/dist/identity/types.js.map +1 -1
  193. package/dist/index.d.ts +1 -2
  194. package/dist/index.d.ts.map +1 -1
  195. package/dist/index.js +3 -10
  196. package/dist/index.js.map +1 -1
  197. package/dist/logger.d.ts +7 -18
  198. package/dist/logger.d.ts.map +1 -1
  199. package/dist/logger.js +45 -49
  200. package/dist/logger.js.map +1 -1
  201. package/dist/money.d.ts +95 -0
  202. package/dist/money.d.ts.map +1 -0
  203. package/dist/money.js +208 -0
  204. package/dist/money.js.map +1 -0
  205. package/dist/notifications/index.d.ts +9 -43
  206. package/dist/notifications/index.d.ts.map +1 -1
  207. package/dist/notifications/index.js +9 -49
  208. package/dist/notifications/index.js.map +1 -1
  209. package/dist/notifications/triggers.d.ts +9 -32
  210. package/dist/notifications/triggers.d.ts.map +1 -1
  211. package/dist/notifications/triggers.js +21 -58
  212. package/dist/notifications/triggers.js.map +1 -1
  213. package/dist/notifications/types.d.ts +6 -8
  214. package/dist/notifications/types.d.ts.map +1 -1
  215. package/dist/notifications/types.js +0 -9
  216. package/dist/notifications/types.js.map +1 -1
  217. package/dist/prompt.d.ts +38 -0
  218. package/dist/prompt.d.ts.map +1 -0
  219. package/dist/prompt.js +118 -0
  220. package/dist/prompt.js.map +1 -0
  221. package/dist/registry.d.ts +32 -0
  222. package/dist/registry.d.ts.map +1 -0
  223. package/dist/registry.js +60 -0
  224. package/dist/registry.js.map +1 -0
  225. package/dist/request-context.d.ts +49 -0
  226. package/dist/request-context.d.ts.map +1 -0
  227. package/dist/request-context.js +100 -0
  228. package/dist/request-context.js.map +1 -0
  229. package/dist/storage/index.d.ts +65 -0
  230. package/dist/storage/index.d.ts.map +1 -0
  231. package/dist/storage/index.js +109 -0
  232. package/dist/storage/index.js.map +1 -0
  233. package/package.json +74 -24
  234. package/src/attachments/errors.ts +18 -0
  235. package/src/attachments/index.ts +22 -0
  236. package/src/attachments/service.ts +178 -0
  237. package/src/attachments/types.ts +6 -0
  238. package/src/conversations/errors.ts +45 -0
  239. package/src/conversations/index.ts +39 -0
  240. package/src/conversations/service.ts +594 -0
  241. package/src/conversations/types.ts +15 -0
  242. package/src/db/client.ts +91 -0
  243. package/src/db/index.ts +3 -0
  244. package/src/db/migrations/0000_baseline.sql +652 -0
  245. package/src/db/migrations/0001_reconcile_chain_built_databases.sql +53 -0
  246. package/src/db/migrations/0002_webhook_claim_lease.sql +1 -0
  247. package/src/db/migrations/0003_local_payments.sql +18 -0
  248. package/src/db/migrations/README.md +103 -36
  249. package/src/db/migrations/legacy-chain.json +206 -0
  250. package/src/db/migrations/meta/0000_snapshot.json +4182 -157
  251. package/src/db/migrations/meta/0002_snapshot.json +2478 -368
  252. package/src/db/migrations/meta/0003_snapshot.json +2567 -554
  253. package/src/db/migrations/meta/_journal.json +8 -274
  254. package/src/db/schema/agents.ts +57 -0
  255. package/src/db/schema/ai.ts +174 -0
  256. package/src/db/schema/auth.ts +183 -0
  257. package/src/db/schema/billing.ts +245 -0
  258. package/src/db/schema/feature-flags.ts +20 -0
  259. package/src/db/schema/identity.ts +250 -0
  260. package/src/db/schema/index.ts +12 -0
  261. package/src/db/schema/notifications.ts +31 -0
  262. package/src/db/schema/usage.ts +269 -0
  263. package/src/db/validate.ts +63 -0
  264. package/src/db/workspace-queries.ts +64 -0
  265. package/src/documents/classifier.ts +61 -0
  266. package/src/documents/errors.ts +44 -0
  267. package/src/documents/index.ts +24 -0
  268. package/src/documents/service.ts +256 -0
  269. package/src/documents/types.ts +24 -0
  270. package/src/email/brand.ts +24 -0
  271. package/src/email/index.ts +19 -0
  272. package/src/email/provider.ts +278 -0
  273. package/src/email/send.ts +169 -0
  274. package/src/email/senders.ts +292 -0
  275. package/src/email/templates/base-layout.tsx +145 -0
  276. package/src/email/templates/index.ts +28 -0
  277. package/src/email/templates/password-reset.tsx +72 -0
  278. package/src/email/templates/payment-failed.tsx +77 -0
  279. package/src/email/templates/quota-warning.tsx +118 -0
  280. package/src/email/templates/subscription-confirmed.tsx +91 -0
  281. package/src/email/templates/trial-expiry.tsx +124 -0
  282. package/src/email/templates/trial-warning.tsx +104 -0
  283. package/src/email/templates/verify-email.tsx +72 -0
  284. package/src/email/templates/welcome.tsx +64 -0
  285. package/src/email/templates/workspace-invitation.tsx +105 -0
  286. package/src/env.ts +180 -0
  287. package/src/identity/audit.ts +65 -0
  288. package/src/identity/errors.ts +44 -0
  289. package/src/identity/index.ts +29 -0
  290. package/src/identity/service.ts +303 -0
  291. package/src/identity/types.ts +58 -0
  292. package/src/index.ts +4 -0
  293. package/src/logger.ts +198 -0
  294. package/src/money.ts +270 -0
  295. package/src/notifications/index.ts +112 -0
  296. package/src/notifications/triggers.ts +158 -0
  297. package/src/notifications/types.ts +26 -0
  298. package/src/prompt.ts +142 -0
  299. package/src/registry.ts +75 -0
  300. package/src/request-context.ts +137 -0
  301. package/src/storage/index.ts +153 -0
  302. package/dist/db/schema/rag.d.ts +0 -171
  303. package/dist/db/schema/rag.d.ts.map +0 -1
  304. package/dist/db/schema/rag.js +0 -42
  305. package/dist/db/schema/rag.js.map +0 -1
  306. package/src/db/migrations/0000_sharp_night_nurse.sql +0 -52
  307. package/src/db/migrations/0001_hesitant_vapor.sql +0 -40
  308. package/src/db/migrations/0002_numerous_lady_vermin.sql +0 -235
  309. package/src/db/migrations/0003_mighty_jean_grey.sql +0 -37
  310. package/src/db/migrations/0004_cynical_grandmaster.sql +0 -2
  311. package/src/db/migrations/0005_careful_switch.sql +0 -8
  312. package/src/db/migrations/0006_tense_blue_marvel.sql +0 -16
  313. package/src/db/migrations/0007_next_squadron_sinister.sql +0 -1
  314. package/src/db/migrations/0008_powerful_scream.sql +0 -39
  315. package/src/db/migrations/0009_sad_ink.sql +0 -1
  316. package/src/db/migrations/0010_shocking_omega_flight.sql +0 -2
  317. package/src/db/migrations/0011_ambiguous_otto_octavius.sql +0 -151
  318. package/src/db/migrations/0011_hnsw_vector_index.sql +0 -17
  319. package/src/db/migrations/0012_user_profiles.sql +0 -30
  320. package/src/db/migrations/0013_trending_seasonal_columns.sql +0 -9
  321. package/src/db/migrations/0014_add_product_type_to_agents.sql +0 -6
  322. package/src/db/migrations/0015_new_v1_tables.sql +0 -149
  323. package/src/db/migrations/0016_document_types.sql +0 -30
  324. package/src/db/migrations/0017_document_metadata.sql +0 -2
  325. package/src/db/migrations/0018_identity_graph.sql +0 -200
  326. package/src/db/migrations/0019_db_driven_prompts.sql +0 -20
  327. package/src/db/migrations/0020_pending_extractions.sql +0 -35
  328. package/src/db/migrations/0021_rag_documents.sql +0 -39
  329. package/src/db/migrations/0022_user_quotas_usage_jsonb.sql +0 -70
  330. package/src/db/migrations/0023_user_facts_user_scoped_unique.sql +0 -17
  331. package/src/db/migrations/0024_user_memories_hnsw.sql +0 -23
  332. package/src/db/migrations/0025_audit_trigger_errcode.sql +0 -21
  333. package/src/db/migrations/0026_user_profile_snapshots_composite_pk.sql +0 -17
  334. package/src/db/migrations/0027_billing_settings_mnt_columns.sql +0 -54
  335. package/src/db/migrations/0028_trial_credits_normalized_email.sql +0 -37
  336. package/src/db/migrations/0029_usage_records_conversation_idx.sql +0 -13
  337. package/src/db/migrations/0030_pending_extractions_composite_idx.sql +0 -11
  338. package/src/db/migrations/0031_rag_documents_hnsw.sql +0 -16
  339. package/src/db/migrations/0032_rate_limit_unique_idx.sql +0 -16
  340. package/src/db/migrations/0033_pending_extractions_partial_idx.sql +0 -18
  341. package/src/db/migrations/0034_rate_limit_count.sql +0 -9
  342. package/src/db/migrations/0035_credit_reservations.sql +0 -24
  343. package/src/db/migrations/0036_executions_audit_jobs.sql +0 -96
  344. package/src/db/migrations/0037_rate_limit_minute_bucket.sql +0 -46
  345. package/src/db/migrations/0038_user_quotas_generic_usage.sql +0 -25
  346. package/src/db/migrations/0039_platform_admin_impersonation.sql +0 -27
  347. package/src/db/migrations/0040_ee_audit_chain.sql +0 -23
  348. package/src/db/migrations/meta/0001_snapshot.json +0 -631
  349. package/src/db/migrations/meta/0004_snapshot.json +0 -2500
  350. package/src/db/migrations/meta/0005_snapshot.json +0 -2548
  351. package/src/db/migrations/meta/0006_snapshot.json +0 -2650
  352. package/src/db/migrations/meta/0007_snapshot.json +0 -2657
  353. package/src/db/migrations/meta/0008_snapshot.json +0 -2719
  354. package/src/db/migrations/meta/0009_snapshot.json +0 -2726
  355. package/src/db/migrations/meta/0010_snapshot.json +0 -2739
  356. package/src/db/migrations/meta/0011_snapshot.json +0 -3886
@@ -0,0 +1,292 @@
1
+ /**
2
+ * Typed wrappers that render a React Email template and send it. They never
3
+ * throw; each returns a SendEmailResult.
4
+ *
5
+ * Every sender attaches a stable `template` key and flat variables so
6
+ * template-based providers (Loops) can send the same email; HTML providers
7
+ * ignore it. Boolean variants use distinct keys (quota-warning /
8
+ * quota-exceeded, trial-warning / trial-depleted) because template providers
9
+ * branch per template, not per variable.
10
+ */
11
+
12
+ import * as React from "react";
13
+ import { emailBrand } from "./brand";
14
+ import { sendEmail, type SendEmailResult } from "./send";
15
+ import { formatMoney, type Money } from "../money";
16
+ import {
17
+ WelcomeEmail,
18
+ VerifyEmailEmail,
19
+ PasswordResetEmail,
20
+ WorkspaceInvitationEmail,
21
+ QuotaWarningEmail,
22
+ TrialWarningEmail,
23
+ TrialExpiryEmail,
24
+ PaymentFailedEmail,
25
+ SubscriptionConfirmedEmail,
26
+ } from "./templates";
27
+
28
+ /** The locale the email copy is written in; amounts are formatted to match. */
29
+ const EMAIL_LOCALE = "en";
30
+
31
+ export async function sendWelcomeEmail(params: {
32
+ to: string;
33
+ userName: string;
34
+ dashboardUrl: string;
35
+ }): Promise<SendEmailResult> {
36
+ return sendEmail({
37
+ to: params.to,
38
+ subject: emailBrand().name
39
+ ? `Welcome to ${emailBrand().name}!`
40
+ : "Welcome!",
41
+ react: React.createElement(WelcomeEmail, {
42
+ userName: params.userName,
43
+ dashboardUrl: params.dashboardUrl,
44
+ }),
45
+ template: {
46
+ key: "welcome",
47
+ variables: {
48
+ userName: params.userName,
49
+ dashboardUrl: params.dashboardUrl,
50
+ },
51
+ },
52
+ });
53
+ }
54
+
55
+ export async function sendVerifyEmail(params: {
56
+ to: string;
57
+ userName: string;
58
+ verificationUrl: string;
59
+ }): Promise<SendEmailResult> {
60
+ return sendEmail({
61
+ to: params.to,
62
+ subject: "Verify your email address",
63
+ react: React.createElement(VerifyEmailEmail, {
64
+ userName: params.userName,
65
+ verificationUrl: params.verificationUrl,
66
+ }),
67
+ template: {
68
+ key: "verify-email",
69
+ variables: {
70
+ userName: params.userName,
71
+ verificationUrl: params.verificationUrl,
72
+ },
73
+ },
74
+ });
75
+ }
76
+
77
+ export async function sendPasswordResetEmail(params: {
78
+ to: string;
79
+ userName: string;
80
+ resetUrl: string;
81
+ }): Promise<SendEmailResult> {
82
+ return sendEmail({
83
+ to: params.to,
84
+ subject: "Reset your password",
85
+ react: React.createElement(PasswordResetEmail, {
86
+ userName: params.userName,
87
+ resetUrl: params.resetUrl,
88
+ }),
89
+ template: {
90
+ key: "password-reset",
91
+ variables: {
92
+ userName: params.userName,
93
+ resetUrl: params.resetUrl,
94
+ },
95
+ },
96
+ });
97
+ }
98
+
99
+ export async function sendInvitationEmail(params: {
100
+ to: string;
101
+ inviterName: string;
102
+ workspaceName: string;
103
+ role: string;
104
+ acceptUrl: string;
105
+ declineUrl: string;
106
+ }): Promise<SendEmailResult> {
107
+ return sendEmail({
108
+ to: params.to,
109
+ subject: `${params.inviterName} invited you to ${params.workspaceName}`,
110
+ react: React.createElement(WorkspaceInvitationEmail, {
111
+ inviterName: params.inviterName,
112
+ workspaceName: params.workspaceName,
113
+ role: params.role,
114
+ acceptUrl: params.acceptUrl,
115
+ declineUrl: params.declineUrl,
116
+ }),
117
+ template: {
118
+ key: "workspace-invitation",
119
+ variables: {
120
+ inviterName: params.inviterName,
121
+ workspaceName: params.workspaceName,
122
+ role: params.role,
123
+ acceptUrl: params.acceptUrl,
124
+ declineUrl: params.declineUrl,
125
+ },
126
+ },
127
+ });
128
+ }
129
+
130
+ /**
131
+ * Send the allowance warning or used-up email. `used` and `allowance`
132
+ * are money in the deployment's billing currency; the template and the
133
+ * provider variables receive them formatted.
134
+ */
135
+ export async function sendQuotaWarningEmail(params: {
136
+ to: string;
137
+ workspaceName: string;
138
+ percentageUsed: number;
139
+ used: Money;
140
+ allowance: Money;
141
+ upgradeUrl: string;
142
+ isExceeded: boolean;
143
+ }): Promise<SendEmailResult> {
144
+ const used = formatMoney(params.used, EMAIL_LOCALE);
145
+ const allowance = formatMoney(params.allowance, EMAIL_LOCALE);
146
+
147
+ return sendEmail({
148
+ to: params.to,
149
+ subject: params.isExceeded
150
+ ? "Monthly allowance used up"
151
+ : `Monthly allowance at ${params.percentageUsed}%`,
152
+ react: React.createElement(QuotaWarningEmail, {
153
+ workspaceName: params.workspaceName,
154
+ percentageUsed: params.percentageUsed,
155
+ used,
156
+ allowance,
157
+ upgradeUrl: params.upgradeUrl,
158
+ isExceeded: params.isExceeded,
159
+ }),
160
+ template: {
161
+ key: params.isExceeded ? "quota-exceeded" : "quota-warning",
162
+ variables: {
163
+ workspaceName: params.workspaceName,
164
+ percentageUsed: params.percentageUsed,
165
+ used,
166
+ allowance,
167
+ currency: params.allowance.currency,
168
+ upgradeUrl: params.upgradeUrl,
169
+ },
170
+ },
171
+ });
172
+ }
173
+
174
+ /** Send trial warning or depleted email. */
175
+ export async function sendTrialWarningEmail(params: {
176
+ to: string;
177
+ workspaceName: string;
178
+ creditsRemaining: number;
179
+ totalCredits: number;
180
+ percentageRemaining: number;
181
+ upgradeUrl: string;
182
+ isDepleted: boolean;
183
+ }): Promise<SendEmailResult> {
184
+ return sendEmail({
185
+ to: params.to,
186
+ subject: params.isDepleted
187
+ ? "Trial credits depleted"
188
+ : "Trial credits running low",
189
+ react: React.createElement(TrialWarningEmail, {
190
+ workspaceName: params.workspaceName,
191
+ creditsRemaining: params.creditsRemaining,
192
+ totalCredits: params.totalCredits,
193
+ percentageRemaining: params.percentageRemaining,
194
+ upgradeUrl: params.upgradeUrl,
195
+ isDepleted: params.isDepleted,
196
+ }),
197
+ template: {
198
+ key: params.isDepleted ? "trial-depleted" : "trial-warning",
199
+ variables: {
200
+ workspaceName: params.workspaceName,
201
+ creditsRemaining: params.creditsRemaining,
202
+ totalCredits: params.totalCredits,
203
+ percentageRemaining: params.percentageRemaining,
204
+ upgradeUrl: params.upgradeUrl,
205
+ },
206
+ },
207
+ });
208
+ }
209
+
210
+ export async function sendPaymentFailedEmail(params: {
211
+ to: string;
212
+ workspaceName: string;
213
+ amount: string;
214
+ updatePaymentUrl: string;
215
+ }): Promise<SendEmailResult> {
216
+ return sendEmail({
217
+ to: params.to,
218
+ subject: `Payment failed for ${params.workspaceName}`,
219
+ react: React.createElement(PaymentFailedEmail, {
220
+ workspaceName: params.workspaceName,
221
+ amount: params.amount,
222
+ updatePaymentUrl: params.updatePaymentUrl,
223
+ }),
224
+ template: {
225
+ key: "payment-failed",
226
+ variables: {
227
+ workspaceName: params.workspaceName,
228
+ amount: params.amount,
229
+ updatePaymentUrl: params.updatePaymentUrl,
230
+ },
231
+ },
232
+ });
233
+ }
234
+
235
+ export async function sendSubscriptionConfirmedEmail(params: {
236
+ to: string;
237
+ workspaceName: string;
238
+ planName: string;
239
+ amount: string;
240
+ dashboardUrl: string;
241
+ }): Promise<SendEmailResult> {
242
+ return sendEmail({
243
+ to: params.to,
244
+ subject: `Subscription confirmed - ${params.planName} plan`,
245
+ react: React.createElement(SubscriptionConfirmedEmail, {
246
+ workspaceName: params.workspaceName,
247
+ planName: params.planName,
248
+ amount: params.amount,
249
+ dashboardUrl: params.dashboardUrl,
250
+ }),
251
+ template: {
252
+ key: "subscription-confirmed",
253
+ variables: {
254
+ workspaceName: params.workspaceName,
255
+ planName: params.planName,
256
+ amount: params.amount,
257
+ dashboardUrl: params.dashboardUrl,
258
+ },
259
+ },
260
+ });
261
+ }
262
+
263
+ export async function sendTrialExpiryEmail(params: {
264
+ to: string;
265
+ workspaceName: string;
266
+ expiryDate: string;
267
+ daysRemaining: number;
268
+ upgradeUrl: string;
269
+ }): Promise<SendEmailResult> {
270
+ return sendEmail({
271
+ to: params.to,
272
+ subject:
273
+ params.daysRemaining <= 0
274
+ ? `Your trial for ${params.workspaceName} has ended`
275
+ : `Your trial ends in ${params.daysRemaining} day${params.daysRemaining === 1 ? "" : "s"}`,
276
+ react: React.createElement(TrialExpiryEmail, {
277
+ workspaceName: params.workspaceName,
278
+ expiryDate: params.expiryDate,
279
+ daysRemaining: params.daysRemaining,
280
+ upgradeUrl: params.upgradeUrl,
281
+ }),
282
+ template: {
283
+ key: "trial-expiry",
284
+ variables: {
285
+ workspaceName: params.workspaceName,
286
+ expiryDate: params.expiryDate,
287
+ daysRemaining: params.daysRemaining,
288
+ upgradeUrl: params.upgradeUrl,
289
+ },
290
+ },
291
+ });
292
+ }
@@ -0,0 +1,145 @@
1
+ import {
2
+ Body,
3
+ Container,
4
+ Head,
5
+ Hr,
6
+ Html,
7
+ Link,
8
+ Preview,
9
+ Section,
10
+ Text,
11
+ } from "@react-email/components";
12
+ import * as React from "react";
13
+
14
+ import { emailBrand } from "../brand";
15
+
16
+ // Inline styles only: email clients do not reliably support CSS classes.
17
+ // Colors are literal values, not CSS variables, so they survive dark-mode
18
+ // email clients.
19
+
20
+ export interface BaseLayoutProps {
21
+ preview: string;
22
+ children: React.ReactNode;
23
+ }
24
+
25
+ const colors = {
26
+ background: "#f4f4f5", // zinc-100
27
+ container: "#ffffff",
28
+ text: "#18181b", // zinc-900
29
+ muted: "#71717a", // zinc-500
30
+ brand: "#7c3aed", // violet-600
31
+ border: "#e4e4e7", // zinc-200
32
+ } as const;
33
+
34
+ export function BaseLayout({ preview, children }: BaseLayoutProps) {
35
+ const brand = emailBrand();
36
+ return (
37
+ <Html lang="en">
38
+ <Head>
39
+ <meta charSet="utf-8" />
40
+ </Head>
41
+ <Preview>{preview}</Preview>
42
+ <Body style={bodyStyle}>
43
+ <Container style={containerStyle}>
44
+ {brand.name ? (
45
+ <Section style={headerStyle}>
46
+ <Text style={logoStyle}>{brand.name}</Text>
47
+ </Section>
48
+ ) : null}
49
+
50
+ <Hr style={hrStyle} />
51
+
52
+ <Section style={contentStyle}>{children}</Section>
53
+
54
+ <Hr style={hrStyle} />
55
+
56
+ <Section style={footerStyle}>
57
+ {brand.name ? (
58
+ <Text style={footerTextStyle}>{brand.name}</Text>
59
+ ) : null}
60
+ <Text style={footerMutedStyle}>
61
+ This is a transactional email
62
+ {brand.name ? ` from ${brand.name}` : ""}.
63
+ {brand.supportEmail ? (
64
+ <>
65
+ {" "}
66
+ If you believe you received this email in error, please
67
+ contact{" "}
68
+ <Link
69
+ href={`mailto:${brand.supportEmail}`}
70
+ style={footerLinkStyle}
71
+ >
72
+ {brand.supportEmail}
73
+ </Link>
74
+ .
75
+ </>
76
+ ) : null}
77
+ </Text>
78
+ </Section>
79
+ </Container>
80
+ </Body>
81
+ </Html>
82
+ );
83
+ }
84
+
85
+ const bodyStyle: React.CSSProperties = {
86
+ backgroundColor: colors.background,
87
+ fontFamily:
88
+ '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif',
89
+ margin: 0,
90
+ padding: "40px 0",
91
+ };
92
+
93
+ const containerStyle: React.CSSProperties = {
94
+ backgroundColor: colors.container,
95
+ borderRadius: "8px",
96
+ maxWidth: "600px",
97
+ margin: "0 auto",
98
+ border: `1px solid ${colors.border}`,
99
+ };
100
+
101
+ const headerStyle: React.CSSProperties = {
102
+ padding: "32px 40px 16px",
103
+ };
104
+
105
+ const logoStyle: React.CSSProperties = {
106
+ color: colors.brand,
107
+ fontSize: "24px",
108
+ fontWeight: 700,
109
+ margin: 0,
110
+ lineHeight: "32px",
111
+ };
112
+
113
+ const hrStyle: React.CSSProperties = {
114
+ borderColor: colors.border,
115
+ borderTop: "none",
116
+ margin: 0,
117
+ };
118
+
119
+ const contentStyle: React.CSSProperties = {
120
+ padding: "24px 40px",
121
+ };
122
+
123
+ const footerStyle: React.CSSProperties = {
124
+ padding: "16px 40px 32px",
125
+ };
126
+
127
+ const footerTextStyle: React.CSSProperties = {
128
+ color: colors.muted,
129
+ fontSize: "13px",
130
+ lineHeight: "20px",
131
+ margin: "0 0 8px",
132
+ fontWeight: 600,
133
+ };
134
+
135
+ const footerMutedStyle: React.CSSProperties = {
136
+ color: colors.muted,
137
+ fontSize: "12px",
138
+ lineHeight: "18px",
139
+ margin: 0,
140
+ };
141
+
142
+ const footerLinkStyle: React.CSSProperties = {
143
+ color: colors.brand,
144
+ textDecoration: "underline",
145
+ };
@@ -0,0 +1,28 @@
1
+ export { BaseLayout, type BaseLayoutProps } from "./base-layout";
2
+ export { WelcomeEmail, type WelcomeEmailProps } from "./welcome";
3
+ export { VerifyEmailEmail, type VerifyEmailEmailProps } from "./verify-email";
4
+ export {
5
+ PasswordResetEmail,
6
+ type PasswordResetEmailProps,
7
+ } from "./password-reset";
8
+ export {
9
+ WorkspaceInvitationEmail,
10
+ type WorkspaceInvitationEmailProps,
11
+ } from "./workspace-invitation";
12
+ export {
13
+ QuotaWarningEmail,
14
+ type QuotaWarningEmailProps,
15
+ } from "./quota-warning";
16
+ export {
17
+ TrialWarningEmail,
18
+ type TrialWarningEmailProps,
19
+ } from "./trial-warning";
20
+ export {
21
+ PaymentFailedEmail,
22
+ type PaymentFailedEmailProps,
23
+ } from "./payment-failed";
24
+ export {
25
+ SubscriptionConfirmedEmail,
26
+ type SubscriptionConfirmedEmailProps,
27
+ } from "./subscription-confirmed";
28
+ export { TrialExpiryEmail, type TrialExpiryEmailProps } from "./trial-expiry";
@@ -0,0 +1,72 @@
1
+ import { Button, Text } from "@react-email/components";
2
+ import * as React from "react";
3
+ import { BaseLayout } from "./base-layout";
4
+
5
+ export interface PasswordResetEmailProps {
6
+ userName: string;
7
+ resetUrl: string;
8
+ }
9
+
10
+ export function PasswordResetEmail({
11
+ userName,
12
+ resetUrl,
13
+ }: PasswordResetEmailProps) {
14
+ const text = {
15
+ preview: "Reset your password",
16
+ heading: "Reset your password",
17
+ greeting: "Hi",
18
+ body: "We received a request to reset your password. Click the button below to choose a new one.",
19
+ button: "Reset Password",
20
+ note: "This link expires in 1 hour. If you didn't request a password reset, you can safely ignore this email.",
21
+ };
22
+
23
+ return (
24
+ <BaseLayout preview={text.preview}>
25
+ <Text style={headingStyle}>{text.heading}</Text>
26
+ <Text style={bodyTextStyle}>
27
+ {text.greeting} {userName},
28
+ </Text>
29
+ <Text style={bodyTextStyle}>{text.body}</Text>
30
+ <Button href={resetUrl} style={buttonStyle}>
31
+ {text.button}
32
+ </Button>
33
+ <Text style={noteStyle}>{text.note}</Text>
34
+ </BaseLayout>
35
+ );
36
+ }
37
+
38
+ const headingStyle: React.CSSProperties = {
39
+ color: "#18181b",
40
+ fontSize: "22px",
41
+ fontWeight: 700,
42
+ lineHeight: "30px",
43
+ margin: "0 0 16px",
44
+ };
45
+
46
+ const bodyTextStyle: React.CSSProperties = {
47
+ color: "#18181b",
48
+ fontSize: "15px",
49
+ lineHeight: "24px",
50
+ margin: "0 0 12px",
51
+ };
52
+
53
+ const buttonStyle: React.CSSProperties = {
54
+ backgroundColor: "#7c3aed",
55
+ borderRadius: "6px",
56
+ color: "#ffffff",
57
+ display: "inline-block",
58
+ fontSize: "15px",
59
+ fontWeight: 600,
60
+ lineHeight: "100%",
61
+ padding: "12px 24px",
62
+ textDecoration: "none",
63
+ textAlign: "center" as const,
64
+ marginTop: "8px",
65
+ };
66
+
67
+ const noteStyle: React.CSSProperties = {
68
+ color: "#71717a",
69
+ fontSize: "13px",
70
+ lineHeight: "20px",
71
+ marginTop: "20px",
72
+ };
@@ -0,0 +1,77 @@
1
+ import { Button, Text } from "@react-email/components";
2
+ import * as React from "react";
3
+ import { BaseLayout } from "./base-layout";
4
+
5
+ export interface PaymentFailedEmailProps {
6
+ workspaceName: string;
7
+ amount: string;
8
+ updatePaymentUrl: string;
9
+ }
10
+
11
+ export function PaymentFailedEmail({
12
+ workspaceName,
13
+ amount,
14
+ updatePaymentUrl,
15
+ }: PaymentFailedEmailProps) {
16
+ const text = {
17
+ preview: `Payment failed for ${workspaceName}`,
18
+ heading: "Payment Failed",
19
+ body1: "We were unable to process the payment of",
20
+ body2: "for your workspace",
21
+ body3: "",
22
+ warning:
23
+ "Your subscription will be restricted to free limits after a 3-day grace period if payment is not updated.",
24
+ button: "Update Payment Method",
25
+ };
26
+
27
+ return (
28
+ <BaseLayout preview={text.preview}>
29
+ <Text style={headingStyle}>{text.heading}</Text>
30
+ <Text style={bodyTextStyle}>
31
+ {text.body1} <strong>{amount}</strong> {text.body2} &lsquo;
32
+ {workspaceName}&rsquo;{text.body3}
33
+ </Text>
34
+ <Text style={warningTextStyle}>{text.warning}</Text>
35
+ <Button href={updatePaymentUrl} style={buttonStyle}>
36
+ {text.button}
37
+ </Button>
38
+ </BaseLayout>
39
+ );
40
+ }
41
+
42
+ const headingStyle: React.CSSProperties = {
43
+ color: "#18181b",
44
+ fontSize: "22px",
45
+ fontWeight: 700,
46
+ lineHeight: "30px",
47
+ margin: "0 0 16px",
48
+ };
49
+
50
+ const bodyTextStyle: React.CSSProperties = {
51
+ color: "#18181b",
52
+ fontSize: "15px",
53
+ lineHeight: "24px",
54
+ margin: "0 0 12px",
55
+ };
56
+
57
+ const warningTextStyle: React.CSSProperties = {
58
+ color: "#dc2626",
59
+ fontSize: "15px",
60
+ fontWeight: 600,
61
+ lineHeight: "24px",
62
+ margin: "0 0 12px",
63
+ };
64
+
65
+ const buttonStyle: React.CSSProperties = {
66
+ backgroundColor: "#7c3aed",
67
+ borderRadius: "6px",
68
+ color: "#ffffff",
69
+ display: "inline-block",
70
+ fontSize: "15px",
71
+ fontWeight: 600,
72
+ lineHeight: "100%",
73
+ padding: "12px 24px",
74
+ textDecoration: "none",
75
+ textAlign: "center" as const,
76
+ marginTop: "8px",
77
+ };