@intelligo-dev/core 1.0.0-beta.1

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 (254) hide show
  1. package/LICENSE +201 -0
  2. package/dist/conversations/errors.d.ts +31 -0
  3. package/dist/conversations/errors.d.ts.map +1 -0
  4. package/dist/conversations/errors.js +25 -0
  5. package/dist/conversations/errors.js.map +1 -0
  6. package/dist/conversations/index.d.ts +13 -0
  7. package/dist/conversations/index.d.ts.map +1 -0
  8. package/dist/conversations/index.js +12 -0
  9. package/dist/conversations/index.js.map +1 -0
  10. package/dist/conversations/service.d.ts +132 -0
  11. package/dist/conversations/service.d.ts.map +1 -0
  12. package/dist/conversations/service.js +347 -0
  13. package/dist/conversations/service.js.map +1 -0
  14. package/dist/conversations/types.d.ts +10 -0
  15. package/dist/conversations/types.d.ts.map +1 -0
  16. package/dist/conversations/types.js +5 -0
  17. package/dist/conversations/types.js.map +1 -0
  18. package/dist/db/client.d.ts +19 -0
  19. package/dist/db/client.d.ts.map +1 -0
  20. package/dist/db/client.js +52 -0
  21. package/dist/db/client.js.map +1 -0
  22. package/dist/db/index.d.ts +4 -0
  23. package/dist/db/index.d.ts.map +1 -0
  24. package/dist/db/index.js +8 -0
  25. package/dist/db/index.js.map +1 -0
  26. package/dist/db/schema/agents.d.ts +400 -0
  27. package/dist/db/schema/agents.d.ts.map +1 -0
  28. package/dist/db/schema/agents.js +39 -0
  29. package/dist/db/schema/agents.js.map +1 -0
  30. package/dist/db/schema/ai.d.ts +2222 -0
  31. package/dist/db/schema/ai.d.ts.map +1 -0
  32. package/dist/db/schema/ai.js +313 -0
  33. package/dist/db/schema/ai.js.map +1 -0
  34. package/dist/db/schema/auth.d.ts +1222 -0
  35. package/dist/db/schema/auth.d.ts.map +1 -0
  36. package/dist/db/schema/auth.js +162 -0
  37. package/dist/db/schema/auth.js.map +1 -0
  38. package/dist/db/schema/billing.d.ts +1199 -0
  39. package/dist/db/schema/billing.d.ts.map +1 -0
  40. package/dist/db/schema/billing.js +150 -0
  41. package/dist/db/schema/billing.js.map +1 -0
  42. package/dist/db/schema/feature-flags.d.ts +143 -0
  43. package/dist/db/schema/feature-flags.d.ts.map +1 -0
  44. package/dist/db/schema/feature-flags.js +25 -0
  45. package/dist/db/schema/feature-flags.js.map +1 -0
  46. package/dist/db/schema/identity.d.ts +1295 -0
  47. package/dist/db/schema/identity.d.ts.map +1 -0
  48. package/dist/db/schema/identity.js +258 -0
  49. package/dist/db/schema/identity.js.map +1 -0
  50. package/dist/db/schema/index.d.ts +16 -0
  51. package/dist/db/schema/index.d.ts.map +1 -0
  52. package/dist/db/schema/index.js +43 -0
  53. package/dist/db/schema/index.js.map +1 -0
  54. package/dist/db/schema/notifications.d.ts +182 -0
  55. package/dist/db/schema/notifications.d.ts.map +1 -0
  56. package/dist/db/schema/notifications.js +38 -0
  57. package/dist/db/schema/notifications.js.map +1 -0
  58. package/dist/db/schema/rag.d.ts +171 -0
  59. package/dist/db/schema/rag.d.ts.map +1 -0
  60. package/dist/db/schema/rag.js +42 -0
  61. package/dist/db/schema/rag.js.map +1 -0
  62. package/dist/db/schema/usage.d.ts +1193 -0
  63. package/dist/db/schema/usage.d.ts.map +1 -0
  64. package/dist/db/schema/usage.js +224 -0
  65. package/dist/db/schema/usage.js.map +1 -0
  66. package/dist/db/validate.d.ts +19 -0
  67. package/dist/db/validate.d.ts.map +1 -0
  68. package/dist/db/validate.js +58 -0
  69. package/dist/db/validate.js.map +1 -0
  70. package/dist/db/workspace-queries.d.ts +75 -0
  71. package/dist/db/workspace-queries.d.ts.map +1 -0
  72. package/dist/db/workspace-queries.js +78 -0
  73. package/dist/db/workspace-queries.js.map +1 -0
  74. package/dist/documents/classifier.d.ts +31 -0
  75. package/dist/documents/classifier.d.ts.map +1 -0
  76. package/dist/documents/classifier.js +41 -0
  77. package/dist/documents/classifier.js.map +1 -0
  78. package/dist/documents/errors.d.ts +32 -0
  79. package/dist/documents/errors.d.ts.map +1 -0
  80. package/dist/documents/errors.js +27 -0
  81. package/dist/documents/errors.js.map +1 -0
  82. package/dist/documents/index.d.ts +14 -0
  83. package/dist/documents/index.d.ts.map +1 -0
  84. package/dist/documents/index.js +13 -0
  85. package/dist/documents/index.js.map +1 -0
  86. package/dist/documents/service.d.ts +54 -0
  87. package/dist/documents/service.d.ts.map +1 -0
  88. package/dist/documents/service.js +146 -0
  89. package/dist/documents/service.js.map +1 -0
  90. package/dist/documents/types.d.ts +27 -0
  91. package/dist/documents/types.d.ts.map +1 -0
  92. package/dist/documents/types.js +5 -0
  93. package/dist/documents/types.js.map +1 -0
  94. package/dist/email/index.d.ts +5 -0
  95. package/dist/email/index.d.ts.map +1 -0
  96. package/dist/email/index.js +5 -0
  97. package/dist/email/index.js.map +1 -0
  98. package/dist/email/provider.d.ts +68 -0
  99. package/dist/email/provider.d.ts.map +1 -0
  100. package/dist/email/provider.js +199 -0
  101. package/dist/email/provider.js.map +1 -0
  102. package/dist/email/send.d.ts +47 -0
  103. package/dist/email/send.d.ts.map +1 -0
  104. package/dist/email/send.js +110 -0
  105. package/dist/email/send.js.map +1 -0
  106. package/dist/email/senders.d.ts +93 -0
  107. package/dist/email/senders.d.ts.map +1 -0
  108. package/dist/email/senders.js +232 -0
  109. package/dist/email/senders.js.map +1 -0
  110. package/dist/email/templates/base-layout.d.ts +7 -0
  111. package/dist/email/templates/base-layout.d.ts.map +1 -0
  112. package/dist/email/templates/base-layout.js +69 -0
  113. package/dist/email/templates/base-layout.js.map +1 -0
  114. package/dist/email/templates/index.d.ts +11 -0
  115. package/dist/email/templates/index.d.ts.map +1 -0
  116. package/dist/email/templates/index.js +17 -0
  117. package/dist/email/templates/index.js.map +1 -0
  118. package/dist/email/templates/password-reset.d.ts +7 -0
  119. package/dist/email/templates/password-reset.d.ts.map +1 -0
  120. package/dist/email/templates/password-reset.js +59 -0
  121. package/dist/email/templates/password-reset.js.map +1 -0
  122. package/dist/email/templates/payment-failed.d.ts +8 -0
  123. package/dist/email/templates/payment-failed.d.ts.map +1 -0
  124. package/dist/email/templates/payment-failed.js +62 -0
  125. package/dist/email/templates/payment-failed.js.map +1 -0
  126. package/dist/email/templates/quota-warning.d.ts +11 -0
  127. package/dist/email/templates/quota-warning.d.ts.map +1 -0
  128. package/dist/email/templates/quota-warning.js +82 -0
  129. package/dist/email/templates/quota-warning.js.map +1 -0
  130. package/dist/email/templates/subscription-confirmed.d.ts +9 -0
  131. package/dist/email/templates/subscription-confirmed.d.ts.map +1 -0
  132. package/dist/email/templates/subscription-confirmed.js +72 -0
  133. package/dist/email/templates/subscription-confirmed.js.map +1 -0
  134. package/dist/email/templates/trial-expiry.d.ts +9 -0
  135. package/dist/email/templates/trial-expiry.d.ts.map +1 -0
  136. package/dist/email/templates/trial-expiry.js +86 -0
  137. package/dist/email/templates/trial-expiry.js.map +1 -0
  138. package/dist/email/templates/trial-warning.d.ts +11 -0
  139. package/dist/email/templates/trial-warning.d.ts.map +1 -0
  140. package/dist/email/templates/trial-warning.js +70 -0
  141. package/dist/email/templates/trial-warning.js.map +1 -0
  142. package/dist/email/templates/verify-email.d.ts +7 -0
  143. package/dist/email/templates/verify-email.d.ts.map +1 -0
  144. package/dist/email/templates/verify-email.js +59 -0
  145. package/dist/email/templates/verify-email.js.map +1 -0
  146. package/dist/email/templates/welcome.d.ts +7 -0
  147. package/dist/email/templates/welcome.d.ts.map +1 -0
  148. package/dist/email/templates/welcome.js +51 -0
  149. package/dist/email/templates/welcome.js.map +1 -0
  150. package/dist/email/templates/workspace-invitation.d.ts +10 -0
  151. package/dist/email/templates/workspace-invitation.d.ts.map +1 -0
  152. package/dist/email/templates/workspace-invitation.js +79 -0
  153. package/dist/email/templates/workspace-invitation.js.map +1 -0
  154. package/dist/env.d.ts +21 -0
  155. package/dist/env.d.ts.map +1 -0
  156. package/dist/env.js +129 -0
  157. package/dist/env.js.map +1 -0
  158. package/dist/identity/audit.d.ts +39 -0
  159. package/dist/identity/audit.d.ts.map +1 -0
  160. package/dist/identity/audit.js +51 -0
  161. package/dist/identity/audit.js.map +1 -0
  162. package/dist/identity/errors.d.ts +32 -0
  163. package/dist/identity/errors.d.ts.map +1 -0
  164. package/dist/identity/errors.js +25 -0
  165. package/dist/identity/errors.js.map +1 -0
  166. package/dist/identity/index.d.ts +16 -0
  167. package/dist/identity/index.d.ts.map +1 -0
  168. package/dist/identity/index.js +15 -0
  169. package/dist/identity/index.js.map +1 -0
  170. package/dist/identity/service.d.ts +70 -0
  171. package/dist/identity/service.d.ts.map +1 -0
  172. package/dist/identity/service.js +179 -0
  173. package/dist/identity/service.js.map +1 -0
  174. package/dist/identity/types.d.ts +27 -0
  175. package/dist/identity/types.d.ts.map +1 -0
  176. package/dist/identity/types.js +5 -0
  177. package/dist/identity/types.js.map +1 -0
  178. package/dist/index.d.ts +3 -0
  179. package/dist/index.d.ts.map +1 -0
  180. package/dist/index.js +11 -0
  181. package/dist/index.js.map +1 -0
  182. package/dist/logger.d.ts +50 -0
  183. package/dist/logger.d.ts.map +1 -0
  184. package/dist/logger.js +183 -0
  185. package/dist/logger.js.map +1 -0
  186. package/dist/notifications/index.d.ts +86 -0
  187. package/dist/notifications/index.d.ts.map +1 -0
  188. package/dist/notifications/index.js +112 -0
  189. package/dist/notifications/index.js.map +1 -0
  190. package/dist/notifications/triggers.d.ts +68 -0
  191. package/dist/notifications/triggers.d.ts.map +1 -0
  192. package/dist/notifications/triggers.js +145 -0
  193. package/dist/notifications/triggers.js.map +1 -0
  194. package/dist/notifications/types.d.ts +19 -0
  195. package/dist/notifications/types.d.ts.map +1 -0
  196. package/dist/notifications/types.js +11 -0
  197. package/dist/notifications/types.js.map +1 -0
  198. package/package.json +101 -0
  199. package/src/db/migrations/0000_sharp_night_nurse.sql +52 -0
  200. package/src/db/migrations/0001_hesitant_vapor.sql +40 -0
  201. package/src/db/migrations/0002_numerous_lady_vermin.sql +235 -0
  202. package/src/db/migrations/0003_mighty_jean_grey.sql +37 -0
  203. package/src/db/migrations/0004_cynical_grandmaster.sql +2 -0
  204. package/src/db/migrations/0005_careful_switch.sql +8 -0
  205. package/src/db/migrations/0006_tense_blue_marvel.sql +16 -0
  206. package/src/db/migrations/0007_next_squadron_sinister.sql +1 -0
  207. package/src/db/migrations/0008_powerful_scream.sql +39 -0
  208. package/src/db/migrations/0009_sad_ink.sql +1 -0
  209. package/src/db/migrations/0010_shocking_omega_flight.sql +2 -0
  210. package/src/db/migrations/0011_ambiguous_otto_octavius.sql +151 -0
  211. package/src/db/migrations/0011_hnsw_vector_index.sql +17 -0
  212. package/src/db/migrations/0012_user_profiles.sql +30 -0
  213. package/src/db/migrations/0013_trending_seasonal_columns.sql +9 -0
  214. package/src/db/migrations/0014_add_product_type_to_agents.sql +6 -0
  215. package/src/db/migrations/0015_new_v1_tables.sql +149 -0
  216. package/src/db/migrations/0016_document_types.sql +30 -0
  217. package/src/db/migrations/0017_document_metadata.sql +2 -0
  218. package/src/db/migrations/0018_identity_graph.sql +200 -0
  219. package/src/db/migrations/0019_db_driven_prompts.sql +20 -0
  220. package/src/db/migrations/0020_pending_extractions.sql +35 -0
  221. package/src/db/migrations/0021_rag_documents.sql +39 -0
  222. package/src/db/migrations/0022_user_quotas_usage_jsonb.sql +70 -0
  223. package/src/db/migrations/0023_user_facts_user_scoped_unique.sql +17 -0
  224. package/src/db/migrations/0024_user_memories_hnsw.sql +23 -0
  225. package/src/db/migrations/0025_audit_trigger_errcode.sql +21 -0
  226. package/src/db/migrations/0026_user_profile_snapshots_composite_pk.sql +17 -0
  227. package/src/db/migrations/0027_billing_settings_mnt_columns.sql +54 -0
  228. package/src/db/migrations/0028_trial_credits_normalized_email.sql +37 -0
  229. package/src/db/migrations/0029_usage_records_conversation_idx.sql +13 -0
  230. package/src/db/migrations/0030_pending_extractions_composite_idx.sql +11 -0
  231. package/src/db/migrations/0031_rag_documents_hnsw.sql +16 -0
  232. package/src/db/migrations/0032_rate_limit_unique_idx.sql +16 -0
  233. package/src/db/migrations/0033_pending_extractions_partial_idx.sql +18 -0
  234. package/src/db/migrations/0034_rate_limit_count.sql +9 -0
  235. package/src/db/migrations/0035_credit_reservations.sql +24 -0
  236. package/src/db/migrations/0036_executions_audit_jobs.sql +96 -0
  237. package/src/db/migrations/0037_rate_limit_minute_bucket.sql +46 -0
  238. package/src/db/migrations/0038_user_quotas_generic_usage.sql +25 -0
  239. package/src/db/migrations/0039_platform_admin_impersonation.sql +27 -0
  240. package/src/db/migrations/0040_ee_audit_chain.sql +23 -0
  241. package/src/db/migrations/README.md +57 -0
  242. package/src/db/migrations/meta/0000_snapshot.json +348 -0
  243. package/src/db/migrations/meta/0001_snapshot.json +631 -0
  244. package/src/db/migrations/meta/0002_snapshot.json +2269 -0
  245. package/src/db/migrations/meta/0003_snapshot.json +2488 -0
  246. package/src/db/migrations/meta/0004_snapshot.json +2500 -0
  247. package/src/db/migrations/meta/0005_snapshot.json +2548 -0
  248. package/src/db/migrations/meta/0006_snapshot.json +2650 -0
  249. package/src/db/migrations/meta/0007_snapshot.json +2657 -0
  250. package/src/db/migrations/meta/0008_snapshot.json +2719 -0
  251. package/src/db/migrations/meta/0009_snapshot.json +2726 -0
  252. package/src/db/migrations/meta/0010_snapshot.json +2739 -0
  253. package/src/db/migrations/meta/0011_snapshot.json +3886 -0
  254. package/src/db/migrations/meta/_journal.json +300 -0
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Documents Module (ADR-0009)
3
+ *
4
+ * Document lifecycle: save, list, read, delete versions, plus
5
+ * ownership and workspace/user access checks. See ./service.ts for
6
+ * the full module doc comment.
7
+ *
8
+ * Use via subpath import: @intelligo-dev/core/documents
9
+ */
10
+ export { getUserDocuments, getDocument, saveDocument, deleteDocumentVersions, } from "./service";
11
+ export { DocumentServiceError, isDocumentServiceError, type DocumentServiceErrorCode, } from "./errors";
12
+ export type { DocumentActor, DocumentFilter, DocumentListItem } from "./types";
13
+ export { registerDocumentPatterns, classifyDocumentTitle, isProductDocument, listRegisteredDocumentPatterns, clearDocumentPatternRegistry, type DocumentPatternEntry, } from "./classifier";
14
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/documents/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EACL,gBAAgB,EAChB,WAAW,EACX,YAAY,EACZ,sBAAsB,GACvB,MAAM,WAAW,CAAC;AAEnB,OAAO,EACL,oBAAoB,EACpB,sBAAsB,EACtB,KAAK,wBAAwB,GAC9B,MAAM,UAAU,CAAC;AAElB,YAAY,EAAE,aAAa,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAE/E,OAAO,EACL,wBAAwB,EACxB,qBAAqB,EACrB,iBAAiB,EACjB,8BAA8B,EAC9B,4BAA4B,EAC5B,KAAK,oBAAoB,GAC1B,MAAM,cAAc,CAAC"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Documents Module (ADR-0009)
3
+ *
4
+ * Document lifecycle: save, list, read, delete versions, plus
5
+ * ownership and workspace/user access checks. See ./service.ts for
6
+ * the full module doc comment.
7
+ *
8
+ * Use via subpath import: @intelligo-dev/core/documents
9
+ */
10
+ export { getUserDocuments, getDocument, saveDocument, deleteDocumentVersions, } from "./service";
11
+ export { DocumentServiceError, isDocumentServiceError, } from "./errors";
12
+ export { registerDocumentPatterns, classifyDocumentTitle, isProductDocument, listRegisteredDocumentPatterns, clearDocumentPatternRegistry, } from "./classifier";
13
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/documents/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EACL,gBAAgB,EAChB,WAAW,EACX,YAAY,EACZ,sBAAsB,GACvB,MAAM,WAAW,CAAC;AAEnB,OAAO,EACL,oBAAoB,EACpB,sBAAsB,GAEvB,MAAM,UAAU,CAAC;AAIlB,OAAO,EACL,wBAAwB,EACxB,qBAAqB,EACrB,iBAAiB,EACjB,8BAA8B,EAC9B,4BAA4B,GAE7B,MAAM,cAAc,CAAC"}
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Document Persistence Service — Server-only
3
+ *
4
+ * Core CRUD operations for AI-generated document artifacts with
5
+ * workspace + user isolation. Ported from
6
+ * @intelligo-dev/agents/documents (ADR-0009): the tables (`documents`,
7
+ * `document_types`) always lived in @intelligo-dev/core's schema, only the
8
+ * service layer sat in a dissolving package.
9
+ *
10
+ * Callers pass a resolved actor (workspaceId, userId) rather than this
11
+ * module resolving one itself — @intelligo-dev/core cannot depend on
12
+ * @intelligo-dev/auth (see tests/architecture/dependency-direction.test.ts),
13
+ * so `requireWorkspace()` moved to the caller. Every query still
14
+ * filters by workspaceId AND userId internally; the actor is never
15
+ * trusted to have done that itself.
16
+ *
17
+ * Failure is reported by throwing `DocumentServiceError` (a small,
18
+ * typed code set) rather than returning a `{ success, error }`
19
+ * envelope — that shaping, plus any error-reporting side effect
20
+ * (Sentry, logging), is a transport concern the caller applies at the
21
+ * Server Action / route boundary.
22
+ *
23
+ * This module is SERVER-ONLY. Do not import from client components.
24
+ */
25
+ import type { DocumentActor, DocumentFilter, DocumentListItem } from "./types";
26
+ /**
27
+ * Get all documents for the actor. Ordered by most recently created
28
+ * first. Uses DISTINCT ON to get the latest version of each document.
29
+ */
30
+ export declare function getUserDocuments(actor: DocumentActor, filter?: DocumentFilter): Promise<DocumentListItem[]>;
31
+ /**
32
+ * Get a single document by id, scoped to the actor.
33
+ * Throws DocumentServiceError("not_found") if no such document exists.
34
+ */
35
+ export declare function getDocument(actor: DocumentActor, id: string): Promise<DocumentListItem>;
36
+ /**
37
+ * Save (create new version of) a document.
38
+ * Throws DocumentServiceError("forbidden") if a document with this id
39
+ * already exists in the workspace under a different user.
40
+ */
41
+ export declare function saveDocument(actor: DocumentActor, params: {
42
+ id: string;
43
+ title: string;
44
+ content: string;
45
+ kind: string;
46
+ }): Promise<DocumentListItem>;
47
+ /**
48
+ * Delete all versions of a document created after `timestamp`.
49
+ * Throws DocumentServiceError("invalid_input") for an unparsable
50
+ * timestamp or one older than the delete window, and ("not_found") if
51
+ * no document exists at that id within the actor's scope.
52
+ */
53
+ export declare function deleteDocumentVersions(actor: DocumentActor, id: string, timestamp: string): Promise<DocumentListItem[]>;
54
+ //# sourceMappingURL=service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../src/documents/service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAOH,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAyB/E;;;GAGG;AACH,wBAAsB,gBAAgB,CACpC,KAAK,EAAE,aAAa,EACpB,MAAM,CAAC,EAAE,cAAc,GACtB,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAuB7B;AAED;;;GAGG;AACH,wBAAsB,WAAW,CAC/B,KAAK,EAAE,aAAa,EACpB,EAAE,EAAE,MAAM,GACT,OAAO,CAAC,gBAAgB,CAAC,CAkB3B;AAMD;;;;GAIG;AACH,wBAAsB,YAAY,CAChC,KAAK,EAAE,aAAa,EACpB,MAAM,EAAE;IACN,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;CACd,GACA,OAAO,CAAC,gBAAgB,CAAC,CAuC3B;AAQD;;;;;GAKG;AACH,wBAAsB,sBAAsB,CAC1C,KAAK,EAAE,aAAa,EACpB,EAAE,EAAE,MAAM,EACV,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,gBAAgB,EAAE,CAAC,CA4C7B"}
@@ -0,0 +1,146 @@
1
+ /**
2
+ * Document Persistence Service — Server-only
3
+ *
4
+ * Core CRUD operations for AI-generated document artifacts with
5
+ * workspace + user isolation. Ported from
6
+ * @intelligo-dev/agents/documents (ADR-0009): the tables (`documents`,
7
+ * `document_types`) always lived in @intelligo-dev/core's schema, only the
8
+ * service layer sat in a dissolving package.
9
+ *
10
+ * Callers pass a resolved actor (workspaceId, userId) rather than this
11
+ * module resolving one itself — @intelligo-dev/core cannot depend on
12
+ * @intelligo-dev/auth (see tests/architecture/dependency-direction.test.ts),
13
+ * so `requireWorkspace()` moved to the caller. Every query still
14
+ * filters by workspaceId AND userId internally; the actor is never
15
+ * trusted to have done that itself.
16
+ *
17
+ * Failure is reported by throwing `DocumentServiceError` (a small,
18
+ * typed code set) rather than returning a `{ success, error }`
19
+ * envelope — that shaping, plus any error-reporting side effect
20
+ * (Sentry, logging), is a transport concern the caller applies at the
21
+ * Server Action / route boundary.
22
+ *
23
+ * This module is SERVER-ONLY. Do not import from client components.
24
+ */
25
+ import { and, desc, eq, gt } from "drizzle-orm";
26
+ import { db } from "../db";
27
+ import { documents } from "../db/schema";
28
+ import { classifyDocumentTitle, isProductDocument } from "./classifier";
29
+ import { DocumentServiceError } from "./errors";
30
+ function toListItem(doc) {
31
+ return {
32
+ id: doc.id,
33
+ title: doc.title,
34
+ kind: doc.kind,
35
+ createdAt: doc.createdAt.toISOString(),
36
+ agentLabel: classifyDocumentTitle(doc.title).agentLabel,
37
+ content: doc.content,
38
+ };
39
+ }
40
+ // ---------------------------------------------------------------------------
41
+ // Query Operations
42
+ // ---------------------------------------------------------------------------
43
+ /**
44
+ * Get all documents for the actor. Ordered by most recently created
45
+ * first. Uses DISTINCT ON to get the latest version of each document.
46
+ */
47
+ export async function getUserDocuments(actor, filter) {
48
+ const uniqueDocs = await db
49
+ .selectDistinctOn([documents.id])
50
+ .from(documents)
51
+ .where(and(eq(documents.workspaceId, actor.workspaceId), eq(documents.userId, actor.userId)))
52
+ .orderBy(documents.id, desc(documents.createdAt));
53
+ let result = uniqueDocs.map(toListItem);
54
+ const filterType = filter?.type ?? "all";
55
+ if (filterType !== "all") {
56
+ result =
57
+ filterType === "report"
58
+ ? result.filter((doc) => isProductDocument(doc.title))
59
+ : result.filter((doc) => doc.kind === filterType);
60
+ }
61
+ return result;
62
+ }
63
+ /**
64
+ * Get a single document by id, scoped to the actor.
65
+ * Throws DocumentServiceError("not_found") if no such document exists.
66
+ */
67
+ export async function getDocument(actor, id) {
68
+ const [doc] = await db
69
+ .selectDistinctOn([documents.id])
70
+ .from(documents)
71
+ .where(and(eq(documents.id, id), eq(documents.workspaceId, actor.workspaceId), eq(documents.userId, actor.userId)))
72
+ .orderBy(documents.id, desc(documents.createdAt));
73
+ if (!doc) {
74
+ throw new DocumentServiceError("not_found", "Document not found");
75
+ }
76
+ return toListItem(doc);
77
+ }
78
+ // ---------------------------------------------------------------------------
79
+ // Mutation Operations
80
+ // ---------------------------------------------------------------------------
81
+ /**
82
+ * Save (create new version of) a document.
83
+ * Throws DocumentServiceError("forbidden") if a document with this id
84
+ * already exists in the workspace under a different user.
85
+ */
86
+ export async function saveDocument(actor, params) {
87
+ const existingDocs = await db
88
+ .select()
89
+ .from(documents)
90
+ .where(and(eq(documents.id, params.id), eq(documents.workspaceId, actor.workspaceId)));
91
+ if (existingDocs.length > 0) {
92
+ const firstDoc = existingDocs[0];
93
+ if (firstDoc && firstDoc.userId !== actor.userId) {
94
+ throw new DocumentServiceError("forbidden", "Document belongs to a different user");
95
+ }
96
+ }
97
+ const [newDocument] = await db
98
+ .insert(documents)
99
+ .values({
100
+ id: params.id,
101
+ userId: actor.userId,
102
+ workspaceId: actor.workspaceId,
103
+ title: params.title,
104
+ content: params.content,
105
+ kind: params.kind,
106
+ createdAt: new Date(),
107
+ })
108
+ .returning();
109
+ if (!newDocument) {
110
+ throw new DocumentServiceError("database_error", "Failed to save document");
111
+ }
112
+ return toListItem(newDocument);
113
+ }
114
+ // ---------------------------------------------------------------------------
115
+ // Delete Operations
116
+ // ---------------------------------------------------------------------------
117
+ const MAX_DELETE_WINDOW_DAYS = 30;
118
+ /**
119
+ * Delete all versions of a document created after `timestamp`.
120
+ * Throws DocumentServiceError("invalid_input") for an unparsable
121
+ * timestamp or one older than the delete window, and ("not_found") if
122
+ * no document exists at that id within the actor's scope.
123
+ */
124
+ export async function deleteDocumentVersions(actor, id, timestamp) {
125
+ const parsedTimestamp = new Date(timestamp);
126
+ if (Number.isNaN(parsedTimestamp.getTime())) {
127
+ throw new DocumentServiceError("invalid_input", "Invalid timestamp");
128
+ }
129
+ const oldestAllowed = new Date(Date.now() - MAX_DELETE_WINDOW_DAYS * 24 * 60 * 60 * 1000);
130
+ if (parsedTimestamp < oldestAllowed) {
131
+ throw new DocumentServiceError("invalid_input", `timestamp must be within the last ${MAX_DELETE_WINDOW_DAYS} days`);
132
+ }
133
+ const existingDocs = await db
134
+ .select()
135
+ .from(documents)
136
+ .where(and(eq(documents.id, id), eq(documents.workspaceId, actor.workspaceId), eq(documents.userId, actor.userId)));
137
+ if (existingDocs.length === 0) {
138
+ throw new DocumentServiceError("not_found", "Document not found");
139
+ }
140
+ const deletedDocs = await db
141
+ .delete(documents)
142
+ .where(and(eq(documents.id, id), eq(documents.workspaceId, actor.workspaceId), eq(documents.userId, actor.userId), gt(documents.createdAt, parsedTimestamp)))
143
+ .returning();
144
+ return deletedDocs.map(toListItem);
145
+ }
146
+ //# sourceMappingURL=service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service.js","sourceRoot":"","sources":["../../src/documents/service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Shared types for the documents service.
3
+ */
4
+ /** Resolved actor identity — every query is scoped to this pair. */
5
+ export type DocumentActor = {
6
+ workspaceId: string;
7
+ userId: string;
8
+ };
9
+ /**
10
+ * Document filter type
11
+ */
12
+ export type DocumentFilter = {
13
+ type?: "all" | "report" | "text" | "code" | "sheet" | "image";
14
+ };
15
+ /**
16
+ * Document list item returned by getUserDocuments / getDocument /
17
+ * saveDocument / deleteDocumentVersions.
18
+ */
19
+ export type DocumentListItem = {
20
+ id: string;
21
+ title: string;
22
+ kind: string;
23
+ createdAt: string;
24
+ agentLabel: string;
25
+ content: string | null;
26
+ };
27
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/documents/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,oEAAoE;AACpE,MAAM,MAAM,aAAa,GAAG;IAC1B,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG;IAC3B,IAAI,CAAC,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,OAAO,CAAC;CAC/D,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,gBAAgB,GAAG;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CACxB,CAAC"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Shared types for the documents service.
3
+ */
4
+ export {};
5
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/documents/types.ts"],"names":[],"mappings":"AAAA;;GAEG"}
@@ -0,0 +1,5 @@
1
+ export { sendEmail, type SendEmailParams, type SendEmailWithComponentParams, type SendEmailResult, } from "./send";
2
+ export { getEmailProvider, resetEmailProviderCache, type EmailProvider, type EmailProviderName, type EmailSendParams, type EmailTemplateRef, ResendProvider, LoopsProvider, ConsoleProvider, } from "./provider";
3
+ export * from "./templates";
4
+ export * from "./senders";
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/email/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,SAAS,EACT,KAAK,eAAe,EACpB,KAAK,4BAA4B,EACjC,KAAK,eAAe,GACrB,MAAM,QAAQ,CAAC;AAChB,OAAO,EACL,gBAAgB,EAChB,uBAAuB,EACvB,KAAK,aAAa,EAClB,KAAK,iBAAiB,EACtB,KAAK,eAAe,EACpB,KAAK,gBAAgB,EACrB,cAAc,EACd,aAAa,EACb,eAAe,GAChB,MAAM,YAAY,CAAC;AACpB,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC"}
@@ -0,0 +1,5 @@
1
+ export { sendEmail, } from "./send";
2
+ export { getEmailProvider, resetEmailProviderCache, ResendProvider, LoopsProvider, ConsoleProvider, } from "./provider";
3
+ export * from "./templates";
4
+ export * from "./senders";
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/email/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,SAAS,GAIV,MAAM,QAAQ,CAAC;AAChB,OAAO,EACL,gBAAgB,EAChB,uBAAuB,EAKvB,cAAc,EACd,aAAa,EACb,eAAe,GAChB,MAAM,YAAY,CAAC;AACpB,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC"}
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Provider-neutral template descriptor attached to every framework email.
3
+ *
4
+ * HTML-capable providers (Resend) ignore it — they send the rendered HTML.
5
+ * Template-based providers (Loops) require it: `key` is resolved to the
6
+ * provider-side template id and `variables` become the template's dynamic
7
+ * data. Keys are stable framework identifiers, e.g. "verify-email".
8
+ */
9
+ export interface EmailTemplateRef {
10
+ key: string;
11
+ variables?: Record<string, string | number>;
12
+ }
13
+ export interface EmailSendParams {
14
+ to: string | string[];
15
+ subject: string;
16
+ html: string;
17
+ from?: string;
18
+ replyTo?: string;
19
+ template?: EmailTemplateRef;
20
+ }
21
+ /**
22
+ * Common interface every email provider must implement.
23
+ */
24
+ export interface EmailProvider {
25
+ send(params: EmailSendParams): Promise<{
26
+ id: string;
27
+ }>;
28
+ }
29
+ export declare class ResendProvider implements EmailProvider {
30
+ private client;
31
+ constructor(apiKey: string);
32
+ send(params: EmailSendParams): Promise<{
33
+ id: string;
34
+ }>;
35
+ }
36
+ export declare class LoopsProvider implements EmailProvider {
37
+ private apiKey;
38
+ private transactionalIds?;
39
+ constructor(apiKey: string, transactionalIds?: Record<string, string> | undefined);
40
+ private resolveTransactionalId;
41
+ send(params: EmailSendParams): Promise<{
42
+ id: string;
43
+ }>;
44
+ }
45
+ export declare class ConsoleProvider implements EmailProvider {
46
+ send(params: EmailSendParams): Promise<{
47
+ id: string;
48
+ }>;
49
+ }
50
+ export type EmailProviderName = "resend" | "loops" | "console";
51
+ /** Test-only: clear the cached provider so env changes take effect. */
52
+ export declare function resetEmailProviderCache(): void;
53
+ /**
54
+ * Returns the email provider based on environment variables.
55
+ *
56
+ * Priority:
57
+ * 1. EMAIL_PROVIDER env var → explicit selection (with API key validation)
58
+ * 2. RESEND_API_KEY → ResendProvider (auto-detect; preferred because it can
59
+ * send every framework email without per-template setup)
60
+ * 3. LOOPS_API_KEY → LoopsProvider (auto-detect; needs
61
+ * LOOPS_TRANSACTIONAL_ID_* mappings for the templates you use)
62
+ * 4. (none) → ConsoleProvider
63
+ *
64
+ * The provider instance is cached (singleton) so a new client is NOT created
65
+ * on every call.
66
+ */
67
+ export declare function getEmailProvider(): EmailProvider;
68
+ //# sourceMappingURL=provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../../src/email/provider.ts"],"names":[],"mappings":"AAcA;;;;;;;GAOG;AACH,MAAM,WAAW,gBAAgB;IAC/B,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,CAAC;CAC7C;AAED,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,gBAAgB,CAAC;CAC7B;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,IAAI,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACxD;AAaD,qBAAa,cAAe,YAAW,aAAa;IAClD,OAAO,CAAC,MAAM,CAAS;gBAEX,MAAM,EAAE,MAAM;IAIpB,IAAI,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC;CAwB7D;AAiBD,qBAAa,aAAc,YAAW,aAAa;IAE/C,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,gBAAgB,CAAC;gBADjB,MAAM,EAAE,MAAM,EACd,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,YAAA;IAGnD,OAAO,CAAC,sBAAsB;IAWxB,IAAI,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC;CA6D7D;AAMD,qBAAa,eAAgB,YAAW,aAAa;IAC7C,IAAI,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC;CAW7D;AAMD,MAAM,MAAM,iBAAiB,GAAG,QAAQ,GAAG,OAAO,GAAG,SAAS,CAAC;AAI/D,uEAAuE;AACvE,wBAAgB,uBAAuB,IAAI,IAAI,CAE9C;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,gBAAgB,IAAI,aAAa,CAoChD"}
@@ -0,0 +1,199 @@
1
+ import { Resend } from "resend";
2
+ /** Error with an HTTP-ish status code so send.ts can decide retryability. */
3
+ function statusError(message, statusCode) {
4
+ const err = new Error(message);
5
+ err.statusCode = statusCode;
6
+ return err;
7
+ }
8
+ // ---------------------------------------------------------------------------
9
+ // ResendProvider
10
+ // ---------------------------------------------------------------------------
11
+ export class ResendProvider {
12
+ constructor(apiKey) {
13
+ this.client = new Resend(apiKey);
14
+ }
15
+ async send(params) {
16
+ const { data, error } = await this.client.emails.send({
17
+ from: params.from ?? "Intelligo <noreply@intelligo.dev>",
18
+ to: Array.isArray(params.to) ? params.to : [params.to],
19
+ subject: params.subject,
20
+ html: params.html,
21
+ replyTo: params.replyTo,
22
+ });
23
+ if (error) {
24
+ // Resend returns an error object rather than throwing
25
+ const err = new Error(error.message);
26
+ // Resend error names map to HTTP status categories
27
+ if (error.name === "validation_error" ||
28
+ error.name === "missing_required_field") {
29
+ err.statusCode = 400;
30
+ }
31
+ throw err;
32
+ }
33
+ return { id: data?.id ?? "unknown" };
34
+ }
35
+ }
36
+ // ---------------------------------------------------------------------------
37
+ // LoopsProvider
38
+ // ---------------------------------------------------------------------------
39
+ // Loops transactional emails are designed in the Loops dashboard and sent by
40
+ // template id — the API accepts no raw HTML and exactly one recipient per
41
+ // call. Template keys resolve to ids through (in order):
42
+ // 1. the `transactionalIds` map passed to the constructor
43
+ // 2. env: LOOPS_TRANSACTIONAL_ID_<KEY> (key upper-snaked,
44
+ // e.g. "verify-email" → LOOPS_TRANSACTIONAL_ID_VERIFY_EMAIL)
45
+ // `from`/`replyTo` are ignored — the sender is configured per template in
46
+ // Loops itself.
47
+ // ---------------------------------------------------------------------------
48
+ const LOOPS_API_URL = "https://app.loops.so/api/v1/transactional";
49
+ export class LoopsProvider {
50
+ constructor(apiKey, transactionalIds) {
51
+ this.apiKey = apiKey;
52
+ this.transactionalIds = transactionalIds;
53
+ }
54
+ resolveTransactionalId(key) {
55
+ const mapped = this.transactionalIds?.[key];
56
+ if (mapped) {
57
+ return mapped;
58
+ }
59
+ const envName = `LOOPS_TRANSACTIONAL_ID_${key
60
+ .toUpperCase()
61
+ .replace(/-/g, "_")}`;
62
+ return process.env[envName];
63
+ }
64
+ async send(params) {
65
+ const template = params.template;
66
+ if (!template) {
67
+ throw statusError(`Loops requires a template key (subject: "${params.subject}") — Loops cannot send raw HTML. Use a framework sender or pass { template }.`, 400);
68
+ }
69
+ const transactionalId = this.resolveTransactionalId(template.key);
70
+ if (!transactionalId) {
71
+ throw statusError(`No Loops transactional id mapped for template "${template.key}". Set LOOPS_TRANSACTIONAL_ID_${template.key
72
+ .toUpperCase()
73
+ .replace(/-/g, "_")} or pass a transactionalIds map to LoopsProvider.`, 400);
74
+ }
75
+ const recipients = Array.isArray(params.to) ? params.to : [params.to];
76
+ // Loops accepts a single recipient per request — fan out sequentially so
77
+ // a failure surfaces with normal retry semantics in send.ts.
78
+ for (const email of recipients) {
79
+ const response = await fetch(LOOPS_API_URL, {
80
+ method: "POST",
81
+ headers: {
82
+ Authorization: `Bearer ${this.apiKey}`,
83
+ "Content-Type": "application/json",
84
+ },
85
+ body: JSON.stringify({
86
+ transactionalId,
87
+ email,
88
+ dataVariables: template.variables ?? {},
89
+ }),
90
+ });
91
+ if (!response.ok) {
92
+ let detail = "";
93
+ try {
94
+ const body = (await response.json());
95
+ detail = body.message ?? body.error?.message ?? "";
96
+ }
97
+ catch {
98
+ // Non-JSON error body — status code alone is enough
99
+ }
100
+ throw statusError(`Loops send failed (${response.status}) for template "${template.key}"${detail ? `: ${detail}` : ""}`, response.status);
101
+ }
102
+ }
103
+ // Loops returns { success: true } with no message id
104
+ return { id: `loops:${transactionalId}` };
105
+ }
106
+ }
107
+ // ---------------------------------------------------------------------------
108
+ // ConsoleProvider (development fallback)
109
+ // ---------------------------------------------------------------------------
110
+ export class ConsoleProvider {
111
+ async send(params) {
112
+ const recipient = Array.isArray(params.to)
113
+ ? params.to.join(", ")
114
+ : params.to;
115
+ console.log(`[Email] Would send to: ${recipient}, subject: ${params.subject}`);
116
+ return { id: `console-${Date.now()}` };
117
+ }
118
+ }
119
+ let cachedProvider = null;
120
+ /** Test-only: clear the cached provider so env changes take effect. */
121
+ export function resetEmailProviderCache() {
122
+ cachedProvider = null;
123
+ }
124
+ /**
125
+ * Returns the email provider based on environment variables.
126
+ *
127
+ * Priority:
128
+ * 1. EMAIL_PROVIDER env var → explicit selection (with API key validation)
129
+ * 2. RESEND_API_KEY → ResendProvider (auto-detect; preferred because it can
130
+ * send every framework email without per-template setup)
131
+ * 3. LOOPS_API_KEY → LoopsProvider (auto-detect; needs
132
+ * LOOPS_TRANSACTIONAL_ID_* mappings for the templates you use)
133
+ * 4. (none) → ConsoleProvider
134
+ *
135
+ * The provider instance is cached (singleton) so a new client is NOT created
136
+ * on every call.
137
+ */
138
+ export function getEmailProvider() {
139
+ if (cachedProvider) {
140
+ return cachedProvider;
141
+ }
142
+ const explicit = process.env.EMAIL_PROVIDER?.toLowerCase();
143
+ if (explicit) {
144
+ cachedProvider = resolveExplicitProvider(explicit);
145
+ if (cachedProvider) {
146
+ return cachedProvider;
147
+ }
148
+ // Unknown value — warn and fall through to auto-detect
149
+ console.warn(`[Email] Unknown EMAIL_PROVIDER="${process.env.EMAIL_PROVIDER}", falling back to auto-detect`);
150
+ }
151
+ // Auto-detect from available API keys (backwards compatible)
152
+ const resendKey = process.env.RESEND_API_KEY;
153
+ if (resendKey) {
154
+ console.log("[Email] Using Resend provider");
155
+ cachedProvider = new ResendProvider(resendKey);
156
+ return cachedProvider;
157
+ }
158
+ const loopsKey = process.env.LOOPS_API_KEY;
159
+ if (loopsKey) {
160
+ console.log("[Email] Using Loops provider");
161
+ cachedProvider = new LoopsProvider(loopsKey);
162
+ return cachedProvider;
163
+ }
164
+ console.log("[Email] Using console provider (no API key set)");
165
+ cachedProvider = new ConsoleProvider();
166
+ return cachedProvider;
167
+ }
168
+ /**
169
+ * Resolve an explicit EMAIL_PROVIDER value to a provider instance.
170
+ * Returns null for unknown values so the caller can fall through to auto-detect.
171
+ */
172
+ function resolveExplicitProvider(provider) {
173
+ switch (provider) {
174
+ case "resend": {
175
+ const key = process.env.RESEND_API_KEY;
176
+ if (!key) {
177
+ console.warn("[Email] EMAIL_PROVIDER=resend but RESEND_API_KEY is not set, falling back to console");
178
+ return new ConsoleProvider();
179
+ }
180
+ console.log("[Email] Using Resend provider (explicit)");
181
+ return new ResendProvider(key);
182
+ }
183
+ case "loops": {
184
+ const key = process.env.LOOPS_API_KEY;
185
+ if (!key) {
186
+ console.warn("[Email] EMAIL_PROVIDER=loops but LOOPS_API_KEY is not set, falling back to console");
187
+ return new ConsoleProvider();
188
+ }
189
+ console.log("[Email] Using Loops provider (explicit)");
190
+ return new LoopsProvider(key);
191
+ }
192
+ case "console":
193
+ console.log("[Email] Using console provider (explicit)");
194
+ return new ConsoleProvider();
195
+ default:
196
+ return null;
197
+ }
198
+ }
199
+ //# sourceMappingURL=provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider.js","sourceRoot":"","sources":["../../src/email/provider.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,47 @@
1
+ import type React from "react";
2
+ import { type EmailTemplateRef } from "./provider";
3
+ export interface SendEmailParams {
4
+ to: string | string[];
5
+ subject: string;
6
+ html: string;
7
+ /** Defaults to EMAIL_FROM env var or "Intelligo <noreply@intelligo.dev>" */
8
+ from?: string;
9
+ replyTo?: string;
10
+ /**
11
+ * Provider-neutral template descriptor. Required by template-based
12
+ * providers (Loops); ignored by HTML-capable providers (Resend).
13
+ */
14
+ template?: EmailTemplateRef;
15
+ }
16
+ export interface SendEmailWithComponentParams {
17
+ to: string | string[];
18
+ subject: string;
19
+ /** A React Email component element. Will be rendered to HTML before sending. */
20
+ react: React.ReactElement;
21
+ /** Defaults to EMAIL_FROM env var or "Intelligo <noreply@intelligo.dev>" */
22
+ from?: string;
23
+ replyTo?: string;
24
+ /**
25
+ * Provider-neutral template descriptor. Required by template-based
26
+ * providers (Loops); ignored by HTML-capable providers (Resend).
27
+ */
28
+ template?: EmailTemplateRef;
29
+ }
30
+ export interface SendEmailResult {
31
+ success: boolean;
32
+ id?: string;
33
+ error?: string;
34
+ }
35
+ /**
36
+ * Send an email through the configured provider with retry logic.
37
+ *
38
+ * Accepts either raw HTML via `{ html }` or a React Email component via
39
+ * `{ react }`. When a React element is provided, it is rendered to HTML
40
+ * using `@react-email/components`'s `render()` before sending.
41
+ *
42
+ * This function NEVER throws. All errors are caught and returned as
43
+ * `{ success: false, error: "..." }`. This prevents email failures
44
+ * from crashing the application (TECH-08).
45
+ */
46
+ export declare function sendEmail(params: SendEmailParams | SendEmailWithComponentParams): Promise<SendEmailResult>;
47
+ //# sourceMappingURL=send.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"send.d.ts","sourceRoot":"","sources":["../../src/email/send.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EAAoB,KAAK,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAcrE,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,4EAA4E;IAC5E,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;OAGG;IACH,QAAQ,CAAC,EAAE,gBAAgB,CAAC;CAC7B;AAED,MAAM,WAAW,4BAA4B;IAC3C,EAAE,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,gFAAgF;IAChF,KAAK,EAAE,KAAK,CAAC,YAAY,CAAC;IAC1B,4EAA4E;IAC5E,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;OAGG;IACH,QAAQ,CAAC,EAAE,gBAAgB,CAAC;CAC7B;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,OAAO,CAAC;IACjB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AA2CD;;;;;;;;;;GAUG;AACH,wBAAsB,SAAS,CAC7B,MAAM,EAAE,eAAe,GAAG,4BAA4B,GACrD,OAAO,CAAC,eAAe,CAAC,CAgF1B"}