@aglyn/plugins-crm 1.0.0-beta.143

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 (669) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +7 -0
  3. package/package.json +57 -0
  4. package/src/index.d.ts +21 -0
  5. package/src/index.js +29 -0
  6. package/src/index.js.map +1 -0
  7. package/src/lib/components/activity-list.d.ts +98 -0
  8. package/src/lib/components/activity-list.js +321 -0
  9. package/src/lib/components/activity-list.js.map +1 -0
  10. package/src/lib/components/activity-queries.d.ts +117 -0
  11. package/src/lib/components/activity-queries.js +198 -0
  12. package/src/lib/components/activity-queries.js.map +1 -0
  13. package/src/lib/components/add-to-list-button.d.ts +25 -0
  14. package/src/lib/components/add-to-list-button.js +64 -0
  15. package/src/lib/components/add-to-list-button.js.map +1 -0
  16. package/src/lib/components/add-to-list-dialog.d.ts +24 -0
  17. package/src/lib/components/add-to-list-dialog.js +327 -0
  18. package/src/lib/components/add-to-list-dialog.js.map +1 -0
  19. package/src/lib/components/assignment-rule-drawer.d.ts +43 -0
  20. package/src/lib/components/assignment-rule-drawer.js +293 -0
  21. package/src/lib/components/assignment-rule-drawer.js.map +1 -0
  22. package/src/lib/components/companies-bulk-bar.d.ts +29 -0
  23. package/src/lib/components/companies-bulk-bar.js +274 -0
  24. package/src/lib/components/companies-bulk-bar.js.map +1 -0
  25. package/src/lib/components/companies-section.d.ts +54 -0
  26. package/src/lib/components/companies-section.js +522 -0
  27. package/src/lib/components/companies-section.js.map +1 -0
  28. package/src/lib/components/company-contacts-card.d.ts +49 -0
  29. package/src/lib/components/company-contacts-card.js +435 -0
  30. package/src/lib/components/company-contacts-card.js.map +1 -0
  31. package/src/lib/components/company-deals-card.d.ts +20 -0
  32. package/src/lib/components/company-deals-card.js +38 -0
  33. package/src/lib/components/company-deals-card.js.map +1 -0
  34. package/src/lib/components/company-detail-page.d.ts +20 -0
  35. package/src/lib/components/company-detail-page.js +165 -0
  36. package/src/lib/components/company-detail-page.js.map +1 -0
  37. package/src/lib/components/company-edit-drawer.d.ts +65 -0
  38. package/src/lib/components/company-edit-drawer.js +433 -0
  39. package/src/lib/components/company-edit-drawer.js.map +1 -0
  40. package/src/lib/components/company-import-drawer.d.ts +42 -0
  41. package/src/lib/components/company-import-drawer.js +99 -0
  42. package/src/lib/components/company-import-drawer.js.map +1 -0
  43. package/src/lib/components/company-picker.d.ts +127 -0
  44. package/src/lib/components/company-picker.js +323 -0
  45. package/src/lib/components/company-picker.js.map +1 -0
  46. package/src/lib/components/company-properties-card.d.ts +47 -0
  47. package/src/lib/components/company-properties-card.js +289 -0
  48. package/src/lib/components/company-properties-card.js.map +1 -0
  49. package/src/lib/components/contact-address-fields.d.ts +29 -0
  50. package/src/lib/components/contact-address-fields.js +149 -0
  51. package/src/lib/components/contact-address-fields.js.map +1 -0
  52. package/src/lib/components/contact-associations-card.d.ts +72 -0
  53. package/src/lib/components/contact-associations-card.js +296 -0
  54. package/src/lib/components/contact-associations-card.js.map +1 -0
  55. package/src/lib/components/contact-custom-columns.d.ts +38 -0
  56. package/src/lib/components/contact-custom-columns.js +102 -0
  57. package/src/lib/components/contact-custom-columns.js.map +1 -0
  58. package/src/lib/components/contact-custom-fields-card.d.ts +39 -0
  59. package/src/lib/components/contact-custom-fields-card.js +204 -0
  60. package/src/lib/components/contact-custom-fields-card.js.map +1 -0
  61. package/src/lib/components/contact-deals-card.d.ts +20 -0
  62. package/src/lib/components/contact-deals-card.js +38 -0
  63. package/src/lib/components/contact-deals-card.js.map +1 -0
  64. package/src/lib/components/contact-detail-page.d.ts +46 -0
  65. package/src/lib/components/contact-detail-page.js +535 -0
  66. package/src/lib/components/contact-detail-page.js.map +1 -0
  67. package/src/lib/components/contact-duplicates-card.d.ts +42 -0
  68. package/src/lib/components/contact-duplicates-card.js +167 -0
  69. package/src/lib/components/contact-duplicates-card.js.map +1 -0
  70. package/src/lib/components/contact-field-drawer.d.ts +64 -0
  71. package/src/lib/components/contact-field-drawer.js +251 -0
  72. package/src/lib/components/contact-field-drawer.js.map +1 -0
  73. package/src/lib/components/contact-import-drawer.d.ts +46 -0
  74. package/src/lib/components/contact-import-drawer.js +149 -0
  75. package/src/lib/components/contact-import-drawer.js.map +1 -0
  76. package/src/lib/components/contact-known-by-card.d.ts +39 -0
  77. package/src/lib/components/contact-known-by-card.js +142 -0
  78. package/src/lib/components/contact-known-by-card.js.map +1 -0
  79. package/src/lib/components/contact-list-columns.d.ts +53 -0
  80. package/src/lib/components/contact-list-columns.js +288 -0
  81. package/src/lib/components/contact-list-columns.js.map +1 -0
  82. package/src/lib/components/contact-merge-dialog.d.ts +79 -0
  83. package/src/lib/components/contact-merge-dialog.js +405 -0
  84. package/src/lib/components/contact-merge-dialog.js.map +1 -0
  85. package/src/lib/components/contact-properties-card.d.ts +89 -0
  86. package/src/lib/components/contact-properties-card.js +492 -0
  87. package/src/lib/components/contact-properties-card.js.map +1 -0
  88. package/src/lib/components/contact-timeline-card.d.ts +68 -0
  89. package/src/lib/components/contact-timeline-card.js +435 -0
  90. package/src/lib/components/contact-timeline-card.js.map +1 -0
  91. package/src/lib/components/contacts-bulk-bar.d.ts +91 -0
  92. package/src/lib/components/contacts-bulk-bar.js +493 -0
  93. package/src/lib/components/contacts-bulk-bar.js.map +1 -0
  94. package/src/lib/components/contacts-section.d.ts +26 -0
  95. package/src/lib/components/contacts-section.js +1025 -0
  96. package/src/lib/components/contacts-section.js.map +1 -0
  97. package/src/lib/components/copy-capture-address-button.d.ts +33 -0
  98. package/src/lib/components/copy-capture-address-button.js +60 -0
  99. package/src/lib/components/copy-capture-address-button.js.map +1 -0
  100. package/src/lib/components/crm-attribution-zone.d.ts +38 -0
  101. package/src/lib/components/crm-attribution-zone.js +36 -0
  102. package/src/lib/components/crm-attribution-zone.js.map +1 -0
  103. package/src/lib/components/crm-booking-zone.d.ts +61 -0
  104. package/src/lib/components/crm-booking-zone.js +50 -0
  105. package/src/lib/components/crm-booking-zone.js.map +1 -0
  106. package/src/lib/components/crm-bulk-bar-frame.d.ts +47 -0
  107. package/src/lib/components/crm-bulk-bar-frame.js +137 -0
  108. package/src/lib/components/crm-bulk-bar-frame.js.map +1 -0
  109. package/src/lib/components/crm-call-actions.d.ts +65 -0
  110. package/src/lib/components/crm-call-actions.js +110 -0
  111. package/src/lib/components/crm-call-actions.js.map +1 -0
  112. package/src/lib/components/crm-column-menu.d.ts +21 -0
  113. package/src/lib/components/crm-column-menu.js +103 -0
  114. package/src/lib/components/crm-column-menu.js.map +1 -0
  115. package/src/lib/components/crm-console-page.d.ts +19 -0
  116. package/src/lib/components/crm-console-page.js +151 -0
  117. package/src/lib/components/crm-console-page.js.map +1 -0
  118. package/src/lib/components/crm-console-sections.d.ts +52 -0
  119. package/src/lib/components/crm-console-sections.js +83 -0
  120. package/src/lib/components/crm-console-sections.js.map +1 -0
  121. package/src/lib/components/crm-custom-field-control.d.ts +26 -0
  122. package/src/lib/components/crm-custom-field-control.js +131 -0
  123. package/src/lib/components/crm-custom-field-control.js.map +1 -0
  124. package/src/lib/components/crm-email-template-tools.d.ts +69 -0
  125. package/src/lib/components/crm-email-template-tools.js +240 -0
  126. package/src/lib/components/crm-email-template-tools.js.map +1 -0
  127. package/src/lib/components/crm-export-all-button.d.ts +39 -0
  128. package/src/lib/components/crm-export-all-button.js +98 -0
  129. package/src/lib/components/crm-export-all-button.js.map +1 -0
  130. package/src/lib/components/crm-filter-bar.d.ts +53 -0
  131. package/src/lib/components/crm-filter-bar.js +294 -0
  132. package/src/lib/components/crm-filter-bar.js.map +1 -0
  133. package/src/lib/components/crm-glance-card.d.ts +54 -0
  134. package/src/lib/components/crm-glance-card.js +219 -0
  135. package/src/lib/components/crm-glance-card.js.map +1 -0
  136. package/src/lib/components/crm-next-activity-column.d.ts +35 -0
  137. package/src/lib/components/crm-next-activity-column.js +100 -0
  138. package/src/lib/components/crm-next-activity-column.js.map +1 -0
  139. package/src/lib/components/crm-record-header.d.ts +97 -0
  140. package/src/lib/components/crm-record-header.js +160 -0
  141. package/src/lib/components/crm-record-header.js.map +1 -0
  142. package/src/lib/components/crm-record-insights-zone.d.ts +50 -0
  143. package/src/lib/components/crm-record-insights-zone.js +169 -0
  144. package/src/lib/components/crm-record-insights-zone.js.map +1 -0
  145. package/src/lib/components/crm-record-picker.d.ts +42 -0
  146. package/src/lib/components/crm-record-picker.js +104 -0
  147. package/src/lib/components/crm-record-picker.js.map +1 -0
  148. package/src/lib/components/crm-send-email-button.d.ts +39 -0
  149. package/src/lib/components/crm-send-email-button.js +81 -0
  150. package/src/lib/components/crm-send-email-button.js.map +1 -0
  151. package/src/lib/components/crm-send-email-dialog.d.ts +61 -0
  152. package/src/lib/components/crm-send-email-dialog.js +851 -0
  153. package/src/lib/components/crm-send-email-dialog.js.map +1 -0
  154. package/src/lib/components/crm-site-picker.d.ts +61 -0
  155. package/src/lib/components/crm-site-picker.js +99 -0
  156. package/src/lib/components/crm-site-picker.js.map +1 -0
  157. package/src/lib/components/crm-suite-lock.d.ts +29 -0
  158. package/src/lib/components/crm-suite-lock.js +114 -0
  159. package/src/lib/components/crm-suite-lock.js.map +1 -0
  160. package/src/lib/components/crm-tasks-due-card.d.ts +42 -0
  161. package/src/lib/components/crm-tasks-due-card.js +225 -0
  162. package/src/lib/components/crm-tasks-due-card.js.map +1 -0
  163. package/src/lib/components/crm-views-control.d.ts +65 -0
  164. package/src/lib/components/crm-views-control.js +518 -0
  165. package/src/lib/components/crm-views-control.js.map +1 -0
  166. package/src/lib/components/csv-import-drawer.d.ts +132 -0
  167. package/src/lib/components/csv-import-drawer.js +746 -0
  168. package/src/lib/components/csv-import-drawer.js.map +1 -0
  169. package/src/lib/components/deal-board.d.ts +70 -0
  170. package/src/lib/components/deal-board.js +478 -0
  171. package/src/lib/components/deal-board.js.map +1 -0
  172. package/src/lib/components/deal-detail-page.d.ts +18 -0
  173. package/src/lib/components/deal-detail-page.js +323 -0
  174. package/src/lib/components/deal-detail-page.js.map +1 -0
  175. package/src/lib/components/deal-edit-drawer.d.ts +59 -0
  176. package/src/lib/components/deal-edit-drawer.js +640 -0
  177. package/src/lib/components/deal-edit-drawer.js.map +1 -0
  178. package/src/lib/components/deal-import-drawer.d.ts +24 -0
  179. package/src/lib/components/deal-import-drawer.js +83 -0
  180. package/src/lib/components/deal-import-drawer.js.map +1 -0
  181. package/src/lib/components/deal-products-card.d.ts +48 -0
  182. package/src/lib/components/deal-products-card.js +614 -0
  183. package/src/lib/components/deal-products-card.js.map +1 -0
  184. package/src/lib/components/deal-properties-card.d.ts +29 -0
  185. package/src/lib/components/deal-properties-card.js +144 -0
  186. package/src/lib/components/deal-properties-card.js.map +1 -0
  187. package/src/lib/components/deal-stage-card.d.ts +24 -0
  188. package/src/lib/components/deal-stage-card.js +199 -0
  189. package/src/lib/components/deal-stage-card.js.map +1 -0
  190. package/src/lib/components/deals-bulk-bar.d.ts +31 -0
  191. package/src/lib/components/deals-bulk-bar.js +340 -0
  192. package/src/lib/components/deals-bulk-bar.js.map +1 -0
  193. package/src/lib/components/deals-section.d.ts +49 -0
  194. package/src/lib/components/deals-section.js +767 -0
  195. package/src/lib/components/deals-section.js.map +1 -0
  196. package/src/lib/components/email-capture-card.d.ts +42 -0
  197. package/src/lib/components/email-capture-card.js +134 -0
  198. package/src/lib/components/email-capture-card.js.map +1 -0
  199. package/src/lib/components/email-template-drawer.d.ts +33 -0
  200. package/src/lib/components/email-template-drawer.js +209 -0
  201. package/src/lib/components/email-template-drawer.js.map +1 -0
  202. package/src/lib/components/email-templates-card.d.ts +33 -0
  203. package/src/lib/components/email-templates-card.js +370 -0
  204. package/src/lib/components/email-templates-card.js.map +1 -0
  205. package/src/lib/components/erase-person-action.d.ts +92 -0
  206. package/src/lib/components/erase-person-action.js +261 -0
  207. package/src/lib/components/erase-person-action.js.map +1 -0
  208. package/src/lib/components/fields-section.d.ts +37 -0
  209. package/src/lib/components/fields-section.js +641 -0
  210. package/src/lib/components/fields-section.js.map +1 -0
  211. package/src/lib/components/form-contact-fields-card.d.ts +46 -0
  212. package/src/lib/components/form-contact-fields-card.js +253 -0
  213. package/src/lib/components/form-contact-fields-card.js.map +1 -0
  214. package/src/lib/components/insert-link-at-caret.d.ts +28 -0
  215. package/src/lib/components/insert-link-at-caret.js +37 -0
  216. package/src/lib/components/insert-link-at-caret.js.map +1 -0
  217. package/src/lib/components/lead-convert-dialog.d.ts +32 -0
  218. package/src/lib/components/lead-convert-dialog.js +493 -0
  219. package/src/lib/components/lead-convert-dialog.js.map +1 -0
  220. package/src/lib/components/lead-detail-page.d.ts +16 -0
  221. package/src/lib/components/lead-detail-page.js +163 -0
  222. package/src/lib/components/lead-detail-page.js.map +1 -0
  223. package/src/lib/components/lead-history-card.d.ts +32 -0
  224. package/src/lib/components/lead-history-card.js +165 -0
  225. package/src/lib/components/lead-history-card.js.map +1 -0
  226. package/src/lib/components/lead-import-drawer.d.ts +24 -0
  227. package/src/lib/components/lead-import-drawer.js +95 -0
  228. package/src/lib/components/lead-import-drawer.js.map +1 -0
  229. package/src/lib/components/lead-owner-select.d.ts +35 -0
  230. package/src/lib/components/lead-owner-select.js +91 -0
  231. package/src/lib/components/lead-owner-select.js.map +1 -0
  232. package/src/lib/components/lead-properties-card.d.ts +61 -0
  233. package/src/lib/components/lead-properties-card.js +395 -0
  234. package/src/lib/components/lead-properties-card.js.map +1 -0
  235. package/src/lib/components/lead-status-chip.d.ts +12 -0
  236. package/src/lib/components/lead-status-chip.js +43 -0
  237. package/src/lib/components/lead-status-chip.js.map +1 -0
  238. package/src/lib/components/lead-surfaces-note.d.ts +126 -0
  239. package/src/lib/components/lead-surfaces-note.js +262 -0
  240. package/src/lib/components/lead-surfaces-note.js.map +1 -0
  241. package/src/lib/components/lead-unqualify-dialog.d.ts +24 -0
  242. package/src/lib/components/lead-unqualify-dialog.js +125 -0
  243. package/src/lib/components/lead-unqualify-dialog.js.map +1 -0
  244. package/src/lib/components/leads-bulk-bar.d.ts +58 -0
  245. package/src/lib/components/leads-bulk-bar.js +307 -0
  246. package/src/lib/components/leads-bulk-bar.js.map +1 -0
  247. package/src/lib/components/leads-section.d.ts +23 -0
  248. package/src/lib/components/leads-section.js +664 -0
  249. package/src/lib/components/leads-section.js.map +1 -0
  250. package/src/lib/components/linked-deals-card.d.ts +32 -0
  251. package/src/lib/components/linked-deals-card.js +163 -0
  252. package/src/lib/components/linked-deals-card.js.map +1 -0
  253. package/src/lib/components/log-activity-dialog.d.ts +60 -0
  254. package/src/lib/components/log-activity-dialog.js +368 -0
  255. package/src/lib/components/log-activity-dialog.js.map +1 -0
  256. package/src/lib/components/lost-reason-dialog.d.ts +26 -0
  257. package/src/lib/components/lost-reason-dialog.js +95 -0
  258. package/src/lib/components/lost-reason-dialog.js.map +1 -0
  259. package/src/lib/components/new-contact-drawer.d.ts +78 -0
  260. package/src/lib/components/new-contact-drawer.js +343 -0
  261. package/src/lib/components/new-contact-drawer.js.map +1 -0
  262. package/src/lib/components/org-lead-surfaces-note.d.ts +57 -0
  263. package/src/lib/components/org-lead-surfaces-note.js +172 -0
  264. package/src/lib/components/org-lead-surfaces-note.js.map +1 -0
  265. package/src/lib/components/owner-avatar.d.ts +18 -0
  266. package/src/lib/components/owner-avatar.js +61 -0
  267. package/src/lib/components/owner-avatar.js.map +1 -0
  268. package/src/lib/components/pipeline-stages-dialog.d.ts +43 -0
  269. package/src/lib/components/pipeline-stages-dialog.js +339 -0
  270. package/src/lib/components/pipeline-stages-dialog.js.map +1 -0
  271. package/src/lib/components/pipelines-dialog.d.ts +55 -0
  272. package/src/lib/components/pipelines-dialog.js +517 -0
  273. package/src/lib/components/pipelines-dialog.js.map +1 -0
  274. package/src/lib/components/recent-activity-feed.d.ts +39 -0
  275. package/src/lib/components/recent-activity-feed.js +103 -0
  276. package/src/lib/components/recent-activity-feed.js.map +1 -0
  277. package/src/lib/components/recipes-card.d.ts +39 -0
  278. package/src/lib/components/recipes-card.js +485 -0
  279. package/src/lib/components/recipes-card.js.map +1 -0
  280. package/src/lib/components/record-activity-card.d.ts +26 -0
  281. package/src/lib/components/record-activity-card.js +121 -0
  282. package/src/lib/components/record-activity-card.js.map +1 -0
  283. package/src/lib/components/record-files-card.d.ts +67 -0
  284. package/src/lib/components/record-files-card.js +290 -0
  285. package/src/lib/components/record-files-card.js.map +1 -0
  286. package/src/lib/components/record-tasks-card.d.ts +32 -0
  287. package/src/lib/components/record-tasks-card.js +306 -0
  288. package/src/lib/components/record-tasks-card.js.map +1 -0
  289. package/src/lib/components/reports/activity-card.d.ts +57 -0
  290. package/src/lib/components/reports/activity-card.js +281 -0
  291. package/src/lib/components/reports/activity-card.js.map +1 -0
  292. package/src/lib/components/reports/closed-deals-card.d.ts +20 -0
  293. package/src/lib/components/reports/closed-deals-card.js +194 -0
  294. package/src/lib/components/reports/closed-deals-card.js.map +1 -0
  295. package/src/lib/components/reports/contacts-mix-card.d.ts +27 -0
  296. package/src/lib/components/reports/contacts-mix-card.js +161 -0
  297. package/src/lib/components/reports/contacts-mix-card.js.map +1 -0
  298. package/src/lib/components/reports/contacts-trend-card.d.ts +31 -0
  299. package/src/lib/components/reports/contacts-trend-card.js +144 -0
  300. package/src/lib/components/reports/contacts-trend-card.js.map +1 -0
  301. package/src/lib/components/reports/forecast-card.d.ts +22 -0
  302. package/src/lib/components/reports/forecast-card.js +251 -0
  303. package/src/lib/components/reports/forecast-card.js.map +1 -0
  304. package/src/lib/components/reports/lead-counts.d.ts +32 -0
  305. package/src/lib/components/reports/lead-counts.js +44 -0
  306. package/src/lib/components/reports/lead-counts.js.map +1 -0
  307. package/src/lib/components/reports/lead-funnel-card.d.ts +38 -0
  308. package/src/lib/components/reports/lead-funnel-card.js +375 -0
  309. package/src/lib/components/reports/lead-funnel-card.js.map +1 -0
  310. package/src/lib/components/reports/pipeline-card.d.ts +19 -0
  311. package/src/lib/components/reports/pipeline-card.js +338 -0
  312. package/src/lib/components/reports/pipeline-card.js.map +1 -0
  313. package/src/lib/components/reports/report-bar-chart.d.ts +39 -0
  314. package/src/lib/components/reports/report-bar-chart.js +133 -0
  315. package/src/lib/components/reports/report-bar-chart.js.map +1 -0
  316. package/src/lib/components/reports/report-breakdown.d.ts +32 -0
  317. package/src/lib/components/reports/report-breakdown.js +105 -0
  318. package/src/lib/components/reports/report-breakdown.js.map +1 -0
  319. package/src/lib/components/reports/report-export.d.ts +37 -0
  320. package/src/lib/components/reports/report-export.js +66 -0
  321. package/src/lib/components/reports/report-export.js.map +1 -0
  322. package/src/lib/components/reports/report-format.d.ts +36 -0
  323. package/src/lib/components/reports/report-format.js +43 -0
  324. package/src/lib/components/reports/report-format.js.map +1 -0
  325. package/src/lib/components/reports/report-scope.d.ts +81 -0
  326. package/src/lib/components/reports/report-scope.js +58 -0
  327. package/src/lib/components/reports/report-scope.js.map +1 -0
  328. package/src/lib/components/reports/report-stat-tile.d.ts +47 -0
  329. package/src/lib/components/reports/report-stat-tile.js +96 -0
  330. package/src/lib/components/reports/report-stat-tile.js.map +1 -0
  331. package/src/lib/components/reports/source-conversion-card.d.ts +28 -0
  332. package/src/lib/components/reports/source-conversion-card.js +205 -0
  333. package/src/lib/components/reports/source-conversion-card.js.map +1 -0
  334. package/src/lib/components/reports/tasks-card.d.ts +26 -0
  335. package/src/lib/components/reports/tasks-card.js +279 -0
  336. package/src/lib/components/reports/tasks-card.js.map +1 -0
  337. package/src/lib/components/reports/use-aggregate-read.d.ts +99 -0
  338. package/src/lib/components/reports/use-aggregate-read.js +195 -0
  339. package/src/lib/components/reports/use-aggregate-read.js.map +1 -0
  340. package/src/lib/components/reports/won-lost-by-owner-card.d.ts +30 -0
  341. package/src/lib/components/reports/won-lost-by-owner-card.js +168 -0
  342. package/src/lib/components/reports/won-lost-by-owner-card.js.map +1 -0
  343. package/src/lib/components/reports-section.d.ts +42 -0
  344. package/src/lib/components/reports-section.js +308 -0
  345. package/src/lib/components/reports-section.js.map +1 -0
  346. package/src/lib/components/sending-addresses-card.d.ts +49 -0
  347. package/src/lib/components/sending-addresses-card.js +262 -0
  348. package/src/lib/components/sending-addresses-card.js.map +1 -0
  349. package/src/lib/components/settings-section.d.ts +151 -0
  350. package/src/lib/components/settings-section.js +783 -0
  351. package/src/lib/components/settings-section.js.map +1 -0
  352. package/src/lib/components/task-cells.d.ts +51 -0
  353. package/src/lib/components/task-cells.js +139 -0
  354. package/src/lib/components/task-cells.js.map +1 -0
  355. package/src/lib/components/task-edit-drawer.d.ts +53 -0
  356. package/src/lib/components/task-edit-drawer.js +483 -0
  357. package/src/lib/components/task-edit-drawer.js.map +1 -0
  358. package/src/lib/components/task-import-drawer.d.ts +24 -0
  359. package/src/lib/components/task-import-drawer.js +82 -0
  360. package/src/lib/components/task-import-drawer.js.map +1 -0
  361. package/src/lib/components/task-snooze-menu.d.ts +65 -0
  362. package/src/lib/components/task-snooze-menu.js +207 -0
  363. package/src/lib/components/task-snooze-menu.js.map +1 -0
  364. package/src/lib/components/tasks-bulk-bar.d.ts +25 -0
  365. package/src/lib/components/tasks-bulk-bar.js +348 -0
  366. package/src/lib/components/tasks-bulk-bar.js.map +1 -0
  367. package/src/lib/components/tasks-calendar.d.ts +38 -0
  368. package/src/lib/components/tasks-calendar.js +228 -0
  369. package/src/lib/components/tasks-calendar.js.map +1 -0
  370. package/src/lib/components/tasks-section.d.ts +27 -0
  371. package/src/lib/components/tasks-section.js +579 -0
  372. package/src/lib/components/tasks-section.js.map +1 -0
  373. package/src/lib/components/use-contact-campaign-emails.d.ts +32 -0
  374. package/src/lib/components/use-contact-campaign-emails.js +83 -0
  375. package/src/lib/components/use-contact-campaign-emails.js.map +1 -0
  376. package/src/lib/components/use-crm-api.d.ts +44 -0
  377. package/src/lib/components/use-crm-api.js +84 -0
  378. package/src/lib/components/use-crm-api.js.map +1 -0
  379. package/src/lib/components/use-crm-inbound-address.d.ts +60 -0
  380. package/src/lib/components/use-crm-inbound-address.js +124 -0
  381. package/src/lib/components/use-crm-inbound-address.js.map +1 -0
  382. package/src/lib/components/use-emails-hub-path.d.ts +24 -0
  383. package/src/lib/components/use-emails-hub-path.js +59 -0
  384. package/src/lib/components/use-emails-hub-path.js.map +1 -0
  385. package/src/lib/components/use-member-email-aliases.d.ts +54 -0
  386. package/src/lib/components/use-member-email-aliases.js +186 -0
  387. package/src/lib/components/use-member-email-aliases.js.map +1 -0
  388. package/src/lib/components/use-org-members.d.ts +40 -0
  389. package/src/lib/components/use-org-members.js +100 -0
  390. package/src/lib/components/use-org-members.js.map +1 -0
  391. package/src/lib/constants/api-routes.d.ts +109 -0
  392. package/src/lib/constants/api-routes.js +74 -0
  393. package/src/lib/constants/api-routes.js.map +1 -0
  394. package/src/lib/constants/bundle-common.d.ts +14 -0
  395. package/src/lib/constants/bundle-common.js +14 -0
  396. package/src/lib/constants/bundle-common.js.map +1 -0
  397. package/src/lib/constants/company-filters.d.ts +18 -0
  398. package/src/lib/constants/company-filters.js +51 -0
  399. package/src/lib/constants/company-filters.js.map +1 -0
  400. package/src/lib/constants/contact-filters.d.ts +38 -0
  401. package/src/lib/constants/contact-filters.js +294 -0
  402. package/src/lib/constants/contact-filters.js.map +1 -0
  403. package/src/lib/hooks/use-contact-field-definitions.d.ts +48 -0
  404. package/src/lib/hooks/use-contact-field-definitions.js +72 -0
  405. package/src/lib/hooks/use-contact-field-definitions.js.map +1 -0
  406. package/src/lib/hooks/use-contact-update.d.ts +25 -0
  407. package/src/lib/hooks/use-contact-update.js +80 -0
  408. package/src/lib/hooks/use-contact-update.js.map +1 -0
  409. package/src/lib/hooks/use-crm-activity-logger.d.ts +73 -0
  410. package/src/lib/hooks/use-crm-activity-logger.js +101 -0
  411. package/src/lib/hooks/use-crm-activity-logger.js.map +1 -0
  412. package/src/lib/hooks/use-crm-bulk-apply.d.ts +52 -0
  413. package/src/lib/hooks/use-crm-bulk-apply.js +112 -0
  414. package/src/lib/hooks/use-crm-bulk-apply.js.map +1 -0
  415. package/src/lib/hooks/use-crm-default-view.d.ts +24 -0
  416. package/src/lib/hooks/use-crm-default-view.js +64 -0
  417. package/src/lib/hooks/use-crm-default-view.js.map +1 -0
  418. package/src/lib/hooks/use-crm-email-templates.d.ts +59 -0
  419. package/src/lib/hooks/use-crm-email-templates.js +103 -0
  420. package/src/lib/hooks/use-crm-email-templates.js.map +1 -0
  421. package/src/lib/hooks/use-crm-hub-path.d.ts +29 -0
  422. package/src/lib/hooks/use-crm-hub-path.js +41 -0
  423. package/src/lib/hooks/use-crm-hub-path.js.map +1 -0
  424. package/src/lib/hooks/use-crm-org-mount.d.ts +97 -0
  425. package/src/lib/hooks/use-crm-org-mount.js +215 -0
  426. package/src/lib/hooks/use-crm-org-mount.js.map +1 -0
  427. package/src/lib/hooks/use-crm-record-names.d.ts +52 -0
  428. package/src/lib/hooks/use-crm-record-names.js +126 -0
  429. package/src/lib/hooks/use-crm-record-names.js.map +1 -0
  430. package/src/lib/hooks/use-crm-records-quota.d.ts +68 -0
  431. package/src/lib/hooks/use-crm-records-quota.js +118 -0
  432. package/src/lib/hooks/use-crm-records-quota.js.map +1 -0
  433. package/src/lib/hooks/use-crm-saved-view.d.ts +96 -0
  434. package/src/lib/hooks/use-crm-saved-view.js +329 -0
  435. package/src/lib/hooks/use-crm-saved-view.js.map +1 -0
  436. package/src/lib/hooks/use-crm-scope.d.ts +117 -0
  437. package/src/lib/hooks/use-crm-scope.js +147 -0
  438. package/src/lib/hooks/use-crm-scope.js.map +1 -0
  439. package/src/lib/hooks/use-crm-tasks.d.ts +85 -0
  440. package/src/lib/hooks/use-crm-tasks.js +153 -0
  441. package/src/lib/hooks/use-crm-tasks.js.map +1 -0
  442. package/src/lib/hooks/use-crm-view-grid.d.ts +55 -0
  443. package/src/lib/hooks/use-crm-view-grid.js +170 -0
  444. package/src/lib/hooks/use-crm-view-grid.js.map +1 -0
  445. package/src/lib/hooks/use-crm-views.d.ts +42 -0
  446. package/src/lib/hooks/use-crm-views.js +84 -0
  447. package/src/lib/hooks/use-crm-views.js.map +1 -0
  448. package/src/lib/hooks/use-deal-stage-api.d.ts +69 -0
  449. package/src/lib/hooks/use-deal-stage-api.js +78 -0
  450. package/src/lib/hooks/use-deal-stage-api.js.map +1 -0
  451. package/src/lib/hooks/use-deals.d.ts +47 -0
  452. package/src/lib/hooks/use-deals.js +105 -0
  453. package/src/lib/hooks/use-deals.js.map +1 -0
  454. package/src/lib/hooks/use-org-leads.d.ts +53 -0
  455. package/src/lib/hooks/use-org-leads.js +114 -0
  456. package/src/lib/hooks/use-org-leads.js.map +1 -0
  457. package/src/lib/hooks/use-org-member-directory.d.ts +36 -0
  458. package/src/lib/hooks/use-org-member-directory.js +116 -0
  459. package/src/lib/hooks/use-org-member-directory.js.map +1 -0
  460. package/src/lib/hooks/use-org-member-options.d.ts +38 -0
  461. package/src/lib/hooks/use-org-member-options.js +131 -0
  462. package/src/lib/hooks/use-org-member-options.js.map +1 -0
  463. package/src/lib/hooks/use-pipeline.d.ts +71 -0
  464. package/src/lib/hooks/use-pipeline.js +159 -0
  465. package/src/lib/hooks/use-pipeline.js.map +1 -0
  466. package/src/lib/model/companies-bulk-writes.d.ts +40 -0
  467. package/src/lib/model/companies-bulk-writes.js +103 -0
  468. package/src/lib/model/companies-bulk-writes.js.map +1 -0
  469. package/src/lib/model/companies-csv.d.ts +36 -0
  470. package/src/lib/model/companies-csv.js +38 -0
  471. package/src/lib/model/companies-csv.js.map +1 -0
  472. package/src/lib/model/companies.d.ts +99 -0
  473. package/src/lib/model/companies.js +168 -0
  474. package/src/lib/model/companies.js.map +1 -0
  475. package/src/lib/model/company-delete-route.d.ts +43 -0
  476. package/src/lib/model/company-delete-route.js +31 -0
  477. package/src/lib/model/company-delete-route.js.map +1 -0
  478. package/src/lib/model/company-delete.d.ts +42 -0
  479. package/src/lib/model/company-delete.js +52 -0
  480. package/src/lib/model/company-delete.js.map +1 -0
  481. package/src/lib/model/contact-duplicates.d.ts +58 -0
  482. package/src/lib/model/contact-duplicates.js +67 -0
  483. package/src/lib/model/contact-duplicates.js.map +1 -0
  484. package/src/lib/model/contact-record.d.ts +113 -0
  485. package/src/lib/model/contact-record.js +70 -0
  486. package/src/lib/model/contact-record.js.map +1 -0
  487. package/src/lib/model/contact-update.d.ts +93 -0
  488. package/src/lib/model/contact-update.js +50 -0
  489. package/src/lib/model/contact-update.js.map +1 -0
  490. package/src/lib/model/contacts-bulk-writes.d.ts +173 -0
  491. package/src/lib/model/contacts-bulk-writes.js +196 -0
  492. package/src/lib/model/contacts-bulk-writes.js.map +1 -0
  493. package/src/lib/model/contacts-csv.d.ts +54 -0
  494. package/src/lib/model/contacts-csv.js +67 -0
  495. package/src/lib/model/contacts-csv.js.map +1 -0
  496. package/src/lib/model/contacts-list-seed.d.ts +51 -0
  497. package/src/lib/model/contacts-list-seed.js +63 -0
  498. package/src/lib/model/contacts-list-seed.js.map +1 -0
  499. package/src/lib/model/crm-activity-report.d.ts +27 -0
  500. package/src/lib/model/crm-activity-report.js +56 -0
  501. package/src/lib/model/crm-activity-report.js.map +1 -0
  502. package/src/lib/model/crm-api.d.ts +49 -0
  503. package/src/lib/model/crm-api.js +47 -0
  504. package/src/lib/model/crm-api.js.map +1 -0
  505. package/src/lib/model/crm-bulk-writes.d.ts +147 -0
  506. package/src/lib/model/crm-bulk-writes.js +207 -0
  507. package/src/lib/model/crm-bulk-writes.js.map +1 -0
  508. package/src/lib/model/crm-company-import.d.ts +154 -0
  509. package/src/lib/model/crm-company-import.js +331 -0
  510. package/src/lib/model/crm-company-import.js.map +1 -0
  511. package/src/lib/model/crm-custom-draft.d.ts +62 -0
  512. package/src/lib/model/crm-custom-draft.js +67 -0
  513. package/src/lib/model/crm-custom-draft.js.map +1 -0
  514. package/src/lib/model/crm-deal-import.d.ts +112 -0
  515. package/src/lib/model/crm-deal-import.js +263 -0
  516. package/src/lib/model/crm-deal-import.js.map +1 -0
  517. package/src/lib/model/crm-import.d.ts +244 -0
  518. package/src/lib/model/crm-import.js +466 -0
  519. package/src/lib/model/crm-import.js.map +1 -0
  520. package/src/lib/model/crm-lead-import.d.ts +105 -0
  521. package/src/lib/model/crm-lead-import.js +255 -0
  522. package/src/lib/model/crm-lead-import.js.map +1 -0
  523. package/src/lib/model/crm-record-routes.d.ts +21 -0
  524. package/src/lib/model/crm-record-routes.js +70 -0
  525. package/src/lib/model/crm-record-routes.js.map +1 -0
  526. package/src/lib/model/crm-routes.d.ts +101 -0
  527. package/src/lib/model/crm-routes.js +92 -0
  528. package/src/lib/model/crm-routes.js.map +1 -0
  529. package/src/lib/model/crm-task-import.d.ts +94 -0
  530. package/src/lib/model/crm-task-import.js +275 -0
  531. package/src/lib/model/crm-task-import.js.map +1 -0
  532. package/src/lib/model/crm-view-param.d.ts +43 -0
  533. package/src/lib/model/crm-view-param.js +49 -0
  534. package/src/lib/model/crm-view-param.js.map +1 -0
  535. package/src/lib/model/deal-board-model.d.ts +241 -0
  536. package/src/lib/model/deal-board-model.js +439 -0
  537. package/src/lib/model/deal-board-model.js.map +1 -0
  538. package/src/lib/model/deal-form-model.d.ts +114 -0
  539. package/src/lib/model/deal-form-model.js +218 -0
  540. package/src/lib/model/deal-form-model.js.map +1 -0
  541. package/src/lib/model/deals-csv.d.ts +32 -0
  542. package/src/lib/model/deals-csv.js +37 -0
  543. package/src/lib/model/deals-csv.js.map +1 -0
  544. package/src/lib/model/import-column-shapes.d.ts +36 -0
  545. package/src/lib/model/import-column-shapes.js +76 -0
  546. package/src/lib/model/import-column-shapes.js.map +1 -0
  547. package/src/lib/model/lead-company-suggestion.d.ts +61 -0
  548. package/src/lib/model/lead-company-suggestion.js +65 -0
  549. package/src/lib/model/lead-company-suggestion.js.map +1 -0
  550. package/src/lib/model/lead-filters.d.ts +29 -0
  551. package/src/lib/model/lead-filters.js +39 -0
  552. package/src/lib/model/lead-filters.js.map +1 -0
  553. package/src/lib/model/lead-surfaces.d.ts +58 -0
  554. package/src/lib/model/lead-surfaces.js +67 -0
  555. package/src/lib/model/lead-surfaces.js.map +1 -0
  556. package/src/lib/model/leads-csv.d.ts +40 -0
  557. package/src/lib/model/leads-csv.js +40 -0
  558. package/src/lib/model/leads-csv.js.map +1 -0
  559. package/src/lib/model/next-activity-api.d.ts +31 -0
  560. package/src/lib/model/next-activity-api.js +57 -0
  561. package/src/lib/model/next-activity-api.js.map +1 -0
  562. package/src/lib/model/next-activity.d.ts +64 -0
  563. package/src/lib/model/next-activity.js +47 -0
  564. package/src/lib/model/next-activity.js.map +1 -0
  565. package/src/lib/model/person-key-web.d.ts +43 -0
  566. package/src/lib/model/person-key-web.js +52 -0
  567. package/src/lib/model/person-key-web.js.map +1 -0
  568. package/src/lib/model/record-facts.d.ts +282 -0
  569. package/src/lib/model/record-facts.js +434 -0
  570. package/src/lib/model/record-facts.js.map +1 -0
  571. package/src/lib/model/task-api.d.ts +28 -0
  572. package/src/lib/model/task-api.js +57 -0
  573. package/src/lib/model/task-api.js.map +1 -0
  574. package/src/lib/model/task-calendar.d.ts +108 -0
  575. package/src/lib/model/task-calendar.js +139 -0
  576. package/src/lib/model/task-calendar.js.map +1 -0
  577. package/src/lib/model/task-routes.d.ts +177 -0
  578. package/src/lib/model/task-routes.js +197 -0
  579. package/src/lib/model/task-routes.js.map +1 -0
  580. package/src/lib/model/task-scope.d.ts +45 -0
  581. package/src/lib/model/task-scope.js +51 -0
  582. package/src/lib/model/task-scope.js.map +1 -0
  583. package/src/lib/model/task-views.d.ts +149 -0
  584. package/src/lib/model/task-views.js +286 -0
  585. package/src/lib/model/task-views.js.map +1 -0
  586. package/src/lib/model/tasks-csv.d.ts +28 -0
  587. package/src/lib/model/tasks-csv.js +28 -0
  588. package/src/lib/model/tasks-csv.js.map +1 -0
  589. package/src/lib/plugin.d.ts +32 -0
  590. package/src/lib/plugin.js +208 -0
  591. package/src/lib/plugin.js.map +1 -0
  592. package/src/lib/server/companies-import.d.ts +57 -0
  593. package/src/lib/server/companies-import.js +242 -0
  594. package/src/lib/server/companies-import.js.map +1 -0
  595. package/src/lib/server/company-delete.d.ts +59 -0
  596. package/src/lib/server/company-delete.js +146 -0
  597. package/src/lib/server/company-delete.js.map +1 -0
  598. package/src/lib/server/contact-email-history.d.ts +82 -0
  599. package/src/lib/server/contact-email-history.js +264 -0
  600. package/src/lib/server/contact-email-history.js.map +1 -0
  601. package/src/lib/server/contact-profile.d.ts +41 -0
  602. package/src/lib/server/contact-profile.js +45 -0
  603. package/src/lib/server/contact-profile.js.map +1 -0
  604. package/src/lib/server/contact-update.d.ts +92 -0
  605. package/src/lib/server/contact-update.js +512 -0
  606. package/src/lib/server/contact-update.js.map +1 -0
  607. package/src/lib/server/contacts-import.d.ts +73 -0
  608. package/src/lib/server/contacts-import.js +263 -0
  609. package/src/lib/server/contacts-import.js.map +1 -0
  610. package/src/lib/server/contacts-merge.d.ts +86 -0
  611. package/src/lib/server/contacts-merge.js +206 -0
  612. package/src/lib/server/contacts-merge.js.map +1 -0
  613. package/src/lib/server/deals-import.d.ts +76 -0
  614. package/src/lib/server/deals-import.js +246 -0
  615. package/src/lib/server/deals-import.js.map +1 -0
  616. package/src/lib/server/email-send.d.ts +119 -0
  617. package/src/lib/server/email-send.js +667 -0
  618. package/src/lib/server/email-send.js.map +1 -0
  619. package/src/lib/server/email-template-duplicate.d.ts +19 -0
  620. package/src/lib/server/email-template-duplicate.js +206 -0
  621. package/src/lib/server/email-template-duplicate.js.map +1 -0
  622. package/src/lib/server/erase-person.d.ts +108 -0
  623. package/src/lib/server/erase-person.js +309 -0
  624. package/src/lib/server/erase-person.js.map +1 -0
  625. package/src/lib/server/import-context.d.ts +85 -0
  626. package/src/lib/server/import-context.js +181 -0
  627. package/src/lib/server/import-context.js.map +1 -0
  628. package/src/lib/server/inbound-address.d.ts +61 -0
  629. package/src/lib/server/inbound-address.js +188 -0
  630. package/src/lib/server/inbound-address.js.map +1 -0
  631. package/src/lib/server/lead-convert.d.ts +78 -0
  632. package/src/lib/server/lead-convert.js +250 -0
  633. package/src/lib/server/lead-convert.js.map +1 -0
  634. package/src/lib/server/leads-import.d.ts +84 -0
  635. package/src/lib/server/leads-import.js +261 -0
  636. package/src/lib/server/leads-import.js.map +1 -0
  637. package/src/lib/server/next-activity-routes.d.ts +33 -0
  638. package/src/lib/server/next-activity-routes.js +110 -0
  639. package/src/lib/server/next-activity-routes.js.map +1 -0
  640. package/src/lib/server/org-activity.d.ts +61 -0
  641. package/src/lib/server/org-activity.js +120 -0
  642. package/src/lib/server/org-activity.js.map +1 -0
  643. package/src/lib/server/org-caller.d.ts +110 -0
  644. package/src/lib/server/org-caller.js +154 -0
  645. package/src/lib/server/org-caller.js.map +1 -0
  646. package/src/lib/server/recipe-routes.d.ts +75 -0
  647. package/src/lib/server/recipe-routes.js +442 -0
  648. package/src/lib/server/recipe-routes.js.map +1 -0
  649. package/src/lib/server/record-facts.d.ts +65 -0
  650. package/src/lib/server/record-facts.js +337 -0
  651. package/src/lib/server/record-facts.js.map +1 -0
  652. package/src/lib/server/record-timeline.d.ts +51 -0
  653. package/src/lib/server/record-timeline.js +215 -0
  654. package/src/lib/server/record-timeline.js.map +1 -0
  655. package/src/lib/server/suite-gate.d.ts +42 -0
  656. package/src/lib/server/suite-gate.js +87 -0
  657. package/src/lib/server/suite-gate.js.map +1 -0
  658. package/src/lib/server/task-routes.d.ts +132 -0
  659. package/src/lib/server/task-routes.js +699 -0
  660. package/src/lib/server/task-routes.js.map +1 -0
  661. package/src/lib/server/tasks-import.d.ts +54 -0
  662. package/src/lib/server/tasks-import.js +157 -0
  663. package/src/lib/server/tasks-import.js.map +1 -0
  664. package/src/lib/server-deal-stage.d.ts +88 -0
  665. package/src/lib/server-deal-stage.js +316 -0
  666. package/src/lib/server-deal-stage.js.map +1 -0
  667. package/src/lib/server.d.ts +149 -0
  668. package/src/lib/server.js +615 -0
  669. package/src/lib/server.js.map +1 -0
