@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,466 @@
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
+ * BRINGING A SPREADSHEET OF PEOPLE INTO THE CRM — the pure half (AGL-2602).
18
+ *
19
+ * A merchant arriving from another CRM has a CSV: a header row naming
20
+ * columns in that product's vocabulary, and one person per line. Nothing
21
+ * about that file is in our shape. This module is every decision about the
22
+ * file that needs no Firestore and no React — which columns mean what, how a
23
+ * cell becomes a stored value, and what to say about a row that cannot be
24
+ * stored — so that the console drawer and the server route read the same
25
+ * rules rather than two copies of them.
26
+ *
27
+ * ## Three stages, and only the last one touches a record
28
+ *
29
+ * 1. {@link guessContactImportMapping} reads the header and proposes a
30
+ * column → field mapping from a table of aliases. It is a PROPOSAL: the
31
+ * drawer shows it and the operator corrects it, because an export's
32
+ * "Company" column may hold a job title and no alias table can know.
33
+ * 2. {@link mapContactImportRow} applies the mapping to one line, producing
34
+ * the raw row the browser posts. Strings only — the browser trims nothing
35
+ * and validates nothing, so the server is the one place the file is
36
+ * judged and a stale drawer cannot judge it differently.
37
+ * 3. {@link normalizeContactImportRow} turns a raw row into the values that
38
+ * will be written, through the SAME normalizers every other door uses:
39
+ * `normalizeContactEmail` for the dedupe key, `normalizePhone` for E.164,
40
+ * `normalizeAddress` for the postal shape, `isContactLifecycleStage` for
41
+ * the stage. An importer with its own idea of a valid phone number is how
42
+ * one collection ends up storing a value three ways.
43
+ *
44
+ * ## A bad cell is dropped and named; a bad row is skipped and named
45
+ *
46
+ * The only thing that makes a row unstorable is an unusable address, because
47
+ * the address is the identity the shared row is keyed by. Everything else is
48
+ * a value on the row: a phone that cannot be read as a number is left off
49
+ * the contact and REPORTED under {@link ContactImportRow.dropped}, so the
50
+ * operator learns that forty rows had a phone in a format we could not read
51
+ * rather than discovering, weeks later, that the phone column silently went
52
+ * nowhere. `list-import.ts` applies the same rule to a line that is not an
53
+ * address: reported, never quietly discarded.
54
+ *
55
+ * ## Ceilings are on the work, never on the audience
56
+ *
57
+ * {@link CONTACT_IMPORT_MAX_ROWS} bounds one FILE, and the drawer says so
58
+ * before anything is sent. {@link CONTACT_IMPORT_CHUNK_SIZE} bounds one
59
+ * REQUEST, so a five-thousand-row file is twenty-five requests with a
60
+ * progress bar between them rather than one that times out halfway with no
61
+ * record of what it did. Neither one ever trims a person to fit: a row past
62
+ * the file ceiling is refused with the file, and a row is never dropped to
63
+ * make a chunk smaller. The audience band is enforced where every capture
64
+ * enforces it — inside `upsertHostContact` — and an import reports that
65
+ * refusal per row rather than pre-empting it with a count of its own.
66
+ */ import { _ as _extends } from "@swc/helpers/_/_extends";
67
+ import { normalizeAddress, normalizePhone } from "@aglyn/aglyn/foundation/definitions/contact.types";
68
+ import { normalizeContactEmail } from "@aglyn/aglyn/app-utils/contacts";
69
+ import { CSV_IMPORT_CHUNK_SIZE, CSV_IMPORT_MAX_BODY_BYTES, CSV_IMPORT_MAX_ROWS, CSV_IMPORT_PREVIEW_ROWS, customImportTarget, emptyImportResult, guessImportMapping, importAliasKeys, importSkippedCsv, importTextValue, mapImportRow, mergeImportResults, parseImportFlag, parseImportTags } from "@aglyn/aglyn/app-utils/csv-import";
70
+ import { CONTACT_LIFECYCLE_STAGE_LABELS, CONTACT_LIFECYCLE_STAGES, isContactLifecycleStage } from "@aglyn/aglyn/app-utils/crm";
71
+ /*
72
+ * The custom-target grammar is the shared module's; it is re-exported here
73
+ * because every reader of a contact mapping has always taken it from this
74
+ * file, and the companies import reads the same two functions from theirs.
75
+ */ export { customImportTarget, customImportTargetKey } from "@aglyn/aglyn/app-utils/csv-import";
76
+ /**
77
+ * The ceilings are the shared ones (`csv-import.ts`), under the names this
78
+ * file has always exported: one file, one request and one preview are
79
+ * bounded the same way for every collection, because the bounds are about
80
+ * the browser's memory and a request's budget rather than about people.
81
+ */ export const CONTACT_IMPORT_MAX_ROWS = CSV_IMPORT_MAX_ROWS;
82
+ export const CONTACT_IMPORT_CHUNK_SIZE = CSV_IMPORT_CHUNK_SIZE;
83
+ export const CONTACT_IMPORT_MAX_BODY_BYTES = CSV_IMPORT_MAX_BODY_BYTES;
84
+ export const CONTACT_IMPORT_PREVIEW_ROWS = CSV_IMPORT_PREVIEW_ROWS;
85
+ /**
86
+ * The most tags one row may carry — the profile drawer's own cap, so an
87
+ * imported person cannot hold more tags than a hand-edited one.
88
+ */ export const CONTACT_IMPORT_TAGS_MAX = 20;
89
+ /** The longest text a name, title, company name or custom text value keeps. */ const NAME_MAX = 120;
90
+ const CUSTOM_TEXT_MAX = 1000;
91
+ /**
92
+ * The standard fields a column may be mapped to, in the order the mapping
93
+ * menu lists them. A custom field is mapped by its key — see
94
+ * {@link ContactImportTargetId}.
95
+ */ export const CONTACT_IMPORT_FIELDS = [
96
+ 'email',
97
+ 'name',
98
+ 'phone',
99
+ 'jobTitle',
100
+ 'companyName',
101
+ 'addressLine1',
102
+ 'addressLine2',
103
+ 'addressCity',
104
+ 'addressState',
105
+ 'addressPostalCode',
106
+ 'addressCountry',
107
+ 'tags',
108
+ 'ownerEmail',
109
+ 'lifecycleStage',
110
+ 'marketingConsent'
111
+ ];
112
+ /** How each field reads in the mapping menu. Typed so a field cannot ship unlabeled. */ export const CONTACT_IMPORT_FIELD_LABELS = {
113
+ email: 'Email (required)',
114
+ name: 'Name',
115
+ phone: 'Phone',
116
+ jobTitle: 'Job title',
117
+ companyName: 'Company name',
118
+ addressLine1: 'Address line 1',
119
+ addressLine2: 'Address line 2',
120
+ addressCity: 'City',
121
+ addressState: 'State or region',
122
+ addressPostalCode: 'Postal code',
123
+ addressCountry: 'Country (two-letter code)',
124
+ tags: 'Tags (comma or | separated)',
125
+ ownerEmail: 'Owner (team member email)',
126
+ lifecycleStage: 'Lifecycle stage',
127
+ marketingConsent: 'Marketing consent (yes/no)'
128
+ };
129
+ /**
130
+ * Header aliases per field, matched after `importHeaderKey` normalization.
131
+ *
132
+ * The vocabulary of the exports people actually arrive with — HubSpot's
133
+ * "First Name"/"Last Name" pair is deliberately NOT here, because two columns
134
+ * cannot map to one field and a guess that took only the first name would
135
+ * store half a name and look right in the preview. An operator with a split
136
+ * name maps one of the two by hand, and the preview shows what they chose.
137
+ */ const FIELD_ALIASES = {
138
+ email: [
139
+ 'email',
140
+ 'email address',
141
+ 'e-mail',
142
+ 'e-mail address',
143
+ 'contact email',
144
+ 'primary email',
145
+ 'work email'
146
+ ],
147
+ name: [
148
+ 'name',
149
+ 'full name',
150
+ 'contact name',
151
+ 'display name',
152
+ 'person'
153
+ ],
154
+ phone: [
155
+ 'phone',
156
+ 'phone number',
157
+ 'telephone',
158
+ 'mobile',
159
+ 'mobile phone',
160
+ 'cell',
161
+ 'work phone'
162
+ ],
163
+ jobTitle: [
164
+ 'job title',
165
+ 'title',
166
+ 'position',
167
+ 'role'
168
+ ],
169
+ companyName: [
170
+ 'company',
171
+ 'company name',
172
+ 'organization',
173
+ 'organisation',
174
+ 'account'
175
+ ],
176
+ addressLine1: [
177
+ 'address',
178
+ 'address line 1',
179
+ 'street',
180
+ 'street address',
181
+ 'address 1'
182
+ ],
183
+ addressLine2: [
184
+ 'address line 2',
185
+ 'address 2',
186
+ 'street 2',
187
+ 'apartment',
188
+ 'suite'
189
+ ],
190
+ addressCity: [
191
+ 'city',
192
+ 'town',
193
+ 'locality'
194
+ ],
195
+ addressState: [
196
+ 'state',
197
+ 'region',
198
+ 'province',
199
+ 'county',
200
+ 'state/region'
201
+ ],
202
+ addressPostalCode: [
203
+ 'postal code',
204
+ 'postcode',
205
+ 'zip',
206
+ 'zip code',
207
+ 'post code'
208
+ ],
209
+ addressCountry: [
210
+ 'country',
211
+ 'country code',
212
+ 'country/region'
213
+ ],
214
+ tags: [
215
+ 'tags',
216
+ 'tag',
217
+ 'labels',
218
+ 'groups',
219
+ 'segments'
220
+ ],
221
+ ownerEmail: [
222
+ 'owner',
223
+ 'owner email',
224
+ 'contact owner',
225
+ 'assigned to',
226
+ 'account owner'
227
+ ],
228
+ lifecycleStage: [
229
+ 'lifecycle stage',
230
+ 'stage',
231
+ 'lifecycle',
232
+ 'status',
233
+ 'lead status'
234
+ ],
235
+ marketingConsent: [
236
+ 'marketing consent',
237
+ 'consent',
238
+ 'opt in',
239
+ 'opt-in',
240
+ 'opted in',
241
+ 'subscribed',
242
+ 'marketing opt in',
243
+ 'email consent'
244
+ ]
245
+ };
246
+ /** {@link FIELD_ALIASES}, normalized once for the matcher. */ const FIELD_ALIAS_KEYS = importAliasKeys(CONTACT_IMPORT_FIELDS, FIELD_ALIASES);
247
+ /**
248
+ * A proposed mapping from a file's header row — the shared matcher over the
249
+ * contact vocabulary. Custom fields win over standard aliases when a header
250
+ * matches a definition's label or key exactly: a merchant who defined a
251
+ * field called "Status" meant THEIR status, not our lifecycle stage.
252
+ */ export function guessContactImportMapping(columns, fields = []) {
253
+ return guessImportMapping(columns, CONTACT_IMPORT_FIELDS, FIELD_ALIAS_KEYS, fields);
254
+ }
255
+ /** One parsed line under the mapping. Empty cells are left absent. */ export function mapContactImportRow(cells, mapping) {
256
+ return mapImportRow(cells, mapping);
257
+ }
258
+ /** How a skip reason reads on screen and in the downloaded file. */ export const CONTACT_IMPORT_SKIP_LABELS = {
259
+ 'invalid-email': 'Not a valid email address',
260
+ duplicate: 'Appears earlier in the file',
261
+ 'audience-band': 'Contact limit reached',
262
+ erased: 'Erased from this workspace at their request',
263
+ 'write-failed': 'Could not be saved'
264
+ };
265
+ /**
266
+ * A tag cell as the tags it names.
267
+ *
268
+ * `|` or `,` separated — the CSV export writes `|`, most other products
269
+ * write `,` — lowercased and trimmed like the profile drawer's own tag
270
+ * field, so an imported `VIP` and a typed `vip` are one tag and not two.
271
+ */ export function parseContactImportTags(value) {
272
+ return parseImportTags(value, CONTACT_IMPORT_TAGS_MAX);
273
+ }
274
+ /**
275
+ * A yes/no cell as a boolean, or `null` when it is neither.
276
+ *
277
+ * The affirmatives are the ones consent and checkbox columns actually
278
+ * carry; the negatives are listed so that an explicit `no` is a `false`
279
+ * rather than an unreadable value that gets reported as dropped.
280
+ */ export function parseContactImportFlag(value) {
281
+ return parseImportFlag(value);
282
+ }
283
+ /**
284
+ * A stage cell as a stage, accepting the stored id (`sales-qualified`), its
285
+ * label ("Sales qualified") and the spellings between them
286
+ * (`Sales_Qualified`), or `null` when it names none of them.
287
+ */ export function parseContactImportLifecycleStage(value) {
288
+ const text = String(value != null ? value : '').trim().toLowerCase();
289
+ if (!text) return null;
290
+ const key = text.replace(/[\s_]+/g, '-');
291
+ if (isContactLifecycleStage(key)) return key;
292
+ for (const stage of CONTACT_LIFECYCLE_STAGES){
293
+ if (CONTACT_LIFECYCLE_STAGE_LABELS[stage].toLowerCase() === text) return stage;
294
+ }
295
+ return null;
296
+ }
297
+ /**
298
+ * A cell as the value a custom field of this type stores.
299
+ *
300
+ * `{ value }` when it read, `{ value: undefined }` for a blank cell (nothing
301
+ * to write and nothing to report), and `null` when the cell held something
302
+ * the type cannot hold — a word in a number field, a choice a select does
303
+ * not offer. A date is stored as epoch milliseconds, the shape every other
304
+ * timestamp on a CRM record takes (`dueAtMs`, `expectedCloseAtMs`).
305
+ */ export function parseContactImportCustomValue(definition, value) {
306
+ const text = String(value != null ? value : '').trim();
307
+ if (!text) return {
308
+ value: undefined
309
+ };
310
+ switch(definition.type){
311
+ case 'text':
312
+ case 'url':
313
+ return {
314
+ value: text.slice(0, CUSTOM_TEXT_MAX)
315
+ };
316
+ case 'number':
317
+ {
318
+ const number = Number(text.replace(/[,\s$€£]/g, ''));
319
+ return Number.isFinite(number) ? {
320
+ value: number
321
+ } : null;
322
+ }
323
+ case 'date':
324
+ {
325
+ const ms = Date.parse(text);
326
+ return Number.isFinite(ms) ? {
327
+ value: ms
328
+ } : null;
329
+ }
330
+ case 'select':
331
+ {
332
+ var _definition_options;
333
+ const wanted = text.toLowerCase();
334
+ const option = ((_definition_options = definition.options) != null ? _definition_options : []).find((candidate)=>String(candidate).trim().toLowerCase() === wanted);
335
+ return option === undefined ? null : {
336
+ value: String(option)
337
+ };
338
+ }
339
+ case 'checkbox':
340
+ {
341
+ const flag = parseContactImportFlag(text);
342
+ return flag === null ? null : {
343
+ value: flag
344
+ };
345
+ }
346
+ default:
347
+ return null;
348
+ }
349
+ }
350
+ /**
351
+ * One raw row as the values that will be written, or the reason it cannot
352
+ * be.
353
+ *
354
+ * `fields` is the holder's live definitions: a custom value under a key
355
+ * with no definition is dropped and reported, because a value nobody
356
+ * defined a field for is a value no form will ever show.
357
+ */ export function normalizeContactImportRow(raw, fields = []) {
358
+ const email = normalizeContactEmail(raw.email);
359
+ if (!email) {
360
+ var _raw_email;
361
+ return {
362
+ ok: false,
363
+ reason: 'invalid-email',
364
+ input: String((_raw_email = raw.email) != null ? _raw_email : '').trim()
365
+ };
366
+ }
367
+ const dropped = [];
368
+ const drop = (field, value)=>{
369
+ dropped.push({
370
+ field,
371
+ value: String(value != null ? value : '').trim()
372
+ });
373
+ };
374
+ const row = {
375
+ email,
376
+ tags: parseContactImportTags(raw.tags),
377
+ marketingConsent: false,
378
+ custom: {},
379
+ dropped
380
+ };
381
+ const name = importTextValue(raw.name, NAME_MAX);
382
+ if (name) row.name = name;
383
+ const jobTitle = importTextValue(raw.jobTitle, NAME_MAX);
384
+ if (jobTitle) row.jobTitle = jobTitle;
385
+ const companyName = importTextValue(raw.companyName, NAME_MAX);
386
+ if (companyName) row.companyName = companyName;
387
+ const phoneText = importTextValue(raw.phone, 64);
388
+ if (phoneText) {
389
+ const phone = normalizePhone(phoneText);
390
+ if (phone) row.phone = phone;
391
+ else drop('phone', phoneText);
392
+ }
393
+ const address = normalizeAddress({
394
+ line1: importTextValue(raw.addressLine1, 200),
395
+ line2: importTextValue(raw.addressLine2, 200),
396
+ city: importTextValue(raw.addressCity, 120),
397
+ state: importTextValue(raw.addressState, 120),
398
+ postalCode: importTextValue(raw.addressPostalCode, 32),
399
+ country: importTextValue(raw.addressCountry, 8)
400
+ });
401
+ if (address) row.address = address;
402
+ // The country is the one address part the normalizer drops silently — a
403
+ // typed name is not a code — so it is the one part the report has to name.
404
+ const countryText = importTextValue(raw.addressCountry, 64);
405
+ if (countryText && !(address == null ? void 0 : address.country)) drop('addressCountry', countryText);
406
+ const ownerText = importTextValue(raw.ownerEmail, 320);
407
+ if (ownerText) {
408
+ const owner = normalizeContactEmail(ownerText);
409
+ if (owner) row.ownerEmail = owner;
410
+ else drop('ownerEmail', ownerText);
411
+ }
412
+ const stageText = importTextValue(raw.lifecycleStage, 64);
413
+ if (stageText) {
414
+ const stage = parseContactImportLifecycleStage(stageText);
415
+ if (stage) row.lifecycleStage = stage;
416
+ else drop('lifecycleStage', stageText);
417
+ }
418
+ const consentText = raw.marketingConsent;
419
+ if (consentText !== undefined && consentText !== null && String(consentText).trim()) {
420
+ const flag = parseContactImportFlag(consentText);
421
+ if (flag === null) drop('marketingConsent', consentText);
422
+ else row.marketingConsent = flag;
423
+ }
424
+ const custom = raw.custom && typeof raw.custom === 'object' && !Array.isArray(raw.custom) ? raw.custom : {};
425
+ const definitions = new Map(fields.map((field)=>[
426
+ field.key,
427
+ field
428
+ ]));
429
+ for (const [key, value] of Object.entries(custom)){
430
+ const definition = definitions.get(key);
431
+ if (!definition) {
432
+ drop(customImportTarget(key), value);
433
+ continue;
434
+ }
435
+ const parsed = parseContactImportCustomValue(definition, value);
436
+ if (!parsed) drop(customImportTarget(key), value);
437
+ else if (parsed.value !== undefined) row.custom[key] = parsed.value;
438
+ }
439
+ return {
440
+ ok: true,
441
+ row
442
+ };
443
+ }
444
+ /** An empty tally, for the drawer to fold chunk results into. */ export function emptyContactImportResult() {
445
+ return _extends({}, emptyImportResult(), {
446
+ companiesCreated: 0
447
+ });
448
+ }
449
+ /**
450
+ * Two results as one — the shared fold, with the company tally beside it.
451
+ * `offset` is where the chunk started in the file, so a skipped row's index
452
+ * comes back as its position in the FILE rather than in the request.
453
+ */ export function mergeContactImportResults(total, chunk, offset = 0) {
454
+ var _chunk_companiesCreated;
455
+ return _extends({}, mergeImportResults(total, chunk, offset), {
456
+ companiesCreated: total.companiesCreated + Number((_chunk_companiesCreated = chunk.companiesCreated) != null ? _chunk_companiesCreated : 0)
457
+ });
458
+ }
459
+ /**
460
+ * The skipped rows as a file the operator can fix and re-import: the
461
+ * original columns verbatim plus a trailing `Skipped because` column.
462
+ */ export function contactImportSkippedCsv(columns, entries) {
463
+ return importSkippedCsv(columns, entries, CONTACT_IMPORT_SKIP_LABELS);
464
+ }
465
+
466
+ //# sourceMappingURL=crm-import.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/crm/src/lib/model/crm-import.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 * BRINGING A SPREADSHEET OF PEOPLE INTO THE CRM — the pure half (AGL-2602).\n *\n * A merchant arriving from another CRM has a CSV: a header row naming\n * columns in that product's vocabulary, and one person per line. Nothing\n * about that file is in our shape. This module is every decision about the\n * file that needs no Firestore and no React — which columns mean what, how a\n * cell becomes a stored value, and what to say about a row that cannot be\n * stored — so that the console drawer and the server route read the same\n * rules rather than two copies of them.\n *\n * ## Three stages, and only the last one touches a record\n *\n * 1. {@link guessContactImportMapping} reads the header and proposes a\n * column → field mapping from a table of aliases. It is a PROPOSAL: the\n * drawer shows it and the operator corrects it, because an export's\n * \"Company\" column may hold a job title and no alias table can know.\n * 2. {@link mapContactImportRow} applies the mapping to one line, producing\n * the raw row the browser posts. Strings only — the browser trims nothing\n * and validates nothing, so the server is the one place the file is\n * judged and a stale drawer cannot judge it differently.\n * 3. {@link normalizeContactImportRow} turns a raw row into the values that\n * will be written, through the SAME normalizers every other door uses:\n * `normalizeContactEmail` for the dedupe key, `normalizePhone` for E.164,\n * `normalizeAddress` for the postal shape, `isContactLifecycleStage` for\n * the stage. An importer with its own idea of a valid phone number is how\n * one collection ends up storing a value three ways.\n *\n * ## A bad cell is dropped and named; a bad row is skipped and named\n *\n * The only thing that makes a row unstorable is an unusable address, because\n * the address is the identity the shared row is keyed by. Everything else is\n * a value on the row: a phone that cannot be read as a number is left off\n * the contact and REPORTED under {@link ContactImportRow.dropped}, so the\n * operator learns that forty rows had a phone in a format we could not read\n * rather than discovering, weeks later, that the phone column silently went\n * nowhere. `list-import.ts` applies the same rule to a line that is not an\n * address: reported, never quietly discarded.\n *\n * ## Ceilings are on the work, never on the audience\n *\n * {@link CONTACT_IMPORT_MAX_ROWS} bounds one FILE, and the drawer says so\n * before anything is sent. {@link CONTACT_IMPORT_CHUNK_SIZE} bounds one\n * REQUEST, so a five-thousand-row file is twenty-five requests with a\n * progress bar between them rather than one that times out halfway with no\n * record of what it did. Neither one ever trims a person to fit: a row past\n * the file ceiling is refused with the file, and a row is never dropped to\n * make a chunk smaller. The audience band is enforced where every capture\n * enforces it — inside `upsertHostContact` — and an import reports that\n * refusal per row rather than pre-empting it with a count of its own.\n */\n\nimport type { AglynPostalAddress } from '@aglyn/aglyn/foundation/definitions/contact.types'\nimport { normalizeAddress, normalizePhone } from '@aglyn/aglyn/foundation/definitions/contact.types'\nimport { normalizeContactEmail } from '@aglyn/aglyn/app-utils/contacts'\nimport {\n CSV_IMPORT_CHUNK_SIZE,\n CSV_IMPORT_MAX_BODY_BYTES,\n CSV_IMPORT_MAX_ROWS,\n CSV_IMPORT_PREVIEW_ROWS,\n customImportTarget,\n customImportTargetKey,\n emptyImportResult,\n guessImportMapping,\n importAliasKeys,\n type ImportChunkResult,\n type ImportDroppedValue,\n importSkippedCsv,\n importTextValue,\n mapImportRow,\n mergeImportResults,\n parseImportFlag,\n parseImportTags,\n} from '@aglyn/aglyn/app-utils/csv-import'\nimport {\n CONTACT_LIFECYCLE_STAGE_LABELS,\n CONTACT_LIFECYCLE_STAGES,\n type ContactCustomValue,\n type ContactFieldDefinition,\n type ContactLifecycleStage,\n isContactLifecycleStage,\n} from '@aglyn/aglyn/app-utils/crm'\n\n/*\n * The custom-target grammar is the shared module's; it is re-exported here\n * because every reader of a contact mapping has always taken it from this\n * file, and the companies import reads the same two functions from theirs.\n */\nexport { customImportTarget, customImportTargetKey } from '@aglyn/aglyn/app-utils/csv-import'\n\n/**\n * The ceilings are the shared ones (`csv-import.ts`), under the names this\n * file has always exported: one file, one request and one preview are\n * bounded the same way for every collection, because the bounds are about\n * the browser's memory and a request's budget rather than about people.\n */\nexport const CONTACT_IMPORT_MAX_ROWS = CSV_IMPORT_MAX_ROWS\n\nexport const CONTACT_IMPORT_CHUNK_SIZE = CSV_IMPORT_CHUNK_SIZE\n\nexport const CONTACT_IMPORT_MAX_BODY_BYTES = CSV_IMPORT_MAX_BODY_BYTES\n\nexport const CONTACT_IMPORT_PREVIEW_ROWS = CSV_IMPORT_PREVIEW_ROWS\n\n/**\n * The most tags one row may carry — the profile drawer's own cap, so an\n * imported person cannot hold more tags than a hand-edited one.\n */\nexport const CONTACT_IMPORT_TAGS_MAX = 20\n\n/** The longest text a name, title, company name or custom text value keeps. */\nconst NAME_MAX = 120\nconst CUSTOM_TEXT_MAX = 1_000\n\n/**\n * The standard fields a column may be mapped to, in the order the mapping\n * menu lists them. A custom field is mapped by its key — see\n * {@link ContactImportTargetId}.\n */\nexport const CONTACT_IMPORT_FIELDS = [\n 'email',\n 'name',\n 'phone',\n 'jobTitle',\n 'companyName',\n 'addressLine1',\n 'addressLine2',\n 'addressCity',\n 'addressState',\n 'addressPostalCode',\n 'addressCountry',\n 'tags',\n 'ownerEmail',\n 'lifecycleStage',\n 'marketingConsent',\n] as const\n\nexport type ContactImportField = (typeof CONTACT_IMPORT_FIELDS)[number]\n\n/** How each field reads in the mapping menu. Typed so a field cannot ship unlabeled. */\nexport const CONTACT_IMPORT_FIELD_LABELS: Record<ContactImportField, string> = {\n email: 'Email (required)',\n name: 'Name',\n phone: 'Phone',\n jobTitle: 'Job title',\n companyName: 'Company name',\n addressLine1: 'Address line 1',\n addressLine2: 'Address line 2',\n addressCity: 'City',\n addressState: 'State or region',\n addressPostalCode: 'Postal code',\n addressCountry: 'Country (two-letter code)',\n tags: 'Tags (comma or | separated)',\n ownerEmail: 'Owner (team member email)',\n lifecycleStage: 'Lifecycle stage',\n marketingConsent: 'Marketing consent (yes/no)',\n}\n\n/**\n * Header aliases per field, matched after `importHeaderKey` normalization.\n *\n * The vocabulary of the exports people actually arrive with — HubSpot's\n * \"First Name\"/\"Last Name\" pair is deliberately NOT here, because two columns\n * cannot map to one field and a guess that took only the first name would\n * store half a name and look right in the preview. An operator with a split\n * name maps one of the two by hand, and the preview shows what they chose.\n */\nconst FIELD_ALIASES: Record<ContactImportField, readonly string[]> = {\n email: [\n 'email',\n 'email address',\n 'e-mail',\n 'e-mail address',\n 'contact email',\n 'primary email',\n 'work email',\n ],\n name: ['name', 'full name', 'contact name', 'display name', 'person'],\n phone: [\n 'phone',\n 'phone number',\n 'telephone',\n 'mobile',\n 'mobile phone',\n 'cell',\n 'work phone',\n ],\n jobTitle: ['job title', 'title', 'position', 'role'],\n companyName: ['company', 'company name', 'organization', 'organisation', 'account'],\n addressLine1: ['address', 'address line 1', 'street', 'street address', 'address 1'],\n addressLine2: ['address line 2', 'address 2', 'street 2', 'apartment', 'suite'],\n addressCity: ['city', 'town', 'locality'],\n addressState: ['state', 'region', 'province', 'county', 'state/region'],\n addressPostalCode: ['postal code', 'postcode', 'zip', 'zip code', 'post code'],\n addressCountry: ['country', 'country code', 'country/region'],\n tags: ['tags', 'tag', 'labels', 'groups', 'segments'],\n ownerEmail: ['owner', 'owner email', 'contact owner', 'assigned to', 'account owner'],\n lifecycleStage: ['lifecycle stage', 'stage', 'lifecycle', 'status', 'lead status'],\n marketingConsent: [\n 'marketing consent',\n 'consent',\n 'opt in',\n 'opt-in',\n 'opted in',\n 'subscribed',\n 'marketing opt in',\n 'email consent',\n ],\n}\n\n/**\n * What a column is mapped to: a standard field by name, or a custom field\n * as `custom:<key>` — see `customImportTarget`.\n */\nexport type ContactImportTargetId = ContactImportField | `custom:${string}`\n\n/** Column index → target. A column absent from the map is not imported. */\nexport type ContactImportMapping = Record<number, ContactImportTargetId>\n\n/** {@link FIELD_ALIASES}, normalized once for the matcher. */\nconst FIELD_ALIAS_KEYS = importAliasKeys(CONTACT_IMPORT_FIELDS, FIELD_ALIASES)\n\n/**\n * A proposed mapping from a file's header row — the shared matcher over the\n * contact vocabulary. Custom fields win over standard aliases when a header\n * matches a definition's label or key exactly: a merchant who defined a\n * field called \"Status\" meant THEIR status, not our lifecycle stage.\n */\nexport function guessContactImportMapping(\n columns: readonly string[],\n fields: readonly Pick<ContactFieldDefinition, 'key' | 'label'>[] = [],\n): ContactImportMapping {\n return guessImportMapping(columns, CONTACT_IMPORT_FIELDS, FIELD_ALIAS_KEYS, fields)\n}\n\n/**\n * What the browser posts for one line: the cells the mapping selected,\n * under the field they were mapped to, verbatim.\n *\n * Values are `unknown` because the server reads this off an untrusted body;\n * the mapper below only ever writes strings into it.\n */\nexport interface ContactImportRawRow {\n email?: unknown\n name?: unknown\n phone?: unknown\n jobTitle?: unknown\n companyName?: unknown\n addressLine1?: unknown\n addressLine2?: unknown\n addressCity?: unknown\n addressState?: unknown\n addressPostalCode?: unknown\n addressCountry?: unknown\n tags?: unknown\n ownerEmail?: unknown\n lifecycleStage?: unknown\n marketingConsent?: unknown\n /** Custom values keyed by definition key. */\n custom?: unknown\n}\n\n/** One parsed line under the mapping. Empty cells are left absent. */\nexport function mapContactImportRow(\n cells: readonly string[],\n mapping: ContactImportMapping,\n): ContactImportRawRow {\n return mapImportRow(cells, mapping)\n}\n\n/** Why one row was not stored. */\nexport type ContactImportSkipReason =\n | 'invalid-email'\n | 'duplicate'\n | 'audience-band'\n /** The person was erased from this workspace at their request (AGL-2623). */\n | 'erased'\n | 'write-failed'\n\n/** How a skip reason reads on screen and in the downloaded file. */\nexport const CONTACT_IMPORT_SKIP_LABELS: Record<ContactImportSkipReason, string> = {\n 'invalid-email': 'Not a valid email address',\n duplicate: 'Appears earlier in the file',\n 'audience-band': 'Contact limit reached',\n erased: 'Erased from this workspace at their request',\n 'write-failed': 'Could not be saved',\n}\n\n/** A cell the file carried that could not be read as the field it was mapped to. */\nexport type ContactImportDroppedValue = ImportDroppedValue\n\n/** One row, ready to be written. */\nexport interface ContactImportRow {\n email: string\n name?: string\n /** E.164. */\n phone?: string\n jobTitle?: string\n companyName?: string\n address?: AglynPostalAddress\n /** Lowercased, deduplicated, capped at {@link CONTACT_IMPORT_TAGS_MAX}. */\n tags: string[]\n /** Normalized, for the server to resolve against the org's members. */\n ownerEmail?: string\n lifecycleStage?: ContactLifecycleStage\n marketingConsent: boolean\n /** Only the keys whose definition the caller supplied and whose value read. */\n custom: Record<string, ContactCustomValue>\n dropped: ContactImportDroppedValue[]\n}\n\nexport type ContactImportRowVerdict =\n | { ok: true; row: ContactImportRow }\n | { ok: false; reason: 'invalid-email'; input: string }\n\n/**\n * A tag cell as the tags it names.\n *\n * `|` or `,` separated — the CSV export writes `|`, most other products\n * write `,` — lowercased and trimmed like the profile drawer's own tag\n * field, so an imported `VIP` and a typed `vip` are one tag and not two.\n */\nexport function parseContactImportTags(value: unknown): string[] {\n return parseImportTags(value, CONTACT_IMPORT_TAGS_MAX)\n}\n\n/**\n * A yes/no cell as a boolean, or `null` when it is neither.\n *\n * The affirmatives are the ones consent and checkbox columns actually\n * carry; the negatives are listed so that an explicit `no` is a `false`\n * rather than an unreadable value that gets reported as dropped.\n */\nexport function parseContactImportFlag(value: unknown): boolean | null {\n return parseImportFlag(value)\n}\n\n/**\n * A stage cell as a stage, accepting the stored id (`sales-qualified`), its\n * label (\"Sales qualified\") and the spellings between them\n * (`Sales_Qualified`), or `null` when it names none of them.\n */\nexport function parseContactImportLifecycleStage(\n value: unknown,\n): ContactLifecycleStage | null {\n const text = String(value ?? '')\n .trim()\n .toLowerCase()\n if (!text) return null\n const key = text.replace(/[\\s_]+/g, '-')\n if (isContactLifecycleStage(key)) return key\n for (const stage of CONTACT_LIFECYCLE_STAGES) {\n if (CONTACT_LIFECYCLE_STAGE_LABELS[stage].toLowerCase() === text) return stage\n }\n return null\n}\n\n/**\n * A cell as the value a custom field of this type stores.\n *\n * `{ value }` when it read, `{ value: undefined }` for a blank cell (nothing\n * to write and nothing to report), and `null` when the cell held something\n * the type cannot hold — a word in a number field, a choice a select does\n * not offer. A date is stored as epoch milliseconds, the shape every other\n * timestamp on a CRM record takes (`dueAtMs`, `expectedCloseAtMs`).\n */\nexport function parseContactImportCustomValue(\n definition: Pick<ContactFieldDefinition, 'type' | 'options'>,\n value: unknown,\n): { value: ContactCustomValue | undefined } | null {\n const text = String(value ?? '').trim()\n if (!text) return { value: undefined }\n switch (definition.type) {\n case 'text':\n case 'url':\n return { value: text.slice(0, CUSTOM_TEXT_MAX) }\n case 'number': {\n const number = Number(text.replace(/[,\\s$€£]/g, ''))\n return Number.isFinite(number) ? { value: number } : null\n }\n case 'date': {\n const ms = Date.parse(text)\n return Number.isFinite(ms) ? { value: ms } : null\n }\n case 'select': {\n const wanted = text.toLowerCase()\n const option = (definition.options ?? []).find(\n (candidate) => String(candidate).trim().toLowerCase() === wanted,\n )\n return option === undefined ? null : { value: String(option) }\n }\n case 'checkbox': {\n const flag = parseContactImportFlag(text)\n return flag === null ? null : { value: flag }\n }\n default:\n return null\n }\n}\n\n/**\n * One raw row as the values that will be written, or the reason it cannot\n * be.\n *\n * `fields` is the holder's live definitions: a custom value under a key\n * with no definition is dropped and reported, because a value nobody\n * defined a field for is a value no form will ever show.\n */\nexport function normalizeContactImportRow(\n raw: ContactImportRawRow,\n fields: readonly Pick<ContactFieldDefinition, 'key' | 'type' | 'options'>[] = [],\n): ContactImportRowVerdict {\n const email = normalizeContactEmail(raw.email)\n if (!email) {\n return { ok: false, reason: 'invalid-email', input: String(raw.email ?? '').trim() }\n }\n const dropped: ContactImportDroppedValue[] = []\n const drop = (field: string, value: unknown) => {\n dropped.push({ field, value: String(value ?? '').trim() })\n }\n\n const row: ContactImportRow = {\n email,\n tags: parseContactImportTags(raw.tags),\n marketingConsent: false,\n custom: {},\n dropped,\n }\n\n const name = importTextValue(raw.name, NAME_MAX)\n if (name) row.name = name\n const jobTitle = importTextValue(raw.jobTitle, NAME_MAX)\n if (jobTitle) row.jobTitle = jobTitle\n const companyName = importTextValue(raw.companyName, NAME_MAX)\n if (companyName) row.companyName = companyName\n\n const phoneText = importTextValue(raw.phone, 64)\n if (phoneText) {\n const phone = normalizePhone(phoneText)\n if (phone) row.phone = phone\n else drop('phone', phoneText)\n }\n\n const address = normalizeAddress({\n line1: importTextValue(raw.addressLine1, 200),\n line2: importTextValue(raw.addressLine2, 200),\n city: importTextValue(raw.addressCity, 120),\n state: importTextValue(raw.addressState, 120),\n postalCode: importTextValue(raw.addressPostalCode, 32),\n country: importTextValue(raw.addressCountry, 8),\n })\n if (address) row.address = address\n // The country is the one address part the normalizer drops silently — a\n // typed name is not a code — so it is the one part the report has to name.\n const countryText = importTextValue(raw.addressCountry, 64)\n if (countryText && !address?.country) drop('addressCountry', countryText)\n\n const ownerText = importTextValue(raw.ownerEmail, 320)\n if (ownerText) {\n const owner = normalizeContactEmail(ownerText)\n if (owner) row.ownerEmail = owner\n else drop('ownerEmail', ownerText)\n }\n\n const stageText = importTextValue(raw.lifecycleStage, 64)\n if (stageText) {\n const stage = parseContactImportLifecycleStage(stageText)\n if (stage) row.lifecycleStage = stage\n else drop('lifecycleStage', stageText)\n }\n\n const consentText = raw.marketingConsent\n if (consentText !== undefined && consentText !== null && String(consentText).trim()) {\n const flag = parseContactImportFlag(consentText)\n if (flag === null) drop('marketingConsent', consentText)\n else row.marketingConsent = flag\n }\n\n const custom =\n raw.custom && typeof raw.custom === 'object' && !Array.isArray(raw.custom)\n ? (raw.custom as Record<string, unknown>)\n : {}\n const definitions = new Map(fields.map((field) => [field.key, field]))\n for (const [key, value] of Object.entries(custom)) {\n const definition = definitions.get(key)\n if (!definition) {\n drop(customImportTarget(key), value)\n continue\n }\n const parsed = parseContactImportCustomValue(definition, value)\n if (!parsed) drop(customImportTarget(key), value)\n else if (parsed.value !== undefined) row.custom[key] = parsed.value\n }\n\n return { ok: true, row }\n}\n\n/** One row the server did not store, by its index in the request, named by address. */\nexport interface ContactImportSkippedRow {\n index: number\n email: string\n reason: ContactImportSkipReason\n}\n\n/**\n * What one request did — the shared tally plus how many companies the\n * company column brought into being. The drawer sums these across a file.\n */\nexport interface ContactImportChunkResult\n extends ImportChunkResult<ContactImportSkippedRow> {\n companiesCreated: number\n}\n\n/** An empty tally, for the drawer to fold chunk results into. */\nexport function emptyContactImportResult(): ContactImportChunkResult {\n return { ...emptyImportResult<ContactImportSkippedRow>(), companiesCreated: 0 }\n}\n\n/**\n * Two results as one — the shared fold, with the company tally beside it.\n * `offset` is where the chunk started in the file, so a skipped row's index\n * comes back as its position in the FILE rather than in the request.\n */\nexport function mergeContactImportResults(\n total: ContactImportChunkResult,\n chunk: ContactImportChunkResult,\n offset = 0,\n): ContactImportChunkResult {\n return {\n ...mergeImportResults(total, chunk, offset),\n companiesCreated: total.companiesCreated + Number(chunk.companiesCreated ?? 0),\n }\n}\n\n/**\n * The skipped rows as a file the operator can fix and re-import: the\n * original columns verbatim plus a trailing `Skipped because` column.\n */\nexport function contactImportSkippedCsv(\n columns: readonly string[],\n entries: readonly { cells: readonly string[]; reason: ContactImportSkipReason }[],\n): string {\n return importSkippedCsv(columns, entries, CONTACT_IMPORT_SKIP_LABELS)\n}\n"],"names":["normalizeAddress","normalizePhone","normalizeContactEmail","CSV_IMPORT_CHUNK_SIZE","CSV_IMPORT_MAX_BODY_BYTES","CSV_IMPORT_MAX_ROWS","CSV_IMPORT_PREVIEW_ROWS","customImportTarget","emptyImportResult","guessImportMapping","importAliasKeys","importSkippedCsv","importTextValue","mapImportRow","mergeImportResults","parseImportFlag","parseImportTags","CONTACT_LIFECYCLE_STAGE_LABELS","CONTACT_LIFECYCLE_STAGES","isContactLifecycleStage","customImportTargetKey","CONTACT_IMPORT_MAX_ROWS","CONTACT_IMPORT_CHUNK_SIZE","CONTACT_IMPORT_MAX_BODY_BYTES","CONTACT_IMPORT_PREVIEW_ROWS","CONTACT_IMPORT_TAGS_MAX","NAME_MAX","CUSTOM_TEXT_MAX","CONTACT_IMPORT_FIELDS","CONTACT_IMPORT_FIELD_LABELS","email","name","phone","jobTitle","companyName","addressLine1","addressLine2","addressCity","addressState","addressPostalCode","addressCountry","tags","ownerEmail","lifecycleStage","marketingConsent","FIELD_ALIASES","FIELD_ALIAS_KEYS","guessContactImportMapping","columns","fields","mapContactImportRow","cells","mapping","CONTACT_IMPORT_SKIP_LABELS","duplicate","erased","parseContactImportTags","value","parseContactImportFlag","parseContactImportLifecycleStage","text","String","trim","toLowerCase","key","replace","stage","parseContactImportCustomValue","definition","undefined","type","slice","number","Number","isFinite","ms","Date","parse","wanted","option","options","find","candidate","flag","normalizeContactImportRow","raw","ok","reason","input","dropped","drop","field","push","row","custom","phoneText","address","line1","line2","city","state","postalCode","country","countryText","ownerText","owner","stageText","consentText","Array","isArray","definitions","Map","map","Object","entries","get","parsed","emptyContactImportResult","companiesCreated","mergeContactImportResults","total","chunk","offset","contactImportSkippedCsv"],"mappings":"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"}
@@ -0,0 +1,105 @@
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 CrmLeadStatus } from '@aglyn/aglyn/app-utils/crm';
18
+ import { type ImportChunkResult, type ImportDroppedValue } from '@aglyn/aglyn/app-utils/csv-import';
19
+ /** The shared ceilings, under this collection's names. */
20
+ export declare const LEAD_IMPORT_MAX_ROWS = 5000;
21
+ export declare const LEAD_IMPORT_CHUNK_SIZE = 200;
22
+ export declare const LEAD_IMPORT_MAX_BODY_BYTES = 2000000;
23
+ export declare const LEAD_IMPORT_PREVIEW_ROWS = 10;
24
+ /** The same caps the lead's own cards hold a typed value to. */
25
+ export declare const LEAD_IMPORT_NOTES_MAX = 4000;
26
+ export declare const LEAD_IMPORT_REASON_MAX = 500;
27
+ /**
28
+ * The statuses a file may set.
29
+ *
30
+ * The list's own status control offers exactly these three, and for the
31
+ * reason given above: `qualified` is written by the conversion, beside the
32
+ * contact it produced.
33
+ */
34
+ export declare const LEAD_IMPORT_STATUSES: readonly CrmLeadStatus[];
35
+ /** The fields a column may be mapped to, in the order the mapping menu lists them. */
36
+ export declare const LEAD_IMPORT_FIELDS: readonly ["email", "name", "status", "ownerEmail", "unqualifiedReason", "notes"];
37
+ export type LeadImportField = (typeof LEAD_IMPORT_FIELDS)[number];
38
+ /** How each field reads in the mapping menu. Typed so a field cannot ship unlabeled. */
39
+ export declare const LEAD_IMPORT_FIELD_LABELS: Record<LeadImportField, string>;
40
+ /** Column index → field. A column absent from the map is not imported. */
41
+ export type LeadImportMapping = Record<number, LeadImportField>;
42
+ /** A proposed mapping from a file's header row, each field taken at most once. */
43
+ export declare function guessLeadImportMapping(columns: readonly string[]): LeadImportMapping;
44
+ /**
45
+ * What the browser posts for one line: the cells the mapping selected,
46
+ * under the field they were mapped to, verbatim. `unknown` because the
47
+ * server reads this off an untrusted body.
48
+ */
49
+ export type LeadImportRawRow = Partial<Record<LeadImportField, unknown>>;
50
+ /** One parsed line under the mapping. Empty cells are left absent; a lead has no custom fields. */
51
+ export declare function mapLeadImportRow(cells: readonly string[], mapping: Record<number, LeadImportField | `custom:${string}`>): LeadImportRawRow;
52
+ export type LeadImportSkipReason = 'invalid-email' | 'duplicate' | 'lead-ceiling' | 'write-failed';
53
+ /** How a skip reason reads on screen and in the downloaded file. */
54
+ export declare const LEAD_IMPORT_SKIP_LABELS: Record<LeadImportSkipReason, string>;
55
+ /** One row, ready for the server to resolve and write. */
56
+ export interface LeadImportRow {
57
+ /** Normalized — the address `personKey` derives the document id from. */
58
+ email: string;
59
+ name?: string;
60
+ /** Absent leaves an existing lead's status alone and a new one reading as `new`. */
61
+ status?: CrmLeadStatus;
62
+ /** Normalized, for the server to resolve against the org's members. */
63
+ ownerEmail?: string;
64
+ /** Only ever set beside `status: 'unqualified'` — the pair is one fact. */
65
+ unqualifiedReason?: string;
66
+ notes?: string;
67
+ dropped: ImportDroppedValue[];
68
+ }
69
+ export type LeadImportRowVerdict = {
70
+ ok: true;
71
+ row: LeadImportRow;
72
+ } | {
73
+ ok: false;
74
+ reason: 'invalid-email';
75
+ input: string;
76
+ };
77
+ /**
78
+ * A status cell by id or by label — `working`, `Working` and `WORKING` are
79
+ * one status. `null` for a cell naming no status a file may set, which
80
+ * includes the well-spelled `Qualified` the export writes for a converted
81
+ * lead.
82
+ */
83
+ export declare function parseImportLeadStatus(value: unknown): CrmLeadStatus | null;
84
+ /**
85
+ * One raw row as the values that will be written, or the reason it cannot
86
+ * be. Refused here only for an unusable address, because the address is
87
+ * the document id; the owner is refused by the server, which alone can
88
+ * look them up.
89
+ */
90
+ export declare function normalizeLeadImportRow(raw: LeadImportRawRow): LeadImportRowVerdict;
91
+ /** One row the server did not store, by its index in the request, named by the address. */
92
+ export interface LeadImportSkippedRow {
93
+ index: number;
94
+ email: string;
95
+ reason: LeadImportSkipReason;
96
+ }
97
+ /** What one request did. The drawer sums these across a file. */
98
+ export type LeadImportChunkResult = ImportChunkResult<LeadImportSkippedRow>;
99
+ export declare function emptyLeadImportResult(): LeadImportChunkResult;
100
+ export declare function mergeLeadImportResults(total: LeadImportChunkResult, chunk: LeadImportChunkResult, offset?: number): LeadImportChunkResult;
101
+ /** The skipped rows as a file the operator can fix and re-import. */
102
+ export declare function leadImportSkippedCsv(columns: readonly string[], entries: readonly {
103
+ cells: readonly string[];
104
+ reason: LeadImportSkipReason;
105
+ }[]): string;