@dealdesk/server 2026.528.2 → 2026.603.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 (146) hide show
  1. package/dist/adapters/builtin-adapter-types.d.ts.map +1 -1
  2. package/dist/adapters/builtin-adapter-types.js +1 -0
  3. package/dist/adapters/builtin-adapter-types.js.map +1 -1
  4. package/dist/adapters/registry.d.ts.map +1 -1
  5. package/dist/adapters/registry.js +19 -0
  6. package/dist/adapters/registry.js.map +1 -1
  7. package/dist/deal-desk/enrichment/__tests__/hunter-client.test.d.ts +2 -0
  8. package/dist/deal-desk/enrichment/__tests__/hunter-client.test.d.ts.map +1 -0
  9. package/dist/deal-desk/enrichment/__tests__/hunter-client.test.js +106 -0
  10. package/dist/deal-desk/enrichment/__tests__/hunter-client.test.js.map +1 -0
  11. package/dist/deal-desk/enrichment/__tests__/hunter-config.test.d.ts +2 -0
  12. package/dist/deal-desk/enrichment/__tests__/hunter-config.test.d.ts.map +1 -0
  13. package/dist/deal-desk/enrichment/__tests__/hunter-config.test.js +73 -0
  14. package/dist/deal-desk/enrichment/__tests__/hunter-config.test.js.map +1 -0
  15. package/dist/deal-desk/enrichment/__tests__/provider.test.d.ts +2 -0
  16. package/dist/deal-desk/enrichment/__tests__/provider.test.d.ts.map +1 -0
  17. package/dist/deal-desk/enrichment/__tests__/provider.test.js +77 -0
  18. package/dist/deal-desk/enrichment/__tests__/provider.test.js.map +1 -0
  19. package/dist/deal-desk/enrichment/__tests__/resolve-contact-email.test.js +33 -0
  20. package/dist/deal-desk/enrichment/__tests__/resolve-contact-email.test.js.map +1 -1
  21. package/dist/deal-desk/enrichment/enrichment-types.d.ts +38 -0
  22. package/dist/deal-desk/enrichment/enrichment-types.d.ts.map +1 -0
  23. package/dist/deal-desk/enrichment/enrichment-types.js +3 -0
  24. package/dist/deal-desk/enrichment/enrichment-types.js.map +1 -0
  25. package/dist/deal-desk/enrichment/hunter-client.d.ts +44 -0
  26. package/dist/deal-desk/enrichment/hunter-client.d.ts.map +1 -0
  27. package/dist/deal-desk/enrichment/hunter-client.js +112 -0
  28. package/dist/deal-desk/enrichment/hunter-client.js.map +1 -0
  29. package/dist/deal-desk/enrichment/hunter-config.d.ts +41 -0
  30. package/dist/deal-desk/enrichment/hunter-config.d.ts.map +1 -0
  31. package/dist/deal-desk/enrichment/hunter-config.js +58 -0
  32. package/dist/deal-desk/enrichment/hunter-config.js.map +1 -0
  33. package/dist/deal-desk/enrichment/provider.d.ts +25 -0
  34. package/dist/deal-desk/enrichment/provider.d.ts.map +1 -0
  35. package/dist/deal-desk/enrichment/provider.js +43 -0
  36. package/dist/deal-desk/enrichment/provider.js.map +1 -0
  37. package/dist/deal-desk/enrichment/resolve-contact-email.d.ts +42 -7
  38. package/dist/deal-desk/enrichment/resolve-contact-email.d.ts.map +1 -1
  39. package/dist/deal-desk/enrichment/resolve-contact-email.js +120 -51
  40. package/dist/deal-desk/enrichment/resolve-contact-email.js.map +1 -1
  41. package/dist/deal-desk/tools/__tests__/enrichment-preference.test.d.ts +2 -0
  42. package/dist/deal-desk/tools/__tests__/enrichment-preference.test.d.ts.map +1 -0
  43. package/dist/deal-desk/tools/__tests__/enrichment-preference.test.js +90 -0
  44. package/dist/deal-desk/tools/__tests__/enrichment-preference.test.js.map +1 -0
  45. package/dist/deal-desk/tools/__tests__/hunter-api-key.test.d.ts +2 -0
  46. package/dist/deal-desk/tools/__tests__/hunter-api-key.test.d.ts.map +1 -0
  47. package/dist/deal-desk/tools/__tests__/hunter-api-key.test.js +101 -0
  48. package/dist/deal-desk/tools/__tests__/hunter-api-key.test.js.map +1 -0
  49. package/dist/deal-desk/tools/enrich-contact.d.ts +5 -2
  50. package/dist/deal-desk/tools/enrich-contact.d.ts.map +1 -1
  51. package/dist/deal-desk/tools/enrich-contact.js +26 -24
  52. package/dist/deal-desk/tools/enrich-contact.js.map +1 -1
  53. package/dist/deal-desk/tools/enrichment-preference.d.ts +8 -0
  54. package/dist/deal-desk/tools/enrichment-preference.d.ts.map +1 -0
  55. package/dist/deal-desk/tools/enrichment-preference.js +41 -0
  56. package/dist/deal-desk/tools/enrichment-preference.js.map +1 -0
  57. package/dist/deal-desk/tools/hunter-api-key.d.ts +11 -0
  58. package/dist/deal-desk/tools/hunter-api-key.d.ts.map +1 -0
  59. package/dist/deal-desk/tools/hunter-api-key.js +67 -0
  60. package/dist/deal-desk/tools/hunter-api-key.js.map +1 -0
  61. package/dist/deal-desk/tools/index.d.ts.map +1 -1
  62. package/dist/deal-desk/tools/index.js +42 -11
  63. package/dist/deal-desk/tools/index.js.map +1 -1
  64. package/dist/deal-desk/tools/outreach-approve.d.ts +4 -0
  65. package/dist/deal-desk/tools/outreach-approve.d.ts.map +1 -1
  66. package/dist/deal-desk/tools/outreach-approve.js +7 -8
  67. package/dist/deal-desk/tools/outreach-approve.js.map +1 -1
  68. package/dist/deal-desk/tools/outreach-draft.d.ts +4 -0
  69. package/dist/deal-desk/tools/outreach-draft.d.ts.map +1 -1
  70. package/dist/deal-desk/tools/outreach-draft.js +8 -6
  71. package/dist/deal-desk/tools/outreach-draft.js.map +1 -1
  72. package/package.json +15 -14
  73. package/ui-dist/assets/{_basePickBy-CaQZTZgE.js → _basePickBy-CBVIeEkV.js} +1 -1
  74. package/ui-dist/assets/{_baseUniq-DvA-iyvx.js → _baseUniq-BcwaQnkH.js} +1 -1
  75. package/ui-dist/assets/{arc-_uwl-PL9.js → arc-DqmTiJ9l.js} +1 -1
  76. package/ui-dist/assets/{architectureDiagram-VXUJARFQ-hoEr3qym.js → architectureDiagram-VXUJARFQ-C2PZuz_4.js} +1 -1
  77. package/ui-dist/assets/{blockDiagram-VD42YOAC-BpNmbQ9P.js → blockDiagram-VD42YOAC-CHzu2Ctw.js} +1 -1
  78. package/ui-dist/assets/{c4Diagram-YG6GDRKO-BG14x8dM.js → c4Diagram-YG6GDRKO-DLvbjDP5.js} +1 -1
  79. package/ui-dist/assets/channel-HcwSzs_N.js +1 -0
  80. package/ui-dist/assets/{chunk-4BX2VUAB-Cb1YcG81.js → chunk-4BX2VUAB-D4IgQx7K.js} +1 -1
  81. package/ui-dist/assets/{chunk-55IACEB6-DkMTjrQj.js → chunk-55IACEB6-BH1i5XQo.js} +1 -1
  82. package/ui-dist/assets/{chunk-B4BG7PRW-BD6QmYfE.js → chunk-B4BG7PRW-CuPShkE9.js} +1 -1
  83. package/ui-dist/assets/{chunk-DI55MBZ5-B_xkiL3H.js → chunk-DI55MBZ5-Bi_J3Z0D.js} +1 -1
  84. package/ui-dist/assets/{chunk-FMBD7UC4-DC95tjc1.js → chunk-FMBD7UC4-BwRwTbFX.js} +1 -1
  85. package/ui-dist/assets/{chunk-QN33PNHL-BkIJ2KXA.js → chunk-QN33PNHL-BN35apwc.js} +1 -1
  86. package/ui-dist/assets/{chunk-QZHKN3VN-BWUNV7If.js → chunk-QZHKN3VN-COm56_LM.js} +1 -1
  87. package/ui-dist/assets/{chunk-TZMSLE5B-NQYnSIs1.js → chunk-TZMSLE5B-Xj2KL_0Y.js} +1 -1
  88. package/ui-dist/assets/classDiagram-2ON5EDUG-B07Ltkzj.js +1 -0
  89. package/ui-dist/assets/classDiagram-v2-WZHVMYZB-B07Ltkzj.js +1 -0
  90. package/ui-dist/assets/clone-B7h-gniq.js +1 -0
  91. package/ui-dist/assets/{cose-bilkent-S5V4N54A-BHo6DkZj.js → cose-bilkent-S5V4N54A-FLFC6_gO.js} +1 -1
  92. package/ui-dist/assets/{dagre-6UL2VRFP-CfzNlqfr.js → dagre-6UL2VRFP-0d32lGTp.js} +1 -1
  93. package/ui-dist/assets/{diagram-PSM6KHXK-DjPk4Vl5.js → diagram-PSM6KHXK-CDNGXG5P.js} +1 -1
  94. package/ui-dist/assets/{diagram-QEK2KX5R-ClmlUcpT.js → diagram-QEK2KX5R-C0vaPlrd.js} +1 -1
  95. package/ui-dist/assets/{diagram-S2PKOQOG-B68LEXtz.js → diagram-S2PKOQOG-UxrlUeu-.js} +1 -1
  96. package/ui-dist/assets/{erDiagram-Q2GNP2WA-CJSnga5T.js → erDiagram-Q2GNP2WA-FL0kguuL.js} +1 -1
  97. package/ui-dist/assets/{flowDiagram-NV44I4VS-Drmp4DHd.js → flowDiagram-NV44I4VS-DnEzeK5O.js} +1 -1
  98. package/ui-dist/assets/{ganttDiagram-JELNMOA3-C8ffQ-2u.js → ganttDiagram-JELNMOA3-f03KncDX.js} +1 -1
  99. package/ui-dist/assets/{gitGraphDiagram-V2S2FVAM-CPjF6oPQ.js → gitGraphDiagram-V2S2FVAM-y4Oi65_k.js} +1 -1
  100. package/ui-dist/assets/{graph-B2qUgzgo.js → graph-CFWov-m4.js} +1 -1
  101. package/ui-dist/assets/{index-FnWH4Q9P.js → index-B-BAVU8b.js} +1 -1
  102. package/ui-dist/assets/{index-DY03uqeZ.js → index-Bd7zw6ip.js} +1 -1
  103. package/ui-dist/assets/{index-CtebvrC7.js → index-BmqFzV8-.js} +1 -1
  104. package/ui-dist/assets/{index-BJ9IksfS.js → index-Btdsi4zo.js} +1 -1
  105. package/ui-dist/assets/{index-CPGHpqpR.js → index-By5eCrIU.js} +1 -1
  106. package/ui-dist/assets/{index-CNEquZvK.js → index-C5zqtXrw.js} +1 -1
  107. package/ui-dist/assets/{index-DWfkKcGS.js → index-CFI3SAZE.js} +1 -1
  108. package/ui-dist/assets/{index-Cf8smU9e.js → index-CTJ29Xh5.js} +1 -1
  109. package/ui-dist/assets/{index-CrrVEpWP.js → index-CU0mrwVT.js} +156 -156
  110. package/ui-dist/assets/{index-BAhZurej.js → index-CV_d1E37.js} +1 -1
  111. package/ui-dist/assets/{index-DnDdXZYl.js → index-CddqJ4G5.js} +1 -1
  112. package/ui-dist/assets/{index-DvRp33UU.js → index-CgGLDqng.js} +1 -1
  113. package/ui-dist/assets/{index-BT7YS1Ir.js → index-CyvVv96c.js} +1 -1
  114. package/ui-dist/assets/{index-ARl1W2jj.js → index-D4ouuOrO.js} +1 -1
  115. package/ui-dist/assets/{index-DXzbokce.js → index-DCn3d1Sw.js} +1 -1
  116. package/ui-dist/assets/{index-CuwS3-lF.js → index-DWAFlBdn.js} +1 -1
  117. package/ui-dist/assets/{index-D1D5GrGc.js → index-DqYJhcon.js} +1 -1
  118. package/ui-dist/assets/{index-6t3ZNnLR.js → index-Dwv7AqVT.js} +1 -1
  119. package/ui-dist/assets/{index-Bkj-OIiI.js → index-DydmEOe-.js} +1 -1
  120. package/ui-dist/assets/{index-BKv2WUK1.js → index-FhdjGuIa.js} +1 -1
  121. package/ui-dist/assets/{index-CW2NmfmI.js → index-RDsxbDSf.js} +1 -1
  122. package/ui-dist/assets/{index-O_WP0QsK.js → index-ScEFFiXG.js} +1 -1
  123. package/ui-dist/assets/{index-B9T1xuwJ.js → index-swVBgd_3.js} +1 -1
  124. package/ui-dist/assets/{infoDiagram-HS3SLOUP-DLOW6p4c.js → infoDiagram-HS3SLOUP-BT8yT7sJ.js} +1 -1
  125. package/ui-dist/assets/{journeyDiagram-XKPGCS4Q-oYaaSMQP.js → journeyDiagram-XKPGCS4Q-C8DG43aT.js} +1 -1
  126. package/ui-dist/assets/{kanban-definition-3W4ZIXB7-BE7mgk6q.js → kanban-definition-3W4ZIXB7-BbShlSAl.js} +1 -1
  127. package/ui-dist/assets/{layout-Cq5BDWzM.js → layout-CCS2XC8t.js} +1 -1
  128. package/ui-dist/assets/{linear-HnEHTC6F.js → linear-2TvgGQfb.js} +1 -1
  129. package/ui-dist/assets/{mermaid.core-JMROPF3S.js → mermaid.core-BAFI4dXm.js} +4 -4
  130. package/ui-dist/assets/{mindmap-definition-VGOIOE7T-DoeZEBQU.js → mindmap-definition-VGOIOE7T-BcHv1Ud7.js} +1 -1
  131. package/ui-dist/assets/{pieDiagram-ADFJNKIX-BtfKQ-xw.js → pieDiagram-ADFJNKIX-CNO1-Z0g.js} +1 -1
  132. package/ui-dist/assets/{quadrantDiagram-AYHSOK5B-CIrjVDBB.js → quadrantDiagram-AYHSOK5B-DfE50a-U.js} +1 -1
  133. package/ui-dist/assets/{requirementDiagram-UZGBJVZJ-CNQ5h-EW.js → requirementDiagram-UZGBJVZJ-CgcgBiHz.js} +1 -1
  134. package/ui-dist/assets/{sankeyDiagram-TZEHDZUN-CrOSPDz5.js → sankeyDiagram-TZEHDZUN-BqpKVSYn.js} +1 -1
  135. package/ui-dist/assets/{sequenceDiagram-WL72ISMW-D96XuK7n.js → sequenceDiagram-WL72ISMW-Vbv-XA05.js} +1 -1
  136. package/ui-dist/assets/{stateDiagram-FKZM4ZOC-BOf9izkD.js → stateDiagram-FKZM4ZOC-C1GZ_hr8.js} +1 -1
  137. package/ui-dist/assets/stateDiagram-v2-4FDKWEC3-D4JPxYX0.js +1 -0
  138. package/ui-dist/assets/{timeline-definition-IT6M3QCI-_lAaYcUI.js → timeline-definition-IT6M3QCI-Gcr-dBCd.js} +1 -1
  139. package/ui-dist/assets/{treemap-GDKQZRPO-BS18z8ox.js → treemap-GDKQZRPO-B_zJkapD.js} +1 -1
  140. package/ui-dist/assets/{xychartDiagram-PRI3JC2R-X82nn6D0.js → xychartDiagram-PRI3JC2R-jk1Yj15T.js} +1 -1
  141. package/ui-dist/index.html +7 -6
  142. package/ui-dist/assets/channel-NmuAvKfd.js +0 -1
  143. package/ui-dist/assets/classDiagram-2ON5EDUG-eS4kRH8R.js +0 -1
  144. package/ui-dist/assets/classDiagram-v2-WZHVMYZB-eS4kRH8R.js +0 -1
  145. package/ui-dist/assets/clone-CbA0swX6.js +0 -1
  146. package/ui-dist/assets/stateDiagram-v2-4FDKWEC3-DEhq019K.js +0 -1