@@ -0,0 +1,61 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Aglyn LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+ import { type PluginApiHandler } from '@aglyn/aglyn/server';
18
+ /**
19
+ * `POST /api/crm/inbound-address` — the workspace's email capture address
20
+ * (AGL-2657).
21
+ *
22
+ * Body: `{ hostId }` under a site, `{ orgId, hostId? }` at the organization
23
+ * level, and `rotate: true` to replace the token. Answers
24
+ * `{ ok: true, address, createdAtMs, rotatedAtMs?, rotated }`.
25
+ *
26
+ * ## Why a route and not a read of the org document
27
+ *
28
+ * The token is on the org document, which every member may read, and the
29
+ * address is the token in a fixed shape — but the shape's domain is the
30
+ * deployment's, `CRM_INBOUND_DOMAIN`, which a browser does not know, and
31
+ * the token does not exist until somebody asks for the address. So the
32
+ * first ask mints it, inside a transaction, and every ask answers the
33
+ * whole address. The org document is the read side for nothing but the
34
+ * rules, which deny the key to every client.
35
+ *
36
+ * ## Who may ask, and who may rotate
37
+ *
38
+ * Asking takes what opening the CRM takes: `data.manage` on the site's
39
+ * org, for a member who reaches the site — the sender's own gate in
40
+ * `email-send.ts`, restated — or, at the organization level, org-wide
41
+ * reach with the same permission. Rotating is a workspace OWNER or ADMIN's
42
+ * act, because the old address stops filing the moment the new token is
43
+ * written and every mailbox rule that carried it goes quiet: the same bar
44
+ * every CRM setting has, and the erasure route's. Staff are admitted to
45
+ * read as they are on every CRM route, and refused the rotation as the
46
+ * erasure route refuses them — it is the workspace's address to retire.
47
+ */
48
+ export declare const CRM_INBOUND_ADDRESS_ROUTE: "crm/inbound-address";
49
+ /** What a successful call answers with. */
50
+ export interface CrmInboundAddressResponse {
51
+ ok: true;
52
+ /** `crm+<token>@<capture domain>`. */
53
+ address: string;
54
+ createdAtMs: number;
55
+ rotatedAtMs?: number;
56
+ /** True when this call replaced the token. */
57
+ rotated: boolean;
58
+ }
59
+ export declare const CRM_INBOUND_ROTATE_REFUSAL = "Rotating the capture address requires a workspace owner or admin.";
60
+ export declare const crmInboundAddressHandler: PluginApiHandler;
61
+ export default crmInboundAddressHandler;
@@ -0,0 +1,188 @@
1
+ import { _ as _extends } from "@swc/helpers/_/_extends";
2
+ /**
3
+ * @license
4
+ * Copyright 2026 Aglyn LLC
5
+ *
6
+ * Licensed under the Apache License, Version 2.0 (the "License");
7
+ * you may not use this file except in compliance with the License.
8
+ * You may obtain a copy of the License at
9
+ *
10
+ * http://www.apache.org/licenses/LICENSE-2.0
11
+ *
12
+ * Unless required by applicable law or agreed to in writing, software
13
+ * distributed under the License is distributed on an "AS IS" BASIS,
14
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ * See the License for the specific language governing permissions and
16
+ * limitations under the License.
17
+ */ import { canManageOrg, crmInboundAddress, crmInboundDomain, isOrgWideMember } from "@aglyn/aglyn/server";
18
+ import { ensureCrmInboundToken, firebaseAdmin, getOrgForHost, logOrgActivity, memberHasOrgPermission, resolveOrgMembership } from "@aglyn/tenant-data-admin";
19
+ import { isRefusedIdToken } from "@aglyn/tenant-data-admin/server/id-token-refusal";
20
+ import { CRM_API_ROUTES } from "../constants/api-routes.js";
21
+ import { authorizeOrgCaller, readCrmRouteScope } from "./org-caller.js";
22
+ import { crmSuiteRefusal } from "./suite-gate.js";
23
+ /**
24
+ * `POST /api/crm/inbound-address` — the workspace's email capture address
25
+ * (AGL-2657).
26
+ *
27
+ * Body: `{ hostId }` under a site, `{ orgId, hostId? }` at the organization
28
+ * level, and `rotate: true` to replace the token. Answers
29
+ * `{ ok: true, address, createdAtMs, rotatedAtMs?, rotated }`.
30
+ *
31
+ * ## Why a route and not a read of the org document
32
+ *
33
+ * The token is on the org document, which every member may read, and the
34
+ * address is the token in a fixed shape — but the shape's domain is the
35
+ * deployment's, `CRM_INBOUND_DOMAIN`, which a browser does not know, and
36
+ * the token does not exist until somebody asks for the address. So the
37
+ * first ask mints it, inside a transaction, and every ask answers the
38
+ * whole address. The org document is the read side for nothing but the
39
+ * rules, which deny the key to every client.
40
+ *
41
+ * ## Who may ask, and who may rotate
42
+ *
43
+ * Asking takes what opening the CRM takes: `data.manage` on the site's
44
+ * org, for a member who reaches the site — the sender's own gate in
45
+ * `email-send.ts`, restated — or, at the organization level, org-wide
46
+ * reach with the same permission. Rotating is a workspace OWNER or ADMIN's
47
+ * act, because the old address stops filing the moment the new token is
48
+ * written and every mailbox rule that carried it goes quiet: the same bar
49
+ * every CRM setting has, and the erasure route's. Staff are admitted to
50
+ * read as they are on every CRM route, and refused the rotation as the
51
+ * erasure route refuses them — it is the workspace's address to retire.
52
+ */ export const CRM_INBOUND_ADDRESS_ROUTE = CRM_API_ROUTES.inboundAddress;
53
+ export const CRM_INBOUND_ROTATE_REFUSAL = 'Rotating the capture address requires a workspace owner or admin.';
54
+ const refuse = (status, error)=>({
55
+ ok: false,
56
+ status,
57
+ error
58
+ });
59
+ /**
60
+ * The site variant's caller: a verified token, then `data.manage` on the
61
+ * site's org for a member who reaches the site, staff passing as they do
62
+ * on every CRM route. Rotation needs the org role itself.
63
+ */ async function authorizeSiteCaller(req, hostId) {
64
+ var _req_headers_authorization, _ref, _decoded_email, _ref1;
65
+ const authorization = String((_req_headers_authorization = req.headers.authorization) != null ? _req_headers_authorization : '');
66
+ const idToken = authorization.startsWith('Bearer ') ? authorization.slice('Bearer '.length) : undefined;
67
+ if (!idToken) return refuse(401, 'Unauthenticated');
68
+ let decoded;
69
+ try {
70
+ decoded = await firebaseAdmin.app().auth().verifyIdToken(idToken);
71
+ } catch (error) {
72
+ // A refused credential is the caller's 401; a failure to check one is
73
+ // ours and keeps a 5xx (AGL-2852).
74
+ if (isRefusedIdToken(error)) return refuse(401, 'Unauthenticated');
75
+ console.error('[crm] inbound-address could not verify the caller', error);
76
+ return refuse(500, 'The sign-in could not be checked. Try again.');
77
+ }
78
+ const resolved = await getOrgForHost(hostId).catch(()=>null);
79
+ if (!resolved) return refuse(404, 'Unknown site');
80
+ const { orgId } = resolved;
81
+ const membership = await resolveOrgMembership(decoded.uid, orgId).catch(()=>null);
82
+ const member = (_ref = membership == null ? void 0 : membership.member) != null ? _ref : null;
83
+ if (decoded.staff !== true) {
84
+ var _member_hostAccess;
85
+ const reaches = isOrgWideMember(member) || Boolean(member == null ? void 0 : (_member_hostAccess = member.hostAccess) == null ? void 0 : _member_hostAccess[hostId]);
86
+ const allowed = member && reaches && await memberHasOrgPermission(orgId, member, 'data.manage');
87
+ if (!allowed) {
88
+ return refuse(403, 'Reading the capture address requires the data.manage permission on this site');
89
+ }
90
+ }
91
+ return {
92
+ ok: true,
93
+ uid: decoded.uid,
94
+ email: (_decoded_email = decoded.email) != null ? _decoded_email : null,
95
+ orgId,
96
+ org: resolved.org,
97
+ canRotate: canManageOrg((_ref1 = member == null ? void 0 : member.role) != null ? _ref1 : null)
98
+ };
99
+ }
100
+ /** The organization variant's caller, by the org the body names (AGL-2634). */ async function authorizeOrgLevelCaller(req, orgId, rotate) {
101
+ const caller = await authorizeOrgCaller(req, orgId, {
102
+ needs: rotate ? 'manage-org' : 'data.manage',
103
+ refusal: rotate ? CRM_INBOUND_ROTATE_REFUSAL : 'Reading the capture address at the organization level requires the ' + 'data.manage permission across the whole workspace'
104
+ });
105
+ if (caller.ok === false) return refuse(caller.status, caller.error);
106
+ return {
107
+ ok: true,
108
+ uid: caller.uid,
109
+ email: caller.email,
110
+ orgId,
111
+ org: caller.org,
112
+ // `manage-org` admitted them when they asked to rotate; a reader who
113
+ // did not ask is not told whether they could.
114
+ canRotate: rotate
115
+ };
116
+ }
117
+ export const crmInboundAddressHandler = async (req, res)=>{
118
+ var _req_body;
119
+ if (req.method !== 'POST') {
120
+ res.setHeader('Allow', 'POST');
121
+ res.status(405).json({
122
+ error: 'Method not allowed'
123
+ });
124
+ return;
125
+ }
126
+ const body = typeof req.body === 'string' ? JSON.parse(req.body) : (_req_body = req.body) != null ? _req_body : {};
127
+ const scope = readCrmRouteScope(body);
128
+ if (!scope) {
129
+ res.status(400).json({
130
+ error: 'Missing hostId'
131
+ });
132
+ return;
133
+ }
134
+ const rotate = body['rotate'] === true;
135
+ try {
136
+ const caller = scope.level === 'org' ? await authorizeOrgLevelCaller(req, scope.orgId, rotate) : await authorizeSiteCaller(req, scope.hostId);
137
+ if (caller.ok === false) {
138
+ res.status(caller.status).json({
139
+ error: caller.error
140
+ });
141
+ return;
142
+ }
143
+ if (rotate && !caller.canRotate) {
144
+ res.status(403).json({
145
+ error: CRM_INBOUND_ROTATE_REFUSAL
146
+ });
147
+ return;
148
+ }
149
+ // The first ask mints the token, so reading the address is a write on
150
+ // a plan without the suite; the webhook refuses such a plan's mail too.
151
+ const suite = crmSuiteRefusal(caller.org, 'The email capture address');
152
+ if (suite) {
153
+ res.status(suite.status).json(suite.body);
154
+ return;
155
+ }
156
+ const firestore = firebaseAdmin.app().firestore();
157
+ const result = await ensureCrmInboundToken(firestore, caller.orgId, {
158
+ rotate
159
+ });
160
+ if (result.rotated) {
161
+ // The old address went quiet with this write; the feed says who did it.
162
+ await logOrgActivity(caller.orgId, {
163
+ uid: caller.uid,
164
+ email: caller.email
165
+ }, 'Rotated the email capture address', {
166
+ type: 'org'
167
+ });
168
+ }
169
+ const answer = _extends({
170
+ ok: true,
171
+ address: crmInboundAddress(result.token, crmInboundDomain()),
172
+ createdAtMs: result.createdAtMs
173
+ }, typeof result.rotatedAtMs === 'number' ? {
174
+ rotatedAtMs: result.rotatedAtMs
175
+ } : {}, {
176
+ rotated: result.rotated
177
+ });
178
+ res.status(200).json(answer);
179
+ } catch (error) {
180
+ console.error('[crm] inbound-address failed', scope, error);
181
+ res.status(500).json({
182
+ error: 'The capture address could not be read.'
183
+ });
184
+ }
185
+ };
186
+ export default crmInboundAddressHandler;
187
+
188
+ //# sourceMappingURL=inbound-address.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/crm/src/lib/server/inbound-address.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n type AglynOrgMember,\n canManageOrg,\n crmInboundAddress,\n crmInboundDomain,\n isOrgWideMember,\n type PluginApiHandler,\n type PluginApiRequest,\n} from '@aglyn/aglyn/server'\nimport {\n ensureCrmInboundToken,\n firebaseAdmin,\n getOrgForHost,\n logOrgActivity,\n memberHasOrgPermission,\n resolveOrgMembership,\n} from '@aglyn/tenant-data-admin'\nimport { isRefusedIdToken } from '@aglyn/tenant-data-admin/server/id-token-refusal'\nimport { CRM_API_ROUTES } from '../constants/api-routes'\nimport { authorizeOrgCaller, readCrmRouteScope } from './org-caller'\nimport { crmSuiteRefusal } from './suite-gate'\n\n/**\n * `POST /api/crm/inbound-address` — the workspace's email capture address\n * (AGL-2657).\n *\n * Body: `{ hostId }` under a site, `{ orgId, hostId? }` at the organization\n * level, and `rotate: true` to replace the token. Answers\n * `{ ok: true, address, createdAtMs, rotatedAtMs?, rotated }`.\n *\n * ## Why a route and not a read of the org document\n *\n * The token is on the org document, which every member may read, and the\n * address is the token in a fixed shape — but the shape's domain is the\n * deployment's, `CRM_INBOUND_DOMAIN`, which a browser does not know, and\n * the token does not exist until somebody asks for the address. So the\n * first ask mints it, inside a transaction, and every ask answers the\n * whole address. The org document is the read side for nothing but the\n * rules, which deny the key to every client.\n *\n * ## Who may ask, and who may rotate\n *\n * Asking takes what opening the CRM takes: `data.manage` on the site's\n * org, for a member who reaches the site — the sender's own gate in\n * `email-send.ts`, restated — or, at the organization level, org-wide\n * reach with the same permission. Rotating is a workspace OWNER or ADMIN's\n * act, because the old address stops filing the moment the new token is\n * written and every mailbox rule that carried it goes quiet: the same bar\n * every CRM setting has, and the erasure route's. Staff are admitted to\n * read as they are on every CRM route, and refused the rotation as the\n * erasure route refuses them — it is the workspace's address to retire.\n */\n\nexport const CRM_INBOUND_ADDRESS_ROUTE = CRM_API_ROUTES.inboundAddress\n\n/** What a successful call answers with. */\nexport interface CrmInboundAddressResponse {\n ok: true\n /** `crm+<token>@<capture domain>`. */\n address: string\n createdAtMs: number\n rotatedAtMs?: number\n /** True when this call replaced the token. */\n rotated: boolean\n}\n\nexport const CRM_INBOUND_ROTATE_REFUSAL =\n 'Rotating the capture address requires a workspace owner or admin.'\n\ntype Refusal = { ok: false; status: number; error: string }\n\ninterface Caller {\n ok: true\n uid: string\n email: string | null\n orgId: string\n /** The org document, for the plan the address belongs to. */\n org: unknown\n /** Whether this caller may replace the token. */\n canRotate: boolean\n}\n\nconst refuse = (status: number, error: string): Refusal => ({ ok: false, status, error })\n\n/**\n * The site variant's caller: a verified token, then `data.manage` on the\n * site's org for a member who reaches the site, staff passing as they do\n * on every CRM route. Rotation needs the org role itself.\n */\nasync function authorizeSiteCaller(\n req: PluginApiRequest,\n hostId: string,\n): Promise<Caller | Refusal> {\n const authorization = String(req.headers.authorization ?? '')\n const idToken = authorization.startsWith('Bearer ')\n ? authorization.slice('Bearer '.length)\n : undefined\n if (!idToken) return refuse(401, 'Unauthenticated')\n let decoded: { uid: string; email?: string; staff?: unknown }\n try {\n decoded = await firebaseAdmin.app().auth().verifyIdToken(idToken)\n } catch (error) {\n // A refused credential is the caller's 401; a failure to check one is\n // ours and keeps a 5xx (AGL-2852).\n if (isRefusedIdToken(error)) return refuse(401, 'Unauthenticated')\n console.error('[crm] inbound-address could not verify the caller', error)\n return refuse(500, 'The sign-in could not be checked. Try again.')\n }\n const resolved = await getOrgForHost(hostId).catch(() => null)\n if (!resolved) return refuse(404, 'Unknown site')\n const { orgId } = resolved\n const membership = await resolveOrgMembership(decoded.uid, orgId).catch(() => null)\n const member = (membership?.member ?? null) as Partial<AglynOrgMember> | null\n if (decoded.staff !== true) {\n const reaches =\n isOrgWideMember(member) || Boolean(member?.hostAccess?.[hostId])\n const allowed =\n member && reaches && (await memberHasOrgPermission(orgId, member, 'data.manage'))\n if (!allowed) {\n return refuse(\n 403,\n 'Reading the capture address requires the data.manage permission on this site',\n )\n }\n }\n return {\n ok: true,\n uid: decoded.uid,\n email: decoded.email ?? null,\n orgId,\n org: resolved.org,\n canRotate: canManageOrg(member?.role ?? null),\n }\n}\n\n/** The organization variant's caller, by the org the body names (AGL-2634). */\nasync function authorizeOrgLevelCaller(\n req: PluginApiRequest,\n orgId: string,\n rotate: boolean,\n): Promise<Caller | Refusal> {\n const caller = await authorizeOrgCaller(req, orgId, {\n needs: rotate ? 'manage-org' : 'data.manage',\n refusal: rotate\n ? CRM_INBOUND_ROTATE_REFUSAL\n : 'Reading the capture address at the organization level requires the ' +\n 'data.manage permission across the whole workspace',\n })\n if (caller.ok === false) return refuse(caller.status, caller.error)\n return {\n ok: true,\n uid: caller.uid,\n email: caller.email,\n orgId,\n org: caller.org,\n // `manage-org` admitted them when they asked to rotate; a reader who\n // did not ask is not told whether they could.\n canRotate: rotate,\n }\n}\n\nexport const crmInboundAddressHandler: PluginApiHandler = async (req, res) => {\n if (req.method !== 'POST') {\n res.setHeader('Allow', 'POST')\n res.status(405).json({ error: 'Method not allowed' })\n return\n }\n const body = (\n typeof req.body === 'string' ? JSON.parse(req.body) : (req.body ?? {})\n ) as Record<string, unknown>\n const scope = readCrmRouteScope(body)\n if (!scope) {\n res.status(400).json({ error: 'Missing hostId' })\n return\n }\n const rotate = body['rotate'] === true\n try {\n const caller =\n scope.level === 'org'\n ? await authorizeOrgLevelCaller(req, scope.orgId, rotate)\n : await authorizeSiteCaller(req, scope.hostId)\n if (caller.ok === false) {\n res.status(caller.status).json({ error: caller.error })\n return\n }\n if (rotate && !caller.canRotate) {\n res.status(403).json({ error: CRM_INBOUND_ROTATE_REFUSAL })\n return\n }\n // The first ask mints the token, so reading the address is a write on\n // a plan without the suite; the webhook refuses such a plan's mail too.\n const suite = crmSuiteRefusal(caller.org, 'The email capture address')\n if (suite) {\n res.status(suite.status).json(suite.body)\n return\n }\n const firestore = firebaseAdmin.app().firestore()\n const result = await ensureCrmInboundToken(firestore, caller.orgId, { rotate })\n if (result.rotated) {\n // The old address went quiet with this write; the feed says who did it.\n await logOrgActivity(\n caller.orgId,\n { uid: caller.uid, email: caller.email },\n 'Rotated the email capture address',\n { type: 'org' },\n )\n }\n const answer: CrmInboundAddressResponse = {\n ok: true,\n address: crmInboundAddress(result.token, crmInboundDomain()),\n createdAtMs: result.createdAtMs,\n ...(typeof result.rotatedAtMs === 'number' ? { rotatedAtMs: result.rotatedAtMs } : {}),\n rotated: result.rotated,\n }\n res.status(200).json(answer)\n } catch (error) {\n console.error('[crm] inbound-address failed', scope, error)\n res.status(500).json({ error: 'The capture address could not be read.' })\n }\n}\n\nexport default crmInboundAddressHandler\n"],"names":["canManageOrg","crmInboundAddress","crmInboundDomain","isOrgWideMember","ensureCrmInboundToken","firebaseAdmin","getOrgForHost","logOrgActivity","memberHasOrgPermission","resolveOrgMembership","isRefusedIdToken","CRM_API_ROUTES","authorizeOrgCaller","readCrmRouteScope","crmSuiteRefusal","CRM_INBOUND_ADDRESS_ROUTE","inboundAddress","CRM_INBOUND_ROTATE_REFUSAL","refuse","status","error","ok","authorizeSiteCaller","req","hostId","decoded","authorization","String","headers","idToken","startsWith","slice","length","undefined","app","auth","verifyIdToken","console","resolved","catch","orgId","membership","uid","member","staff","reaches","Boolean","hostAccess","allowed","email","org","canRotate","role","authorizeOrgLevelCaller","rotate","caller","needs","refusal","crmInboundAddressHandler","res","method","setHeader","json","body","JSON","parse","scope","level","suite","firestore","result","rotated","type","answer","address","token","createdAtMs","rotatedAtMs"],"mappings":"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"}
@@ -0,0 +1,78 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Aglyn LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+ /**
18
+ * `POST /api/crm/lead-convert` — a lead becomes a contact, and optionally a
19
+ * company and a deal (AGL-2608).
20
+ *
21
+ * This is the console's door onto `convertHostLead` (the tenancy runtime),
22
+ * which owns the four writes, their order, and the idempotency on the lead;
23
+ * the REST API's `POST /v1/leads/{id}/convert` is the other door onto the
24
+ * same function (AGL-2627). What lives here is what only this door knows:
25
+ * the ID token, the body the convert dialog posts, and the statuses and
26
+ * sentences the dialog shows.
27
+ *
28
+ * ## What the caller has to be
29
+ *
30
+ * A signed-in member of the host's org holding `data.manage` — the same key
31
+ * the console gate on the CRM surface enforces — with a role on this site.
32
+ * Checked here with the Admin SDK rather than trusted from the client,
33
+ * because this route writes into collections the caller's own rules would
34
+ * otherwise decide about.
35
+ */
36
+ import { type PluginApiHandler } from '@aglyn/aglyn/server';
37
+ export { stageForNewDeal } from '@aglyn/tenant-runtime/convert-host-lead';
38
+ /** The body the console's convert dialog posts. */
39
+ export interface LeadConvertRequest {
40
+ hostId: string;
41
+ /** `hosts/{hostId}/leads/{leadId}` — the document id, which is the person key. */
42
+ leadId: string;
43
+ /**
44
+ * Who owns the resulting contact (and deal). Defaults to the lead's own
45
+ * owner; failing that the org's assignment rules and the site's default
46
+ * owner decide (AGL-2618), and failing those the caller — somebody
47
+ * converted this person, and a record with no owner is one nobody
48
+ * follows up.
49
+ */
50
+ ownerUid?: string;
51
+ /** Link an existing `orgs/{orgId}/companies/{companyId}`. */
52
+ companyId?: string;
53
+ /** Or create one. Ignored when `companyId` is given. */
54
+ createCompany?: {
55
+ name: string;
56
+ domain?: string;
57
+ };
58
+ /** Open a deal in the org's default pipeline. */
59
+ deal?: {
60
+ title: string;
61
+ amountCents?: number;
62
+ /** Lowercase ISO 4217; `usd` when absent or malformed. */
63
+ currency?: string;
64
+ /** A stage of the default pipeline; its first open stage when absent. */
65
+ stageId?: string;
66
+ };
67
+ }
68
+ /** What the route answers on success. */
69
+ export interface LeadConvertResponse {
70
+ ok: true;
71
+ contactId: string;
72
+ companyId?: string;
73
+ dealId?: string;
74
+ /** The lead was converted before this call; nothing was created now. */
75
+ alreadyConverted: boolean;
76
+ }
77
+ export declare const leadConvertHandler: PluginApiHandler;
78
+ export default leadConvertHandler;
@@ -0,0 +1,250 @@
1
+ import { _ as _extends } from "@swc/helpers/_/_extends";
2
+ /**
3
+ * @license
4
+ * Copyright 2026 Aglyn LLC
5
+ *
6
+ * Licensed under the Apache License, Version 2.0 (the "License");
7
+ * you may not use this file except in compliance with the License.
8
+ * You may obtain a copy of the License at
9
+ *
10
+ * http://www.apache.org/licenses/LICENSE-2.0
11
+ *
12
+ * Unless required by applicable law or agreed to in writing, software
13
+ * distributed under the License is distributed on an "AS IS" BASIS,
14
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ * See the License for the specific language governing permissions and
16
+ * limitations under the License.
17
+ */ /**
18
+ * `POST /api/crm/lead-convert` — a lead becomes a contact, and optionally a
19
+ * company and a deal (AGL-2608).
20
+ *
21
+ * This is the console's door onto `convertHostLead` (the tenancy runtime),
22
+ * which owns the four writes, their order, and the idempotency on the lead;
23
+ * the REST API's `POST /v1/leads/{id}/convert` is the other door onto the
24
+ * same function (AGL-2627). What lives here is what only this door knows:
25
+ * the ID token, the body the convert dialog posts, and the statuses and
26
+ * sentences the dialog shows.
27
+ *
28
+ * ## What the caller has to be
29
+ *
30
+ * A signed-in member of the host's org holding `data.manage` — the same key
31
+ * the console gate on the CRM surface enforces — with a role on this site.
32
+ * Checked here with the Admin SDK rather than trusted from the client,
33
+ * because this route writes into collections the caller's own rules would
34
+ * otherwise decide about.
35
+ */ import { CONTACT_ERASED_MESSAGE, CRM_RECORDS_BAND_FULL_MESSAGE, normalizeCompanyDomain } from "@aglyn/aglyn/server";
36
+ import { firebaseAdmin, getOrgForHost } from "@aglyn/tenant-data-admin";
37
+ import { convertHostLead } from "@aglyn/tenant-runtime/convert-host-lead";
38
+ import { resolveOrgPermissions } from "@aglyn/tenant-runtime/org-permissions";
39
+ import { holdsDataManage } from "./org-caller.js";
40
+ import { crmSuiteRefusal } from "./suite-gate.js";
41
+ // The stage picker moved to the runtime with the writes; re-exported so the
42
+ // pipeline code that imports it from here keeps its import.
43
+ export { stageForNewDeal } from "@aglyn/tenant-runtime/convert-host-lead";
44
+ const COMPANY_NAME_MAX = 120;
45
+ const DEAL_TITLE_MAX = 200;
46
+ const CURRENCY_PATTERN = /^[a-z]{3}$/;
47
+ /**
48
+ * How each refusal the writes can answer reads at this door — the status
49
+ * and the sentence the convert dialog has always shown for it.
50
+ */ const REFUSALS = {
51
+ 'unknown-lead': {
52
+ status: 404,
53
+ body: {
54
+ error: 'Unknown lead'
55
+ }
56
+ },
57
+ 'no-email': {
58
+ status: 422,
59
+ body: {
60
+ error: 'This lead has no usable email address to convert'
61
+ }
62
+ },
63
+ 'contact-not-created': {
64
+ status: 409,
65
+ body: {
66
+ error: 'The contact could not be created — the audience band may be ' + 'full. Nothing was changed.'
67
+ }
68
+ },
69
+ 'band-full': {
70
+ status: 409,
71
+ body: {
72
+ error: CRM_RECORDS_BAND_FULL_MESSAGE,
73
+ reason: 'band'
74
+ }
75
+ },
76
+ // The contact create route's own answer for an erased address (AGL-2623),
77
+ // so the convert dialog and the add-contact drawer say one thing about
78
+ // one person.
79
+ erased: {
80
+ status: 409,
81
+ body: {
82
+ error: CONTACT_ERASED_MESSAGE,
83
+ reason: 'erased'
84
+ }
85
+ },
86
+ 'unknown-company': {
87
+ status: 404,
88
+ body: {
89
+ error: 'Unknown company'
90
+ }
91
+ },
92
+ 'no-stages': {
93
+ status: 409,
94
+ body: {
95
+ error: 'The default pipeline has no stages to open a deal in'
96
+ }
97
+ }
98
+ };
99
+ export const leadConvertHandler = async (req, res)=>{
100
+ var _req_headers_authorization, _req_body, _body_hostId, _body_leadId, _body_companyId;
101
+ if (req.method !== 'POST') {
102
+ res.setHeader('Allow', 'POST');
103
+ res.status(405).json({
104
+ error: 'Method not allowed'
105
+ });
106
+ return;
107
+ }
108
+ const authorization = String((_req_headers_authorization = req.headers.authorization) != null ? _req_headers_authorization : '');
109
+ const idToken = authorization.startsWith('Bearer ') ? authorization.slice('Bearer '.length) : undefined;
110
+ if (!idToken) {
111
+ res.status(401).json({
112
+ error: 'Unauthenticated'
113
+ });
114
+ return;
115
+ }
116
+ const body = typeof req.body === 'string' ? JSON.parse(req.body) : (_req_body = req.body) != null ? _req_body : {};
117
+ const hostId = String((_body_hostId = body.hostId) != null ? _body_hostId : '').trim();
118
+ const leadId = String((_body_leadId = body.leadId) != null ? _body_leadId : '').trim();
119
+ if (!hostId || !leadId) {
120
+ res.status(400).json({
121
+ error: 'Missing hostId or leadId'
122
+ });
123
+ return;
124
+ }
125
+ /*
126
+ * Validate the optional parts BEFORE any read, so a malformed request costs
127
+ * nothing and a bad company domain is refused rather than silently dropped
128
+ * — a converter who typed a domain expects the company to carry it.
129
+ */ const requestedCompanyId = String((_body_companyId = body.companyId) != null ? _body_companyId : '').trim();
130
+ let createCompany = null;
131
+ if (!requestedCompanyId && body.createCompany) {
132
+ var _body_createCompany_name, _body_createCompany_domain;
133
+ const name = String((_body_createCompany_name = body.createCompany.name) != null ? _body_createCompany_name : '').trim().slice(0, COMPANY_NAME_MAX);
134
+ if (!name) {
135
+ res.status(400).json({
136
+ error: 'A company needs a name'
137
+ });
138
+ return;
139
+ }
140
+ const rawDomain = String((_body_createCompany_domain = body.createCompany.domain) != null ? _body_createCompany_domain : '').trim();
141
+ const domain = rawDomain ? normalizeCompanyDomain(rawDomain) : null;
142
+ if (rawDomain && !domain) {
143
+ res.status(400).json({
144
+ error: 'That does not look like a domain'
145
+ });
146
+ return;
147
+ }
148
+ createCompany = {
149
+ name,
150
+ domain
151
+ };
152
+ }
153
+ let deal = null;
154
+ if (body.deal) {
155
+ var _body_deal_title, _body_deal_currency;
156
+ const title = String((_body_deal_title = body.deal.title) != null ? _body_deal_title : '').trim().slice(0, DEAL_TITLE_MAX);
157
+ if (!title) {
158
+ res.status(400).json({
159
+ error: 'A deal needs a title'
160
+ });
161
+ return;
162
+ }
163
+ const amount = Number(body.deal.amountCents);
164
+ const currency = String((_body_deal_currency = body.deal.currency) != null ? _body_deal_currency : '').trim().toLowerCase();
165
+ deal = {
166
+ title,
167
+ amountCents: Number.isFinite(amount) && amount >= 0 ? Math.round(amount) : null,
168
+ currency: CURRENCY_PATTERN.test(currency) ? currency : 'usd',
169
+ stageId: body.deal.stageId ? String(body.deal.stageId) : undefined
170
+ };
171
+ }
172
+ try {
173
+ var _decoded_email;
174
+ const decoded = await firebaseAdmin.app().auth().verifyIdToken(idToken);
175
+ const staff = decoded['staff'] === true;
176
+ /*
177
+ * The console's own gate on the CRM is `data.manage`, asked of the
178
+ * permission catalog (`holdsDataManage`), and additionally that the
179
+ * caller has a role on THIS site — an org member scoped to a sibling site
180
+ * holds the key but not the host, and a lead is the host's record.
181
+ * `resolveOrgPermissions` answers the site role and fails closed on a
182
+ * lookup error when a host is named, so an absent membership refuses.
183
+ */ const membership = await resolveOrgPermissions(decoded.uid, {
184
+ hostId
185
+ });
186
+ if (!staff && !(membership.hostRole && await holdsDataManage(membership.orgId, decoded.uid))) {
187
+ res.status(403).json({
188
+ error: 'Converting a lead requires the data permission on this site'
189
+ });
190
+ return;
191
+ }
192
+ const resolved = await getOrgForHost(hostId);
193
+ if (!resolved) {
194
+ res.status(404).json({
195
+ error: 'Unknown site'
196
+ });
197
+ return;
198
+ }
199
+ const { orgId, org } = resolved;
200
+ // A lead's conversion is the CRM's, like its status and owner (AGL-2787).
201
+ const suite = crmSuiteRefusal(org, 'Converting a lead');
202
+ if (suite) {
203
+ res.status(suite.status).json(suite.body);
204
+ return;
205
+ }
206
+ const result = await convertHostLead(_extends({
207
+ firestore: firebaseAdmin.app().firestore(),
208
+ hostId,
209
+ orgId,
210
+ org: org,
211
+ leadId,
212
+ actor: {
213
+ uid: decoded.uid,
214
+ email: (_decoded_email = decoded.email) != null ? _decoded_email : null,
215
+ kind: 'member'
216
+ }
217
+ }, body.ownerUid ? {
218
+ ownerUid: String(body.ownerUid)
219
+ } : {}, requestedCompanyId ? {
220
+ companyId: requestedCompanyId
221
+ } : {}, {
222
+ createCompany,
223
+ deal
224
+ }));
225
+ if (result.ok === false) {
226
+ const refusal = REFUSALS[result.reason];
227
+ res.status(refusal.status).json(refusal.body);
228
+ return;
229
+ }
230
+ const answer = _extends({
231
+ ok: true,
232
+ contactId: result.contactId
233
+ }, result.companyId ? {
234
+ companyId: result.companyId
235
+ } : {}, result.dealId ? {
236
+ dealId: result.dealId
237
+ } : {}, {
238
+ alreadyConverted: result.alreadyConverted
239
+ });
240
+ res.status(200).json(answer);
241
+ } catch (error) {
242
+ console.error('lead-convert failed', error);
243
+ res.status(500).json({
244
+ error: 'The lead could not be converted.'
245
+ });
246
+ }
247
+ };
248
+ export default leadConvertHandler;
249
+
250
+ //# sourceMappingURL=lead-convert.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/crm/src/lib/server/lead-convert.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * `POST /api/crm/lead-convert` — a lead becomes a contact, and optionally a\n * company and a deal (AGL-2608).\n *\n * This is the console's door onto `convertHostLead` (the tenancy runtime),\n * which owns the four writes, their order, and the idempotency on the lead;\n * the REST API's `POST /v1/leads/{id}/convert` is the other door onto the\n * same function (AGL-2627). What lives here is what only this door knows:\n * the ID token, the body the convert dialog posts, and the statuses and\n * sentences the dialog shows.\n *\n * ## What the caller has to be\n *\n * A signed-in member of the host's org holding `data.manage` — the same key\n * the console gate on the CRM surface enforces — with a role on this site.\n * Checked here with the Admin SDK rather than trusted from the client,\n * because this route writes into collections the caller's own rules would\n * otherwise decide about.\n */\n\nimport {\n CONTACT_ERASED_MESSAGE,\n CRM_RECORDS_BAND_FULL_MESSAGE,\n normalizeCompanyDomain,\n type PluginApiHandler,\n} from '@aglyn/aglyn/server'\nimport { firebaseAdmin, getOrgForHost } from '@aglyn/tenant-data-admin'\nimport {\n type ConvertHostLeadRefusal,\n convertHostLead,\n} from '@aglyn/tenant-runtime/convert-host-lead'\nimport { resolveOrgPermissions } from '@aglyn/tenant-runtime/org-permissions'\nimport { holdsDataManage } from './org-caller'\nimport { crmSuiteRefusal } from './suite-gate'\n\n// The stage picker moved to the runtime with the writes; re-exported so the\n// pipeline code that imports it from here keeps its import.\nexport { stageForNewDeal } from '@aglyn/tenant-runtime/convert-host-lead'\n\n/** The body the console's convert dialog posts. */\nexport interface LeadConvertRequest {\n hostId: string\n /** `hosts/{hostId}/leads/{leadId}` — the document id, which is the person key. */\n leadId: string\n /**\n * Who owns the resulting contact (and deal). Defaults to the lead's own\n * owner; failing that the org's assignment rules and the site's default\n * owner decide (AGL-2618), and failing those the caller — somebody\n * converted this person, and a record with no owner is one nobody\n * follows up.\n */\n ownerUid?: string\n /** Link an existing `orgs/{orgId}/companies/{companyId}`. */\n companyId?: string\n /** Or create one. Ignored when `companyId` is given. */\n createCompany?: { name: string; domain?: string }\n /** Open a deal in the org's default pipeline. */\n deal?: {\n title: string\n amountCents?: number\n /** Lowercase ISO 4217; `usd` when absent or malformed. */\n currency?: string\n /** A stage of the default pipeline; its first open stage when absent. */\n stageId?: string\n }\n}\n\n/** What the route answers on success. */\nexport interface LeadConvertResponse {\n ok: true\n contactId: string\n companyId?: string\n dealId?: string\n /** The lead was converted before this call; nothing was created now. */\n alreadyConverted: boolean\n}\n\nconst COMPANY_NAME_MAX = 120\nconst DEAL_TITLE_MAX = 200\nconst CURRENCY_PATTERN = /^[a-z]{3}$/\n\n/**\n * How each refusal the writes can answer reads at this door — the status\n * and the sentence the convert dialog has always shown for it.\n */\nconst REFUSALS: Record<\n ConvertHostLeadRefusal,\n { status: number; body: Record<string, unknown> }\n> = {\n 'unknown-lead': { status: 404, body: { error: 'Unknown lead' } },\n 'no-email': {\n status: 422,\n body: { error: 'This lead has no usable email address to convert' },\n },\n 'contact-not-created': {\n status: 409,\n body: {\n error:\n 'The contact could not be created — the audience band may be ' +\n 'full. Nothing was changed.',\n },\n },\n 'band-full': {\n status: 409,\n body: { error: CRM_RECORDS_BAND_FULL_MESSAGE, reason: 'band' },\n },\n // The contact create route's own answer for an erased address (AGL-2623),\n // so the convert dialog and the add-contact drawer say one thing about\n // one person.\n erased: {\n status: 409,\n body: { error: CONTACT_ERASED_MESSAGE, reason: 'erased' },\n },\n 'unknown-company': { status: 404, body: { error: 'Unknown company' } },\n 'no-stages': {\n status: 409,\n body: { error: 'The default pipeline has no stages to open a deal in' },\n },\n}\n\nexport const leadConvertHandler: PluginApiHandler = async (req, res) => {\n if (req.method !== 'POST') {\n res.setHeader('Allow', 'POST')\n res.status(405).json({ error: 'Method not allowed' })\n return\n }\n const authorization = String(req.headers.authorization ?? '')\n const idToken = authorization.startsWith('Bearer ')\n ? authorization.slice('Bearer '.length)\n : undefined\n if (!idToken) {\n res.status(401).json({ error: 'Unauthenticated' })\n return\n }\n const body: Partial<LeadConvertRequest> =\n typeof req.body === 'string' ? JSON.parse(req.body) : (req.body ?? {})\n const hostId = String(body.hostId ?? '').trim()\n const leadId = String(body.leadId ?? '').trim()\n if (!hostId || !leadId) {\n res.status(400).json({ error: 'Missing hostId or leadId' })\n return\n }\n\n /*\n * Validate the optional parts BEFORE any read, so a malformed request costs\n * nothing and a bad company domain is refused rather than silently dropped\n * — a converter who typed a domain expects the company to carry it.\n */\n const requestedCompanyId = String(body.companyId ?? '').trim()\n let createCompany: { name: string; domain: string | null } | null = null\n if (!requestedCompanyId && body.createCompany) {\n const name = String(body.createCompany.name ?? '')\n .trim()\n .slice(0, COMPANY_NAME_MAX)\n if (!name) {\n res.status(400).json({ error: 'A company needs a name' })\n return\n }\n const rawDomain = String(body.createCompany.domain ?? '').trim()\n const domain = rawDomain ? normalizeCompanyDomain(rawDomain) : null\n if (rawDomain && !domain) {\n res.status(400).json({ error: 'That does not look like a domain' })\n return\n }\n createCompany = { name, domain }\n }\n let deal: {\n title: string\n amountCents: number | null\n currency: string\n stageId: string | undefined\n } | null = null\n if (body.deal) {\n const title = String(body.deal.title ?? '')\n .trim()\n .slice(0, DEAL_TITLE_MAX)\n if (!title) {\n res.status(400).json({ error: 'A deal needs a title' })\n return\n }\n const amount = Number(body.deal.amountCents)\n const currency = String(body.deal.currency ?? '')\n .trim()\n .toLowerCase()\n deal = {\n title,\n amountCents:\n Number.isFinite(amount) && amount >= 0 ? Math.round(amount) : null,\n currency: CURRENCY_PATTERN.test(currency) ? currency : 'usd',\n stageId: body.deal.stageId ? String(body.deal.stageId) : undefined,\n }\n }\n\n try {\n const decoded = await firebaseAdmin.app().auth().verifyIdToken(idToken)\n const staff = decoded['staff'] === true\n /*\n * The console's own gate on the CRM is `data.manage`, asked of the\n * permission catalog (`holdsDataManage`), and additionally that the\n * caller has a role on THIS site — an org member scoped to a sibling site\n * holds the key but not the host, and a lead is the host's record.\n * `resolveOrgPermissions` answers the site role and fails closed on a\n * lookup error when a host is named, so an absent membership refuses.\n */\n const membership = await resolveOrgPermissions(decoded.uid, { hostId })\n if (\n !staff &&\n !(membership.hostRole && (await holdsDataManage(membership.orgId, decoded.uid)))\n ) {\n res\n .status(403)\n .json({ error: 'Converting a lead requires the data permission on this site' })\n return\n }\n\n const resolved = await getOrgForHost(hostId)\n if (!resolved) {\n res.status(404).json({ error: 'Unknown site' })\n return\n }\n const { orgId, org } = resolved\n // A lead's conversion is the CRM's, like its status and owner (AGL-2787).\n const suite = crmSuiteRefusal(org, 'Converting a lead')\n if (suite) {\n res.status(suite.status).json(suite.body)\n return\n }\n const result = await convertHostLead({\n firestore: firebaseAdmin.app().firestore(),\n hostId,\n orgId,\n org: org as Record<string, unknown>,\n leadId,\n actor: { uid: decoded.uid, email: decoded.email ?? null, kind: 'member' },\n ...(body.ownerUid ? { ownerUid: String(body.ownerUid) } : {}),\n ...(requestedCompanyId ? { companyId: requestedCompanyId } : {}),\n createCompany,\n deal,\n })\n if (result.ok === false) {\n const refusal = REFUSALS[result.reason]\n res.status(refusal.status).json(refusal.body)\n return\n }\n const answer: LeadConvertResponse = {\n ok: true,\n contactId: result.contactId,\n ...(result.companyId ? { companyId: result.companyId } : {}),\n ...(result.dealId ? { dealId: result.dealId } : {}),\n alreadyConverted: result.alreadyConverted,\n }\n res.status(200).json(answer)\n } catch (error) {\n console.error('lead-convert failed', error)\n res.status(500).json({ error: 'The lead could not be converted.' })\n }\n}\n\nexport default leadConvertHandler\n"],"names":["CONTACT_ERASED_MESSAGE","CRM_RECORDS_BAND_FULL_MESSAGE","normalizeCompanyDomain","firebaseAdmin","getOrgForHost","convertHostLead","resolveOrgPermissions","holdsDataManage","crmSuiteRefusal","stageForNewDeal","COMPANY_NAME_MAX","DEAL_TITLE_MAX","CURRENCY_PATTERN","REFUSALS","status","body","error","reason","erased","leadConvertHandler","req","res","method","setHeader","json","authorization","String","headers","idToken","startsWith","slice","length","undefined","JSON","parse","hostId","trim","leadId","requestedCompanyId","companyId","createCompany","name","rawDomain","domain","deal","title","amount","Number","amountCents","currency","toLowerCase","isFinite","Math","round","test","stageId","decoded","app","auth","verifyIdToken","staff","membership","uid","hostRole","orgId","resolved","org","suite","result","firestore","actor","email","kind","ownerUid","ok","refusal","answer","contactId","dealId","alreadyConverted","console"],"mappings":"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"}