@@ -1,6 +1,21 @@
1
1
  import { and, eq } from "drizzle-orm";
2
2
  import { ddContacts, ddTargets } from "@dealdesk/db";
3
- import { ApolloApiError, resolvePersonEmail, } from "./apollo-client.js";
3
+ import { ApolloApiError, resolvePersonEmail } from "./apollo-client.js";
4
+ import { HunterApiError, resolveHunterEmail } from "./hunter-client.js";
5
+ /**
6
+ * Build a provider-aware selection loader from handler deps. Prefers an explicit
7
+ * `loadEnrichment`; otherwise wraps a legacy Apollo-only `loadApolloKey` as the
8
+ * apollo provider. Returns a loader that yields null when nothing is configured.
9
+ */
10
+ export function enrichmentLoaderFrom(deps) {
11
+ if (deps.loadEnrichment)
12
+ return deps.loadEnrichment;
13
+ const legacy = deps.loadApolloKey;
14
+ return async (companyId) => {
15
+ const apiKey = legacy ? await legacy(companyId) : null;
16
+ return apiKey ? { provider: "apollo", apiKey } : null;
17
+ };
18
+ }
4
19
  function extractCompanyDomain(website) {
5
20
  if (!website)
6
21
  return null;
@@ -43,22 +58,75 @@ export async function loadContactForEnrichment(db, args) {
43
58
  companyDomain: extractCompanyDomain(row.website),
44
59
  };
45
60
  }
61
+ const TRUSTED_ENRICHMENT_SOURCES = new Set(["apollo", "hunter"]);
62
+ /**
63
+ * Whether a contact needs (re)enrichment. An email is trusted as-is only when it
64
+ * came from a known enrichment provider and is already verified; everything else
65
+ * gets resolved/verified again.
66
+ *
67
+ * Name retained for backwards compatibility; covers all providers.
68
+ */
46
69
  export function contactNeedsApolloEnrichment(contact) {
47
70
  if (!contact.email)
48
71
  return true;
49
- // Only Apollo-sourced emails are trusted as-is; anything else gets Apollo-verified.
50
- if (contact.source !== "apollo")
72
+ if (!contact.source || !TRUSTED_ENRICHMENT_SOURCES.has(contact.source))
51
73
  return true;
52
74
  return contact.emailStatus === "unverified";
53
75
  }
76
+ /** Provider-agnostic alias. */
77
+ export const contactNeedsEnrichment = contactNeedsApolloEnrichment;
78
+ function mapApolloError(err) {
79
+ if (!(err instanceof ApolloApiError))
80
+ return null;
81
+ if (err.code === "apollo_plan_blocked") {
82
+ return {
83
+ ok: false,
84
+ code: "apollo_plan_blocked",
85
+ reason: "Apollo cannot reveal emails on this plan. Upgrade at https://app.apollo.io/ or add a verified email manually.",
86
+ };
87
+ }
88
+ if (err.code === "apollo_master_key_required") {
89
+ return {
90
+ ok: false,
91
+ code: "apollo_master_key_required",
92
+ reason: "Apollo requires a Master API key for enrichment. Create one at https://app.apollo.io/#/settings/integrations/api",
93
+ };
94
+ }
95
+ if (err.code === "apollo_credits_exhausted") {
96
+ return {
97
+ ok: false,
98
+ code: "apollo_credits_exhausted",
99
+ reason: "Apollo enrichment credits exhausted. Add credits at https://app.apollo.io/ or add a verified email manually.",
100
+ };
101
+ }
102
+ return {
103
+ ok: false,
104
+ code: "apollo_lookup_failed",
105
+ reason: err.message,
106
+ };
107
+ }
108
+ function mapHunterError(err) {
109
+ if (!(err instanceof HunterApiError))
110
+ return null;
111
+ if (err.code === "hunter_auth_failed") {
112
+ return { ok: false, code: "hunter_auth_failed", reason: err.message };
113
+ }
114
+ if (err.code === "hunter_rate_limited") {
115
+ return { ok: false, code: "hunter_rate_limited", reason: err.message };
116
+ }
117
+ if (err.code === "hunter_pii_restricted") {
118
+ return { ok: false, code: "hunter_pii_restricted", reason: err.message };
119
+ }
120
+ return { ok: false, code: "hunter_lookup_failed", reason: err.message };
121
+ }
54
122
  export async function resolveContactEmail(deps) {
55
- const resolveFn = deps.resolvePersonEmailFn ?? resolvePersonEmail;
56
- const apiKey = await deps.loadApolloKey(deps.companyId);
57
- if (!apiKey) {
123
+ const loadSelection = enrichmentLoaderFrom(deps);
124
+ const selection = await loadSelection(deps.companyId);
125
+ if (!selection) {
58
126
  return {
59
127
  ok: false,
60
128
  code: "apollo_not_configured",
61
- reason: "Apollo.io API key not configured for this company. Visit /deal-desk/email-accounts to set it up.",
129
+ reason: "No contact-enrichment provider configured for this company. Visit /deal-desk/email-accounts to add an Apollo.io or Hunter.io API key.",
62
130
  };
63
131
  }
64
132
  const contact = await loadContactForEnrichment(deps.db, {
@@ -66,11 +134,7 @@ export async function resolveContactEmail(deps) {
66
134
  contactId: deps.contactId,
67
135
  });
68
136
  if (!contact) {
69
- return {
70
- ok: false,
71
- code: "contact_not_found",
72
- reason: "contact not found",
73
- };
137
+ return { ok: false, code: "contact_not_found", reason: "contact not found" };
74
138
  }
75
139
  if (contact.dealDeskCompanyId !== deps.companyId) {
76
140
  return {
@@ -88,42 +152,41 @@ export async function resolveContactEmail(deps) {
88
152
  }
89
153
  let match;
90
154
  try {
91
- match = await resolveFn({
92
- firstName: contact.firstName,
93
- lastName: contact.lastName,
94
- companyDomain: contact.companyDomain,
95
- title: contact.title ?? undefined,
96
- apiKey,
97
- });
155
+ if (selection.provider === "hunter") {
156
+ const resolveHunterFn = deps.resolveHunterEmailFn ?? resolveHunterEmail;
157
+ const result = await resolveHunterFn({
158
+ firstName: contact.firstName,
159
+ lastName: contact.lastName,
160
+ companyDomain: contact.companyDomain,
161
+ title: contact.title ?? undefined,
162
+ apiKey: selection.apiKey,
163
+ });
164
+ match = { email: result.email, emailStatus: result.emailStatus };
165
+ }
166
+ else {
167
+ const resolveApolloFn = deps.resolvePersonEmailFn ?? resolvePersonEmail;
168
+ const result = await resolveApolloFn({
169
+ firstName: contact.firstName,
170
+ lastName: contact.lastName,
171
+ companyDomain: contact.companyDomain,
172
+ title: contact.title ?? undefined,
173
+ apiKey: selection.apiKey,
174
+ });
175
+ match = {
176
+ email: result.email,
177
+ emailStatus: result.emailStatus,
178
+ apolloPersonId: result.apolloPersonId ?? null,
179
+ };
180
+ }
98
181
  }
99
182
  catch (err) {
100
- if (err instanceof ApolloApiError) {
101
- if (err.code === "apollo_plan_blocked") {
102
- return {
103
- ok: false,
104
- code: "apollo_plan_blocked",
105
- reason: "Apollo cannot reveal emails on this plan. Upgrade at https://app.apollo.io/ or add a verified email manually.",
106
- };
107
- }
108
- if (err.code === "apollo_master_key_required") {
109
- return {
110
- ok: false,
111
- code: "apollo_master_key_required",
112
- reason: "Apollo requires a Master API key for enrichment. Create one at https://app.apollo.io/#/settings/integrations/api",
113
- };
114
- }
115
- if (err.code === "apollo_credits_exhausted") {
116
- return {
117
- ok: false,
118
- code: "apollo_credits_exhausted",
119
- reason: "Apollo enrichment credits exhausted. Add credits at https://app.apollo.io/ or add a verified email manually.",
120
- };
121
- }
122
- }
123
- const message = err instanceof Error ? err.message : "Apollo lookup failed";
183
+ const mapped = selection.provider === "hunter" ? mapHunterError(err) : mapApolloError(err);
184
+ if (mapped)
185
+ return mapped;
186
+ const message = err instanceof Error ? err.message : "Enrichment lookup failed";
124
187
  return {
125
188
  ok: false,
126
- code: "apollo_lookup_failed",
189
+ code: selection.provider === "hunter" ? "hunter_lookup_failed" : "apollo_lookup_failed",
127
190
  reason: message,
128
191
  };
129
192
  }
@@ -138,7 +201,7 @@ export async function resolveContactEmail(deps) {
138
201
  ok: true,
139
202
  email: match.email,
140
203
  emailStatus: match.emailStatus ?? "unverified",
141
- source: "apollo",
204
+ source: selection.provider,
142
205
  apolloPersonId: match.apolloPersonId ?? null,
143
206
  contactId: contact.id,
144
207
  firstName: contact.firstName,
@@ -152,30 +215,32 @@ export async function persistResolvedContactEmail(db, args) {
152
215
  .set({
153
216
  email: args.email,
154
217
  emailStatus: args.emailStatus,
155
- source: "apollo",
218
+ source: args.source,
156
219
  enrichedAt: new Date(),
157
220
  enrichedByAgentId: args.enrichedByAgentId ?? null,
158
221
  updatedAt: new Date(),
159
222
  })
160
223
  .where(eq(ddContacts.id, args.contactId));
161
224
  }
225
+ /**
226
+ * Ensure a contact has a usable email, enriching via the company's configured
227
+ * provider when needed. Name retained for backwards compatibility; works for
228
+ * any provider.
229
+ */
162
230
  export async function ensureContactEmailFromApollo(deps) {
163
231
  const contact = await loadContactForEnrichment(deps.db, {
164
232
  companyId: deps.companyId,
165
233
  contactId: deps.contactId,
166
234
  });
167
235
  if (!contact) {
168
- return {
169
- ok: false,
170
- code: "contact_not_found",
171
- reason: "contact not found",
172
- };
236
+ return { ok: false, code: "contact_not_found", reason: "contact not found" };
173
237
  }
174
238
  if (!contactNeedsApolloEnrichment(contact)) {
175
239
  return {
176
240
  ok: true,
177
241
  email: contact.email,
178
242
  emailStatus: contact.emailStatus,
243
+ source: contact.source ?? "apollo",
179
244
  enriched: false,
180
245
  };
181
246
  }
@@ -187,13 +252,17 @@ export async function ensureContactEmailFromApollo(deps) {
187
252
  contactId: resolved.contactId,
188
253
  email: resolved.email,
189
254
  emailStatus: resolved.emailStatus,
255
+ source: resolved.source,
190
256
  enrichedByAgentId: deps.enrichedByAgentId ?? null,
191
257
  });
192
258
  return {
193
259
  ok: true,
194
260
  email: resolved.email,
195
261
  emailStatus: resolved.emailStatus,
262
+ source: resolved.source,
196
263
  enriched: true,
197
264
  };
198
265
  }
266
+ /** Provider-agnostic alias. */
267
+ export const ensureContactEmail = ensureContactEmailFromApollo;
199
268
  //# sourceMappingURL=resolve-contact-email.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"resolve-contact-email.js","sourceRoot":"","sources":["../../../src/deal-desk/enrichment/resolve-contact-email.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"resolve-contact-email.js","sourceRoot":"","sources":["../../../src/deal-desk/enrichment/resolve-contact-email.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=enrichment-preference.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"enrichment-preference.test.d.ts","sourceRoot":"","sources":["../../../../src/deal-desk/tools/__tests__/enrichment-preference.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,90 @@
1
+ import express from "express";
2
+ import request from "supertest";
3
+ import { describe, it, expect } from "vitest";
4
+ import { enrichmentPreferenceGetHandler, enrichmentPreferencePutHandler, } from "../enrichment-preference.js";
5
+ import { APOLLO_API_KEY_SECRET_KEY } from "../../enrichment/apollo-config.js";
6
+ import { HUNTER_API_KEY_SECRET_KEY } from "../../enrichment/hunter-config.js";
7
+ function makeStore(initial = {}) {
8
+ const byKey = new Map(Object.entries(initial));
9
+ return {
10
+ async getByKey(_companyId, key) {
11
+ const v = byKey.get(key);
12
+ return v ? { id: v.id } : null;
13
+ },
14
+ async create(_companyId, args) {
15
+ const id = `secret-${byKey.size + 1}`;
16
+ byKey.set(args.key, { id, value: args.value });
17
+ return { id };
18
+ },
19
+ async replace(secretId, args) {
20
+ for (const [k, v] of byKey.entries()) {
21
+ if (v.id === secretId) {
22
+ byKey.set(k, { ...v, value: args.value });
23
+ return;
24
+ }
25
+ }
26
+ },
27
+ async remove(secretId) {
28
+ for (const [k, v] of byKey.entries())
29
+ if (v.id === secretId)
30
+ byKey.delete(k);
31
+ },
32
+ async load(_companyId, secretId) {
33
+ for (const v of byKey.values())
34
+ if (v.id === secretId)
35
+ return v.value;
36
+ return null;
37
+ },
38
+ };
39
+ }
40
+ function getApp(store) {
41
+ const app = express();
42
+ app.use(express.json());
43
+ app.get("/c/:companyId/enrichment-preference", enrichmentPreferenceGetHandler({ store }));
44
+ app.put("/c/:companyId/enrichment-preference", enrichmentPreferencePutHandler({ store }));
45
+ return app;
46
+ }
47
+ describe("enrichment-preference handlers", () => {
48
+ it("reports both unconfigured with null effective provider", async () => {
49
+ const res = await request(getApp(makeStore())).get("/c/co-1/enrichment-preference");
50
+ expect(res.body).toMatchObject({
51
+ apolloConfigured: false,
52
+ hunterConfigured: false,
53
+ preferred: null,
54
+ effective: null,
55
+ });
56
+ });
57
+ it("auto-selects the only configured provider", async () => {
58
+ const store = makeStore({ [HUNTER_API_KEY_SECRET_KEY]: { id: "s1", value: "hk" } });
59
+ const res = await request(getApp(store)).get("/c/co-1/enrichment-preference");
60
+ expect(res.body).toMatchObject({
61
+ apolloConfigured: false,
62
+ hunterConfigured: true,
63
+ effective: "hunter",
64
+ });
65
+ });
66
+ it("honors the saved preference when both providers are configured", async () => {
67
+ const store = makeStore({
68
+ [APOLLO_API_KEY_SECRET_KEY]: { id: "s1", value: "ak" },
69
+ [HUNTER_API_KEY_SECRET_KEY]: { id: "s2", value: "hk" },
70
+ });
71
+ const app = getApp(store);
72
+ // Default (no preference) -> apollo
73
+ const before = await request(app).get("/c/co-1/enrichment-preference");
74
+ expect(before.body.effective).toBe("apollo");
75
+ // Switch preference to hunter
76
+ const put = await request(app).put("/c/co-1/enrichment-preference").send({ provider: "hunter" });
77
+ expect(put.status).toBe(200);
78
+ expect(put.body.effective).toBe("hunter");
79
+ const after = await request(app).get("/c/co-1/enrichment-preference");
80
+ expect(after.body.preferred).toBe("hunter");
81
+ expect(after.body.effective).toBe("hunter");
82
+ });
83
+ it("rejects an invalid provider", async () => {
84
+ const res = await request(getApp(makeStore()))
85
+ .put("/c/co-1/enrichment-preference")
86
+ .send({ provider: "clearbit" });
87
+ expect(res.status).toBe(400);
88
+ });
89
+ });
90
+ //# sourceMappingURL=enrichment-preference.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"enrichment-preference.test.js","sourceRoot":"","sources":["../../../../src/deal-desk/tools/__tests__/enrichment-preference.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=hunter-api-key.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hunter-api-key.test.d.ts","sourceRoot":"","sources":["../../../../src/deal-desk/tools/__tests__/hunter-api-key.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,101 @@
1
+ import express from "express";
2
+ import request from "supertest";
3
+ import { describe, it, expect, vi } from "vitest";
4
+ import { hunterApiKeyGetHandler, hunterApiKeyPostHandler, hunterApiKeyDeleteHandler, } from "../hunter-api-key.js";
5
+ import { HunterApiError } from "../../enrichment/hunter-client.js";
6
+ import { HUNTER_API_KEY_SECRET_KEY, HUNTER_CAPABILITIES_SECRET_KEY, } from "../../enrichment/hunter-config.js";
7
+ function makeStore(initial = {}) {
8
+ const byKey = new Map(Object.entries(initial));
9
+ return {
10
+ async getByKey(_companyId, key) {
11
+ const v = byKey.get(key);
12
+ return v ? { id: v.id } : null;
13
+ },
14
+ async create(_companyId, args) {
15
+ const id = `secret-${byKey.size + 1}`;
16
+ byKey.set(args.key, { id, value: args.value });
17
+ return { id };
18
+ },
19
+ async replace(secretId, args) {
20
+ for (const [k, v] of byKey.entries()) {
21
+ if (v.id === secretId) {
22
+ byKey.set(k, { ...v, value: args.value });
23
+ return;
24
+ }
25
+ }
26
+ },
27
+ async remove(secretId) {
28
+ for (const [k, v] of byKey.entries()) {
29
+ if (v.id === secretId)
30
+ byKey.delete(k);
31
+ }
32
+ },
33
+ async load(_companyId, secretId) {
34
+ for (const v of byKey.values())
35
+ if (v.id === secretId)
36
+ return v.value;
37
+ return null;
38
+ },
39
+ };
40
+ }
41
+ function makeApp(handler, method) {
42
+ const app = express();
43
+ app.use(express.json());
44
+ app[method]("/c/:companyId/hunter-api-key", handler);
45
+ return app;
46
+ }
47
+ describe("hunter-api-key handlers", () => {
48
+ it("GET reports not configured initially", async () => {
49
+ const app = makeApp(hunterApiKeyGetHandler({ store: makeStore() }), "get");
50
+ const res = await request(app).get("/c/co-1/hunter-api-key");
51
+ expect(res.status).toBe(200);
52
+ expect(res.body.configured).toBe(false);
53
+ });
54
+ it("POST stores the key, probes capabilities, and GET then reports configured", async () => {
55
+ const store = makeStore();
56
+ const probe = vi.fn().mockResolvedValue({
57
+ valid: true,
58
+ planName: "Free",
59
+ searchesUsed: 0,
60
+ searchesAvailable: 25,
61
+ lastValidatedAt: "2026-06-01T00:00:00.000Z",
62
+ });
63
+ const postApp = makeApp(hunterApiKeyPostHandler({ store, probeCapabilities: probe }), "post");
64
+ const postRes = await request(postApp)
65
+ .post("/c/co-1/hunter-api-key")
66
+ .send({ apiKey: "hunter-key-123" });
67
+ expect(postRes.status).toBe(200);
68
+ expect(postRes.body.ok).toBe(true);
69
+ expect(postRes.body.capabilities.valid).toBe(true);
70
+ expect(probe).toHaveBeenCalledWith("hunter-key-123");
71
+ const getApp = makeApp(hunterApiKeyGetHandler({ store }), "get");
72
+ const getRes = await request(getApp).get("/c/co-1/hunter-api-key");
73
+ expect(getRes.body.configured).toBe(true);
74
+ expect(getRes.body.planName).toBe("Free");
75
+ expect(getRes.body.searchesAvailable).toBe(25);
76
+ });
77
+ it("POST returns 400 for a key that fails auth", async () => {
78
+ const probe = vi.fn().mockRejectedValue(new HunterApiError(401, "nope"));
79
+ const app = makeApp(hunterApiKeyPostHandler({ store: makeStore(), probeCapabilities: probe }), "post");
80
+ const res = await request(app).post("/c/co-1/hunter-api-key").send({ apiKey: "bad-key-123" });
81
+ expect(res.status).toBe(400);
82
+ expect(res.body.code).toBe("hunter_auth_failed");
83
+ });
84
+ it("POST rejects a too-short key", async () => {
85
+ const app = makeApp(hunterApiKeyPostHandler({ store: makeStore() }), "post");
86
+ const res = await request(app).post("/c/co-1/hunter-api-key").send({ apiKey: "short" });
87
+ expect(res.status).toBe(400);
88
+ });
89
+ it("DELETE removes the key", async () => {
90
+ const store = makeStore({
91
+ [HUNTER_API_KEY_SECRET_KEY]: { id: "s1", value: "hunter-key-123" },
92
+ [HUNTER_CAPABILITIES_SECRET_KEY]: { id: "s2", value: "{}" },
93
+ });
94
+ const app = makeApp(hunterApiKeyDeleteHandler({ store }), "delete");
95
+ const res = await request(app).delete("/c/co-1/hunter-api-key");
96
+ expect(res.status).toBe(200);
97
+ const getRes = await request(makeApp(hunterApiKeyGetHandler({ store }), "get")).get("/c/co-1/hunter-api-key");
98
+ expect(getRes.body.configured).toBe(false);
99
+ });
100
+ });
101
+ //# sourceMappingURL=hunter-api-key.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hunter-api-key.test.js","sourceRoot":"","sources":["../../../../src/deal-desk/tools/__tests__/hunter-api-key.test.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import type { RequestHandler } from "express";
2
2
  import type { Db } from "@dealdesk/db";
3
- import { ensureContactEmailFromApollo, resolveContactEmail } from "../enrichment/resolve-contact-email.js";
3
+ import { ensureContactEmailFromApollo, resolveContactEmail, type LoadEnrichment } from "../enrichment/resolve-contact-email.js";
4
4
  import { z } from "zod";
5
5
  export declare const enrichContactInputSchema: z.ZodObject<{
6
6
  targetId: z.ZodOptional<z.ZodString>;
@@ -15,7 +15,10 @@ export declare const enrichContactInputSchema: z.ZodObject<{
15
15
  export type EnrichContactInput = z.infer<typeof enrichContactInputSchema>;
16
16
  export interface EnrichContactDeps {
17
17
  db: Db;
18
- loadApolloKey: (companyId: string) => Promise<string | null>;
18
+ /** Provider-aware loader (preferred). */
19
+ loadEnrichment?: LoadEnrichment;
20
+ /** Legacy Apollo-only loader; still accepted for backwards compatibility. */
21
+ loadApolloKey?: (companyId: string) => Promise<string | null>;
19
22
  }
20
23
  export declare function enrichContactHandler(deps: EnrichContactDeps): RequestHandler;
21
24
  export { ensureContactEmailFromApollo, resolveContactEmail };
@@ -1 +1 @@
1
- {"version":3,"file":"enrich-contact.d.ts","sourceRoot":"","sources":["../../../src/deal-desk/tools/enrich-contact.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAqB,cAAc,EAAE,MAAM,SAAS,CAAC;AAGjE,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EACL,4BAA4B,EAC5B,mBAAmB,EACpB,MAAM,wCAAwC,CAAC;AAChD,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,wBAAwB;;;;;;;;;EAGnC,CAAC;AAEH,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAE1E,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,EAAE,CAAC;IACP,aAAa,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;CAC9D;AAOD,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,iBAAiB,GAAG,cAAc,CAmF5E;AAED,OAAO,EAAE,4BAA4B,EAAE,mBAAmB,EAAE,CAAC"}
1
+ {"version":3,"file":"enrich-contact.d.ts","sourceRoot":"","sources":["../../../src/deal-desk/tools/enrich-contact.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAqB,cAAc,EAAE,MAAM,SAAS,CAAC;AAGjE,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EACL,4BAA4B,EAC5B,mBAAmB,EACnB,KAAK,cAAc,EACpB,MAAM,wCAAwC,CAAC;AAChD,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,wBAAwB;;;;;;;;;EAGnC,CAAC;AAEH,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAE1E,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,EAAE,CAAC;IACP,yCAAyC;IACzC,cAAc,CAAC,EAAE,cAAc,CAAC;IAChC,6EAA6E;IAC7E,aAAa,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;CAC/D;AA2BD,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,iBAAiB,GAAG,cAAc,CA+D5E;AAED,OAAO,EAAE,4BAA4B,EAAE,mBAAmB,EAAE,CAAC"}
@@ -10,6 +10,25 @@ function resolveEnrichedByAgentId(req) {
10
10
  const agentId = req.agentId;
11
11
  return agentId ?? null;
12
12
  }
13
+ function httpStatusForEnrichCode(code) {
14
+ switch (code) {
15
+ case "contact_not_found":
16
+ return 404;
17
+ case "missing_contact_fields":
18
+ case "no_email_found":
19
+ case "apollo_plan_blocked":
20
+ case "apollo_credits_exhausted":
21
+ case "hunter_pii_restricted":
22
+ return 422;
23
+ case "apollo_lookup_failed":
24
+ case "hunter_lookup_failed":
25
+ case "hunter_rate_limited":
26
+ return 502;
27
+ default:
28
+ // apollo_not_configured, hunter_auth_failed, apollo_master_key_required, …
29
+ return 412;
30
+ }
31
+ }
13
32
  export function enrichContactHandler(deps) {
14
33
  return async (req, res) => {
15
34
  const companyId = req.params.companyId ?? "";
@@ -22,39 +41,21 @@ export function enrichContactHandler(deps) {
22
41
  res.status(400).json({ ok: false, reason: "contactId param required" });
23
42
  return;
24
43
  }
25
- const apiKey = await deps.loadApolloKey(companyId);
26
- if (!apiKey) {
27
- res.status(412).json({
28
- ok: false,
29
- reason: "Apollo.io API key not configured for this company. " +
30
- "Visit /deal-desk/email-accounts to set it up.",
31
- code: "apollo_not_configured",
32
- });
33
- return;
34
- }
35
44
  const resolved = await resolveContactEmail({
36
45
  db: deps.db,
37
46
  companyId,
38
47
  contactId,
48
+ loadEnrichment: deps.loadEnrichment,
39
49
  loadApolloKey: deps.loadApolloKey,
40
50
  });
41
51
  if (!resolved.ok) {
42
- const status = resolved.code === "contact_not_found"
43
- ? 404
44
- : resolved.code === "missing_contact_fields" ||
45
- resolved.code === "no_email_found"
46
- ? 422
47
- : resolved.code === "apollo_plan_blocked" ||
48
- resolved.code === "apollo_credits_exhausted"
49
- ? 422
50
- : resolved.code === "apollo_lookup_failed"
51
- ? 502
52
- : 412;
53
52
  if (resolved.code === "no_email_found") {
54
53
  res.status(200).json({ ok: false, reason: resolved.reason, code: resolved.code });
55
54
  return;
56
55
  }
57
- res.status(status).json({ ok: false, reason: resolved.reason, code: resolved.code });
56
+ res
57
+ .status(httpStatusForEnrichCode(resolved.code))
58
+ .json({ ok: false, reason: resolved.reason, code: resolved.code });
58
59
  return;
59
60
  }
60
61
  const updated = await deps.db
@@ -62,7 +63,7 @@ export function enrichContactHandler(deps) {
62
63
  .set({
63
64
  email: resolved.email,
64
65
  emailStatus: resolved.emailStatus,
65
- source: "apollo",
66
+ source: resolved.source,
66
67
  enrichedAt: new Date(),
67
68
  enrichedByAgentId: resolveEnrichedByAgentId(req),
68
69
  updatedAt: new Date(),
@@ -77,7 +78,8 @@ export function enrichContactHandler(deps) {
77
78
  ok: true,
78
79
  email: resolved.email,
79
80
  emailStatus: resolved.emailStatus,
80
- code: "apollo_enriched",
81
+ source: resolved.source,
82
+ code: "enriched",
81
83
  });
82
84
  };
83
85
  }